在 DevOps 實踐中,基礎設施即程式碼 (IaC) 已成為不可或缺的一環。本文將詳細說明如何利用 Terraform 和 Azure DevOps 建構自動化的基礎設施佈署流程,提升團隊開發效率並確保系統穩定性。首先,我們會透過 Azure Pipelines 將 Terraform 組態檔案釋出至 Azure 儲存函式庫,實作持續整合。接著,利用持續交付管道,從儲存函式庫提取組態檔案,並將 Terraform 狀態檔案安全地儲存在 Azure 儲存帳戶中。此流程確保每次變更皆有紀錄可循,並方便團隊協作。此外,我們也會探討如何將 Azure Pipelines 與 Azure 儲存帳戶整合,讓 Terraform 能夠順利存取狀態檔案,並在需要時匯入現有資源。實際操作方面,我們將以在 VMware 平台上使用 Terraform 建立 Windows 虛擬機器,並自動安裝 SaltStack 作為範例。其中包含安裝 SaltStack Minion 的 PowerShell 指令碼、Terraform 組態程式碼,以及確保虛擬機器能連線至網際網路和 SaltStack Master 的注意事項。透過這個範例,讀者可以瞭解如何將 Terraform 與 SaltStack 整合,實作更全面的自動化組態管理。

使用 Azure DevOps 與 Terraform 實作基礎設施自動化

在現代的 DevOps 環境中,基礎設施即程式碼(Infrastructure as Code, IaC)已成為主要趨勢。Terraform 是一個廣受歡迎的開源工具,能夠幫助開發者自動化基礎設施的佈署與管理。結合 Azure DevOps,我們可以實作持續整合與持續交付(CI/CD),進一步提升開發效率與系統穩定性。以下是玄貓如何使用 Azure Pipelines 與 Terraform 實作基礎設施自動化的詳細步驟。

基本架構

Azure Pipelines 可以與多種平台整合,並從這些平台中擷取所需的引數,將其填入 Terraform 組態檔案中。以下是整個流程的詳細說明:

  1. 匯入邏輯

    • Azure Pipelines 可以將組態檔案釋出到 Azure 儲存函式庫中,這是 Microsoft Azure DevOps 提供的原生整合功能。這種方式稱為持續整合(CI),因為它能夠自動將組態檔案檢查進 Azure DevOps 儲存函式庫。
    • 在新資源建立時,使用者可以使用 Visual Studio 或其他編輯器將組態檔案檢查進 Azure DevOps 儲存函式庫。
  2. 持續交付管道

    • Terraform 組態檔案會從 Azure DevOps 儲存函式庫中提取,用於持續佈署。然而,我們需要將 Terraform 狀態檔案儲存在安全的地方。
    • 在這個模型中,我們將狀態檔案儲存在 Azure 儲存帳戶中。因此,Pipelines 程式碼可以提供與 Azure 儲存帳戶整合並上傳 Terraform 狀態檔案的邏輯。
  3. 與 Azure 儲存整合

    • 每當 Terraform 需要對基礎設施進行變更時,都需要參考狀態檔案。Azure Pipelines 程式碼可以參考 Azure 儲存帳戶金鑰,從而輕鬆存取儲存帳戶資源。
    • 當我們需要匯入現有資源時,Azure Pipelines 可以匯入資源並將生成的狀態檔案上傳到儲存帳戶以供未來參考。

安裝 Terraform 與執行計劃

以下是具體操作步驟:

  1. 安裝 Terraform

    • 在步驟 3 中引入了 Azure Pipelines。我們需要定義安裝 Terraform 執行檔案到管道代理並初始化 SDK 的需求,以便與目標平台整合。
    • 在我們的例子中,管道代理需要安裝 Azure 工具包以便與 Azure 號子和資源群組互動。
  2. 執行 Terraform Plan

    • 安裝成功後,Azure Pipelines 可以執行 Terraform Plan,該計劃會參考儲存在 Azure 儲存帳戶中的狀態檔案。計劃會找出基礎設施所需的變更。
  3. 應用變更

    • 在管道中的執行步驟會應用在步驟 6 中識別出的增量變更,並將其釋出到 Azure 平台上的目標資源上。

強調安全性與穩定性

為確保整個流程的安全性與穩定性,玄貓特別強調以下幾點:

  • 安全儲存狀態檔案:Terraform 狀態檔案必須儲存在安全且可靠的地方。在這個範例中,我們選擇了 Azure 儲存帳戶來儲存狀態檔案。
  • 自動化流程:從匯入組態到最終應用變更的整個流程都被自動化,確保每個步驟都能夠順利進行且減少人為錯誤。

舉例說明:SaltStack 與 Terraform 的整合

在這個實戰練習中,我們將展示如何在 VMware 平台上使用 Terraform 建立 Windows 虛擬機器並安裝 SaltStack。以下是詳細步驟:

功能需求

  • 建立 Windows 虛擬機器
  • 安裝 SaltStack minion
  • 組態 SaltStack master 與 minion 的連線

安裝 SaltStack Minion 的 PowerShell 指令碼

以下是 PowerShell 指令碼 Install_Minion.ps1 的範例:

$SALTMASTER = 'x.x.x.x' # 必填欄位
$MINIONNAME = $env:COMPUTERNAME
echo $MINIONNAME

# 若系統已安裝 SaltStack 則不再佈署
if ([System.IO.File]::Exists("c:\salt\bin\python.exe")) {
    Write-output "nothing to do: Salt is already installed"
    #exit 0
}

Write-output "Salt is not installed, Starting Salt Deployment script"

# 下載 Salt 安裝包到臨時資料夾
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }
$webclient = New-Object system.net.webclient
$tempfolder = $env:TEMP
Write-output "Downloading Salt Minion to $tempfolder"
$webclient.DownloadFile("https://repo.saltproject.io/salt/py3/windows/latest/Salt-Minion-3006.3-Py3-AMD64-Setup.exe", "$tempfolder\Salt-Minion-3006.3-Py3-AMD64-Setup.exe")

下載指令碼

您可以從 GitHub 下載完整的 Install_Minion.ps1 指令碼: GitHub Repository

主要注意事項

  • 新建的 VMware 虛擬機器必須能夠連線到網際網路,以便下載 SaltStack minion 執行檔案。
  • 新建的 VMware 虛擬機器必須能夠與 SaltStack master 在必要的連線埠(預設為 4505 和 4506)進行通訊。

摘要

透過這些步驟,我們展示瞭如何使用 Azure DevOps 與 Terraform 自動化基礎設施佈署。這種方法不僅提高了開發效率,還確保了系統的穩定性和安全性。希望這些實務經驗和具體案例能夠幫助您更好地理解和應用這些技術。


注意:

由於本文涉及大量技術細節及程式碼範例,請務必依照相關指引和檔案進行操作,以避免潛在風險和錯誤。

安裝與整合 SaltStack 的 Terraform 指令碼

安裝 Salt Minion 的 PowerShell 指令碼

SaltStack 是一個強大的自動化和組態管理工具,透過安裝 Salt Minion 來管理遠端機器。以下是用於安裝 Salt Minion 的 PowerShell 指令碼,這個指令碼會下載 Salt Minion 可執行檔、組態必要的設定,並啟動 Salt Minion 服務。

$tempfolder = "C:\temp"
$MINIONNAME = "minion1"
$SALTMASTER = "saltmaster.example.com"

# 下載 Salt Minion 可執行檔
Invoke-WebRequest -Uri "https://repo.saltproject.io/salt/py3/windows/latest/Salt-Minion-3006.3-Py3-AMD64-Setup.exe" -OutFile "$tempfolder\saltminion.exe"

# 檢查下載是否成功
if (![System.IO.File]::Exists("$tempfolder\saltminion.exe")) {
    Write-Output "FAILED - Failed to find $tempfolder\saltminion.exe, was supposed to download from https://repo.saltproject.io/salt/py3/windows/latest/Salt-Minion-3006.3-Py3-AMD64-Setup.exe, please investigate, exiting script."
    exit 1
}

Write-Output "SALT executable download successful"

# 組態 Salt Minion 設定
$MINIONCONF = @"
id: $MINIONNAME
master: $SALTMASTER
tcp_keepalive: True
tcp_keepalive_idle: 60
"@

# 建立必要的目錄
New-Item -Path "C:\ProgramData\Salt Project\Salt\conf" -ItemType Directory
New-Item -Path "C:\ProgramData\Salt Project\Salt\conf\minion.d" -ItemType Directory

# 建立 minion.conf 設定檔
Set-Content "C:\ProgramData\Salt Project\Salt\conf\minion.d\minion.conf" $MINIONCONF

# 安裝 Salt Minion
Start-Process -FilePath "$tempfolder\saltminion.exe" -ArgumentList "/S /master=$SALTMASTER /minion-name=$MINIONNAME", "/install-dir='C:\salt'" -Wait

# 建立符號連結
New-Item -ItemType SymbolicLink -Path "C:\salt\conf" -Target "C:\ProgramData\Salt Project\Salt\conf"
New-Item -ItemType SymbolicLink -Path "C:\salt\var" -Target "C:\ProgramData\Salt Project\Salt\var"

sleep 5

# 檢查 Salt Minion 服務是否啟動
if (-not (Get-Service 'salt-minion' -ErrorAction SilentlyContinue)) {
    Write-Output "Did not find salt-minion service, sleeping 30 seconds and retrying."
    sleep 30

    if (-not (Get-Service 'salt-minion' -ErrorAction SilentlyContinue)) {
        Write-Output "FAILED - Did not find salt-minion service."
        Write-Output "Removing C:\salt because salt installed failed"
        Remove-Item -Path "C:\salt" -Force -Recurse
        Write-Output "FAILED - Salt Minion Failed to Install, please investigate, exiting script."
        exit 1
    }
}

Write-Output "Salt Service is running"
Write-Output "
---
-
---
-
---
-
---
-
---
-
---
-
---
-
---
-
---
-
---
-
---
"
Write-Output "Installation of SaltMinion was successful!"
Write-Output "
---
-
---
-
---
-
---
-
---
-
---
-
---
-
---
-
---
-
---
-
---
"
exit 0

內容解密:

玄貓對上述安裝指令碼進行分析如下:

  1. 下載 Salt Minion:使用 Invoke-WebRequest 命令下載最新的 Salt Minion 安裝程式,並將其儲存在暫存目錄中。
  2. 檢查下載成功:使用 [System.IO.File]::Exists 檢查下載的檔案是否存在,如果沒有找到,則輸出錯誤訊息並離開指令碼。
  3. 組態設定檔:建立 minion.conf 檔案,並設定必要的引數如 idmastertcp_keepalive 等。
  4. 建立目錄與符號連結:建立必要的目錄結構,並使用符號連結來連線不同路徑。
  5. 安裝 Salt Minion:使用 Start-Process 命令執行安裝程式,並等待安裝完成。
  6. 檢查服務啟動:使用 Get-Service 命令檢查 Salt Minion 服務是否已啟動,如果未啟動則等待一段時間後重試。

整合 Terraform 與 SaltStack

在瞭解了安裝指令碼後,接下來玄貓將說明如何將其整合到 Terraform 中。以下是一個簡單的 Terraform 組態範例,用於佈署虛擬機器並執行安裝指令碼。

provider "vsphere" {
  vsphere_server   = "vcslab01.dc.com"
  user             = "administrator@vsphere.local"
  password         = "XXXXX"
  allow_unverified_ssl = true
}

data "vsphere_datacenter" "dc" {
  name = "Lab"
}

data "vsphere_resource_pool" "pool" {
  name              = "vcslab01.dc.com/Resources"
  datacenter_id     = "${data.vsphere_datacenter.dc.id}"
}

data "vsphere_datastore" "datastore" {
  name              = "XYZ"
  datacenter_id     = "${data.vsphere_datacenter.dc.id}"
}

data "vsphere_network" "network" {
  name              = "VM Network"
  datacenter_id     = "${data.vsphere_datacenter.dc.id}"
}

data "vsphere_virtual_machine" "template" {
  name              = "Win2K16"
  datacenter_id     = "${data.vsphere_datacenter.dc.id}"
}

resource "vsphere_virtual_machine" "vm" {
  name             = "Windows2016_terraform"
  resource_pool_id = "${data.vsphere_resource_pool.pool.id}"
  datastore_id     = "${data.vsphere_datastore.datastore.id}"
  num_cpus         = 4
  cpu_hot_add_enabled   = true
  memory           = 12288
  memory_hot_add_enabled   = true
  wait_for_guest_net_timeout = 0
  wait_for_guest_ip_timeout = 0
  firmware         = "efi"
  guest_id         = "${data.vsphere_virtual_machine.template.guest_id}"
  scsi_type        = "${data.vsphere_virtual_machine.template.scsi_type}"

  network_interface {
    network_id   = "${data.vsphere_network.network.id}"
    adapter_type = "${data.vsphere_virtual_machine.template.network_interface_types[0]}"
  }

disk {
      label            = "${var.name}-disk1"
      size             = var.size_gb # Disk size in GB (must be >=1)
      thin_provisioned =
      eagerly_scrub     =
}
}
clone {
template_uuid =
customize {

windows_options {
computer_name =
admin_password =
full_name =
auto_logon =
auto_logon_count =
}
network_interface {
ipv4_address =
ipv4_netmask =
}
ipv4_gateway =
}
}
provisioner local-exec{
command=copy-item C:\\terraform\\Test\\Install_Minion.ps1-destination C:\\\
-Credential (new-object typename System.Management.Automation.PSCredential argumentlist local\\Administrator, (convertto-securestring-AsPlainText-Force-Str XXXX)))
interpreter=[PowerShell,“-Command]
}
provisioner local-exec{
command=Invoke-Command-ComputerName-Credential (new-object-typename System.Management.Automation.PSCredential argumentlist local\\Administrator, (convertto-securestring-AsPlainText-Force-Str XXXX))-\ScriptBlock{C:\\Install_Minion.ps1}
interpreter=[PowerShell,“-Command]
}}

內容解密:

玄貓針對這段 Terraform 指令碼進行了詳細說明如下:

  1. 定義 VSphere 提供者:組態 VSphere 提供者的基本引數,包括伺服器位址、使用者名稱、密碼及 SSL 驗證選項。
  2. 取得資料中心與資源池:使用 data 資源來取得指定資料中心、資源池、儲存裝置、網路及範本虛擬機器的資訊。
  3. 建立虛擬機器:使用 resource 資源來建立新的虛擬機器,並組態其基本引數如 CPU、記憶體、網路介面及磁碟等。
  4. 複製與執行安裝指令碼:使用 provisioner 資源來複製安裝指令碼到新佈署的虛擬機器中,並執行該指令碼以完成 Salt Minion 的安裝。

整合後的效果

當我們執行 terraform apply 命令時,Terraform 必須能夠根據上述組態佈署虛擬機器,並在佈署完成後自動執行安裝指令碼以完成 Salt Minion 的安裝。這樣可以確保我們能夠快速且自動化地佈署和組態遠端機器。

單一工作流程圖示

此圖示展示了 Terraform 與 SaltStack 的整合流程:

@startuml
skinparam backgroundColor #FEFEFE

title Azure DevOps 與 Terraform 基礎設施自動化實踐

|開發者|
start
:提交程式碼;
:推送到 Git;

|CI 系統|
:觸發建置;
:執行單元測試;
:程式碼品質檢查;

if (測試通過?) then (是)
    :建置容器映像;
    :推送到 Registry;
else (否)
    :通知開發者;
    stop
endif

|CD 系統|
:部署到測試環境;
:執行整合測試;

if (驗證通過?) then (是)
    :部署到生產環境;
    :健康檢查;
    :完成部署;
else (否)
    :回滾變更;
endif

stop

@enduml

內容解密:

此圖示說明瞭整合流程:

  1. Terraform 組態:開始於 Terraform 的主組態檔。
  2. 佈署 VM:Terraform 執行虛擬機器的佈署流程。
  3. 複製 Install_Minion.ps1 指令碼:在新 VM 上複製安裝指令碼。
  4. 執行 Install_Minion.ps1 指令碼:在新 VM 上執行安裝指令碼。
  5. 完成 Salt Minion 安裝:最終完成了 VM 上的 Salt Minion 安裝。