在現代雲端維運實務中,基礎設施即程式碼(IaC)是確保環境一致性與可擴展性的核心原則。本篇技術探討將深入解析一套完整的自動化工作流程,從映像檔的標準化構建到宣告式佈建,再到最終的組態管理。透過整合 Packer、Terraform 及 Ansible 於 Azure Pipelines 之中,企業能大幅提升部署效率與可靠性,並實踐 DevOps 協同合作模式,加速價值交付週期。

Azure Pipelines 整合 Packer 進行映像自動構建

本節將延續上一部分,詳細說明如何在 Azure Pipelines 中配置和執行 Packer 管道,以自動化 Azure 虛擬機器 (VM) 映像的構建過程。

配置 Packer 管道以使用 Azure 服務主體

為了讓 Packer 在 Azure Pipelines 中能夠訪問和操作 Azure 資源,需要配置 Azure 服務主體 (Service Principal) 的憑證資訊。這些憑證將作為環境變數傳遞給 Packer。

  1. 定義環境變數: 在 YAML 管道文件中,您需要定義與 Azure 服務主體相關的環境變數。這些變數必須遵循 PKR_VAR_<variable name> 的格式,以便 Packer 能夠識別並使用它們。例如:

    • PKR_VAR_clientid: Azure 服務主體的客戶端 ID。
    • PKR_VAR_clientsecret: Azure 服務主體的客戶端密碼。
    • PKR_VAR_subscriptionid: Azure 訂閱 ID。
    • PKR_VAR_tenantid: Azure 租用戶 ID。

    這些變數的值通常從 Azure Pipelines 的變數組中獲取,以確保安全性,避免將敏感資訊硬編碼在管道文件中。

  2. 提交與推送管道文件: 將包含這些環境變數配置的 YAML 管道文件提交並推送到您的 Git 倉庫(例如 GitHub、Azure Repos 或 Bitbucket)。

  3. 創建與運行 Azure Pipeline:

    • 在 Azure Pipelines 中,創建一個新的管道。
    • 選擇包含 Packer 範本和 YAML 管道文件的 Git 倉庫。
    • 選擇「Use an existing YAML pipeline file」選項,並指定文件的路徑。
    • 在管道的編輯模式下,為之前定義的 Azure 服務主體環境變數(PKR_VAR_clientidPKR_VAR_clientsecret 等)添加相應的變數值。這些值應從 Azure 服務主體的配置中獲取,並建議使用 Azure Pipelines 的 Secret 變數功能來保護敏感資訊。
    • 保存並運行管道。
  4. 監控執行與驗證結果: 管道運行後,您可以查看執行日誌,確認 Packer 命令是否成功執行。最終,在 Azure 門戶的指定資源群組中,您應該能夠看到由 Packer 自動構建的 VM 映像。

執行 Terraform 和 Ansible 在 Azure Pipelines 中

在成功構建 Packer 映像後,下一步是創建一個新的 CI/CD 管道,該管道將利用 Packer 生成的映像來佈建 Azure 虛擬機器,並使用 Ansible 進行進一步的配置。

Terraform 配置: 本節將使用的 Terraform 代碼會執行以下操作:

  • 創建一個新的 Azure 資源群組。
  • 創建一個虛擬網絡及其子網。
  • 基於 Packer 生成的映像,創建一個 Linux 虛擬機器,並打上 role: webserver 的標籤。

Ansible 配置: Terraform 佈建完虛擬機器後,Ansible 將被調用,用於在該虛擬機器上安裝 Nginx 伺服器。

視覺化 Packer 管道變數配置與執行

以下圖示展示了如何在 Azure Pipelines 中配置 Packer 管道的環境變數,以及管道的執行與結果驗證。

@startuml
!define DISABLE_LINK
!define PLANTUML_FORMAT svg
!theme _none_

skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 16
skinparam minClassWidth 100

start

component "Azure Pipelines Packer Variable Integration" {
  node "YAML Pipeline Definition" {
    :Define Packer script steps;
    :Reference environment variables (e.g., PKR_VAR_...);
  }

  node "Azure Service Principal Credentials" {
    :Client ID;
    :Client Secret;
    :Subscription ID;
    :Tenant ID;
  }

  node "Azure Pipelines Variables" {
    :Store credentials securely;
    :Map to PKR_VAR_ format;
  }

  node "Pipeline Execution" {
    :Run pipeline;
    :Packer commands execute with provided variables;
  }

  node "Result Verification" {
    :Check execution logs;
    :Verify VM image in Azure Portal;
  }
}

YAML Pipeline Definition --> Azure Pipelines Variables : Reference Variables
Azure Service Principal Credentials --> Azure Pipelines Variables : Provide Sensitive Data
Pipeline Execution --> Result Verification : Confirm Success
Azure Pipelines Variables --> Pipeline Execution : Inject Credentials

stop

@enduml

看圖說話:

此圖示展示了 Azure Pipelines 如何整合 Packer,並通過配置環境變數來實現自動化映像構建。首先,「YAML Pipeline Definition」部分定義了 Packer 的執行腳本,並引用了環境變數。

