Kubernetes:Job剖析

一. 簡介

Deployment、StatefulSet,以及 DaemonSet 這三個主要編排的對象,都是“在線業(yè)務(wù)”,都屬于Long Running Task(長作業(yè))。
但是有一類作業(yè)顯然不滿足這樣的條件,這就是“離線業(yè)務(wù)”,叫作 Batch Job(計算業(yè)務(wù))。針對這種在計算完成后就直接退出的業(yè)務(wù),可以使用我們今天的重點:Job來解決。

關(guān)于本文的項目的代碼,都放于鏈接:GitHub資源

二. Job

2.1 案例

如下,我們創(chuàng)建一個計算pi后面100位的案例,需要執(zhí)行10個這樣的任務(wù)。
demo-job.yaml 文件如下:

apiVersion: batch/v1
kind: Job
metadata:
  name: demo-job
spec:
  parallelism: 3
  completions: 10
  template:
    spec:
      containers:
      - name: pi
        image: resouer/ubuntu-bc
        command: ["sh", "-c", "echo 'scale=100; 4*a(1)' | bc -l "]
      restartPolicy: Never
  backoffLimit: 4
  activeDeadlineSeconds: 300

2.2 檢查Selector

運行完畢后,我們將看到如下的狀態(tài):

kubectl describe jobs/demo-job
# result
Name:                     demo-job
Namespace:                default
Selector:                 controller-uid=bde35f54-a1f8-4f1b-845f-d42e9c570f23
Labels:                   controller-uid=bde35f54-a1f8-4f1b-845f-d42e9c570f23
                          job-name=demo-job
Annotations:              <none>
Parallelism:              3
Completions:              10
Start Time:               Sat, 27 Mar 2021 23:58:51 +0000
Completed At:             Sat, 27 Mar 2021 23:59:11 +0000
Duration:                 20s
Active Deadline Seconds:  300s
Pods Statuses:            0 Running / 10 Succeeded / 0 Failed
result

可以看到,這個 Job 對象在創(chuàng)建后,它的 Pod 模板,被自動加上了一個 controller-uid=< 一個隨機字符串 > 這樣的 Label。而這個 Job 對象本身,則被自動加上了這個 Label 對應(yīng)的 Selector,從而 保證了 Job 與它所管理的 Pod 之間的匹配關(guān)系。之所以要使用這種攜帶了 UID 的 Label,就是為了避免不同 Job 對象所管理的 Pod 發(fā)生重合。

2.3 參數(shù)

關(guān)于上面的YAML參數(shù),詳細分析如下:

  • spec.backoffLimit
    指定在標記此作業(yè)失敗之前重試的次數(shù),默認為6。并且,Job Controller 重新創(chuàng)建 Pod 的間隔是呈指數(shù)增加的,即下一次重新創(chuàng)建 Pod 的動作會分別發(fā)生在 10 s、20 s、40 s …后。
  • spec.activeDeadlineSeconds
    指定相對于startTime的持續(xù)時間(以秒為單位),在系統(tǒng)嘗試終止該作業(yè)之前,該作業(yè)可能處于活動狀態(tài);值必須為正整數(shù)。例如,一旦運行超過了 300 s,這個 Job 的所有 Pod 都會被終止。并且,可以在 Pod 的狀態(tài)里看到終止的原因是 reason: DeadlineExceeded。
  • restartPolicy
    restartPolicy 在 Job 對象里只允許被設(shè)置為 Never 和 OnFailure,關(guān)于restartPolicy有如下倆種選項:
    • Never
      配置為當前參數(shù)后,那么離線作業(yè)失敗后 Job Controller 就會不斷地嘗試創(chuàng)建一個新 Pod。
      當然,這個嘗試肯定不能無限進行下去,這個與spec.backoffLimit參數(shù)是配合使用的。
    • OnFailure
      配置為當前參數(shù)后,那么離線作業(yè)失敗后,Job Controller 就不會去創(chuàng)建新的 Pod,而是會不斷地嘗試重啟 Pod 里的容器。

三. Job Controller

3.1 原理

Job Controller 控制的對象就是 Pod。
其次,Job Controller 在控制循環(huán)中進行的調(diào)諧(Reconcile)操作,是根據(jù)實際在 Running 狀態(tài) Pod 的數(shù)目、已經(jīng)成功退出的 Pod 的數(shù)目,以及 parallelism、completions 參數(shù)的值共同計算出在這個周期里,應(yīng)該創(chuàng)建或者刪除的 Pod 數(shù)目,然后調(diào)用 Kubernetes API 來執(zhí)行這個操作。

如果在這次調(diào)諧周期里,Job Controller 發(fā)現(xiàn)實際在 Running 狀態(tài)的 Pod 數(shù)目,比 parallelism 還大,那么它就會刪除一些 Pod,使兩者相等。

Job Controller 實際上控制了作業(yè)執(zhí)行的并行度,以及總共需要完成的任務(wù)數(shù)這兩個重要參數(shù)。而在實際使用時,我們需要根據(jù)作業(yè)的特性,來決定并行度(parallelism)和任務(wù)數(shù)(completions)的合理取值。

3.2 參數(shù)

在 Job 對象中,負責并行控制的參數(shù)有兩個:

  • spec.parallelism
    指定作業(yè)在任何給定時間應(yīng)運行的Pod的最大期望數(shù)目。
    ((.spec.completions-.status.successful)<.spec.parallelism),即當要做的工作小于最大并行度時,穩(wěn)定狀態(tài)下運行的Pod的實際數(shù)量將小于此數(shù)量。
  • spec.completion
    指定與作業(yè)一起運行所需的成功完成的Pod數(shù)量。
    設(shè)置為nil表示任何Pod的成功都表示所有Pod的成功,并允許并行性具有任何正值。設(shè)置為1意味著并行度被限制為1,并且pod的成功標志著工作的成功。

