Azure Container Apps のアプリを安全に更新する|新しいバージョンを確かめてから切り替える手順
Azure Container Apps でアプリを更新すると、既定の設定では、新しいバージョンが正しく動くかを確かめる前に、利用者のアクセスがすべて新しいバージョンへ切り替わってしまいます。
既定の単一リビジョン方式では、新しいリビジョンが既定のチェック(待ち受けのポートに接続できるか)に合格した時点で、通信が自動で新しい版へ切り替わります。複数リビジョン方式に変えた直後も、通信の設定は「最新のリビジョンに100%」のままです。新しい版を確かめてから切り替えるには、現行のリビジョンを100%に固定してから投入します。
この記事は、Azure Container Apps のリビジョンの仕組みをご存じの方に向けたものです。弊社は、稼働中のアプリのベースイメージを更新する作業の中で、この2つの点に気づきました。
この記事では、新しい版を本番の利用者に流さずに投入し、専用のURLで確かめてから切り替え、問題があればすぐに戻す手順を解説します。
目次
株式会社ロクシアシステムズは、福岡と東京を拠点に、全国のお客様へ Microsoft 365・Azure の導入支援と、AIの業務活用(AIプライベート)の支援を提供しているIT企業です。
動いているコンテナも、更新しなければならない理由
コンテナのアプリは、一度動けば手を入れずに済むと思われがちです。しかし、イメージの土台にしたベースイメージには、言語のランタイムや OS の部品が含まれています。ランタイムがコミュニティのサポート終了を迎えると、そのイメージにはセキュリティの修正が届かなくなります。
ここで、同じサーバーレスの Azure Functions とは事情が違います。Functions はランタイムを Microsoft が提供するため、サポートの終了が近づくと Microsoft から通知のメールが届きます。一方、Container Apps で動かすのは自社で作ったイメージなので、プラットフォームから使用を止められることはありません。その代わり、ランタイムのサポート終了を知らせる通知も届きません。
| サービス | ランタイムを用意するのは | サポート終了後に起きること |
|---|---|---|
| Azure Functions | Microsoft | 動き続けるが、新機能・セキュリティの修正・性能の改善の対象外になる。必要な場合は、割り当てるインスタンスの数を1に制限することがあると明記されている |
| Azure Container Apps | 自社(ベースイメージを選んでビルドする) | プラットフォームからの制限はない。ただし、イメージを作り直さない限りセキュリティの修正は届かない |
「動いているから触らない」は、Container Apps では通用しません。ベースイメージを定期的に見直し、更新するたびに本番のアプリを入れ替える必要があります。そこで問題になるのが、入れ替えの手順です。
「既定のままでも無停止なのでは?」への答え
Container Apps のリビジョン方式には、単一リビジョン方式(Single)と複数リビジョン方式(Multiple)があり、既定は単一リビジョン方式です。単一リビジョン方式でも、更新は無停止で行われます。Microsoft Learn によると、新しいリビジョンが次の条件をすべて満たすまで、それまでのリビジョンが通信の100%を受け続けます。
- リビジョンのプロビジョニングが成功している
- それまでのリビジョンと同じレプリカ数まで増えている(新しいリビジョンの最小・最大レプリカ数の範囲で)
- すべてのレプリカが、起動時のチェック(startup プローブ)と準備完了のチェック(readiness プローブ)に合格している
更新に失敗した場合も、通信はそれまでのリビジョンに残ります。ここまでは安心できる仕組みです。問題は、条件を満たした時点で、通信が自動で新しいリビジョンへ移ることです。
「準備完了」は、ポートが開いたという意味でしかない
プローブを自分で定義していない場合、イングレスを有効にするとポータルが既定のプローブを追加します。Learn に載っている既定の値は次のとおりで、いずれもイングレスの宛先ポートへの TCP 接続を見るだけです。
| プローブ | 確かめる方法 | 見ていること |
|---|---|---|
| Startup | TCP(イングレスの宛先ポート) | アプリが起動して、ポートで待ち受けを始めたか |
| Readiness | TCP(イングレスの宛先ポート) | レプリカが要求を受けられる状態か(接続できるか) |
| Liveness | TCP(イングレスの宛先ポート) | アプリが動き続けているか |
つまり、データベースや外部の API への接続設定が間違っていても、新しいランタイムで一部のライブラリが動かなくても、ポートで待ち受けさえ始めれば「準備完了」になります。Learn も、単一リビジョン方式では「readiness プローブが成功した時点で、通信は自動で切り替わる」と書いています。
無停止で切り替わることと、確かめてから切り替えることは別の話です。前者は既定で手に入りますが、後者は自分で手順を組む必要があります。なお、開発中で頻繁に更新するアプリや検証環境なら、更新するたびに最新の版へ全量を流す単一リビジョン方式の手軽さが合います。本番の利用者がいるアプリで、確かめてから切り替えたい場合に、次の手順を使います。

