Kubernetes CronJob 定時任務管理

Kubernetes CronJob Scheduled Task Management

前言

在現代雲原生應用程式中,定時任務是不可或缺的一部分。無論是資料備份、報表生成、日誌清理還是定期同步作業,都需要可靠的排程機制。Kubernetes 提供了 CronJob 資源,讓我們能夠在叢集中以 Cron 表達式的方式排程執行 Job。本文將詳細介紹 CronJob 的使用方法與最佳實踐。

CronJob 概述

CronJob 是 Kubernetes 中用於管理定時任務的資源物件。它會根據指定的 Cron 表達式,在預定的時間自動建立 Job 物件來執行任務。

CronJob 的特點

  • 基於時間排程:使用標準 Cron 表達式定義執行時間
  • 自動建立 Job:每次排程觸發時自動產生新的 Job
  • 歷史記錄管理:可設定保留成功與失敗的 Job 數量
  • 並發控制:支援多種並發策略
  • 暫停與恢復:可隨時暫停排程而不刪除 CronJob

CronJob 與 Job 的關係

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
CronJob (排程器)
    ├── Job 1 (07:00 執行)
    │     └── Pod 1
    ├── Job 2 (08:00 執行)
    │     └── Pod 2
    └── Job 3 (09:00 執行)
          └── Pod 3

Cron 表達式語法

CronJob 使用標準的 Cron 表達式來定義排程時間,格式如下:

1
2
3
4
5
6
7
┌───────────── 分鐘 (0 - 59)
│ ┌───────────── 小時 (0 - 23)
│ │ ┌───────────── 日期 (1 - 31)
│ │ │ ┌───────────── 月份 (1 - 12)
│ │ │ │ ┌───────────── 星期幾 (0 - 6,0 為星期日)
│ │ │ │ │
* * * * *

常用表達式範例

表達式說明
0 * * * *每小時整點執行
*/15 * * * *每 15 分鐘執行一次
0 0 * * *每天午夜 00:00 執行
0 2 * * *每天凌晨 2:00 執行
0 0 * * 0每週日午夜執行
0 0 1 * *每月 1 日午夜執行
0 0 1 1 *每年 1 月 1 日午夜執行
0 9-17 * * 1-5週一至週五,9:00 到 17:00 每小時執行

基本 CronJob YAML

以下是一個完整的 CronJob 定義範例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
apiVersion: batch/v1
kind: CronJob
metadata:
  name: database-backup
  namespace: production
spec:
  schedule: "0 2 * * *"
  timeZone: "Asia/Taipei"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: backup
            image: mysql:8.0
            command:
            - /bin/sh
            - -c
            - |
              mysqldump -h $DB_HOST -u $DB_USER -p$DB_PASSWORD \
                --all-databases > /backup/db-$(date +%Y%m%d).sql              
            env:
            - name: DB_HOST
              value: "mysql-service"
            - name: DB_USER
              valueFrom:
                secretKeyRef:
                  name: db-credentials
                  key: username
            - name: DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: db-credentials
                  key: password
            volumeMounts:
            - name: backup-storage
              mountPath: /backup
          restartPolicy: OnFailure
          volumes:
          - name: backup-storage
            persistentVolumeClaim:
              claimName: backup-pvc

建立與查看 CronJob:

1
2
3
4
5
6
7
8
# 建立 CronJob
kubectl apply -f cronjob.yaml

# 查看所有 CronJob
kubectl get cronjobs

# 查看 CronJob 詳細資訊
kubectl describe cronjob database-backup

並發策略設定

CronJob 提供 concurrencyPolicy 欄位來控制並發執行的行為,有三種策略可選:

Allow(預設)

允許並發執行,新的 Job 會與尚未完成的 Job 同時運行。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
apiVersion: batch/v1
kind: CronJob
metadata:
  name: allow-concurrent
spec:
  schedule: "*/5 * * * *"
  concurrencyPolicy: Allow
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: task
            image: busybox:1.36
            command: ["sh", "-c", "echo 開始處理; sleep 600; echo 處理完成"]
          restartPolicy: OnFailure

Forbid

