在建置 CI/CD 流程時,有效管理 Jenkins Worker 至關重要。本文將分享我如何使用 Terraform 在 Azure 上設定 Jenkins Worker 的自動調整規模功能,讓 Worker 能夠根據負載自動增減,提升效率並節省成本。

利用 Terraform 佈署與動態調整 Azure Jenkins Worker

為了將建置任務從 Jenkins Master 解除安裝,我們需要佈署 Jenkins Worker。這些 Worker 將位於自動調整規模集中,允許根據需求動態佈建。

設定虛擬機器擴充功能集

首先,我們需要在機器擴充功能集中佈署 Jenkins Worker 機器。這些機器將根據我們先前使用 Packer 建置的 Jenkins Worker 映像檔,並佈署在私有子網路中。以下的 jenkins_workers.tf 檔案展示瞭如何設定:

data "azurerm_image" "jenkins_worker_image" {
  name                = var.jenkins_worker_image
  resource_group_name = data.azurerm_resource_group.management.name
}

resource "azurerm_virtual_machine_scale_set" "jenkins_workers_set" {
  name                = "jenkins-workers-set"
  location            = var.location
  resource_group_name = data.azurerm_resource_group.management.name
  upgrade_policy_mode = "Manual"

  sku {
    name     = var.jenkins_vm_size
    tier     = "Standard"
    capacity = 2
  }

  storage_profile_image_reference {
    id = data.azurerm_image.jenkins_worker_image.id
  }

  storage_profile_os_disk {
    caching           = "ReadWrite"
    create_option     = "FromImage"
    managed_disk_type = "Standard_LRS"
  }

  os_profile {
    computer_name_prefix  = "jenkins-worker"
    admin_username        = var.config["vm_username"]
  }

  os_profile_linux_config {
    disable_password_authentication = true
    ssh_keys {
      path     = "/home/${var.config["vm_username"]}/.ssh/authorized_keys"
      key_data = file(var.public_ssh_key)
    }
  }

  network_profile {
    name    = "private-network"
    primary = true
    network_security_group_id = azurerm_network_security_group.jenkins_worker_security_group.id

    ip_configuration {
      name                          = "private-ip-configuration"
      primary                       = true
      subnet_id                     = data.azurerm_subnet.private_subnet.id
      load_balancer_backend_address_pools_ids = [
        azurerm_lb_backend_address_pool.jenkins_backend.id
      ]
    }
  }
}

這段程式碼定義了一個 Azure 虛擬機器擴充功能集。namelocationresource_group_name 分別指定了名稱、位元置和資源群組。upgrade_policy_mode 設定為 “Manual”,表格示升級需要手動觸發。sku 區塊定義了虛擬機器的規格,套件括名稱、層級和初始容量。storage_profile 設定了儲存選項,os_profile 設定了作業系統相關設定,例如電腦名稱字首和管理員使用者名稱。os_profile_linux_config 停用了密碼驗證,並設定了 SSH 金鑰。network_profile 將虛擬機器連線到私有網路,並關聯到負載平衡器和網路安全群組。

每個 Jenkins Worker 機器在啟動時都會執行一個自訂指令碼 (join-cluster.tpl),用於加入 Jenkins 叢集。以下程式碼片段展示瞭如何使用 template_file data source 來管理這個指令碼:

data "template_file" "jenkins_worker_startup_script" {
  template = file("scripts/join-cluster.tpl")

  vars = {
    jenkins_url          = "http://${azurerm_public_ip.jenkins_lb_public_ip.ip_address}:8080"
    jenkins_username     = var.jenkins_username
    jenkins_password     = var.jenkins_password
    jenkins_credentials_id = var.jenkins_credentials_id
  }
}

這段程式碼定義了一個名為 jenkins_worker_startup_scripttemplate_file data source。它會讀取 scripts/join-cluster.tpl 檔案,並使用 vars 區塊中定義的變數來渲染這個範本。這些變數包含了 Jenkins 的 URL、使用者名稱、密碼和憑證 ID,以便指令碼可以連線到 Jenkins Master 並加入叢集。

