メインコンテンツへスキップ
友田 陽大
Azure Container Apps 本番運用
Azure
Container Apps
CI/CD
GitHub Actions
Bicep
DevOps
インフラ
セキュリティ

Azure Container Apps CI/CD ガイド:GitHub Actions・OIDC鍵レス・Bicep・Blue/Greenリビジョンで安全に自動デプロイ

Azure Container AppsのCI/CDを本番品質で組む実装ガイド。azure/container-apps-deploy-action、OIDC(フェデレーション資格情報)による鍵レス認証、ACR pullのマネージドID、Bicepによる宣言的デプロイ、リビジョンのトラフィック分割によるBlue/Green・カナリア、自動ロールバックまでを、Microsoft Learn公式に忠実なYAML/Bicep/az CLIで解説します。

公開日
読了時間
8分
著者
友田 陽大
シェア

デプロイは「動けばいい」ではなく、安全に・繰り返し可能に・鍵を漏らさずに回す仕組みが本番品質を決めます。長期シークレットをGitHubに置く、latestタグで上書きする、失敗時に戻せない——どれも事故の温床です。

この記事は、Microsoft LearnのGitHub Actionsドキュメントに忠実に、Azure Container Apps(ACA)の本番CI/CDを組み立てます。私はAWSでOIDCによる鍵レスCI/CDFargateのBlue/Greenデプロイを本番運用してきました。「短命トークンを信頼する」「失敗したら切り替えない」というデプロイの原則は、Azureでも同型です。ACA全体は Azure Container Apps 本番運用ガイド を参照してください。


全体像:コミット → 新リビジョン