禁止並發執行,如果前一個 Job 尚未完成,則跳過本次排程。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
apiVersion: batch/v1
kind: CronJob
metadata:
  name: forbid-concurrent
spec:
  schedule: "*/5 * * * *"
  concurrencyPolicy: Forbid
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: task
            image: busybox:1.36
            command: ["sh", "-c", "echo 執行任務; sleep 120"]
          restartPolicy: OnFailure

Replace

取代執行,如果前一個 Job 尚未完成,則終止它並啟動新的 Job。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
apiVersion: batch/v1
kind: CronJob
metadata:
  name: replace-concurrent
spec:
  schedule: "*/5 * * * *"
  concurrencyPolicy: Replace
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: task
            image: busybox:1.36
            command: ["sh", "-c", "echo 執行最新任務"]
          restartPolicy: OnFailure

歷史記錄保留

CronJob 會自動保留執行過的 Job 記錄,可透過以下欄位控制保留數量:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
apiVersion: batch/v1
kind: CronJob
metadata:
  name: log-cleanup
spec:
  schedule: "0 3 * * *"
  successfulJobsHistoryLimit: 3    # 保留最近 3 個成功的 Job
  failedJobsHistoryLimit: 1        # 保留最近 1 個失敗的 Job
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: cleanup
            image: alpine:3.18
            command: ["sh", "-c", "find /logs -mtime +7 -delete"]
            volumeMounts:
            - name: logs
              mountPath: /logs
          restartPolicy: OnFailure
          volumes:
          - name: logs
            hostPath:
              path: /var/log/app

查看 Job 歷史記錄:

1
2
3
4
5
# 列出 CronJob 產生的所有 Job
kubectl get jobs --selector=job-name -l "app=log-cleanup"

# 或使用 owner 查詢
kubectl get jobs | grep log-cleanup

暫停與恢復

CronJob 支援暫停功能,暫停後不會建立新的 Job,但不影響已經運行中的 Job。

使用 YAML 暫停

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
apiVersion: batch/v1
kind: CronJob
metadata:
  name: report-generator
spec:
  schedule: "0 8 * * 1"
  suspend: true                    # 設定為 true 暫停排程
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: report
            image: python:3.11-slim
            command: ["python", "/scripts/generate_report.py"]
          restartPolicy: OnFailure

使用 kubectl 暫停與恢復

1
2
3
4
5
6
7
8
# 暫停 CronJob
kubectl patch cronjob report-generator -p '{"spec":{"suspend":true}}'

# 恢復 CronJob
kubectl patch cronjob report-generator -p '{"spec":{"suspend":false}}'

# 或使用 edit 直接編輯
kubectl edit cronjob report-generator

手動觸發執行

有時候我們需要在排程時間之外手動觸發 CronJob 執行,可以從 CronJob 建立一個 Job:

1
2
3
4
5
6
7
8
# 從 CronJob 手動建立 Job
kubectl create job manual-backup-001 --from=cronjob/database-backup

# 查看手動建立的 Job 狀態
kubectl get job manual-backup-001

# 查看 Job 的 Pod 日誌
kubectl logs job/manual-backup-001

也可以使用 YAML 方式手動建立:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
apiVersion: batch/v1
kind: Job
metadata:
  name: manual-backup-002
spec:
  template:
    spec:
      containers:
      - name: backup
        image: mysql:8.0
        command: ["/scripts/backup.sh"]
      restartPolicy: OnFailure

失敗處理

CronJob 提供多種機制來處理任務失敗的情況:

啟動期限設定

使用 startingDeadlineSeconds 設定 Job 的啟動期限,超過期限則視為錯過該次排程:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
apiVersion: batch/v1
kind: CronJob
metadata:
  name: time-sensitive-job
spec:
  schedule: "*/10 * * * *"
  startingDeadlineSeconds: 200     # 200 秒內必須啟動
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: task
            image: busybox:1.36
            command: ["echo", "時效性任務執行中"]
          restartPolicy: OnFailure

Job 失敗重試設定

在 Job 層級設定重試次數與超時時間:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
apiVersion: batch/v1
kind: CronJob
metadata:
  name: retry-job
