「夜間にレポートを生成したい」「キューに溜まった処理を捌きたい」「CIのRunnerを自前で動かしたい」——常駐サービスではなく走って終わる処理は、Azure Container Apps Jobs の領分です。常駐アプリと同じ基盤で扱えるのに、設計を誤ると二重実行・取りこぼし・無限リトライが起きます。
この記事は、Microsoft LearnのJobsドキュメントに忠実に、Container Apps Jobsの本番設計を解説します。私はAWSでSQS駆動の冪等バッチを本番運用してきました。「リトライを正常系にする=冪等に作る」という原則はAzureでも同じです。ACA全体は Azure Container Apps 本番運用ガイド を参照してください。
ジョブとは:走って終わるタスク
Azure Container Apps jobs enable you to run containerized tasks that run for a finite duration and then stop.(— Jobs in Azure Container Apps)
アプリ(常駐サービス)とジョブは、同じ環境で動き、ネットワークとログを共有します。違いは「終わるかどうか」。
| アプリ(App) | ジョブ(Job) | |
|---|---|---|
| 性質 | 継続的に動く | 有限時間で走って止まる |
| 失敗時 | コンテナが落ちれば自動再起動 | 非ゼロ終了は失敗。リトライ設定可 |
| 例 | HTTP API・Webアプリ・常駐ワーカー | 夜間バッチ・データ移行・キュー1件処理 |
アプリとジョブの使い分け(公式の例)
| やりたいこと | 選ぶ |
|---|---|
| Webコンテンツ/APIを返すHTTPサーバー | App(HTTPスケールルール) |
| 毎晩レポートを生成 | Job(Scheduleトリガー+cron) |
| Service Busキューを継続的に処理 | App(カスタムスケールルール) |
| キューの1件/小バッチを処理して止まる | Job(Eventトリガー) |
| オンデマンドで起動して終わる背景処理 | Job(Manualトリガー) |
| セルフホストCI Runner | Job(Eventトリガー) |
3つのトリガー
A job's trigger type determines how the job is started.(— Jobs)
- Manual:オンデマンド(CLI・ポータル・ARM API)。
- Schedule:cron式で定期。
- Event:KEDAスケーラーでイベント起点。
Manual:オンデマンド実行
データ移行のような単発処理に。作成して、必要なときに起動します。
az containerapp job create \
--name migrate-job --resource-group my-rg --environment my-env \
--trigger-type "Manual" \
--replica-timeout 1800 --replica-retry-limit 0 \
--replica-completion-count 1 --parallelism 1 \
--image myregistry.azurecr.io/migrate:2026-06-26-a1b2c3d \
--cpu "0.5" --memory "1.0Gi"
# 起動(設定の上書きも可能)
az containerapp job start --name migrate-job --resource-group my-rg
起動時に設定を上書きできます(環境変数や起動コマンドを変えて同じジョブを別入力で走らせる)。ただし
When you override a configuration, the job's entire template configuration is replaced——テンプレート全体が置き換わるので、必要な設定を全部含めること。
Schedule:cron(UTC)
毎晩0時のレポート生成など。
az containerapp job create \
--name nightly-report --resource-group my-rg --environment my-env \
--trigger-type "Schedule" --cron-expression "0 0 * * *" \
--replica-timeout 1800 --replica-retry-limit 1 \
--replica-completion-count 1 --parallelism 1 \
--image myregistry.azurecr.io/report:2026-06-26-a1b2c3d \
--cpu "0.5" --memory "1.0Gi"
cron式の例(標準5フィールド):
| 式 | 意味 |
|---|---|
*/5 * * * * | 5分ごと |
0 */2 * * * | 2時間ごと |
0 0 * * * | 毎日0時 |
0 0 * * 0 | 毎週日曜0時 |
0 0 1 * * | 毎月1日0時 |
重要:
Cron expressions in scheduled jobs are evaluated in Coordinated Universal Time (UTC).——cronはUTC評価です。「毎日深夜2時(JST)」なら、UTCで0 17 * * *(前日17:00 UTC)と書きます。タイムゾーンのズレは事故の定番なので注意。
Event:KEDAイベント駆動
キューにメッセージが来たら起動。1イベント=1実行が基本です。
az containerapp job create \
--name queue-job --resource-group my-rg --environment my-env \
--trigger-type "Event" \
--replica-timeout 1800 \
--image myregistry.azurecr.io/queue-job:2026-06-26-a1b2c3d \
--cpu "0.5" --memory "1.0Gi" \
--min-executions 0 --max-executions 10 \
--scale-rule-name "queue" --scale-rule-type "azure-queue" \
--scale-rule-metadata "accountName=mystorage" "queueName=myqueue" "queueLength=1" \
--scale-rule-auth "connection=connection-string-secret" \
--secrets "connection-string-secret=<QUEUE_CONNECTION_STRING>"
アプリとジョブのKEDAの使い方の違いは、スケーリングガイドで詳説していますが要点はこれ——アプリは「レプリカ数」を、ジョブは「実行数」をスケールルールで決めます。「1イベントごとに専用リソースの新インスタンスが要る/長時間処理」ならジョブが向きます。
ジョブ設定:4つの主役
| 設定 | プロパティ | 意味 |
|---|---|---|
| 完了待ち上限 | replicaTimeout | レプリカ完了を待つ最大秒数。超えたら打ち切り |
| リトライ上限 | replicaRetryLimit | 失敗レプリカのリトライ回数。0でリトライ無し |
| 並列度 | parallelism | 1実行あたりのレプリカ数(多くは1) |
| 完了数 | replicaCompletionCount | 成功とみなすのに必要な完了レプリカ数(≤parallelism) |
The replicaTimeout setting takes precedence if it expires before all retries occur.——timeoutがリトライより優先。「3回リトライ」でも、timeoutが先に来れば打ち切られます。timeoutは想定処理時間より十分長く取ります。
並列バッチ(分割処理)
大量データを分割して並列処理するなら、parallelismとreplicaCompletionCountを上げます。
az containerapp job create \
--name batch-job --resource-group my-rg --environment my-env \
--trigger-type "Schedule" --cron-expression "0 0 * * *" \
--replica-timeout 1800 --replica-retry-limit 3 \
--parallelism 5 --replica-completion-count 5 \
--image myregistry.azurecr.io/batch:2026-06-26-a1b2c3d \
--cpu "0.5" --memory "1.0Gi"
各レプリカが自分の担当範囲(環境変数やキューで割り当て)を処理し、5つ全部成功で実行成功。大規模並列が必要ならAWS Batch相当の使い方ができます。
冪等性:リトライを正常系にする
ジョブはリトライ前提です。replicaRetryLimitで再試行し、イベント駆動なら同じメッセージが再配信されることもある。だから——
⚠️ ジョブ本体を冪等に作る。同じ入力(メッセージ・日付・ID)を2回処理しても、結果が1回分にしかならないこと。
決済や課金が絡むなら、冪等性キー(メッセージID・注文ID)で「処理済みか」を記録し、二度目はスキップする。これは決済基盤で本番二重課金0件を達成した設計の核で、冪等な非同期処理の設計がそのまま使えます。「リトライしても壊れない」=「リトライを正常系として扱える」=本番で安心して自動リトライを有効化できる、ということです。
CI Runner:イベント駆動ジョブの定番
イベント駆動ジョブの強力な用途が、セルフホストのCI Runnerです。
A self-hosted GitHub Actions runner or Azure Pipelines agent that runs when a new job is queued in a workflow or pipeline.(— Jobs)
ワークフローにジョブがキューされたら、KEDAがそれを検知してRunnerコンテナを1実行起動し、終わったら消える。常駐Runnerを抱えずに、必要なときだけスケールする——コスト効率とセキュリティ(使い捨て)の両方で優れた構成です。
ジョブの制約と監視
制約:IngressもDaprも無い
The following features aren't supported: Dapr; Ingress and related features such as custom domains and SSL certificates.(— Jobs)
ジョブはIngressを持たない(外部から叩けない)し、Daprも使えません。HTTPで受ける処理はアプリに、Daprのサービス呼び出しが要るならアプリに寄せます。なお、ジョブが起動時に他アプリを呼ぶ場合、sidecar containers (such as the Envoy proxy) are guaranteed to be ready before the main job container begins execution——Envoyサイドカーは主コンテナ起動前に必ず準備完了するので、起動時のapp-to-app呼び出しに接続失敗対策のリトライを足す必要はありません。
監視:実行履歴とログ
# 直近の実行ステータス
az containerapp job execution list --name my-job --resource-group my-rg
The execution history for scheduled and event-based jobs is limited to the most recent 100 successful and failed job executions.——実行履歴は直近100件。それ以上の監査や詳細出力は、環境のLog Analyticsにクエリします(可観測性の設計)。長期保持・アラートが要るなら、Log Analytics+Azure Monitorアラートで「失敗実行が閾値を超えたら通知」を組みます。
設計チェックリスト
- 「走って終わる」処理はJob、「常駐」はAppに正しく分ける。
- トリガーを選ぶ:単発=Manual、定期=Schedule(cronはUTC!)、イベント=Event。
- 冪等に作る(リトライ・再配信で二重実行しない)。決済系は冪等性キー必須。
-
replicaTimeoutは想定処理時間より十分長く。replicaRetryLimitはリトライ方針に応じて(0で無効)。 - イメージタグはコミットSHAで一意(latest禁止)。
- Ingress/Daprは使えない前提で設計。HTTP受けやDaprはアプリへ。
- 実行履歴は100件。監査・アラートはLog Analytics+Azure Monitorで。
まとめ
Container Apps Jobsは、常駐アプリと同じ基盤で有限時間のタスクを扱える機能です。トリガーはManual/Schedule(cron・UTC)/Event(KEDA)の3種。本番品質の鍵は——正しいトリガー選択、UTCを意識したcron、そして何より冪等な設計(リトライを正常系にする)。バッチ・定期処理・キュー駆動・CI Runnerを、同じ語彙で安全に回せます。
バッチ・定期処理・イベント駆動ジョブの設計と冪等化のご相談はお問い合わせへ。本番運用全体は Azure Container Apps 本番運用ガイド をどうぞ。