在現代雲端原生應用開發中,自動化是提升交付速度與品質的關鍵。將應用程式容器化、基礎設施程式碼化,並透過 CI/CD 管道串連,已成為業界標準實踐。本文將聚焦於一套整合性解決方案,探討如何運用 Azure Pipelines 作為自動化引擎,協調 Docker 的容器打包能力與 Terraform 的基礎設施佈建功能。此方法不僅實現了從程式碼提交到雲端部署的全自動化流程,更將應用程式邏輯與底層資源管理明確分離,提升了系統的可維護性。文章後續將進一步延伸 Docker 的應用範疇,說明如何將 Terraform 這類命令行工具本身容器化,藉此確保在任何開發或執行環境中,工具鏈的版本與行為都能保持完全一致,從而根除環境差異所引發的潛在問題。

CI/CD 管道配置與 Terraform 執行細節

本節將詳細闡述如何在 Azure Pipelines 中配置 CI/CD 管道,以實現 Docker 映像的自動構建、推送以及透過 Terraform 部署到 Azure Container Instances (ACI)。

Azure Pipelines 管道配置

  1. 連接源代碼: 在 Azure Pipelines 中創建新的構建定義時,首先需要配置源代碼連接。您可以選擇連接到 GitHub 倉庫,並指定包含 Terraform 配置和 Dockerfile 的根目錄。此步驟確保管道能夠訪問部署所需的代碼文件。

  2. 定義管道變數: 為了使管道更靈活且易於管理,我們需要在「Variables」選項卡中定義必要的變數。這些變數通常包括:

    • Azure 連接信息: 例如 ARM_CLIENT_ID, ARM_CLIENT_SECRET, ARM_TENANT_ID, ARM_SUBSCRIPTION_ID,這些用於 Terraform 驗證 Azure 環境。
    • Docker Hub 用戶名: dockerhub-username,用於標記和推送映像。
    • 映像標籤: imageversion,指定要部署的 Docker 映像版本。

    這些變數的設置允許您在不修改管道定義文件的情況下,輕鬆地更改部署的映像版本或 Azure 服務主體憑證。

  3. 配置管道任務: 管道的執行邏輯定義在「Tasks」選項卡中。對於我們的場景,主要包含以下三個關鍵任務:

    • A. Docker 構建與推送: 此任務負責構建 Docker 映像並將其推送到 Docker Hub。

      • 任務類型: 通常選擇一個集成的 Docker 任務(例如 Azure Pipelines 提供的 Docker 任務)。
      • 配置:
        • Docker Hub 服務連接: 需要配置一個指向您的 Docker Hub 帳戶的服務連接(Service Connection),以便管道能夠進行身份驗證。
        • 映像標籤: 指定要推送的 Docker 映像的名稱和標籤,通常會使用之前定義的變數,例如 ${dockerhub-username}/${imageversion}
        • 命令: 選擇「Build and push」操作。
    • B. Terraform 安裝與初始化: 在執行 Terraform 命令之前,需要確保管道代理上安裝了 Terraform。

      • 任務類型: 可以使用 Azure Pipelines Marketplace 中提供的 Terraform 安裝任務(例如 charleszipp.azure-pipelines-tasks-terraform)。
      • 配置: 指定所需的 Terraform 版本。安裝完成後,通常需要一個 Terraform 初始化步驟 (terraform init) 來下載所需的提供程序(如 azurerm)。
    • C. Terraform 執行 (Apply): 這是部署的核心步驟,負責執行 Terraform 代碼以創建或更新 Azure 資源。

      • 任務類型: 通常使用一個 Bash 或 PowerShell 腳本任務來執行 Terraform 命令。
      • 配置:
        • 環境變數設置: 在腳本中,需要導出 Azure 服務主體的憑證信息為環境變數,以便 Terraform 可以連接到 Azure。例如:
          export ARM_CLIENT_ID="$(ARM_CLIENT_ID)"
          export ARM_CLIENT_SECRET="$(ARM_CLIENT_SECRET)"
          export ARM_TENANT_ID="$(ARM_TENANT_ID)"
          export ARM_SUBSCRIPTION_ID="$(ARM_SUBSCRIPTION_ID)"
          
        • Terraform 命令: 執行 terraform init(如果未單獨配置)和 terraform apply 命令。
          terraform init
          terraform apply -auto-approve \
            -var="dockerhub-username=$(DOCKER_USERNAME)" \
            -var="imageversion=$(IMAGE_TAG)"
          
          • -auto-approve: 自動批准 Terraform 的變更,避免手動確認。
          • -var: 將管道變數的值傳遞給 Terraform 變數。這裡的 $(DOCKER_USERNAME)$(IMAGE_TAG) 是 Azure Pipelines 中的預定義或自定義變數,它們的值會對應到我們在管道變數中定義的 dockerhub-usernameimageversion

視覺化 CI/CD 管道任務流程

以下圖示展示了 Azure Pipelines 中 CI/CD 管道的任務配置和執行流程。

@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

title Azure Pipelines CI/CD Task Flow

start

component "Azure Pipelines Agent" {
  artifact "Task 1: Docker Build & Push" as TASK_DOCKER
  artifact "Task 2: Terraform Installer" as TASK_TERRAFORM_INSTALL
  artifact "Task 3: Bash Script (Terraform Apply)" as TASK_BASH
}

component "External Services" {
  artifact "Docker Hub" as DOCKER_HUB
  artifact "Azure Cloud (ACI, Resource Group)" as AZURE_CLOUD
}

TASK_DOCKER --> DOCKER_HUB : Pushes Image
TASK_TERRAFORM_INSTALL : Installs Terraform

TASK_BASH --> TASK_TERRAFORM_INSTALL : Uses Terraform
TASK_BASH --> AZURE_CLOUD : Provisions/Updates Resources via Terraform
TASK_BASH : Exports Azure Credentials\n(ARM_CLIENT_ID, etc.)
TASK_BASH : Passes Image Variables\n(dockerhub-username, imageversion)

TASK_DOCKER --> TASK_BASH : (Implicitly) Provides Image Name/Tag for Terraform

stop

@enduml

看圖說話:

此圖示描繪了 Azure Pipelines CI/CD 管道中各個任務的執行順序和依賴關係。首先,「Azure Pipelines Agent」執行「Task 1: Docker Build & Push」,該任務負責構建 Docker 映像並將其推送到「Docker Hub」。

緊接著,「Task 2: Terraform Installer」任務確保 Terraform 工具已安裝在代理上,為後續的 Terraform 操作做好準備。

最後,「Task 3: Bash Script (Terraform Apply)」執行核心的部署邏輯。它首先導出 Azure 雲端所需的身份驗證憑證(如 ARM_CLIENT_ID),然後執行 Terraform 命令。這個任務會將從管道變數獲取的映像相關信息(如 dockerhub-usernameimageversion)傳遞給 Terraform。Terraform 接著與「Azure Cloud」互動,利用這些信息來創建或更新 ACI 實例。這個流程實現了從代碼提交到雲端部署的自動化。

CI/CD 管道觸發與應用程式驗證

本節將延續前述內容,重點闡述 CI/CD 管道的觸發機制,並展示管道成功執行後,應用程式如何在 Azure Container Instances (ACI) 中運行並可供訪問。最後,我們將引導至 Docker 的另一種實用場景:運行命令行工具。

CI/CD 管道觸發配置

  1. 代理作業選項: 為了確保管道在合適的環境中運行,我們需要配置代理作業(Agent job)的選項。通常會選擇一個託管的 Ubuntu 代理,例如「Ubuntu 16.04」,這為 Terraform 和 Docker 命令的執行提供了必要的環境。

  2. 啟用持續整合 (CI) 觸發器: 在管道的「Triggers」選項卡中,啟用持續整合 (CI) 功能。這意味著每次代碼提交到指定的倉庫分支時,管道將會自動觸發執行。這種自動化機制確保了應用程式的更新能夠快速且可靠地部署。

管道執行與結果驗證

當 CI/CD 管道被觸發並成功執行後,將會產生一系列可觀察的結果:

  1. Docker Hub 映像更新: 管道成功構建並推送新的 Docker 映像到 Docker Hub 後,您可以在 Docker Hub 上看到新版本的映像。這個新版本的標籤通常與構建的構建號(Build.BuildNumber)對應,標誌著一次成功的部署週期。

  2. ACI 資源更新: Terraform 的 apply 命令執行後,Azure Container Instances (ACI) 中的應用程式實例將會被更新。在 Azure 入口網站中,您可以查看 ACI 資源(例如 aci-app)及其中的容器(例如 mydemoapp)。如果一切順利,您會看到容器正在運行。

  3. 應用程式訪問: 要訪問部署在 ACI 中的應用程式,需要從 Azure 入口網站獲取容器的公共完全限定域名 (FQDN)。通過在網頁瀏覽器中輸入此 FQDN,您應該能夠看到已正確部署並運行的 Web 應用程式。

    這個端到端的流程展示了從代碼變更到雲端部署的自動化能力。每次應用程式更新,管道都會自動執行,推送新映像,並更新 ACI 中的容器,確保始終運行最新版本的應用程式。

Docker 運行命令行工具的應用場景

在探討了 Docker 的 Web 應用容器化和 CI/CD 部署後,我們將轉向 Docker 的另一種重要應用場景:運行命令行工具

這種用法特別適合於那些依賴特定環境、依賴庫或版本控制的命令行工具。通過將這些工具及其依賴打包到 Docker 映像中,我們可以確保它們在任何環境下都能以一致的方式運行,避免了本地環境配置的複雜性。

為說明這一點,我們將以運行 Terraform 為例。在這種場景下,Terraform 二進制文件本身並非安裝在本地機器上,而是運行在一個包含 Terraform 的 Docker 容器內部。這使得我們可以在不污染本地環境的情況下,執行 Terraform 操作。

使用 Docker 運行 Terraform

為了在 Docker 容器內運行 Terraform,我們需要執行以下步驟:

  1. 拉取 Terraform Docker 映像: 首先,從 Docker Hub 拉取官方的 Terraform Docker 映像。

    docker pull hashicorp/terraform:latest
    

    此命令會下載最新的 Terraform 映像到本地 Docker 環境。

  2. 執行 Terraform 命令: 在包含 Terraform 配置文件的本地目錄中,使用 docker run 命令來執行 Terraform 工作流。這通常涉及以下幾個 Terraform 命令:initplanapply

    • 執行 terraform init:

      docker run -i -t -v ${PWD}:/usr/tf \
        --env ARM_CLIENT_ID="<azure_client_id>" \
        --env ARM_CLIENT_SECRET="<azure_client_secret>" \
        --env ARM_SUBSCRIPTION_ID="<azure_subscription_id>" \
        --env ARM_TENANT_ID="<azure_tenant_id>" \
        hashicorp/terraform:latest init -backend-config="backend.tfvars"
      

      此命令的關鍵參數解釋如下:

      • -v ${PWD}:/usr/tf: 將當前本地目錄(包含 Terraform 配置)掛載到容器內的 /usr/tf 目錄。這使得容器內的 Terraform 可以訪問和讀取本地的配置文件。
      • -w /usr/tf: 指定容器的工作目錄為 /usr/tf,即掛載的目錄。
      • --env ...: 將 Azure 認證信息設置為環境變量,供 Terraform 在容器內使用。
      • hashicorp/terraform:latest: 指定使用的 Docker 映像。
      • init -backend-config="backend.tfvars": 傳遞給 Terraform 的命令及其參數,用於初始化 Terraform 並配置後端。
    • 執行 terraform plan: 接下來,執行 terraform plan 命令來預覽將要進行的變更。

      docker run -i -t -v ${PWD}:/usr/tf -w /usr/tf \
        --env ARM_CLIENT_ID="<azure_client_id>" \
        --env ARM_CLIENT_SECRET="<azure_client_secret>" \
        --env ARM_SUBSCRIPTION_ID="<azure_subscription_id>" \
        --env ARM_TENANT_ID="<azure_tenant_id>" \
        hashicorp/terraform:latest plan
      

      此命令的結構與 init 命令類似,只是傳遞的 Terraform 命令變為 plan

縱觀現代技術領導者的效能挑戰,自動化部署流程不僅是技術實踐,更是管理思維的延伸。將 CI/CD、容器化與基礎設施即代碼(IaC)整合,實質上是將充滿不確定性的人為操作,轉化為可預測、可複驗的系統化資產。

此方法的核心價值,在於將 Docker 的環境一致性、Terraform 的狀態管理能力,與 Azure Pipelines 的流程自動化深度整合,形成一套完整的價值交付閉環。然而,其真正的瓶頸往往不在技術本身,而在於團隊從傳統手動部署到自動化思維的轉換陣痛,以及初期建立標準化流程所需的心力投入。管理者必須意識到,這不僅是工具導入,更是對團隊工作模式與風險管理哲學的重塑。

展望未來,這種將應用與其運行環境(甚至工具本身)打包為獨立單元的能力,將成為衡量技術團隊成熟度的關鍵指標。我們預見,領導者的角色將從監督執行,轉向設計與優化這些自動化「價值生產線」,而團隊成員的技能需求,也將從單點操作轉向跨領域的系統整合與治理。

玄貓認為,對於追求卓越效能與持續交付的管理者而言,投資於建立此類自動化系統,並引導團隊擁抱其背後的系統化思維,是釋放組織創新潛能、構築長期競爭壁壘的關鍵修養。