Kubernetes:Job剖析

一. 簡介

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

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

二. Job

2.1 案例

如下,我們創(chuàng)建一個(gè)計(jì)算pi后面100位的案例,需要執(zhí)行10個(gè)這樣的任務(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

運(yùn)行完畢后,我們將看到如下的狀態(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

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

2.3 參數(shù)

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

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

三. Job Controller

3.1 原理

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

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

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

3.2 參數(shù)

在 Job 對(duì)象中,負(fù)責(zé)并行控制的參數(shù)有兩個(gè):

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

3.3 場景

3.3.1 parallelism和completions都確定

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

3.3.2 parallelism不確定,completions確定

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

3.3.3 parallelism確定,completions不確定

由于任務(wù)數(shù)目的總數(shù)不固定,所以每一個(gè) Pod 必須能夠知道,什么時(shí)候可以退出。比如,借助上面例子,簡單地以“隊(duì)列為空”,作為任務(wù)全部完成的標(biāo)志。
在這種情況下,難點(diǎn)在于任務(wù)的總數(shù)是未知的,所以不僅需要一個(gè)工作隊(duì)列來負(fù)責(zé)任務(wù)分發(fā),還需要能夠判斷工作隊(duì)列已經(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

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

4.2 Unix Cron

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

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

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

kubectl get jobs
kubectl get cronjob demo-cronjob

結(jié)果如下:


cron job

4.3 并發(fā)策略

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

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

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

四. 總結(jié)

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

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

Reference

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

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

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

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

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