前言
在現代雲原生應用程式中,定時任務是不可或缺的一部分。無論是資料備份、報表生成、日誌清理還是定期同步作業,都需要可靠的排程機制。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
|
最佳實踐
- 設定適當的資源限制:避免 CronJob 佔用過多叢集資源
- 使用並發策略:根據任務特性選擇合適的並發策略
- 設定歷史記錄限制:避免產生過多的 Job 物件
- 實作冪等性:確保任務重複執行不會造成問題
- 設定啟動期限:避免累積太多錯過的排程
- 加入監控告警:及時發現任務失敗或延遲
- 使用時區設定:明確指定 timeZone 避免混淆
總結
Kubernetes CronJob 是管理定時任務的強大工具,本文涵蓋了:
- CronJob 概述:理解 CronJob 與 Job 的關係
- Cron 表達式:掌握排程時間的設定方式
- 並發策略:Allow、Forbid、Replace 三種策略的使用場景
- 歷史記錄管理:控制 Job 記錄的保留數量
- 暫停與恢復:靈活控制 CronJob 的執行
- 手動觸發:在排程之外手動執行任務
- 失敗處理:設定重試機制與超時限制
- 監控方式:使用 kubectl 和 Prometheus 監控 CronJob
透過合理使用 CronJob,可以有效管理叢集中的定時任務,提高系統的自動化程度。
參考資料