3.3 場景

3.3.1 parallelism和completions都確定

在這種模式下使用 Job 對象,completionsparallelism 這兩個字段都應(yīng)該使用默認值 1,而不應(yīng)該由我們自行設(shè)置。
一般實際落地方案就是:外部管理器 +Job 模板。作業(yè) Pod 的并行控制,應(yīng)該完全交由外部工具來進行管理(比如,KubeFlow)。

3.3.2 parallelism不確定,completions確定

當只關(guān)心最后是否有指定數(shù)目(spec.completions)個任務(wù)成功退出,而不關(guān)系任務(wù)并行度時。
一般采用:外部MQ+Job。利用確定的Pod數(shù),主動去消費MQ里面的消息達到目標數(shù)量即可。
例如,每個 Pod 只需要將任務(wù)信息讀取出來,處理完成,然后退出即可。而作為用戶,只關(guān)心最終一共有 10 個計算任務(wù)啟動并且退出,只要這個目標達到,就認為整個 Job 處理完成了。

3.3.3 parallelism確定,completions不確定

由于任務(wù)數(shù)目的總數(shù)不固定,所以每一個 Pod 必須能夠知道,什么時候可以退出。比如,借助上面例子,簡單地以“隊列為空”,作為任務(wù)全部完成的標志。
在這種情況下,難點在于任務(wù)的總數(shù)是未知的,所以不僅需要一個工作隊列來負責任務(wù)分發(fā),還需要能夠判斷工作隊列已經(jīng)為空。

四. Cron Job

4.1 原理

此處先看demo-cronjob.yaml文件:

apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: demo-cronjob
spec:
  schedule: "*/5 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: hello
            image: busybox
            args:
            - /bin/sh
            - -c
            - date; echo Hello World
          restartPolicy: OnFailure
  concurrencyPolicy: Replace
  startingDeadlineSeconds: 500

在這個 YAML 文件中,最重要的關(guān)鍵詞就是 jobTemplateCronJob 是一個 Job 對象的控制器。CronJob 與 Job 的關(guān)系,正如同 Deployment 與 ReplicaSet 的關(guān)系一樣。

4.2 Unix Cron

CronJob 是一個專門用來管理 Job 對象的控制器。只不過,它創(chuàng)建和刪除 Job 的依據(jù),是 schedule 字段定義的、一個標準的Unix Cron格式的表達式。
Cron 表達式中的五個部分分別代表:分鐘、小時、日、月、星期。

*/5 * * * * 這個 Cron 表達式里 */5 中的 * 表示從 0 開始,/ 表示“每”,1 表示偏移量。含義就是:從 0 開始,每 5 個時間單位執(zhí)行一次。

關(guān)于上面的任務(wù),執(zhí)行如下倆條指令可以查看結(jié)果(等待5min):

kubectl get jobs
kubectl get cronjob demo-cronjob

結(jié)果如下:


cron job

4.3 并發(fā)策略

由于定時任務(wù)的特殊性,很可能某個 Job 還沒有執(zhí)行完,另外一個新 Job 就產(chǎn)生了。這時候,你可以通過 spec.concurrencyPolicy字段來定義具體的處理策略。
concurrencyPolicy 有如下三種配置參數(shù):

  • Allow
    允許CronJobs并發(fā)運行,默認值。
  • Forbid
    禁止同時運行,如果前一個運行尚未完成,則跳過下一個運行。
  • Replace
    取消當前正在運行的作業(yè),并將其替換為新作業(yè)。

如果由于任何原因錯過了計劃的時間,則以秒為單位的可選截止期限,用于開始工作。當在指定的時間窗口內(nèi),miss 的數(shù)目達到 100 時,那么 CronJob 會停止再創(chuàng)建這個 Job。這個時間窗口,可以由 spec.startingDeadlineSeconds 字段指定。
在上面例子中, startingDeadlineSeconds=500,意味著在過去 500 s 里,如果 miss 的數(shù)目達到了 100 次,那么這個 Job 就不會被創(chuàng)建執(zhí)行了。

四. 總結(jié)

關(guān)于Job,Cron Job 和 Job Controller 這三者,都是采用了控制器模式設(shè)計,利用對象管理對象,是一種樹狀的層級管理。這點與Deployment,ReplicaSet和Deployment Controller之間的設(shè)計理念一致。
用一個對象控制另一個對象,是 Kubernetes 編排的精髓所在!

歡迎收藏個人博客: Wyatt's Blog ,非常感謝~

Reference

https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • “離線業(yè)務(wù)”,或者叫作 Batch Job(計算業(yè)務(wù))。這種業(yè)務(wù)在計算完成后就直接退出了,而此時如果你依然用 De...
    xuxw閱讀 919評論 0 0
  • 前言 Pod的分類 自助式pod 只要pod退出了,此類型的pod不會被重建,該pod沒有管理者,死亡后不會被拉起...
    小波同學(xué)閱讀 748評論 0 0
  • 容器技術(shù)概念入門篇 從進程說開去 容器本身沒有價值,有價值的是“容器編排”。 容器其實是一種沙盒技術(shù)。顧名思義,沙...
    白板時鐘閱讀 2,776評論 0 2
  • 一、Kubernetes介紹 核心功能 Kubernetes抽象了數(shù)據(jù)中心的硬件設(shè)施,使得對外暴露的只是一個巨大的...
    睡不醒的大橘閱讀 1,333評論 0 5
  • MySQL集群的流程遷移到 Kubernetes Master 節(jié)點和 Slave 節(jié)點需要有不同的配置文件(即:...
    小王的平凡生活_jerome閱讀 514評論 0 0

友情鏈接更多精彩內(nèi)容