定時作業

CronJob 按照重複的日程啟動一次性 Job。
特性狀態: Kubernetes v1.21 [stable]

CronJob 按照重複日程建立Job

CronJob 用於執行定期計劃的操作,例如備份、報告生成等。一個 CronJob 物件就像 Unix 系統上 crontab(cron 表)檔案中的一行。它根據給定的日程(以 Cron 格式編寫)定期執行 Job。

CronJob 有其侷限性和特殊性。例如,在某些情況下,單個 CronJob 可能建立多個併發 Job。請參閱下面的侷限性

當控制面為 CronJob 建立新的 Job 和(間接地)Pod 時,CronJob 的 .metadata.name 是這些 Pod 命名基礎的一部分。CronJob 的名稱必須是有效的 DNS 子域名 值,但這可能會對 Pod 主機名產生意外結果。為了獲得最佳相容性,名稱應遵循更嚴格的 DNS 標籤 規則。即使名稱是 DNS 子域名,其長度也不得超過 52 個字元。這是因為 CronJob 控制器會自動在你提供的名稱後附加 11 個字元,並且存在 Job 名稱長度不得超過 63 個字元的限制。

示例

此 CronJob 示例清單每分鐘列印當前時間和一條問候訊息

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

使用 CronJob 執行自動化任務 更詳細地介紹了此示例)。

編寫 CronJob 規約

日程語法

.spec.schedule 欄位是必需的。該欄位的值遵循 Cron 語法。

# ┌───────────── minute (0 - 59)
# │ ┌───────────── hour (0 - 23)
# │ │ ┌───────────── day of the month (1 - 31)
# │ │ │ ┌───────────── month (1 - 12)
# │ │ │ │ ┌───────────── day of the week (0 - 6) (Sunday to Saturday)
# │ │ │ │ │                                   OR sun, mon, tue, wed, thu, fri, sat
# │ │ │ │ │
# │ │ │ │ │
# * * * * *

例如,0 3 * * 1 表示此任務計劃在每週一凌晨 3 點執行。

該格式還包含擴充套件的“Vixie cron”步進值。如 FreeBSD 手冊 中所述:

步進值可以與範圍結合使用。在範圍後加上 /<number> 指定在範圍內跳過指定數字的值。例如,0-23/2 可以在小時欄位中使用,以指定每隔一小時執行一次命令(V7 標準中的替代方案是 0,2,4,6,8,10,12,14,16,18,20,22)。星號後也允許使用步進,因此如果你想表示“每兩小時”,只需使用 */2

除了標準語法外,還可以使用一些宏,例如 @monthly

條目描述等價於
@yearly(或 @annually)每年 1 月 1 日午夜執行一次0 0 1 1 *
@monthly每月第一天午夜執行一次0 0 1 * *
@weekly每週日早上午夜執行一次0 0 * * 0
@daily(或 @midnight)每天午夜執行一次0 0 * * *
@hourly每小時開始時執行一次0 * * * *

要生成 CronJob 排程表示式,你還可以使用 crontab.guru 等網頁工具。

Job 模板

.spec.jobTemplate 定義了 CronJob 建立的 Job 的模板,它是必需的。它與 Job 具有完全相同的模式,只是它是巢狀的,沒有 apiVersionkind。你可以為模板化的 Job 指定通用元資料,例如標籤註解。有關編寫 Job .spec 的資訊,請參閱編寫 Job 規約

延遲 Job 啟動的截止時間

.spec.startingDeadlineSeconds 欄位是可選的。此欄位定義了 Job 啟動的截止時間(以整秒為單位),如果 Job 因任何原因錯過了其計劃時間。

錯過截止時間後,CronJob 會跳過該 Job 例項(未來的事件仍會排程)。例如,如果你有一個每天執行兩次的備份 Job,你可能會允許它最多延遲 8 小時啟動,但不能再晚,因為任何更晚的備份都將無用:你寧願等待下一個計劃執行。

對於錯過其配置截止時間的 Job,Kubernetes 會將其視為失敗的 Job。如果你未為 CronJob 指定 startingDeadlineSeconds,則 Job 事件沒有截止時間。

如果設定了 .spec.startingDeadlineSeconds 欄位(不為 null),CronJob 控制器會測量 Job 預期建立時間與當前時間之間的時間。如果差異高於該限制,它將跳過此執行。

例如,如果設定為 200,它允許 Job 在實際排程後最多 200 秒內建立。

併發策略

.spec.concurrencyPolicy 欄位也是可選的。它指定如何處理由該 CronJob 建立的 Job 的併發執行。規約只能指定以下併發策略之一:

  • Allow(預設):CronJob 允許併發執行 Job。
  • Forbid:CronJob 不允許併發執行;如果到了新的 Job 執行時間而之前的 Job 執行尚未完成,CronJob 會跳過新的 Job 執行。另請注意,當之前的 Job 執行完成後,.spec.startingDeadlineSeconds 仍然會考慮,並可能導致新的 Job 執行。
  • Replace:如果到了新的 Job 執行時間而之前的 Job 執行尚未完成,CronJob 會用新的 Job 執行替換當前正在執行的 Job 執行。

請注意,併發策略僅適用於由同一 CronJob 建立的 Job。如果存在多個 CronJob,它們的各自 Job 始終允許併發執行。

排程暫停

