「週期性工作」模式為「批次工作」模式加上時間維度,讓工作單元的執行可以由時間事件觸發。

問題#

在分散式系統與微服務的世界裡,明顯的趨勢是走向即時、事件驅動的應用互動,使用 HTTP 與輕量訊息傳遞。然而不管軟體開發的最新潮流如何,工作排程有著悠久歷史,至今依然重要。週期性工作常用於自動化系統維護或管理任務,對需要定期執行特定任務的商業應用同樣切題,典型例子包括:

  • 透過檔案傳輸進行企業對企業(B2B)整合
  • 透過輪詢資料庫進行應用整合
  • 寄送電子報
  • 清理與封存舊檔案

傳統上,系統維護用途的週期性工作靠專門的排程軟體或 Cron 來處理。但這兩條路都有問題:

  • 專門軟體對簡單的使用案例來說可能過於昂貴。
  • 單一伺服器上的 Cron job 難以維護,而且構成單點故障

因此開發者往往傾向自己實作一套「同時處理排程面向與所需商業邏輯」的方案。Java 世界裡,Quartz、Spring Batch,或用 ScheduledThreadPoolExecutor 類別自製的實作,都能執行定時任務。

但這條路與 Cron 一樣,主要困難在於如何讓排程能力具備韌性與高可用,而這會導致高資源消耗。更麻煩的是,這種做法讓「基於時間的工作排程器」成為應用的一部分——要讓排程器高可用,整個應用就得高可用。這通常意味著執行多個應用實例,同時又要確保只有單一實例是活躍的、負責排程工作,於是又牽扯出領導者選舉與其他分散式系統難題。

最後,一個「每天複製幾個檔案」的簡單服務,可能演變成需要多個節點、分散式領導者選舉機制等等。

Kubernetes 的 CronJob 實作解決了這一切:它允許用眾所熟知的 Cron 格式來排程 Job 資源,讓開發者只專注於實作要做的工作本身,而不必處理時間排程面向

解法#

「批次工作」一章談到的使用案例與能力,全部適用於本章——因為 CronJob 原語就建立在 Job 之上。一個 CronJob 實例類似 Unix crontab 中的一行,負責管理 Job 的時間面向,讓 Job 在指定的時間點週期性執行。

apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: random-generator
spec:
  # 每三分鐘執行一次的 cron 規格
  schedule: "*/3 * * * *"
  jobTemplate: # 使用與一般 Job 相同規格的 Job 範本
    spec:
      template:
        spec:
          containers:
            - image: k8spatterns/random-generator:1.0
              name: random-generator
              command:
                ["java", "-cp", "/", "RandomRunner", "/numbers.txt", "10000"]
          restartPolicy: OnFailure

除了 Job 規格之外,CronJob 還有幾個定義時間面向的欄位:

  • .spec.schedule:指定 Job 排程的 crontab 條目(例如 0 * * * * 表示每小時執行)。
  • .spec.startingDeadlineSeconds:若錯過排定時間,啟動 Job 的最後期限(秒)。某些使用案例中,任務只有在特定時間範圍內執行才有效,遲了就沒用。例如 Job 因運算資源不足或依賴缺失而未能準時執行,此時乾脆跳過這次執行可能更好,因為它該處理的資料已經過期。
  • .spec.concurrencyPolicy:指定如何管理由同一個 CronJob 建立的 Job 之間的並行執行。
    • Allow(預設):即使前一批 Job 尚未完成,仍建立新的 Job 實例。
    • Forbid:若當前執行尚未完成,就跳過下一次執行。
    • Replace:取消當前執行中的 Job,並啟動一個新的。
  • .spec.suspend:暫停所有後續執行,但不影響已啟動的執行。
  • .spec.successfulJobsHistoryLimit.spec.failedJobsHistoryLimit:指定要保留多少已完成與失敗的 Job 供稽核之用。

CronJob 是非常專門的原語,只在工作單元具有時間維度時才適用。即使它不是通用原語,卻是個絕佳範例,展示 Kubernetes 的各項能力如何層層堆疊,並支援非雲原生的使用案例

討論#

CronJob 本身是個相當簡單的原語,只是為既有的 Job 定義加上叢集化的、類 Cron 的行為。但當它與 Pod、容器資源隔離,以及「自動化配置」、「健康探針」等 Kubernetes 功能結合時,就成為一套非常強大的工作排程系統

這讓開發者能完全專注於問題領域,實作一個「只負責商業邏輯」的容器化應用。排程發生在應用之外、作為平台的一部分,連帶享有平台帶來的高可用、韌性、容量與政策驅動的 Pod 配置等好處。

當然,如同 Job 的實作,撰寫 CronJob 容器時,你的應用必須自行考慮所有邊角與失敗情境:重複執行、完全未執行、平行執行,以及取消。

更多資訊#

  • Periodic Job Example
  • Cron Jobs
  • Cron