返回文章列表

多雲環境高用性Jenkins佈署實踐

本文闡述如何利用 Packer 與 Terraform 在多雲環境下佈署高用性 Jenkins 叢集,涵蓋 Azure 虛擬機器映像建立、Terraform 基礎設施佈署、虛擬網路設定與 Azure Bastion 安全存取等關鍵步驟,並提供程式碼範例與詳細引數說明,有效提升 CI/CD 流程效率。

DevOps 雲端運算

在現代軟體開發流程中,持續整合與持續交付(CI/CD)至關重要。Jenkins 作為常用的自動化伺服器,其高用性佈署更是不可或缺。本文將著重於 Packer 和 Terraform 的運用,實作多雲環境下 Jenkins 叢集的建置與管理,特別針對 Azure 平台進行實務操作說明,包含映像建立、網路設定、安全存取等導向,以確保 Jenkins 服務的穩定性和可靠性。此方法能有效降低佈署成本、提升自動化程度,並確保 CI/CD 流程的順暢執行。

在多雲供應商上佈署高用性 Jenkins

使用 Packer 建立 Azure 映像

在 Azure 上建立 Jenkins worker 和 master 映像,需要使用 Packer。以下是一個範例的 template.json 檔案,用於建立 Jenkins worker 映像:

{
  "variables": {
    "subscription_id": "{{user `subscription_id`}}",
    "client_id": "{{user `client_id`}}",
    "client_secret": "{{user `client_secret`}}",
    "tenant_id": "{{user `tenant_id`}}",
    "resource_group": "{{user `resource_group`}}",
    "location": "{{user `location`}}"
  },
  "builders": [
    {
      "type": "azure-arm",
      "subscription_id": "{{user `subscription_id`}}",
      "client_id": "{{user `client_id`}}",
      "client_secret": "{{user `client_secret`}}",
      "tenant_id": "{{user `tenant_id`}}",
      "managed_image_resource_group_name": "{{user `resource_group`}}",
      "managed_image_name": "jenkins-worker",
      "os_type": "Linux",
      "image_publisher": "OpenLogic",
      "image_offer": "CentOS",
      "image_sku": "8.0",
      "location": "{{user `location`}}",
      "vm_size": "Standard_B1s"
    }
  ],
  "provisioners": [
    {
      "type": "shell",
      "script": "./setup.sh",
      "execute_command": "sudo -E -S sh '{{ .Path }}'"
    }
  ]
}

內容解密:

  • 使用 azure-arm builder 型別來建立 Azure 資源。
  • 需要提供 Azure 的訂閱 ID、客戶端 ID、客戶端密碼和租戶 ID。
  • 使用 CentOS 8.0 作為基礎映像,並安裝必要的依賴項。
  • 使用 setup.sh 指令碼來安裝 Jenkins worker 所需的軟體。

建立 Jenkins Master 映像

建立 Jenkins master 映像的流程與建立 worker 映像類別似,只是需要修改一些引數。以下是一個範例的 template.json 檔案,用於建立 Jenkins master 映像:

{
  "variables": {
    ...
  },
  "builders": [
    {
      "type": "azure-arm",
      "subscription_id": "{{user `subscription_id`}}",
      "client_id": "{{user `client_id`}}",
      "client_secret": "{{user `client_secret`}}",
      "tenant_id": "{{user `tenant_id`}}",
      "managed_image_resource_group_name": "{{user `resource_group`}}",
      "managed_image_name": "jenkins-master-v22041",
      "os_type": "Linux",
      "image_publisher": "OpenLogic",
      "image_offer": "CentOS",
      "image_sku": "8.0",
      "location": "{{user `location`}}",
      "vm_size": "Standard_B1ms"
    }
  ],
  "provisioners": [
    ...
  ]
}

內容解密:

  • 建立 Jenkins master 映像的流程與建立 worker 映像類別似。
  • 需要修改 managed_image_namevm_size 等引數。

使用 Terraform 佈署虛擬網路

在佈署 Jenkins 叢集之前,需要建立一個虛擬網路。以下是一個範例的 virtual_network.tf 檔案,用於建立虛擬網路:

data "azurerm_resource_group" "management" {
  name = var.resource_group
}

resource "azurerm_virtual_network" "management" {
  name                = "management"
  location            = var.location
  resource_group_name = data.azurerm_resource_group.management.name
  address_space       = [var.base_cidr_block]
  dns_servers         = ["10.0.0.4", "10.0.0.5"]

  dynamic "subnet" {
    for_each = [for s in var.subnets: {
      name = s.name
      prefix = cidrsubnet(var.base_cidr_block, 8, s.number)
    }]
    content {
      name          = subnet.value.name
      address_prefix = subnet.value.prefix
    }
  }

  subnet {
    name          = "AzureBastionSubnet"
    address_prefix = cidrsubnet(var.base_cidr_block, 11, 224)
  }

  tags = {
    environment = "management"
  }
}

圖表翻譯:

此圖表呈現了虛擬網路的架構,包括公有和私有子網路,以及一個專用的 AzureBastionSubnet 子網路。

此虛擬網路的建立是為了確保 Jenkins 叢集的安全性和可管理性。

Terraform變數定義

Terraform 使用變數來引數化和自定義佈署。以下是一些常用的變數:

