Kubernetes之CronJob


CronJob簡介

定時任務對我們並不陌生,例如Linux的crontab,各種編程語言都內置了定時任務支持,這在我們應用開發中比較常見,但這種定時任務在分布式系統中使用會有限制,因此需要分布式計划任務。 Kubernetes的CronJob可以理解為Kubernetes對分布式計划任務的支持。
Kubernetes集群使用CronJob管理基於時間的作業,可以在指定的時間點執行一次或在指定時間點執行多次任務。 一個CronJob就好像Linux crontab中的一行,可以按照Cron定時運行任務。
在使用CronJob之前需要確認Kubernetes集群的版本>=1.5。
所有 CronJob 的 schedule: 時間都是基於初始 Job 的主控節點的時區。

CronJob Spec

.spec.schedule:調度,必需字段,指定任務運行周期,格式同 Cron

.spec.jobTemplate:Job 模板,必需字段,指定需要運行的任務,格式同 Job,只是不需要 apiVersion 和 kind。

.spec.startingDeadlineSeconds :啟動 Job 的期限(秒級別),該字段是可選的。如果因為任何原因而錯過了被調度的時間,那么錯過執行時間的 Job 將被認為是失敗的。如果沒有指定,則沒有期限

.spec.concurrencyPolicy:並發策略,該字段也是可選的。它指定了如何處理被 CronJob 創建的 Job 的並發執行。只允許指定下面策略中的一種:

  • Allow(默認):允許並發運行 Job
  • Forbid:禁止並發運行,如果前一個還沒有完成,則直接跳過下一個
  • Replace:取消當前正在運行的 Job,用一個新的來替換
    注意,當前策略只能應用於同一個 Cron Job 創建的 Job。如果存在多個 Cron Job,它們創建的 Job 之間總是允許並發運行。

.spec.suspend :掛起,該字段也是可選的。如果設置為 true,后續所有執行都會被掛起。它對已經開始執行的 Job 不起作用。默認值為 false。

.spec.successfulJobsHistoryLimit 和 .spec.failedJobsHistoryLimit :歷史限制,是可選的字段。它們指定了可以保留多少完成和失敗的 Job。
默認情況下,它們分別設置為 3 和 1。設置限制的值為 0,相關類型的 Job 完成后將不會被保留。

CronJob 限制

一個 CronJob 在時間計划中的每次執行時刻,都創建大約一個Job對象,在少數情況下會創建兩個Job對象,或者不創建Job對象。盡管K8S盡最大的可能性避免這種情況的出現,但是並不能完全杜絕此現象的發生。因此Job程序必須是冪等的。
當以下兩個條件都滿足時,Job 將至少運行一次:

  • startingDeadlineSeconds 被設置為一個較大的值,或者不設置該值
  • concurrencyPolicy 被設置為 Allow

對於每一個 CronJob,CronJob 控制器將檢查自上一次執行的時間點到現在為止有多少次執行被錯過了。如果錯過的執行次數超過了 100,則 CronJob 控制器將不再創建 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,控制器將按照從 startingDeadlineSeconds 秒之前到現在為止的時間段計算被錯過的執行次數,而不是按照從上一次執行的時間點到現在為止的時間段來計算被錯過的執行次數。例如,如果 startingDeadlineSeconds 被設置為 200,則,控制器將計算過去 200 秒內,被錯過的執行次數。

當 CronJob 在其計划的時間點應該創建 Job 時卻創建失敗,此時 CronJob 被認為錯過了一次執行。例如,如果 concurrencyPolicy 被設置為 Forbid 且 CronJob 上一次創建的 Job 仍然在運行,此時 CronJob 再次遇到一個新的計划執行的時間點並嘗試創建一個 Job,該此創建嘗試將失敗,並被認為錯過了一次執行。

又例如,假設某個 CronJob 被設置為:自 08:30:00 開始,每分鍾創建一個新的 Job,且 CronJob 的 startingDeadlineSeconds 字段未被設置。如果 CronJob 控制器恰好在 08:29:00 到 10:21:00 這個時間段出現故障(例如 Crash),則該 CronJob 將不會再次執行,因為其錯過的執行次數已經超過了 100。

