Webサーバーは動き続けることが正常ですが、バックアップや集計処理は完了して終了することが正常です。Kubernetesでは、前者を主にDeployment、後者を Job で表現します。

Deployment・Job・CronJobの違い
| 種類 | 正常な状態 | 例 |
|---|---|---|
| Deployment | 指定数のPodが動き続ける | Web、API |
| Job | 指定回数の処理が成功して終了する | 移行、集計、一括送信 |
| CronJob | スケジュールごとにJobを作る | 日次集計、定期同期 |
終了するプログラムをDeploymentに入れると、終了のたびに再起動され続けます。処理のライフサイクルに合うオブジェクトを選ぶことが第一歩です。
1回だけ実行するJob
apiVersion: batch/v1
kind: Job
metadata:
name: example-report
namespace: YOUR_NAMESPACE
spec:
backoffLimit: 3
activeDeadlineSeconds: 1800
ttlSecondsAfterFinished: 86400
template:
metadata:
labels:
app: example-report
spec:
restartPolicy: Never
containers:
- name: report
image: registry.gitlab.com/GROUP/PROJECT/IMAGE:TAG
args: ["report", "--date", "2026-08-29"]
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi
| 設定 | 意味 |
|---|---|
restartPolicy | Jobでは Never または OnFailure |
backoffLimit | 失敗を許容する再試行回数 |
activeDeadlineSeconds | Job全体の最大実行時間 |
ttlSecondsAfterFinished | 完了後に自動削除するまでの秒数 |
適用後はJobと、それが作ったPodの両方を確認します。
kubectl apply -f job.yaml
kubectl get jobs,pods -n YOUR_NAMESPACE
kubectl describe job example-report -n YOUR_NAMESPACE
kubectl logs job/example-report -n YOUR_NAMESPACE
kubectl wait --for=condition=complete job/example-report \
-n YOUR_NAMESPACE --timeout=30m
同じ名前の完了済みJobへマニフェストを再適用しても、処理をもう一度実行する操作にはなりません。再実行時は実行IDを含む別名にするか、CronJobから手動Jobを作ります。
定期実行するCronJob
apiVersion: batch/v1
kind: CronJob
metadata:
name: nightly-report
namespace: YOUR_NAMESPACE
spec:
schedule: "0 2 * * *"
timeZone: "Asia/Tokyo"
concurrencyPolicy: Forbid
startingDeadlineSeconds: 900
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 3
jobTemplate:
spec:
backoffLimit: 3
activeDeadlineSeconds: 1800
template:
spec:
restartPolicy: Never
containers:
- name: report
image: registry.gitlab.com/GROUP/PROJECT/IMAGE:TAG
args: ["report", "--previous-day"]
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi
schedule は5フィールドのcron形式です。コントローラーのローカル時刻を推測せず、対応クラスタでは timeZone を明示します。
重複実行をどう扱うか
concurrencyPolicy | 動作 |
|---|---|
Allow | 前回実行中でも次を開始。既定 |
Forbid | 前回実行中なら次を見送る |
Replace | 前回を停止し、新しいJobへ置き換える |
Forbid を指定しても、分散システム上の「厳密に1回だけ」を保証するものではありません。アプリ側で処理対象に一意キーを持たせ、再実行しても二重請求や二重送信にならない冪等性を設計します。
本番時刻を待たずに手動テストする
kubectl apply -f cronjob.yaml
kubectl create job --from=cronjob/nightly-report \
nightly-report-manual-001 -n YOUR_NAMESPACE
kubectl logs -f job/nightly-report-manual-001 -n YOUR_NAMESPACE
CronJobのテンプレートから即時Jobを作れるため、時刻を変更して検証する必要がありません。テスト後は作ったJobだけを明示して削除します。
停止・調査・再開
kubectl patch cronjob nightly-report -n YOUR_NAMESPACE \
--type=merge -p '{"spec":{"suspend":true}}'
kubectl get cronjob,jobs -n YOUR_NAMESPACE
kubectl describe cronjob nightly-report -n YOUR_NAMESPACE
kubectl patch cronjob nightly-report -n YOUR_NAMESPACE \
--type=merge -p '{"spec":{"suspend":false}}'
停止中に見送った実行が再開時にどう扱われるかは startingDeadlineSeconds などの設定に影響されます。再開前に想定外のまとめ実行が起きないか確認します。
GKEとCloud Run Jobsの分岐
既にGKEがあり、Kubernetes内のServiceやVolumeへ近い処理はJobが自然です。一方、たまにしか動かず、Kubernetes固有機能を必要としない独立バッチはCloud Run Jobsの方が基盤費用と管理を減らせる場合があります。第15回で判断基準を比較します。