這個指令碼會利用 Azure Instance Metadata Service (IMDS) 取得機器的私有 IP 位元址和主機名稱,然後向 Jenkins RESTful API 傳送 POST 請求,建立雙向連線並將 Worker 加入叢集。

為了提升安全性,我們將網路安全群組附加到虛擬網路介面。以下程式碼片段展示瞭如何設定安全群組規則,允許 SSH 連線:

resource "azurerm_network_security_group" "jenkins_worker_security_group" {
  name                = "jenkins-worker-sg"
  location            = var.location
  resource_group_name = data.azurerm_resource_group.management.name

  security_rule {
    name                       = "AllowSSH"
    priority                   = 100
    direction                  = "Inbound"
    access                     = "Allow"
    protocol                   = "Tcp"
    source_port_range          = "*"
    destination_port_range     = "22"
    source_address_prefix      = "*"
    destination_address_prefix = "*"
  }
}

這段程式碼建立了一個名為 jenkins-worker-sg 的網路安全群組,並定義了一個名為 AllowSSH 的入站安全規則。這個規則允許從任何來源 IP 位元址 (*) 的任何連線埠 (*) 透過 TCP 協定連線到目標連線埠 22 (SSH)。

(後續內容待補充)

##  DigitalOcean 上的 Jenkins 叢集佈署:Terraform 的應用程式

在雲端運算領域,AzureGoogle Cloud  AWS 通常是大家耳熟能詳的選項。然而,DigitalOcean 作為一個相對較新的平台,以其簡潔性、易用性和價格優勢,成為許多開發者的首選,尤其對於初創公司和資源有限的團隊而言更是如此。我個人在一些專案中也體驗過 DigitalOcean 的優勢,它能讓我快速佈署和管理虛擬機器,而不會迷失在複雜的服務目錄中。

本文將探討如何利用 Terraform  DigitalOcean 上佈署 Jenkins 叢集,套件含 Master  Worker 節點的設定,並分享一些我在實務中獲得的經驗和技巧。

###  準備階段:API 權杖與快照建立

在開始之前,我們需要先產生 DigitalOcean API 權杖,賦予其讀取和寫入許可權。此權杖將用於 Packer  Terraform  DigitalOcean 進行互動。

接下來,我們將使用 Packer 建立 Jenkins Worker  Master 的映像檔快照。以下列出建立 Worker 快照的 Packer 範本:

```json
{
  "variables": {
    "api_token": "YOUR_DIGITALOCEAN_API_TOKEN",
    "region": "YOUR_DIGITALOCEAN_REGION"
  },
  "builders": [
    {
      "type": "digitalocean",
      "api_token": "{{user `api_token`}}",
      "image": "centos-8-x64",
      "region": "{{user `region`}}",
      "size": "512mb",
      "ssh_username": "root",
      "snapshot_name": "jenkins-worker"
    }
  ],
  "provisioners": [
    {
      "type": "shell",
      "script": "./setup.sh",
      "execute_command": "sudo -E -S sh '{{ .Path }}'"
    }
  ]
}

這個 Packer 範本定義瞭如何建立 DigitalOcean Droplet 並將其變形為快照。builders 區塊指定了使用 digitalocean 建置器,並設定了 API 權杖、區域、Droplet 大小、SSH 使用者名稱和快照名稱等引數。provisioners 區塊則定義了在 Droplet 建立後執行的 shell 指令碼 setup.sh,用於安裝 Jenkins Worker 所需的工具。

執行 packer build template.json 命令後,Packer 會根據此範本建立一個 CentOS 8 Droplet,執行 setup.sh 指令碼進行初始化設定,最後將 Droplet 儲存為名為 jenkins-worker 的快照。

同樣地,我們也需要建立 Jenkins Master 的快照。Master 快照的 Packer 範本與 Worker 類別似,但需要額外設定 Jenkins 憑證,以便與 Worker 建立 SSH 連線。

Terraform 佈署:Jenkins Master

設定好快照後,我們就可以開始使用 Terraform 進行佈署。首先,在 terraform.tf 檔案中宣告 DigitalOcean 供應商,並設定 API 權杖:

provider "digitalocean" {
  token = var.token
}

接著,在 jenkins_master.tf 檔案中定義 Jenkins Master Droplet 資源:

data "digitalocean_image" "jenkins_master_image" {
  name = var.jenkins_master_image
}

resource "digitalocean_droplet" "jenkins_master" {
  name   = "jenkins-master"
  image  = data.digitalocean_image.jenkins_master_image.id
  region = var.region
  size   = "s-1vcpu-2gb"
  ssh_keys = [var.ssh_fingerprint]
}

這段程式碼定義了一個名為 jenkins-masterdigitalocean_droplet 資源。它使用了先前建立的 Jenkins Master 快照作為映像檔,並設定了 Droplet 的名稱、區域、大小和 SSH 金鑰。s-1vcpu-2gb Droplet 類別型提供 2GB 記憶體和 1 個 vCPU,適用於小型 Jenkins 叢集。對於更大規模的叢集,建議選擇更大規格的 Droplet。

Terraform 佈署:Jenkins Worker

最後,在 jenkins_workers.tf 檔案中定義 Jenkins Worker Droplet 資源:

data "digitalocean_image" "jenkins_worker_image" {
  name = var.jenkins_worker_image
}

data "template_file" "jenkins_worker_startup_script" {
  template = "${file("scripts/join-cluster.tpl")}"

  vars = {
    jenkins_url          = "http://${digitalocean_droplet.jenkins_master.ipv4_address}:8080"
    jenkins_username     = var.jenkins_username
    jenkins_password     = var.jenkins_password
    jenkins_credentials_id = var.jenkins_credentials_id
  }
}

resource "digitalocean_droplet" "jenkins_workers" {
  count  = var.jenkins_workers_count
  name   = "jenkins-worker"
  image  = data.digitalocean_image.jenkins_worker_image.id
  region = var.region
  size   = "s-1vcpu-2gb"
  ssh_keys = [var.ssh_fingerprint]
  user_data = data.template_file.jenkins_worker_startup_script.rendered
  depends_on = [digitalocean_droplet.jenkins_master]
}

這段程式碼定義了多個 Jenkins Worker Droplet,數量由 jenkins_workers_count 變數決定。每個 Worker 使用先前建立的 jenkins-worker 快照作為映像檔,並透過 user_data 屬性執行 join-cluster.tpl 指令碼,將 Worker 自動加入 Jenkins 叢集。depends_on 屬性確保 Worker 在 Master 建立完成後才開始建立。

透過以上步驟,我們可以利用 Terraform 和 Packer 在 DigitalOcean 上快速佈署 Jenkins 叢集。使用 Terraform 管理基礎設施,可以提高佈署效率、確保一致性,並方便日後維護和擴充功能。在我的經驗中,使用 Terraform 模組可以進一步簡化設定,提高程式碼的可重用性。

  graph LR
subgraph Packer
    A[Jenkins Master Image] --> B(DigitalOcean Snapshot)
    C[Jenkins Worker Image] --> D(DigitalOcean Snapshot)
end
subgraph Terraform
    B --> E(Jenkins Master Droplet)
    D --> F(Jenkins Worker Droplet)
    F --> G(Join Jenkins Cluster)
end
E --> G

上圖展示了 Packer 和 Terraform 如何協同工作,構建和佈署 Jenkins 叢集。Packer 負責建立 Jenkins Master 和 Worker 的映像檔快照,而 Terraform 則負責將這些快照佈署到 DigitalOcean,並將 Worker 加入叢集。

在實際應用程式中,建議根據專案需求調整 Droplet 的大小和數量,並設定適當的監控和告警機制,確保叢集的穩定性和效能。 使用 Terraform 設定 DigitalOcean Jenkins Worker,開發自動化基礎設施

在建構 CI/CD 流程時,自動化基礎設施的建立至關重要。本文將探討如何利用 Terraform 在 DigitalOcean 上設定 Jenkins Worker,實作可重複、一致與安全的基礎架構自動化。

設定 Jenkins Worker Droplet

首先,我們需要定義 DigitalOcean Droplet 資源,作為 Jenkins Worker 的執行環境。以下程式碼片段展示瞭如何使用 Terraform 建立 Droplet:

resource "digitalocean_droplet" "jenkins_workers" {
  count = var.worker_count
  name   = "jenkins-worker-${count.index}"
  image  = "ubuntu-20-04-x64"
  region = "nyc3"
  size   = "s-1vcpu-1gb"
  ssh_keys = [var.ssh_key_fingerprint]
  user_data = <<-EOT
    #!/bin/bash
    INSTANCE_NAME=$(curl -s http://169.254.169.254/metadata/v1/hostname)
    INSTANCE_IP=$(curl -s http://169.254.169.254/metadata/v1/interfaces/public/0/ipv4/address)
    # ... 其他啟動指令碼 ...
  EOT
  depends_on = [digitalocean_droplet.jenkins_master]
}

這段程式碼定義了一組 DigitalOcean Droplet,數量由 worker_count 變數決定。每個 Droplet 使用 Ubuntu 20.04 映像檔,位元於 nyc3 區域,並使用指定的 SSH 金鑰。user_data 屬性包含啟動指令碼,用於設定 Droplet,例如取得 Droplet 的 IP 位元址和主機名稱。depends_on 屬性確保 Jenkins Master Droplet 先於 Worker 建立。

設定防火牆規則

為了確保 Jenkins Master 和 Worker 之間的通訊安全,我們需要設定防火牆規則。以下程式碼片段展示瞭如何使用 Terraform 建立防火牆:

resource "digitalocean_firewall" "jenkins_workers_firewall" {
  name        = "jenkins-workers-firewall"
  droplet_ids = [for worker in digitalocean_droplet.jenkins_workers : worker.id]

  inbound_rule {
    protocol         = "tcp"
    port_range       = "22"
    source_droplet_ids = [digitalocean_droplet.jenkins_master.id]
  }
}

這段程式碼建立了一個名為 “jenkins-workers-firewall” 的防火牆,並將其應用程式於所有 Jenkins Worker Droplet。防火牆規則允許從 Jenkins Master Droplet 的 TCP 連線埠 22 的輸入流量,確保 SSH 連線的安全性。

驗證佈署

完成 Terraform 設定後,幾分鐘內 Worker Droplet 就會完成佈建。您可以在 DigitalOcean 儀錶板中檢視 Droplet 狀態。回到 Jenkins 儀錶板,啟動指令碼執行完成後,新的 Worker 就會自動加入叢集。

實務建議與進階技巧

在實際應用程式中,我建議使用 Terraform 模組來管理 DigitalOcean 佈署。模組化可以簡化組態,提高程式碼的可重複使用性和可維護性。此外,可以考慮使用 DigitalOcean 提供的 Load Balancer 來分配 Worker 負載,提高系統的容錯性和可擴充功能性。

為 Microservices 架構定義 CI Pipeline

接下來,我們將探討如何為 Microservices 架構定義 CI Pipeline。這將涵蓋程式碼組織策略、多分支 Pipeline 設定,以及使用 GitHub Webhook 觸發建置。同時,我們也會比較單一儲存函式庫和多個儲存函式庫的優缺點,並提供一些最佳實踐建議。

建構高效的 CI/CD 流程對於現代軟體開發至關重要。透過自動化基礎設施的建立和維護,可以顯著提高開發效率,縮短交付週期,並確保系統的穩定性和可靠性。本文提供的 Terraform 設定範例和實務建議,可以幫助您快速搭建 DigitalOcean Jenkins Worker 環境,並為 Microservices 架構構建穩固的 CI/CD 基礎。