CTS-KB

Job・CronJob入門:Kubernetesでバッチ処理を安全に実行する

⏱ 約 3 分で読めます
#Kubernetes#GKE#Job#CronJob#バッチ

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

Deployment・Job・CronJobの所有関係

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
設定意味
restartPolicyJobでは Never または OnFailure
backoffLimit失敗を許容する再試行回数
activeDeadlineSecondsJob全体の最大実行時間
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回で判断基準を比較します。

参考資料