複数リビジョン方式に変えただけでは、まだ安全ではない
確かめてから切り替えるには、複数リビジョン方式を使います。複数のリビジョンを同時に動かし、どのリビジョンにどれだけ通信を流すかを自分で決められる方式です。まず、今の方式を確かめます。
az containerapp show \
--resource-group <リソースグループ名> \
--name <アプリ名> \
--query "properties.configuration.activeRevisionsMode" -o tsv
# Single と表示されたら、複数リビジョン方式に切り替える
az containerapp revision set-mode \
--resource-group <リソースグループ名> \
--name <アプリ名> \
--mode multiple
方式の変更はアプリ全体の設定の変更なので、新しいリビジョンは作られません。ここで「これで新しい版を0%で投入できる」と考えるのが自然ですが、弊社の環境では、切り替えた直後の通信の設定は次のようになっていました。
az containerapp ingress traffic show \
--resource-group <リソースグループ名> \
--name <アプリ名> -o table
# LatestRevision Weight
# ---------------- --------
# True 100
LatestRevision が True で Weight が100、つまり「最新のリビジョンに、通信の100%を自動で流す」設定です。このまま新しいイメージを投入すると、新しいリビジョンが最新になった時点で全量を受けます。単一リビジョン方式のときと、結果は変わりません。
現行のリビジョンを、名指しで100%に固定する
正しい手順は、投入の前に、いま本番の通信を受けているリビジョンを名前で指定して100%に固定することです。これで「最新に自動で流す」設定が外れ、新しく作られるリビジョンは通信を受けない状態(0%)で起動します。
az containerapp revision list \
--resource-group <リソースグループ名> \
--name <アプリ名> -o table
az containerapp ingress traffic set \
--resource-group <リソースグループ名> \
--name <アプリ名> \
--revision-weight <現行のリビジョン名>=100
Microsoft Learn の blue-green デプロイの手順も、アプリを作った直後に、このように現行のリビジョンへ100%を固定しています。ただし、その手順は複数リビジョン方式でアプリを新しく作るところから始まります。稼働中の単一リビジョン方式のアプリを途中で切り替える場合は、この固定を自分で入れる必要があり、そこが見落とされやすい点です。
0%で投入し、専用のURLで確かめる
固定ができたら、新しいイメージを投入します。このとき、リビジョンの名前の末尾(サフィックス)を自分で指定しておくと、あとで名前を探す手間が省けます。リビジョンの名前は「アプリ名–サフィックス」の形になります。
az containerapp update \
--resource-group <リソースグループ名> \
--name <アプリ名> \
--image <レジストリ名>.azurecr.io/<イメージ名>:<新しいタグ> \
--revision-suffix <サフィックス>
サフィックスに使えるのは英小文字・数字・ハイフンで、英字で始めて英数字で終わり、ハイフンを2つ続けず、64文字以内にする決まりがあります。ビルドの番号や、ランタイムの更新なら更新先の版を表す短い語にしておくと、どのリビジョンが何かが一目で分かります。
通信0%のリビジョンにも、直接アクセスできる
複数リビジョン方式では、アプリの URL に届いた通信は割合の設定どおりに振り分けられますが、それとは別に、各リビジョンへ直接アクセスする URL があります。通信の割合が0%のリビジョンでも、この URL からは要求を送れます。本番の利用者に1件も流さずに、新しい版の実際の動きを確かめられるわけです。
az containerapp revision show \
--resource-group <リソースグループ名> \
--name <アプリ名> \
--revision <アプリ名>--<サフィックス> \
--query "properties.fqdn" -o tsv
# 表示された URL のヘルスチェック用のパスに要求を送る
curl -i https://<表示された URL>/healthz
弊社の作業でも、この URL でヘルスチェックの応答と、アプリの主な機能を確かめてから切り替えました。なお、最小レプリカ数を0にしているアプリでは、最初の要求で起動を待つ時間が生じます。最小レプリカ数と料金の関係は、Azure Container Apps の料金を抑える設定で解説しています。
繰り返し使うなら、ラベルの URL が便利
リビジョンへ直接アクセスする方法には、リビジョンそのものの URL のほかに、ラベルを使う方法があります。ラベルは、リビジョンに付ける「staging」のような名前で、ラベルごとに固定の URL が作られます。Learn の blue-green デプロイの手順では、このラベルの URL で新しい版を確かめています。
| 方法 | URL の形 | 向いている使い方 |
|---|---|---|
| リビジョンの URL | アプリ名–サフィックス.環境の既定のドメイン | 1回きりの更新を、その場で確かめる。リビジョンごとに URL が変わる |
| ラベルの URL | アプリ名—ラベル名.環境の既定のドメイン(ハイフン3つ) | 検証の担当者や自動テストに、毎回同じ URL を渡したい。ラベルを次のリビジョンへ付け替えても URL は変わらない |
az containerapp revision label add \
--resource-group <リソースグループ名> \
--name <アプリ名> \
--revision <アプリ名>--<サフィックス> \
--label staging
ラベルは1つのリビジョンに1つだけ付けられ、別のリビジョンに付けると付け替えになります。更新のたびに同じ URL で確かめたいなら、ラベルを使う手順に揃えておくと運用が安定します。
切り替えてよいかを、ログで判断できるようにしておく
専用の URL で確かめられるようになっても、何を見れば切り替えてよいと言えるかが決まっていなければ、判断は担当者の勘に頼ることになります。弊社が今回の作業で即座に判断できたのは、アプリ側に次の2つを用意していたからです。
- ヘルスチェックの応答:アプリが要求を処理できるかを、専用のパスで返す
- 起動時の自己診断:起動したときに、依存しているサービス(データベース、AI のサービス、ストレージなど)へ実際に接続を試し、結果を1行でログに出す
ヘルスチェックの応答だけでは、依存先への接続に必要な権限や設定が新しいイメージで正しく効いているかまでは分かりません。起動時の自己診断を、マネージド ID での認証まで含めて行い、その結果をログに出しておくと、「ポートは開いたが、肝心の接続ができない」状態を切り替えの前に見つけられます。
az containerapp logs show \
--resource-group <リソースグループ名> \
--name <アプリ名> \
--revision <アプリ名>--<サフィックス> \
--tail 50
依存先の確認を、準備完了のチェックに入れるかは慎重に
Learn は、HTTP のプローブを使えば、依存先の状態を確かめてから正常と返す独自の処理を組めると説明しています。依存先の確認を readiness プローブに入れれば、接続できない版には通信が移らなくなります。
ただし、その場合は依存先の側で一時的な障害が起きたときに、動いているすべてのレプリカが「準備未完了」になり、アプリ全体が要求を受けなくなるおそれがあります。弊社は、readiness プローブはアプリ自身が要求を受けられるかを見るのにとどめ、依存先への接続は起動時の自己診断としてログに出す形にしています。どちらを選ぶかは、依存先が止まったときにアプリをどう振る舞わせたいかで決めます。
切り替えと切り戻し、そして切り戻しでは戻らないもの
確かめ終わったら、通信を新しいリビジョンへ移します。一度に100%を移すほか、20%だけ移して様子を見る、といった段階的な切り替えもできます。割合の合計は100%にする決まりです。
# 一度に切り替える
az containerapp ingress traffic set \
--resource-group <リソースグループ名> \
--name <アプリ名> \
--revision-weight <アプリ名>--<サフィックス>=100
# 段階的に切り替える(例:旧80%・新20%)
az containerapp ingress traffic set \
--resource-group <リソースグループ名> \
--name <アプリ名> \
--revision-weight <旧リビジョン名>=80 <アプリ名>--<サフィックス>=20
切り替えたあとに問題が見つかったら、通信を旧リビジョンへ戻すだけで済みます。旧リビジョンは動いたまま残っているので、イメージを作り直す必要も、もう一度投入する必要もありません。
az containerapp ingress traffic set \
--resource-group <リソースグループ名> \
--name <アプリ名> \
--revision-weight <旧リビジョン名>=100