spec:
  schedule: "0 * * * *"
  jobTemplate:
    spec:
      backoffLimit: 3              # 最多重試 3 次
      activeDeadlineSeconds: 600   # 整個 Job 最長執行 600 秒
      template:
        spec:
          containers:
          - name: task
            image: alpine:3.18
            command: ["sh", "-c", "exit 1"]  # 模擬失敗
          restartPolicy: OnFailure

Pod 失敗處理策略

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
apiVersion: batch/v1
kind: CronJob
metadata:
  name: pod-failure-policy
spec:
  schedule: "0 4 * * *"
  jobTemplate:
    spec:
      backoffLimit: 6
      template:
        spec:
          containers:
          - name: task
            image: alpine:3.18
            command: ["sh", "-c", "做一些可能失敗的事情"]
            resources:
              requests:
                memory: "64Mi"
                cpu: "250m"
              limits:
                memory: "128Mi"
                cpu: "500m"
          restartPolicy: OnFailure

監控 CronJob

有效監控 CronJob 對於確保定時任務正常運行至關重要。

使用 kubectl 監控

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# 查看 CronJob 狀態
kubectl get cronjobs

# 輸出範例:
# NAME              SCHEDULE      SUSPEND   ACTIVE   LAST SCHEDULE   AGE
# database-backup   0 2 * * *     False     0        6h              30d

# 查看最近執行的 Job
kubectl get jobs --sort-by=.metadata.creationTimestamp | tail -10

# 查看 CronJob 事件
kubectl describe cronjob database-backup

# 監控 Pod 狀態
kubectl get pods --selector=job-name --watch

設定告警通知

結合 Kubernetes Events 和監控工具設定告警:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
apiVersion: batch/v1
kind: CronJob
metadata:
  name: monitored-job
  labels:
    app: monitored-job
    alert: enabled
spec:
  schedule: "0 * * * *"
  jobTemplate:
    metadata:
      labels:
        app: monitored-job
    spec:
      template:
        metadata:
          labels:
            app: monitored-job
        spec:
          containers:
          - name: task
            image: alpine:3.18
            command:
            - sh
            - -c
            - |
              if ! /scripts/run-task.sh; then
                curl -X POST $WEBHOOK_URL -d '{"text":"CronJob 執行失敗"}'
                exit 1
              fi              
            env:
            - name: WEBHOOK_URL
              valueFrom:
                secretKeyRef:
                  name: alert-config
                  key: webhook-url
          restartPolicy: OnFailure

使用 Prometheus 監控

可透過 kube-state-metrics 收集 CronJob 相關指標:

1
2
3
4
5
6
7
8
9
# 常用的 Prometheus 查詢語句
# 查看最後一次成功執行時間
kube_cronjob_status_last_successful_time

# 查看活躍的 Job 數量
kube_cronjob_status_active

# 查看下次排程時間
kube_cronjob_next_schedule_time

最佳實踐

  1. 設定適當的資源限制:避免 CronJob 佔用過多叢集資源
  2. 使用並發策略:根據任務特性選擇合適的並發策略
  3. 設定歷史記錄限制:避免產生過多的 Job 物件
  4. 實作冪等性:確保任務重複執行不會造成問題
  5. 設定啟動期限:避免累積太多錯過的排程
  6. 加入監控告警:及時發現任務失敗或延遲
  7. 使用時區設定:明確指定 timeZone 避免混淆

總結

Kubernetes CronJob 是管理定時任務的強大工具,本文涵蓋了:

  1. CronJob 概述:理解 CronJob 與 Job 的關係
  2. Cron 表達式:掌握排程時間的設定方式
  3. 並發策略:Allow、Forbid、Replace 三種策略的使用場景
  4. 歷史記錄管理:控制 Job 記錄的保留數量
  5. 暫停與恢復:靈活控制 CronJob 的執行
  6. 手動觸發:在排程之外手動執行任務
  7. 失敗處理:設定重試機制與超時限制
  8. 監控方式:使用 kubectl 和 Prometheus 監控 CronJob

透過合理使用 CronJob,可以有效管理叢集中的定時任務,提高系統的自動化程度。

參考資料

comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy