Kubernetes Job & CronJob - 排程與一次性任務

與長期運行的 Service (如 Web Server) 不同,有些任務是 一次性 的,執行完畢就結束(Exit Code 0)。 Kubernetes 提供了 JobCronJob 來處理這類工作負載。

Job (一次性任務)

Job 會建立一個或多個 Pod,並確保指定數量的 Pod 成功終止 (Successfully Terminate)。 如果 Pod 失敗 (Exit Code 非 0),Job 會依照設定重試建立新的 Pod,直到成功為止。

定義 Job

建立 pi-job.yaml (計算圓周率):

# pi-job.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: pi
spec:
  template:
    spec:
      containers:
        - name: pi
          image: perl
          command: ['perl', '-Mbignum=bpi', '-wle', 'print bpi(2000)']
      restartPolicy: Never
  backoffLimit: 4 # 重試次數限制
  • restartPolicy: Job 的 Pod 只能設為 NeverOnFailure (不能用 Always,因為 Job 預期會結束)。
    • Never: 當 Pod 失敗 (Exit Code != 0) 時,K8s 會 建立一個全新的 Pod 來重試。舊的失敗 Pod 會被保留(便於查看 logs 或除錯),但同時也會留下較多紀錄。
    • OnFailure: 當 Pod 失敗時,K8s 會 原地重啟該 Pod 內的容器。Pod 的 IP 和連接的 Volume 保持不變,適合資料量大或初始化成本高的任務。
  • backoffLimit: 如果失敗,最多重試幾次。

執行 Job

將上述內容儲存為 pi-job.yaml 後,執行:

kubectl apply -f pi-job.yaml

查看執行狀態與結果:

# 查看 Job 狀態 (COMPLETIONS 顯示 1/1 代表成功)
kubectl get job pi

# 查看產生的 Pod (名稱會是 pi-xxxx)
kubectl get pods

# 查看執行結果 output (因為是計算圓周率,會印出結果)
kubectl logs job/pi

Job 控制參數 (批次處理)

如果你有一個很大的任務需要處理(例如:處理 100 張圖片),你可以讓一個 Job 建立多個 Pod 來分工合作。

  • completions: 總共需要成功幾次
    • 例如設定 10,代表這個 Job 必須要有 10 個 Pod 成功執行完畢,整個 Job 才算完成。
  • parallelism: 同時跑幾個 Pod (並行數)。
    • 例如設定 2,代表 K8s 會隨時保持 2 個 Pod 在執行,直到湊滿 10 次成功為止。

範例情境:你需要處理 10 筆資料,但為了避免瞬間資源飆高,你希望一次只處理 2 筆。

spec:
  completions: 10 # 總共要完成 10 個 Pod
  parallelism: 2 # 同一時間最多 2 個 Pod 在跑

流程會是:

  1. 啟動 2 個 Pod。
  2. 其中 1 個跑完了 -> 再補 1 個新的 (維持 2 個)。
  3. 直到總共有 10 個 Pod 成功跑完為止。

CronJob (排程任務)

CronJob 就是 K8s 版本的 Crontab。它會根據設定的時間表 (Schedule) 定期建立 Job。

定義 CronJob

建立 hello-cronjob.yaml (每分鐘印一次 Hello):

# hello-cronjob.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
  name: hello
spec:
  schedule: '*/1 * * * *'
  jobTemplate:
    spec:
      template:
        spec:
          containers:
            - name: hello
              image: busybox
              imagePullPolicy: IfNotPresent
              command:
                - /bin/sh
                - -c
                - date; echo Hello from the Kubernetes cluster
          restartPolicy: OnFailure

執行 CronJob:

kubectl apply -f hello-cronjob.yaml

Cron 表達式

格式與 Linux Crontab 相同: 分 時 日 月 週

  • */1 * * * *: 每分鐘
  • 0 0 * * *: 每天午夜
  • 0 9 * * 1: 每週一早上 9 點

常用指令

# 查看 CronJob 設定
kubectl get cronjob

# 查看由 CronJob 產生的 Jobs (可見歷史執行紀錄)
kubectl get jobs

# 刪除 CronJob (也會清理相關的 Jobs 與 Pods)
kubectl delete cronjob hello

手動觸發 CronJob

有時候我們不想要等到排程時間,想立刻執行一次測試(例如測試備份腳本)。 可以使用 create job --from 指令,從現有的 CronJob Template 建立一個 Job:

# 從 CronJob "hello" 建立一個名為 "hello-manual-001" 的 Job
kubectl create job --from=cronjob/hello hello-manual-001

這會立即啟動一個 Job,內容完全參照 CronJob 裡的設定。

CronJob 重要參數

這些參數位於 spec 層級下,用來控制排程行為:

spec:
  schedule: '*/1 * * * *'
  startingDeadlineSeconds: 100
  concurrencyPolicy: Forbid
  jobTemplate: ...
  • startingDeadlineSeconds:
    • 如果到了預定時間因為某些原因 (如資源不足、Control Plane 忙碌) 沒跑,錯過多久就不跑了。
    • 例如設定 100 秒,如果超過 100 秒還沒排程成功,這次就放棄。
  • concurrencyPolicy (並發策略):
    • 這決定了「如果上一次 Job 還沒跑完,下一次時間到了該怎麼辦」。
    • Allow (預設): 允許並發。不管上一次跑完沒,新的照樣跑 (可能同時有好幾個 Job)。
    • Forbid: 禁止並發。上一次沒跑完,這一次就跳過 (Skip)。
    • Replace: 取代。停掉上一次還沒跑完的 Job,強制跑新的。

總結

使用 Job 處理批次運算、資料庫遷移 (Migration);使用 CronJob 處理定期備份、報表生成等任務。