Skip to content

GitLab CI/CD 部署至 Azure App Service

以 GitLab CI/CD Pipeline 搭配 Azure CLI 將容器服務或原始碼直接部署至 Azure App Service 的完整 SOP。

概述

Azure App Service 是 Azure 的 PaaS 平台,可直接運行容器映像或自動偵測原始碼環境部署。相較於 Azure DevOps Pipeline 透過 Azure Service Connection 管理認證,GitLab CI/CD 採用在 Pipeline Job 的 before_script 中直接呼叫 az login 的方式進行認證,適合已使用 GitLab 作為程式碼管理平台的團隊,不需要引入 Azure DevOps 即可完成完整的 CI/CD 流程。

本文記錄兩種認證方式(帳號密碼 vs. Service Principal)與兩種部署方式(容器映像 vs. az webapp up 原始碼部署)的組合,以及從私人 Container Registry(ACR)拉取映像時的額外設定。

核心內容

認證方式比較

方式使用場景優缺點
帳號密碼(az login -u/-p快速測試、開發環境設定簡單;帳號可能因 MFA 策略無法在 CI 中使用
Service Principal(--service-principal正式 CI/CD 自動化細粒度權限控制、無 MFA 問題;需先在 App Registration 建立 SP 並授權

Service Principal 需在 Azure App Registration 建立後,將其授予目標 App Service 及 App Service Plan 的存取權限(Contributor 角色或自訂角色)。三個必要環境變數:APP_ID(Client ID)、APP_PASS(Client Secret)、APP_TENANT(Tenant ID)。

部署方式比較

方式適用情境特點
容器映像部署前端 Web 服務、已容器化後端映像在 Registry 管理,部署只需更換 Image Tag
az webapp up 原始碼部署Python、Node.js 等直接部署自動偵測執行環境、打包、同時支援初次建立與後續更新

容器映像部署四步驟

  1. az webapp create — 建立 App Service(若已存在則通常略過)
  2. az webapp config appsettings set — 設定環境變數(含 WEBSITES_PORT 指定容器對外 Port)
  3. az webapp config container set — 更新容器映像來源(用於後續 Image 更新部署)
  4. az webapp restart — 重啟服務使設定生效

az webapp up 則自動執行:建立(若不存在)或更新 App Service、偵測執行環境、打包並部署當前目錄原始碼,一行指令完成完整部署。

私人 Registry 映像拉取

從 ACR 等私人 Registry 拉取映像時,須額外設定 Docker 認證環境變數。這些憑證建議透過 GitLab CI/CD Variables 或 Azure Key Vault 管理,避免明文出現在 Pipeline 腳本或版本控制中。

關鍵要點

  • Service Principal 是正式 CI/CD 的推薦認證方式,需預先在 App Registration 建立並授予 App Service 存取權
  • az webapp create 後若 App Service 已存在,需另外呼叫 az webapp config container set 才能更新映像
  • WEBSITES_PORT 環境變數告知 App Service 容器對外監聽的 Port(不設定可能導致 502)
  • az webapp up 適合 Python/Node.js 等簡單應用,不需 Dockerfile 即可上線
  • 私人 Registry 認證必須透過 appsettings set 注入,否則 App Service 拉取映像時會失敗
  • CI_COMMIT_BRANCH 是 GitLab 內建變數,用於 rules: if: 限制特定分支觸發部署

實際應用

  • 前後端分離架構:前端 React/Next.js 以容器映像部署;後端 Python FastAPI 以 az webapp up 原始碼部署,共用同一 App Service Plan 節省成本
  • GitLab + Azure 混合環境:程式碼管理在 GitLab,部署目標在 Azure,不需引入 Azure DevOps 即可完成完整 CI/CD
  • 多分支環境:以 rules: if: $CI_COMMIT_BRANCH == 控制不同分支對應不同部署目標

部署設定參考

以下為實際部署時使用的完整設定,供日後查詢與複製使用。

環境參數

項目
Resource Groupwy-BizAut-dev-rsg
App Service PlanWiwynnAngel
Web Service 名稱budget-web-service
Python Service 名稱budget-py
Web Service Port3300(透過 WEBSITES_PORT 設定)
CI Runner Tagbj0600
Azure CLI Imagemcr.microsoft.com/azure-cli

Service Principal 環境變數

環境變數說明
APP_IDApp Registration 的 Application (client) ID
APP_PASSClient Secret
APP_TENANTAzure AD Tenant ID

容器映像部署完整 GitLab CI Job

yaml
deploy-web:
  image: mcr.microsoft.com/azure-cli
  stage: deploy
  before_script:
    - az login -u ${AZURE_USER} -p ${AZURE_PASS}
  script:
    - az webapp create
        --name budget-web-service
        --resource-group wy-BizAut-dev-rsg
        --plan WiwynnAngel
        --https-only
        --deployment-container-image-name ${AZURE_SERVICE_IMAGE}
    - az webapp config appsettings set
        --resource-group wy-BizAut-dev-rsg
        --name budget-web-service
        --settings WEBSITES_PORT=3300
    - az webapp config container set
        --name budget-web-service
        --resource-group wy-BizAut-dev-rsg
        --docker-custom-image-name ${AZURE_SERVICE_IMAGE}
    - az webapp restart
        --name budget-web-service
        --resource-group wy-BizAut-dev-rsg
  rules:
    - if: $CI_COMMIT_BRANCH == "2024-dev"
  tags:
    - bj0600

az webapp up 原始碼部署完整 GitLab CI Job

yaml
deploy-python:
  image: mcr.microsoft.com/azure-cli
  stage: deploy
  before_script:
    - az login -u ${AZURE_USER} -p ${AZURE_PASS}
  script:
    - az webapp up
        --name budget-py
        --resource-group wy-BizAut-dev-rsg
        --plan WiwynnAngel
  rules:
    - if: $CI_COMMIT_BRANCH == "2024"
  tags:
    - bj0600

Service Principal 認證(替換 before_script)

bash
az login --service-principal \
  --username ${APP_ID} \
  --password ${APP_PASS} \
  --tenant ${APP_TENANT}

私人 Registry 映像拉取設定

bash
az webapp config appsettings set \
  --resource-group wy-BizAut-dev-rsg \
  --name budget-web-service \
  --settings \
    DOCKER_REGISTRY_SERVER_URL=<registry_url> \
    DOCKER_REGISTRY_SERVER_USERNAME=<registry_username> \
    DOCKER_REGISTRY_SERVER_PASSWORD=<registry_password>

相關概念

來源