Azure Container Apps allows you to use GitHub Actions to publish revisions to your container app. As commits are pushed to your GitHub repository, a workflow is triggered which updates the container image in the container registry. Azure Container Apps creates a new revision based on the updated container image.(— Publish revisions with GitHub Actions

流れはシンプル:コミット → ワークフロー起動 → イメージをビルドしてレジストリへ → ACAが新リビジョンを作成。ACAのリビジョンは不変スナップショットなので、デプロイ=新リビジョンへの切り替えです。


公式アクション:azure/container-apps-deploy-action

To build and deploy your container app, you add the azure/container-apps-deploy-action action to your GitHub Actions workflow.

このアクションは3つのシナリオに対応します。

  • Dockerfileからビルドしてデプロイ
  • Dockerfile無しでソースからビルドしてデプロイ(.NET・Java・Node.js・PHP・Python)
  • 既存のコンテナイメージをデプロイ

既存イメージをデプロイ(最も制御しやすい)

ビルドを別ステップで行い、**一意タグ(コミットSHA)**のイメージをデプロイする形が、本番では最も追跡しやすい:

- name: Build and deploy Container App
  uses: azure/container-apps-deploy-action@v1
  with:
    acrName: myregistry
    containerAppName: my-container-app
    resourceGroup: my-rg
    imageToDeploy: myregistry.azurecr.io/app:${{ github.sha }}

公式も警告しています。

If you're building a container image in a separate step, make sure you use a unique tag such as the commit SHA instead of a stable tag like latest.

latestは使わず、${{ github.sha }}等で一意に。これはキャッシュ問題と「どのリビジョンが何のコードか分からない」事故を防ぎます。


認証:サービスプリンシパル vs OIDC(鍵レス)

最短だが負債になりうる:サービスプリンシパル

公式のスターターは、サービスプリンシパルのJSON資格情報をAZURE_CREDENTIALSシークレットに置く方式です。

az ad sp create-for-rbac --name my-app-credentials \
  --role contributor \
  --scopes /subscriptions/<SUBSCRIPTION_ID>/resourceGroups/my-container-app-rg \
  --json-auth

動きますが、長期の資格情報(パスワード)をGitHubに保存します。漏洩リスクとローテーション負担が残る。学習やPoCならよいですが、本番では次のOIDCにします。

本番の正解:OIDC(フェデレーション資格情報)

GitHub ActionsのOIDCトークンをMicrosoft Entraのフェデレーション資格情報で信頼し、長期シークレットを1つも置かないazure/loginclient-id/tenant-id/subscription-idだけで認証します。

name: deploy-aca
on:
  push: { branches: [main] }
permissions:
  id-token: write      # OIDCトークン発行に必須
  contents: read
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Log in to Azure (OIDC, keyless)
        uses: azure/login@v2
        with:
          client-id: ${{ secrets.AZURE_CLIENT_ID }}
          tenant-id: ${{ secrets.AZURE_TENANT_ID }}
          subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

      - name: Build and deploy Container App
        uses: azure/container-apps-deploy-action@v1
        with:
          acrName: myregistry
          containerAppName: my-container-app
          resourceGroup: my-rg
          imageToDeploy: myregistry.azurecr.io/app:${{ github.sha }}

フェデレーション資格情報は、対象のEntraアプリ/マネージドIDに「このリポジトリのmainブランチからのトークンを信頼する」という条件(subject)を登録するだけ。鍵の保存・ローテーションが消えます。考え方はAWSのIAM OIDCプロバイダと完全に同型です(GitHub Actions OIDCで鍵を捨てる)。


レジストリ認証:push と pull を分ける

CI(push)とアプリ(pull)は、それぞれ別の最小権限IDで認証します。

To pull images, Azure Container Apps uses either managed identity (recommended) or admin credentials to authenticate with the Azure Container Registry.(— github-actions

アプリのイメージpullはマネージドID(推奨)。アプリのマネージドIDにAcrPullロールを付与し、レジストリ設定で--identityを指定します。

# アプリにシステム割当IDを付与
az containerapp identity assign \
  --name my-container-app --resource-group my-rg --system-assigned

# そのIDにACRのAcrPullロールを付与(pull専用の最小権限)
az role assignment create \
  --assignee <MANAGED_IDENTITY_PRINCIPAL_ID> \
  --role AcrPull --scope <ACR_RESOURCE_ID>

# レジストリをマネージドID認証に設定
az containerapp registry set \
  --name my-container-app --resource-group my-rg \
  --server myregistry.azurecr.io --identity system

これでレジストリのパスワードをどこにも持たない。CIはpush権限、アプリはpull権限だけ——責務と権限が分離されます(最小権限の原則)。

GHCR等の非ACRレジストリも使えます。その場合はaz containerapp registry set --server ghcr.ioで認証情報(PATのread:packages)を設定します。公開イメージでも認証設定は必要です。


デプロイ戦略:Blue/Green・カナリア・ロールバック

単一リビジョンモード:ゼロダウンタイム(既定)

何も設定しなければ、ACAは新リビジョンが準備完了(全プローブ通過+旧台数までスケール)してから自動で全切替します。失敗すれば旧リビジョンに留まる。多くのサービスはこれで十分です。AWS Fargateの「ローリング+デプロイサーキットブレーカー」と同じ安全側の挙動です。

複数リビジョンモード:トラフィック分割

慎重に出したいなら複数リビジョンモードにし、トラフィックを%で割り当てます。

# 複数リビジョンモードに(一度だけ)
az containerapp revision set-mode --name my-api --resource-group my-rg --mode multiple

# カナリア:新版に10%だけ
az containerapp ingress traffic set --name my-api --resource-group my-rg \
  --revision-weight my-api--green=10 my-api--blue=90

# 問題なければ昇格(Blue/Green切替)
az containerapp ingress traffic set --name my-api --resource-group my-rg \
  --revision-weight my-api--green=100

# 異常を検知したら即ロールバック(旧版へ100%戻す)
az containerapp ingress traffic set --name my-api --resource-group my-rg \
  --revision-weight my-api--blue=100

ロールバックが「旧リビジョンに100%戻す」だけで済むのが、不変リビジョンモデルの強みです。旧版はアクティブに残っているので、再ビルドも再デプロイも要らず、秒で戻せる

パイプラインに組み込むなら、デプロイ後にスモークテスト→メトリクス監視→traffic setで昇格、という段階を自動化します。SLO違反を検知したら自動でロールバックする、というガード(症状ベースのアラート設計)を足すと、本番品質が一段上がります。


IaC:Bicep / Terraform で宣言的に

クリック操作やazの手打ちは再現性がなく、技術的負債になります。本番は宣言的なコードで。

Bicep(Azureネイティブ)

param image string   // CIから一意タグを渡す(例: myregistry.azurecr.io/app:<sha>)

resource app 'Microsoft.App/containerApps@2025-02-02-preview' = {
  name: 'my-api'
  location: location
  identity: { type: 'SystemAssigned' }
  properties: {
    managedEnvironmentId: environmentId
    configuration: {
      activeRevisionsMode: 'single'
      ingress: { external: true, targetPort: 8080, transport: 'auto' }
      registries: [
        { server: 'myregistry.azurecr.io', identity: 'system' }  // マネージドIDでpull
      ]
    }
    template: {
      containers: [
        { name: 'api', image: image, resources: { cpu: json('0.5'), memory: '1.0Gi' } }
      ]
      scale: { minReplicas: 1, maxReplicas: 20 }
    }
  }
}

CIからはaz deployment group create --parameters image=...:${{ github.sha }}でこのBicepを流す。インフラもアプリも同じパイプラインで宣言的にデプロイできます。Terraform(azurerm_container_app)派なら同じ構成をHCLで書けます(本番運用ガイドのTerraform例)。

スターターワークフローの自動生成

ゼロから書くのが面倒なら、az containerapp github-action add系のCLIでスターターワークフローを生成できます。まず動かして、そこから本番要件(OIDC・IaC・トラフィック分割)に育てる——KISS/YAGNIの順序です。

az containerapp up --source . --ingress external は、リソース作成・イメージビルド・レジストリ保存・デプロイを一気にやる学習用の最短コマンド。PoCはup、本番はIaCと使い分けます。


CI/CDチェックリスト

  • **認証はOIDC(フェデレーション資格情報)**で鍵レス。AZURE_CREDENTIALSの長期シークレットを本番で使わない。
  • イメージタグはコミットSHAで一意。latest禁止。
  • ACR pullはマネージドID(AcrPull)。CIのpushとアプリのpullを別IDで最小権限に。
  • デプロイは単一モードでゼロダウンタイム、慎重に出すなら複数モードでカナリア→昇格
  • ロールバックはtraffic setで旧リビジョンへ(秒で戻る)。
  • インフラはBicep/Terraformで宣言的に。手打ち・クリックを排除。
  • デプロイ後にスモークテスト+SLO監視、違反で自動ロールバック。

まとめ

ACAのCI/CDは、azure/container-apps-deploy-actionでビルド&デプロイし、コミットごとに不変リビジョンを作るシンプルなモデルです。本番品質の鍵は4つ——OIDC鍵レス認証コミットSHAの一意タグマネージドIDによる最小権限pullトラフィック分割によるBlue/Green+秒で戻せるロールバック。これらはAWSで鍵レスCI/CDとBlue/Greenを運用してきた原則と、語彙が違うだけで同型です。

鍵レスCI/CD・Blue/Greenデプロイ・IaC化のご相談はお問い合わせへ。本番運用全体は Azure Container Apps 本番運用ガイド をどうぞ。

友田

友田 陽大

経済産業大臣賞 受賞プロダクト開発者。TypeScript + Python + AWS で、SaaS・業界DX・ 実用レベルの生成AI(RAG)を、要件定義からインフラ・運用まで一人で完遂します。

この記事で解説した技術の適用事例

経済産業大臣賞受賞 | 木材流通業界のDXを実現したB2BサブスクリプションSaaS

ケーススタディを見る