「Azure Service Principal Credentials」代表了執行操作所需的 Azure 認證資訊。這些敏感資訊被安全地存儲在「Azure Pipelines Variables」中,並映射到 Packer 所需的 PKR_VAR_ 格式。

在「Pipeline Execution」階段,管道運行時,這些變數會被注入,使得 Packer 命令能夠成功執行。最後,「Result Verification」階段,通過檢查執行日誌和在 Azure 門戶中驗證生成的 VM 映像,確認整個過程的成功。

Azure Pipelines 整合 Terraform 與 Ansible 自動化基礎設施部署

本章將聚焦於如何利用 Azure Pipelines,結合 Terraform 和 Ansible,實現基礎設施的自動化部署與配置。這個流程將利用先前通過 Packer 構建的自定義映像,創建虛擬機器,並進行必要的軟體安裝。

Terraform 部署流程

Terraform 在此場景中負責基礎設施的佈建。Azure Pipelines 將執行 Terraform 的工作流程,包括初始化、規劃和應用。

  1. Terraform 初始化 (terraform init):

    • 腳本: script: terraform init --backend-config backend.tfvars
    • 顯示名稱: Terraform init
    • 工作目錄: $(Build.SourcesDirectory)/CHAP08/terraform
    • 環境變數:
      • ARM_CLIENT_ID: $(AZURE_CLIENT_ID)
      • ARM_CLIENT_SECRET: $(AZURE_SECRET)
      • ARM_SUBSCRIPTION_ID: $(AZURE_SUBSCRIPTION_ID)
      • ARM_TENANT_ID: $(AZURE_TENANT)
    • 說明: 此步驟初始化 Terraform 工作區,下載必要的提供者插件,並配置遠端後端(backend.tfvars)來存儲 Terraform 狀態。環境變數(以 ARM_ 開頭)用於 Terraform 驗證與 Azure 的連接。這些變數的值將從 Azure Pipelines 的變數組中獲取。
  2. Terraform 規劃 (terraform plan):

    • 腳本: script: terraform plan
    • 顯示名稱: Terraform plan
    • 工作目錄: $(Build.SourcesDirectory)/CHAP08/terraform
    • 環境變數:
      • ARM_CLIENT_ID: $(AZURE_CLIENT_ID)
      • ARM_CLIENT_SECRET: $(AZURE_SECRET)
      • ARM_SUBSCRIPTION_ID: $(AZURE_SUBSCRIPTION_ID)
      • ARM_TENANT_ID: $(AZURE_TENANT)
    • 說明: 此步驟生成 Terraform 執行計劃,顯示將要對基礎設施進行的變更。這是一個預覽步驟,用於確認即將發生的操作。

Ansible 配置流程

在 Terraform 完成虛擬機器的佈建後,Ansible 將接管,負責配置虛擬機器上的軟體。

  1. Ansible 劇本與動態清單:

    • Ansible 劇本 (playbookdemo.yml): 包含在 CHAP08/ansible/ 目錄下,用於在 Linux 虛擬機器上安裝 Nginx 伺服器。
    • 動態清單 (inv.azure_rm.yml): 使用 Azure 的動態清單功能,根據指定的 Azure 資源群組和 VM 標籤自動發現目標虛擬機器,無需手動維護主機列表。
  2. 在 Azure Pipelines 中執行 Ansible: 在 YAML 管道文件中,將添加執行 Ansible 的步驟。這通常涉及:

    • 指定 Ansible 劇本的路徑。
    • 指定動態清單的配置。
    • 配置連接到目標虛擬機器的憑證或 SSH 金鑰。
    • 執行 Ansible 命令。

Azure Pipelines YAML 管道示例

以下是一個簡化的 azure-pipeline.yaml 文件結構,展示了 Terraform 和 Ansible 的執行步驟:

# ... (前置的 Packer 相關配置,若有)