為了進一步解釋這個概念,我們再列舉一個例子,假設某個 CronJob 被設置為:自 08:30:00 開始,每分鍾創建一個新的 Job,且 CronJob 的 startingDeadlineSeconds 字段被設置為 200 秒。同樣,如果 CronJob 控制器恰好在 08:29:00 到 10:21:00 這個時間段出現故障(時間段與上個例子相同),此時 CronJob 控制器將在 10:22:00 為該 CronJob 創建一個 Job。這是因為,在這個例子中,控制器將只計算過去 200 秒中錯過的執行次數(大約 3 次),而不是從上一次執行的時間點開始計算錯過的執行次數。

CronJob 只負責按照時間計划的規定創建 Job 對象,由 Job 來負責管理具體 Pod 的創建和執行。

創建及運行CronJob

打印一次當前時間並輸出 hello world 信息:
SPEC方式

apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: hello
spec:
  schedule: "*/1 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: hello
            image: busybox
            args:
            - /bin/sh
            - -c
            - date; echo Hello from the Kubernetes cluster
          restartPolicy: OnFailure
$ kubectl create -f ./cronjob.yaml
cronjob "hello" created

命令行模式

$ kubectl run hello --schedule="*/1 * * * *" --restart=OnFailure --image=busybox -- /bin/sh -c "date; echo Hello from the Kubernetes cluster"
cronjob "hello" created

查看狀態

$ kubectl get cronjob hello
NAME      SCHEDULE      SUSPEND   ACTIVE    LAST-SCHEDULE
hello     */1 * * * *   False     0         <none>

NAME:CronJob名稱。
SCHEDULE:基於時間的調度規則。
SUSPEND:如果其值為True表示此CronJob暫時失效,不變成False之前不再創建新任務。對於已經創建的任務沒有影響。
ACTIVE:表示當前活動的任務數,0表示當前沒有活動任務。1表示有一個活動任務。此值可能大於1,原因如下:
1.任務允許重復啟動,如前一次啟動后還沒有退出,下一次已經啟動。
2.允許延后啟動,當CronJob Controller發現因為某種原因錯誤啟動,並且任務允許延后啟動,則會啟動任務。
LAST-SCHEDULE:表示最后一次調度時間, 表示未曾調度過任務。
查看CronJob創建的Job

$ kubectl get jobs --watch
NAME               DESIRED   SUCCESSFUL   AGE
hello-4111706356   1         1         2s
$ kubectl get cronjob hello
NAME    SCHEDULE      SUSPEND   ACTIVE   LAST SCHEDULE   AGE
hello   */1 * * * *   False     0        50s             75s

NAME:表示CronJob創建的Job名稱,后邊的數字由系統自動生成,保證不重復。
DESIRED:表示CronJob只創建的是最簡單的一次Job,只創建一個pod。
SUCCESSFUL:表示pod成功個數。
AGE:表示上JOB生存時間。
輸出結果顯示,該 CronJob 在 LAST SCHEDULE 這個時間點成功創建了一個 Job。當前 ACTIVE Job 數為 0,意味着,該 Job 已經成功結束,或者已經失敗。
查看Pod日志

# 將 "hello-4111706356" 替換成自己系統中的 Job name
$ pods=$(kubectl get pods --show-all --selector=job-name=hello-4111706356 --output=jsonpath={.items..metadata.name})
$ echo $pods
hello-4111706356-o9qcm
$ kubectl logs $pods
Mon Aug 29 21:34:09 UTC 2019

刪除CronJob

當不再需要某個 CronJob 時,可以使用命令將其刪除 kubectl delete cronjob

$ kubectl delete cronjob hello
cronjob "hello" deleted

刪除 CronJob 時,將移除該 CronJob 創建的所有 Job 和 Pod,並且 CronJob 控制器將不會為其在創建任何新的 Job。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM