# Azure Container Apps Jobs 実装ガイド：バッチ・スケジュール（cron）・イベント駆動の本番設計

> Azure Container Apps Jobsを本番品質で設計する実装ガイド。Manual/Schedule/Eventの3トリガー、cron式（UTC）、replicaTimeout・retry・parallelism・completionの設定、KEDAイベント駆動ジョブ、セルフホストCI Runner、冪等な設計と実行履歴の監視までを、Microsoft Learn公式に忠実なaz CLI/ARMで解説します。

- 公開日: 2026-06-26
- 著者: 友田 陽大
- タグ: Azure, Container Apps, ジョブ, バッチ, KEDA, 信頼性, 冪等性, アーキテクチャ設計
- URL: https://tomodahinata.com/blog/azure-container-apps-jobs-batch-scheduled-event-driven-guide

## 要点

- Container Apps Jobsは『有限時間で走って止まる』タスク。アプリ（常駐サービス）と同じ環境・同じネットワーク／ログを共有しつつ、トリガーはManual（手動）・Schedule（cron）・Event（KEDA）の3種
- ジョブはIngressもDaprも持たない。リトライ前提（replicaRetryLimit）なので、ジョブ本体も冪等に作る——同じイベントを2回処理しても壊れない設計が必須
- 設定の主役はreplicaTimeout（完了待ち上限）・replicaRetryLimit（0でリトライ無し）・parallelism（並列レプリカ数）・replicaCompletionCount（成功に必要な完了数）。多くは parallelism=1, completion=1
- イベント駆動ジョブはKEDAで1イベント=1実行を起こす。セルフホストGitHub Actions Runner/Azure Pipelinesエージェントの定番実装でもある
- cron式はUTC評価。スケジュール／イベントジョブの実行履歴は直近100件まで。詳細ログはLog Analyticsへクエリする

---

「夜間にレポートを生成したい」「キューに溜まった処理を捌きたい」「CIのRunnerを自前で動かしたい」——常駐サービスではなく**走って終わる処理**は、Azure Container Apps Jobs の領分です。常駐アプリと同じ基盤で扱えるのに、設計を誤ると**二重実行・取りこぼし・無限リトライ**が起きます。

この記事は、[Microsoft LearnのJobsドキュメント](https://learn.microsoft.com/en-us/azure/container-apps/jobs)に忠実に、Container Apps Jobsの**本番設計**を解説します。私はAWSで[SQS駆動の冪等バッチ](/blog/aws-sqs-lambda-eventbridge-idempotent-async-processing-guide)を本番運用してきました。「リトライを正常系にする＝冪等に作る」という原則はAzureでも同じです。ACA全体は [Azure Container Apps 本番運用ガイド](/blog/azure-container-apps-production-guide) を参照してください。

---

## ジョブとは：走って終わるタスク

> Azure Container Apps jobs enable you to run containerized tasks that run for a finite duration and then stop.（— [Jobs in Azure Container Apps](https://learn.microsoft.com/en-us/azure/container-apps/jobs)）

アプリ（常駐サービス）とジョブは、**同じ環境**で動き、ネットワークとログを共有します。違いは「終わるかどうか」。

| | アプリ（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](https://learn.microsoft.com/en-us/azure/container-apps/jobs)）

- **Manual**：オンデマンド（CLI・ポータル・ARM API）。
- **Schedule**：cron式で定期。
- **Event**：KEDAスケーラーでイベント起点。

### Manual：オンデマンド実行

データ移行のような単発処理に。作成して、必要なときに起動します。

```azurecli
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時のレポート生成など。

```azurecli
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実行**が基本です。

```azurecli
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の使い方の違いは、[スケーリングガイド](/blog/azure-container-apps-keda-autoscaling-scale-to-zero-event-driven-guide)で詳説していますが要点はこれ——**アプリは「レプリカ数」を、ジョブは「実行数」を**スケールルールで決めます。「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`を上げます。

```azurecli
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件を達成した設計の核で、[冪等な非同期処理の設計](/blog/aws-sqs-lambda-eventbridge-idempotent-async-processing-guide)がそのまま使えます。「リトライしても壊れない」=「リトライを正常系として扱える」=本番で安心して自動リトライを有効化できる、ということです。

---

## 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](https://learn.microsoft.com/en-us/azure/container-apps/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](https://learn.microsoft.com/en-us/azure/container-apps/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呼び出しに接続失敗対策のリトライを足す必要はありません。

### 監視：実行履歴とログ

```azurecli
# 直近の実行ステータス
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**にクエリします（[可観測性の設計](/blog/opentelemetry-observability-production-tracing-metrics-logs)）。長期保持・アラートが要るなら、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を、同じ語彙で安全に回せます。

バッチ・定期処理・イベント駆動ジョブの設計と冪等化のご相談は[お問い合わせ](/contact)へ。本番運用全体は [Azure Container Apps 本番運用ガイド](/blog/azure-container-apps-production-guide) をどうぞ。