jobs:
- job: DeployInfrastructure
  displayName: 'Deploy Infrastructure with Terraform and Ansible'
  pool:
    vmImage: 'ubuntu-latest' # 或其他適合的代理機鏡像
  steps:
  - script: terraform init --backend-config backend.tfvars
    displayName: 'Terraform init'
    workingDirectory: '$(Build.SourcesDirectory)/CHAP08/terraform'
    env:
      ARM_CLIENT_ID: $(AZURE_CLIENT_ID)
      ARM_CLIENT_SECRET: $(AZURE_SECRET)
      ARM_SUBSCRIPTION_ID: $(AZURE_SUBSCRIPTION_ID)
      ARM_TENANT_ID: $(AZURE_TENANT)
      # 可能需要 ARM_ACCESS_KEY 或其他認證方式

  - script: terraform plan
    displayName: 'Terraform plan'
    workingDirectory: '$(Build.SourcesDirectory)/CHAP08/terraform'
    env:
      ARM_CLIENT_ID: $(AZURE_CLIENT_ID)
      ARM_CLIENT_SECRET: $(AZURE_SECRET)
      ARM_SUBSCRIPTION_ID: $(AZURE_SUBSCRIPTION_ID)
      ARM_TENANT_ID: $(AZURE_TENANT)

  - script: terraform apply -auto-approve
    displayName: 'Terraform apply'
    workingDirectory: '$(Build.SourcesDirectory)/CHAP08/terraform'
    env:
      ARM_CLIENT_ID: $(AZURE_CLIENT_ID)
      ARM_CLIENT_SECRET: $(AZURE_SECRET)
      ARM_SUBSCRIPTION_ID: $(AZURE_SUBSCRIPTION_ID)
      ARM_TENANT_ID: $(AZURE_TENANT)

  # 在 Terraform apply 完成後,添加 Ansible 執行步驟
  - task: Ansible@1 # 使用 Azure Pipelines 的 Ansible 任務
    displayName: 'Run Ansible Playbook'
    inputs:
      azureSubscription: '<Your Azure Service Connection Name>' # Azure 服務連接名稱
      ScriptType: 'playbook'
      PlayBookPath: '$(Build.SourcesDirectory)/CHAP08/ansible/playbookdemo.yml'
      InventoryPath: '$(Build.SourcesDirectory)/CHAP08/ansible/inv.azure_rm.yml'
      # 可能需要配置 SSH 憑證等連接資訊

注意: 上述 Ansible 任務的配置細節(如 <Your Azure Service Connection Name> 和 SSH 憑證)需要根據您的 Azure DevOps 環境和安全策略進行調整。

視覺化 Terraform 和 Ansible 管道流程

以下圖示展示了 Terraform 和 Ansible 在 Azure Pipelines 中的協同工作流程。

@startuml
!define DISABLE_LINK
!define PLANTUML_FORMAT svg
!theme _none_

skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 16
skinparam minClassWidth 100

start

component "IaC Deployment Pipeline" {
  node "Terraform Initialization" {
    :Execute 'terraform init';
    :Configure backend and providers;
  }

  node "Terraform Planning" {
    :Execute 'terraform plan';
    :Generate execution plan;
  }

  node "Terraform Application" {
    :Execute 'terraform apply -auto-approve';
    :Provision Azure resources (VM, Network);
  }

  node "Ansible Inventory" {
    :Use dynamic inventory (inv.azure_rm.yml);
    :Discover provisioned VM hosts;
  }

  node "Ansible Configuration" {
    :Execute 'ansible-playbook playbookdemo.yml';
    :Install Nginx on VM;
  }

  node "Final Infrastructure State" {
    :VM with Nginx running;
  }
}

Terraform Initialization --> Terraform Planning : Prepare for Deployment
Terraform Planning --> Terraform Application : Confirm and Execute
Terraform Application --> Ansible Inventory : Identify Target Hosts
Ansible Inventory --> Ansible Configuration : Target Hosts for Configuration
Ansible Configuration --> Final Infrastructure State : Deployed and Configured

stop

@enduml

看圖說話:

此圖示描繪了在 Azure Pipelines 中,Terraform 和 Ansible 如何協同工作以實現基礎設施的自動化部署。流程始於「Terraform Initialization」,執行 terraform init 來準備工作環境。

接著,「Terraform Planning」階段運行 terraform plan,生成一個預覽變更的執行計劃。隨後,「Terraform Application」階段執行 terraform apply,實際在 Azure 中創建虛擬機器和網絡等資源。

Terraform 佈建完成後,「Ansible Inventory」階段利用動態清單自動發現新創建的虛擬機器。最後,「Ansible Configuration」階段執行 Ansible 劇本,在這些虛擬機器上安裝 Nginx,最終達成「Final Infrastructure State」,即一個部署完成並配置好 Nginx 的虛擬機器。


結論

縱觀現代雲端維運的多元挑戰,將 Packer、Terraform 與 Ansible 整合於 Azure Pipelines 的自動化流程,不僅是技術堆疊的組合,更是一種系統性的工程思維體現。此整合架構的核心價值在於其協同效應:Packer 預先烘焙的標準化映像,從源頭消除了環境不一致的風險,為 Terraform 的基礎設施佈建提供了穩定基石;而 Terraform 透過代碼精準定義資源後,Ansible 的動態清單無縫接軌,實現了從無到有的全自動配置。這種分層負責的模式,有效突破了傳統手動部署的效率瓶頸與人為錯誤,將「基礎設施即代碼」的理念從理論轉化為可高度重複、可稽核的日常實踐。

展望未來,此類整合管道將進一步朝向 GitOps 模式演化,讓 Git 倉儲成為驅動基礎設施生命週期的唯一真相來源。隨著實踐社群的成熟,圍繞此核心流程的監控、安全掃描與成本優化工具鏈將更趨完整,形成一個自我強化的維運生態系統。

玄貓認為,對於追求高部署頻率與系統韌性的技術團隊,採納此一分層自動化架構,不僅是提升效率的手段,更是奠定長期技術競爭力的關鍵策略投資。