之前需要定期執行的任務:比如每天凌晨清理日誌、每週日凌晨備份數據庫、每小時同步一次數據。剛開始用Linux的crontab在集羣節點上跑,但節點故障後任務就中斷了,還不好統一管理。後來發現Kubernetes的CronJob完美解決了這些問題——它能在集羣中調度定時任務,自動容錯,還能通過資源配置控制任務資源佔用,比單機crontab靠譜多了。

一、CronJob與Job的核心區別

很多人會混淆CronJob和Job,其實兩者的定位很清晰:

  • Job 是“一次性任務”,比如批量處理一批數據,執行完就結束,Pod也會隨之終止;
  • CronJob 是“週期性任務”,基於crontab表達式循環創建Job,再由Job啓動Pod執行具體邏輯。

簡單説,CronJob是Job的“調度器”,每次觸發都會生成一個新的Job實例,即使某次任務失敗,下次還能正常執行,容錯性更強。

二、CronJob的工作原理

1. 調度機制

CronJob的調度完全遵循crontab格式(分 時 日 月 周),比如0 3 * * *表示每天凌晨3點執行。Kubernetes會通過控制器定期檢查調度規則,到達指定時間後,自動創建對應的Job資源。

2. 任務執行流程

  1. CronJob控制器按調度規則觸發Job創建;
  2. Job控制器根據parallelism(併發數)和completions(完成數)啓動Pod;
  3. Pod執行任務,成功後退出(退出碼0),Job標記為完成;
  4. CronJob會保留一定數量的歷史Job(由successfulJobsHistoryLimitfailedJobsHistoryLimit控制),方便排查問題。

三、實戰:用CronJob實現日誌清理

1. 準備工作

先寫一個簡單的日誌清理腳本clean-logs.sh,用於刪除 /var/log/app 目錄下7天前的日誌文件:

#!/bin/bash
# 清理7天前的日誌文件
find /var/log/app -name "app-*.log" -mtime +7 -delete
echo "日誌清理完成,刪除了7天前的歷史日誌"

然後構建Docker鏡像,編寫Dockerfile

FROM alpine:3.18
# 安裝find工具(alpine默認沒有)
RUN apk add --no-cache findutils
COPY clean-logs.sh /usr/local/bin/
# 增加執行權限
RUN chmod +x /usr/local/bin/clean-logs.sh
# 容器啓動時執行腳本
ENTRYPOINT ["/usr/local/bin/clean-logs.sh"]

構建並推送鏡像(假設私有倉庫地址為registry.company.com/tools/clean-logs:v1.0):

docker build -t registry.company.com/tools/clean-logs:v1.0 .
docker push registry.company.com/tools/clean-logs:v1.0

2. 創建CronJob配置文件

編寫clean-logs-cronjob.yaml,設置每天凌晨2點執行:

apiVersion: batch/v1
kind: CronJob
metadata:
  name: clean-logs-cronjob
  namespace: tools
spec:
  # 調度規則:每天凌晨2點執行(分 時 日 月 周)
  schedule: "0 2 * * *"
  # 併發策略:禁止併發(避免多個清理任務同時執行)
  concurrencyPolicy: Forbid
  # 任務執行超時時間(10分鐘)
  activeDeadlineSeconds: 600
  # 保留3個成功的歷史Job
  successfulJobsHistoryLimit: 3
  # 保留1個失敗的歷史Job(方便排查)
  failedJobsHistoryLimit: 1
  # 觸發後1分鐘內未執行則視為失敗
  startingDeadlineSeconds: 60
  jobTemplate:
    spec:
      template:
        spec:
          # 任務完成後自動刪除Pod
          restartPolicy: OnFailure
          containers:
          - name: clean-logs
            image: registry.company.com/tools/clean-logs:v1.0
            # 掛載需要清理的日誌目錄(根據實際場景調整)
            volumeMounts:
            - name: app-logs
              mountPath: /var/log/app
          volumes:
          - name: app-logs
            hostPath:
              path: /data/app/logs
              type: Directory

3. 應用配置並查看狀態

執行部署命令:

# 創建命名空間(如果不存在)
kubectl create namespace tools --dry-run=client -o yaml | kubectl apply -f -
# 部署CronJob
kubectl apply -f clean-logs-cronjob.yaml

查看CronJob狀態:

# 查看CronJob列表
kubectl get cronjob -n tools
# 查看具體信息(包括下次執行時間)
kubectl describe cronjob clean-logs-cronjob -n tools
# 查看已觸發的Job
kubectl get jobs -n tools
# 查看Pod日誌(驗證執行結果)
kubectl logs <pod-name> -n tools

四、常見問題與解決方案

1. 任務未按時執行

排查步驟:

  • 先檢查調度表達式是否正確,比如把0 2 * * *寫成0 2 * *(少了一位)會導致解析失敗;
  • 查看CronJob事件:kubectl describe cronjob <name> -n <namespace>,如果有“Missed schedule”提示,可能是節點資源不足或startingDeadlineSeconds設置過短;
  • 確認集羣時間同步正常,節點時間不一致會導致調度紊亂。

2. Job和Pod堆積

原因:successfulJobsHistoryLimitfailedJobsHistoryLimit默認值為3和1,若未調整,長期運行後會堆積大量歷史資源。 解決:根據需求設置合理的保留數量,比如生產環境保留3個成功Job、1個失敗Job,測試環境可設為1和0。

3. 任務併發衝突

比如清理日誌時,前一次任務還沒結束,下一次又觸發了。 解決:設置concurrencyPolicy: Forbid(禁止併發)或Replace(替換正在運行的任務),根據業務場景選擇。

五、總結

CronJob是K8s集羣中定時任務的“得力助手”,相比單機crontab,它具備高可用、易管理、資源可控的優勢。使用時要注意三點:一是調度表達式要準確,二是合理配置併發策略和超時時間,三是及時清理歷史Job避免資源浪費。

實際場景中,除了日誌清理,還可以用它做數據庫備份、數據同步、定時報表生成等。比如我們團隊用CronJob每週日凌晨3點執行MySQL備份,同時將備份文件上傳到對象存儲,至今零故障運行。只要掌握好配置要點,CronJob就能成為集羣運維的“好幫手”,讓定時任務管理更省心、更可靠。