你可以透過將可選的 .spec.suspend 欄位設定為 true 來暫停 CronJob 的 Job 執行。該欄位預設為 false。

此設定**不**影響 CronJob 已經啟動的 Job。

如果你將該欄位設定為 true,則所有後續執行都將被暫停(它們仍處於計劃狀態,但 CronJob 控制器不會啟動 Job 來執行任務),直到你解除 CronJob 的暫停。

Job 歷史限制

.spec.successfulJobsHistoryLimit.spec.failedJobsHistoryLimit 欄位指定應保留多少個已完成和失敗的 Job。這兩個欄位都是可選的。

  • .spec.successfulJobsHistoryLimit:此欄位指定要保留的成功完成的 Job 的數量。預設值為 3。將此欄位設定為 0 將不保留任何成功的 Job。

  • .spec.failedJobsHistoryLimit:此欄位指定要保留的失敗完成的 Job 的數量。預設值為 1。將此欄位設定為 0 將不保留任何失敗的 Job。

有關自動清理 Job 的另一種方法,請參閱自動清理已完成的 Job

時區

特性狀態: Kubernetes v1.27 [穩定]

對於未指定時區的 CronJob,kube-controller-manager 根據其本地時區解釋排程。

你可以透過將 .spec.timeZone 設定為有效的時區名稱來為 CronJob 指定時區。例如,設定 .spec.timeZone: "Etc/UTC" 會指示 Kubernetes 根據協調世界時解釋排程。

Go 標準庫中的時區資料庫包含在二進位制檔案中,並在系統上沒有外部資料庫時用作備用。

CronJob 的侷限性

不支援的時區規範

.spec.schedule 中使用 CRON_TZTZ 變數指定時區**不被官方支援**(也從未被支援)。如果你嘗試設定包含 TZCRON_TZ 時區規範的排程,Kubernetes 將因驗證錯誤而無法建立或更新資源。你應該改用時區欄位來指定時區。

修改 CronJob

根據設計,CronJob 包含一個**新** Job 的模板。如果你修改一個現有 CronJob,你所做的更改將應用於在你修改完成後開始執行的新 Job。已經開始執行的 Job(及其 Pod)將繼續執行,不受更改影響。也就是說,CronJob **不會**更新現有 Job,即使它們仍在執行。

Job 建立

CronJob 大約每執行一次排程時間就會建立一個 Job 物件。排程是近似的,因為在某些情況下可能會建立兩個 Job,或者可能不會建立 Job。Kubernetes 試圖避免這些情況,但不能完全阻止它們。因此,你定義的 Job 應該是**冪等的**。

從 Kubernetes v1.32 開始,CronJob 會為其建立的 Job 應用一個註解 batch.kubernetes.io/cronjob-scheduled-timestamp。此註解指示 Job 最初的排程建立時間,並以 RFC3339 格式表示。

如果 startingDeadlineSeconds 設定為較大值或未設定(預設),並且 concurrencyPolicy 設定為 Allow,則 Job 至少會執行一次。

對於每個 CronJob,CronJob 控制器會檢查從上次排程時間到現在錯過了多少次排程。如果錯過了超過 100 次排程,則它不會啟動 Job 並記錄錯誤。

Cannot determine if job needs to be started. Too many missed start time (> 100). Set or decrease .spec.startingDeadlineSeconds or check clock skew.

需要注意的是,如果設定了 startingDeadlineSeconds 欄位(不為 nil),控制器會計算從 startingDeadlineSeconds 的值到現在錯過了多少次 Job,而不是從上次排程時間到現在。例如,如果 startingDeadlineSeconds200,控制器會計算在過去 200 秒內錯過了多少次 Job。

如果 CronJob 未能在其計劃時間建立,則將其視為錯過。例如,如果 concurrencyPolicy 設定為 Forbid,並且當上一個排程仍在執行時嘗試排程 CronJob,則它將被視為錯過。

例如,假設 CronJob 設定為從 08:30:00 開始每分鐘排程一個新 Job,並且其 startingDeadlineSeconds 欄位未設定。如果 CronJob 控制器恰好在 08:29:0010:21:00 期間宕機,則 Job 將不會啟動,因為錯過計劃的 Job 數量大於 100。

為了進一步說明這個概念,假設 CronJob 設定為從 08:30:00 開始每分鐘排程一個新 Job,並且其 startingDeadlineSeconds 設定為 200 秒。如果 CronJob 控制器恰好在與上一個示例相同的時間段(08:29:0010:21:00)宕機,Job 仍將在 10:22:00 啟動。這是因為控制器現在檢查過去 200 秒內錯過了多少次排程(即 3 次錯過的排程),而不是從上次排程時間到現在。

CronJob 僅負責建立與其排程匹配的 Job,而 Job 又負責管理其所代表的 Pod。

下一步

  • 瞭解 CronJob 所依賴的兩個概念:PodJob
  • 閱讀有關 CronJob .spec.schedule 欄位的詳細格式
  • 有關建立和使用 CronJob 的說明,以及 CronJob 清單示例,請參閱使用 CronJob 執行自動化任務
  • CronJob 是 Kubernetes REST API 的一部分。有關更多詳細資訊,請參閱 CronJob API 參考。
上次修改時間:2025 年 1 月 7 日 下午 5:38 PST:更新 CronJob 不支援的時區欄位資訊 (d0fa9da4b2)