アプリ全体の設定は、切り戻しても戻らない
ここで見落としやすいのが、切り戻しで戻るのはリビジョンが持つ設定だけ、という点です。Learn は、変更を2種類に分けています。リビジョンの単位の変更(イメージ、コンテナーの設定、スケールのルール、サフィックス)は新しいリビジョンを作ります。一方、アプリ全体の変更は新しいリビジョンを作らず、すべてのリビジョンに効きます。アプリ全体の変更に当たるのは、次のような設定です。
- シークレットの値(反映には、リビジョンの再起動が必要)
- リビジョン方式
- イングレスの設定(有効・無効、通信の割合、ラベル)
- プライベートなレジストリーの資格情報
- Dapr の設定
たとえば、新しい版に合わせてシークレットの値を変えてから切り替え、問題が出て旧リビジョンへ戻しても、シークレットは新しい値のままです。旧リビジョンがその値で動かなければ、切り戻した先でも障害が続きます。イメージの更新とアプリ全体の設定の変更は、同じ作業の中で混ぜず、別々に行うのが安全です。
更新が終わったあとの片付け
複数リビジョン方式では、旧リビジョンは自動では止まりません。すぐに切り戻せる状態を保てる半面、旧リビジョンのレプリカが動いている間は、その分の料金がかかります。弊社は、新しい版がしばらく安定して動くのを見届けてから、旧リビジョンを非アクティブにしています。
az containerapp revision deactivate \
--resource-group <リソースグループ名> \
--name <アプリ名> \
--revision <旧リビジョン名>
Learn によると、非アクティブなリビジョンには料金がかからず、既定で100件まで履歴として残り、いつでもアクティブに戻せます。ただし、戻したあとはレプリカの起動を待つ必要があるため、「通信を戻すだけ」の即時の切り戻しではなくなります。非アクティブにする時期は、切り戻しの可能性がどれだけ残っているかで決めます。
次の更新からは、何もしなければ0%で入る
通信を特定のリビジョンに固定した状態は、そのあとも続きます。次に新しいイメージを投入すると、新しいリビジョンは0%で起動します。安全な既定になった一方で、切り替えの手順を知らない人が更新すると、「更新したのに本番に反映されていない」と戸惑うことになります。複数リビジョン方式にしたアプリは、切り替えまでを含めた手順書を必ず残しておきます。
稼働中の Container Apps を安全に更新するためのまとめ
既定の方式で起きること
- 単一リビジョン方式は無停止だが、準備完了と判定された時点で通信の100%が自動で移る
- 既定のプローブは、ポートへの TCP 接続を見るだけ
- 複数リビジョン方式に変えた直後は「最新に100%」の設定が残る
確かめてから切り替える手順
- 複数リビジョン方式に切り替える
- 現行のリビジョンを名指しで100%に固定する
- サフィックスを付けて新しいイメージを投入する(0%で起動する)
- リビジョンまたはラベルの URL で、ヘルスチェックと起動時の自己診断のログを確かめる
- 通信を新しいリビジョンへ移す
切り戻しと片付け
- 切り戻しは、通信を旧リビジョンへ戻すだけ
- シークレットやイングレスなどアプリ全体の設定は、切り戻しでは戻らない
- 旧リビジョンは、安定を見届けてから非アクティブにする
弊社の支援
弊社は、お客様専用のAI基盤やアプリを Azure 上に構築し、構築後の運用まで支援しています。Azure Container Apps で動かすアプリは、ベースイメージの更新のように、作ったあとにも本番の入れ替えが定期的に発生します。
弊社では、構築の段階でリビジョン方式、ヘルスチェックと起動時の自己診断、切り替えと切り戻しの手順までを決めてお渡しすることを重視しています。デプロイの承認や切り戻しを仕組みとして組み込む方法は、Azure DevOps で本番環境へのデプロイを管理するもあわせてご覧ください。
よくあるご質問
こちらをクリックして「よくある質問」を表示
単一リビジョン方式のままでは、何が問題なのですか?
更新は無停止で行われますが、新しいリビジョンが準備完了と判定された時点で、通信の100%が自動で移ります。既定のプローブはポートへの接続を見るだけなので、依存先への接続設定の誤りなどがあっても、確かめる機会がないまま本番の利用者に届きます。
複数リビジョン方式にすると、料金は増えますか?
方式そのものに料金はかかりません。ただし、旧リビジョンと新しいリビジョンを同時に動かしている間は、両方のレプリカの分の料金がかかります。非アクティブにしたリビジョンには料金がかからないので、新しい版が安定したら旧リビジョンを非アクティブにします。
リビジョンの URL とラベルの URL は、どちらを使えばよいですか?
1回きりの更新をその場で確かめるだけなら、リビジョンの URL で足ります。検証の担当者や自動テストに毎回同じ URL を渡したい場合は、ラベルを使います。ラベルを次のリビジョンへ付け替えても、URL は変わりません。
一部の利用者だけに新しい版を使ってもらうことはできますか?
できます。通信の割合を、旧リビジョン80%・新しいリビジョン20%のように設定すると、アプリの URL に届いた通信がその割合で振り分けられます。割合の合計は100%にします。特定の担当者だけに使ってもらいたい場合は、ラベルの URL を渡す方法もあります。
シークレットを変えたあとで切り戻すと、シークレットも元に戻りますか?
戻りません。シークレットの値はアプリ全体の設定で、すべてのリビジョンに効きます。通信を旧リビジョンへ戻しても、シークレットは新しい値のままです。イメージの更新とシークレットの変更は、別々の作業に分けることをお勧めします。
既定のプローブは、変えたほうがよいですか?
本番のアプリでは、ヘルスチェック用のパスを用意し、HTTP のプローブに変えることをお勧めします。ポートが開いたかだけでなく、アプリが要求を処理できるかを判定できるようになります。依存先の確認まで含めるかは、依存先が止まったときにアプリ全体が要求を受けなくなってよいかを踏まえて決めます。
本番で動いているアプリの更新手順は、障害が起きてから見直されることの多い領域です。現在の構成や更新の進め方をお聞かせいただければ、リビジョン方式の選び方からヘルスチェックの設計、切り替えと切り戻しの手順書まで、ご提案します。お問い合わせよりお気軽にご相談ください。
関連サービス・関連コラム
- クラウド導入支援(Azure)|アセスメントから移行・運用まで一気通貫で伴走
- Azure Container Apps の料金を抑える設定|使わない間は止めるか、常時起動にするかの判断基準
- Azure DevOps で本番環境へのデプロイを管理する|承認・自動確認・切り戻しの組み立て方
- Azure Functions Flex Consumption のデプロイと運用|従来プランとの違いと、利用の注意点
- Azureの構成をBicepで管理するときの落とし穴|手作業の設定が消える理由と、本番に適用する前の確認
まずは無料トライアルで、効果をご確認ください
「AIプライベート」は短期・低コストで試せます。帳票入力(AI-OCR)・電話対応(AI-Voice)・計画づくり(AI-Enhance)の自動化から、クラウド(Azure・Microsoft 365)・DXのご相談まで、お気軽にどうぞ。