名稱型別描述
subscription_idStringNone要使用的訂閱 ID。也可以從 ARM_SUBSCRIPTION_ID 環境變數中取得。
client_idStringNone要使用的客戶端 ID。也可以從 ARM_CLIENT_ID 環境變數中取得。
client_secretStringNone要使用的客戶端密碼。也可以從 ARM_CLIENT_SECRET 環境變數中取得。
tenant_idStringNone要使用的租戶/目錄 ID。也可以從 ARM_TENANT_ID 環境變數中取得。
resource_groupStringNone要在其中建立虛擬網路的資源群組名稱。
locationStringNone要建立虛擬網路的位置/區域。更改此值會強制建立新的資源。
base_cidr_blockString10.0.0.0/16用於虛擬網路的位址空間(CIDR區塊)。
subnetsMapNone要在虛擬網路中建立的子網路列表。

圖表翻譯:

此表格呈現了 Terraform 中定義的變數及其描述,有助於瞭解每個變數的作用和用途。

綜上所述,本文介紹瞭如何使用 Packer 和 Terraform 在 Azure 上佈署高用性的 Jenkins 叢集。首先,使用 Packer 建立了 Jenkins worker 和 master 的映像;然後,使用 Terraform 建立了一個虛擬網路,以確保 Jenkins 叢集的安全性和可管理性。

在 Azure 上佈署高用性 Jenkins 叢集

使用 Azure Bastion 服務實作安全存取

為了安全地存取私有 Jenkins 機器,需要佈署一個閘道或代理伺服器,也就是所謂的跳板機(jump box)或堡壘主機(bastion host)。Azure 提供了一個稱為 Azure Bastion 的受控服務,可以提供遠端桌面協定(RDP)和 SSH 存取任何虛擬機器,而無需管理一個強化的堡壘例項並應用安全補丁(無維運開銷)。

建立 Azure Bastion 服務

首先,建立一個名為 bastion.tf 的檔案,內容如下:

resource "azurerm_public_ip" "bastion_public_ip" {
  name                = "bastion-public-ip"
  location            = var.location
  resource_group_name = data.azurerm_resource_group.management.name
  allocation_method   = "Static"
  sku                 = "Standard"
}

data "azurerm_subnet" "bastion_subnet" {
  name                 = "AzureBastionSubnet"
  virtual_network_name = azurerm_virtual_network.management.name
  resource_group_name = data.azurerm_resource_group.management.name
  depends_on           = [azurerm_virtual_network.management]
}

resource "azurerm_bastion_host" "bastion" {
  name                = "bastion"
  location            = var.location
  resource_group_name = data.azurerm_resource_group.management.name
  depends_on          = [azurerm_virtual_network.management]

  ip_configuration {
    name                 = "bastion-configuration"
    subnet_id            = data.azurerm_subnet.bastion_subnet.id
    public_ip_address_id = azurerm_public_ip.bastion_public_ip.id
  }
}

output "bastion" {
  value = azurerm_public_ip.bastion_public_ip.ip_address
}

程式碼說明

  1. 建立公用 IP 位址azurerm_public_ip 資源用於請求一個靜態的公用 IP 位址。
  2. 參考子網路data "azurerm_subnet" 用於參考將要建立堡壘主機的子網路。
  3. 建立 Azure Bastion 主機azurerm_bastion_host 資源用於建立 Azure Bastion 主機,並將其與公用 IP 位址和子網路關聯。
  4. 輸出 Bastion IP 位址:使用 output 將 Bastion 主機的公用 IP 位址輸出。

佈署 Jenkins 主虛擬機器

在 VPN 佈署完成後,可以開始佈署 Jenkins 叢集。目標架構如圖所示。

建立 Jenkins 主虛擬機器

定義 jenkins_master.tf 檔案中的資源如下:

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

resource "azurerm_virtual_machine" "jenkins_master" {
  name                  = "jenkins-master"
  resource_group_name  = data.azurerm_resource_group.management.name
  location              = var.location
  vm_size               = var.jenkins_vm_size
  network_interface_ids = [
    azurerm_network_interface.jenkins_network_interface.id,
  ]

  os_profile {
    computer_name  = var.config["os_name"]
    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)
    }
  }

  storage_os_disk {
    name              = "main"
    caching           = "ReadWrite"
    managed_disk_type = "Standard_LRS"
    create_option     = "FromImage"
    disk_size_gb      = "30"
  }

  storage_image_reference {
    id = data.azurerm_image.jenkins_master_image.id
  }

  delete_os_disk_on_termination = true
}

網路介面組態

data "azurerm_subnet" "private_subnet" {
  name                 = var.subnets[2].name
  virtual_network_name = azurerm_virtual_network.management.name
  resource_group_name = data.azurerm_resource_group.management.name
  depends_on           = [azurerm_virtual_network.management]
}

resource "azurerm_network_interface" "jenkins_network_interface" {
  name                = "jenkins_network_interface"
  location            = var.location
  resource_group_name = data.azurerm_resource_group.management.name
  depends_on          = [azurerm_virtual_network.management]

  ip_configuration {
    name                          = "internal"
    subnet_id                     = data.azurerm_subnet.private_subnet.id
    private_ip_address_allocation = "Dynamic"
  }
}

程式碼說明

  1. 參考 Jenkins 主映像data "azurerm_image" 用於參考先前使用 Packer 建立的 Jenkins 主映像。
  2. 建立虛擬機器azurerm_virtual_machine 資源用於建立 Jenkins 主虛擬機器。
  3. 網路介面組態azurerm_network_interface 資源用於將 Jenkins 主虛擬機器連線到私有網路子網路。
  4. SSH 金鑰組態:在 os_profile_linux_config 中停用密碼驗證並啟用 SSH 金鑰驗證。