前言
大家好,我是秋意零。
在上一篇中,我們講解了 DaemonSet 控制器,相信你以及理解了其的工作過程,分為三部。一是,獲取所有 Node 節(jié)點中的 Pod;二是,判斷是否有符合 DaemonSet 管理的 Pod;三是,通過“親和性”和“容忍”來精確控制并保證 Pod 在目標節(jié)點運行。
今天的內(nèi)容是 Job 與 CronJob 離線業(yè)務(wù)控制器。
?? 簡介
- ?? 個人主頁: 秋意零
- ?? 賬號:全平臺同名, 秋意零 賬號創(chuàng)作者、 云社區(qū) 創(chuàng)建者
- ?? 個人介紹:在校期間參與眾多云計算相關(guān)比賽,如:?? “省賽”、“國賽”,并斬獲多項獎項榮譽證書
- ?? 目前狀況:24 屆畢業(yè)生,拿到一家私有云(IAAS)公司 offer,暑假開始實習
- ??歡迎大家:歡迎大家一起學習云計算,走向年薪 30 萬
- ??推廣:CSDN 主頁左側(cè),是個人扣扣群推廣。方便大家技術(shù)交流、技術(shù)博客互助。
系列文章目錄
【云原生|探索 Kubernetes-1】容器的本質(zhì)是進程
【云原生|探索 Kubernetes-2】容器 Linux Cgroups 限制
【云原生|探索 Kubernetes 系列 3】深入理解容器進程的文件系統(tǒng)
【云原生|探索 Kubernetes 系列 4】現(xiàn)代云原生時代的引擎
【云原生|探索 Kubernetes 系列 5】簡化 Kubernetes 的部署,深入解析其工作流程
更多點擊專欄查看:深入探索 Kubernetes
正文開始:
- 快速上船,馬上開始掌舵了(Kubernetes),距離開船還有 3s,2s,1s...
一、離線業(yè)務(wù)
通過前面篇章中的學習的控制器,如:Deployment、StatefulSet、DaemonSet 這三個編排控制器,它們所部署的服務(wù)都有什么共同點嗎?
答案是:有的。
- 其實,它們主要編排的對象業(yè)務(wù),都是“在線業(yè)務(wù)”,即:Long Running Task(長作業(yè))。比如:Nginx、Tomcat、Apache、MySQL 等等,這部分業(yè)務(wù)只要一運行起來,如果不出現(xiàn)錯誤或手動停止刪除,這些服務(wù)的容器(進程)會一直運行(Running)下去。
既然有了這種“在線業(yè)務(wù)”,那是不是就一定有“離線業(yè)務(wù)”呢?
答案:是的。
- “離線業(yè)務(wù)”對比“在線業(yè)務(wù)”是相反的概率,就是服務(wù)不會一直運行下去,而是服務(wù)自己的任務(wù)完成之后就會自動退出。
如果使用控制“在線業(yè)務(wù)”的控制器,來編排“離線業(yè)務(wù)”會是怎么樣呢?
- “離線業(yè)務(wù)”或者叫作 Batch Job(計算業(yè)務(wù)):這種情況下是沒有意義的,比如:使用 Deployment 來編排一個“離線業(yè)務(wù)”,“離線業(yè)務(wù)”完成后就會自動退出,而因為 Deployment 的緣故會實際狀態(tài)的 Pod 個數(shù)保持在期望狀態(tài)的 Pod 個數(shù),也就會重新創(chuàng)建這個“離線業(yè)務(wù)”。
- 咋一看,好像也沒什么,如果將“離線業(yè)務(wù)”任務(wù)是用來計算 1+1 的這種運行結(jié)果時,不斷重建“離線業(yè)務(wù)”是不是就失去了意義了呢?
- 因為完全沒有必要。而使用 Deployment 的“滾動更新”功能也是一樣的道理,無意義。
二、Job 基本概念與用法
現(xiàn)在,我們來看一個 Job 計算 π 后 10000 位小數(shù)的例子:
apiVersion: batch/v1
kind: Job
metadata:
name: pi
spec:
template:
spec:
containers:
- name: pi
image: resouer/ubuntu-bc
command: ["sh", "-c", "echo 'scale=10000; 4*a(1)' | bc -l "]
restartPolicy: Never
backoffLimit: 4
可以看到,這個例子的 spec.template
字段可謂是非常熟悉了吧(Pod 模板)。但是,跟其他控制器不同的是,Job 對象并不要求你定義一個 spec.selector 來綁定要控制哪些 Pod。
這個 Job 使用的一個 ubuntu 鏡像 ,安裝有 bc 精度的計算命令,并運行了一條計算 π 后 10000 位小數(shù)的命令:
echo 'scale=10000; 4*a(1)' | bc -l
- scale:定義某些操作如何使用小數(shù)點后的數(shù)字,默認為 0;
- 4*a(1):a(1),是調(diào)用數(shù)學庫中的 arctangent 函數(shù),4*atan(1) 正好就是 π,也就是 3.1415926…;
- -l 參數(shù):定義使用的標準數(shù)學庫。
- 運行這個 Job:
[root@master01 yaml]# kubectl apply -f job.yaml
job.batch/pi created
[root@master01 yaml]# kubectl describe job/pi
我們來查看一下這個 Job 對象詳細信息:
- 可以看到創(chuàng)建 Job 之后,Job 自動為 Pod Template 添加了一個標簽,格式為:controller-uid=<一個隨機字符串>。Job 本身也添加了對應(yīng)的 Selector,從而保證了 Job 與它所管理的 Pod 之間的匹配關(guān)系。
- 而 Job 控制器使用這種 UID 的標簽,就是為了避免不同 Job 對象所管理的 Pod 發(fā)生重合。因為它不需要對特定的副本進行選擇或管理,Job 僅負責執(zhí)行一次性任務(wù),而不需要與其他副本進行交互或進行標簽選擇。
- Job 中也沒有 replicas 字段。因為, Job 的主要目的是確保任務(wù)的完成,不是保持一定數(shù)量的副本運行。當 Job 中定義的任務(wù)成功完成后,Job 會認為任務(wù)已經(jīng)完成,并且不會重新創(chuàng)建新的任務(wù)。因此,replicas 字段在 Job 中沒有意義。
- 創(chuàng)建 Job 后,查看 Pod 的狀態(tài):
[root@master01 yaml]# kubectl get pod
NAME READY STATUS RESTARTS AGE
pi-nxplz 1/1 Running 0 31s
幾分鐘后 Pod 進入 Completed 狀態(tài),說明它的任務(wù)已經(jīng)完成。不重啟的原因:我們在 Pod 模板中定義過了 restartPolicy=Never 策略。
Job 中的重啟策略 restartPolicy,只能被設(shè)置為 Never 和 OnFailure;
[root@master01 yaml]# kubectl get pod
NAME READY STATUS RESTARTS AGE
pi-nxplz 0/1 Completed 0 4m
[root@master01 yaml]# kubectl get job
NAME COMPLETIONS DURATION AGE
pi 0/1 3s 3s
- kubectl logs 命令,查看運行結(jié)果:
[root@master01 ~]# kubectl logs pod/pi-nxplz
3.141592653589793238462643383279502884197169399375105820974944592307\
81640628620899862803482534211706798214808651328230664709384460955058\
22317253594081284811174502841027019385211055596446229489549303819644\
28810975665933446128475648233786783165271201909145648566923460348610\
....
- 離線作業(yè)失敗了要怎么辦?
由于,定義了 restartPolicy=Never
,那么離線作業(yè)失敗后 Job Controller 就會不斷地嘗試創(chuàng)建一個新 Pod,如:
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
pi-55h89 0/1 ContainerCreating 0 2s
pi-tqbcz 0/1 Error 0 5s
不過,為了不讓這個 Pod 一直創(chuàng)建下去,因為一直創(chuàng)建下去說明我們程序就有問題,這個時候我們使用 spec.backoffLimit
字段來設(shè)置重試次數(shù),這個 Job 為 4,這個字段的默認值是 6。
需要注意的是:Job Controller 重新創(chuàng)建 Pod 的間隔是呈指數(shù)增加的,即:下一次重新創(chuàng)建 Pod 的動作會分別發(fā)生在 10 s、20 s、40 s …后。
而如果你定義的 restartPolicy=OnFailure
,那么離線作業(yè)失敗后,Job Controller 就不會去嘗試創(chuàng)建新的 Pod。但是,它會不斷地嘗試重啟 Pod 里的容器。
- 如果這個 Pod 因為某種原因一直不肯結(jié)束呢?
spec.activeDeadlineSeconds
字段可以設(shè)置最長運行時間,比如:
spec:
backoffLimit: 4
activeDeadlineSeconds: 100
這個程序運行一旦超過 100 s,那 Pod 會被終止。
以上,就是一個 Job API 對象最主要的概念和用法了。不過,離線業(yè)務(wù)之所以被稱為 Batch Job,當然是因為它們可以以“Batch”(批處理),也就是并行的方式去運行。
三、Job Controller 并行作業(yè)的控制方法
在 Job 對象中,負責并行控制的參數(shù)有兩個:
- 1. spec.parallelism:Job 最多可以啟動多少個 Pod 同時運行;
- 2. spec.completions:Job 至少要完成的 Pod 數(shù)目,即 Job 的最小完成數(shù)。
在之前計算 Pi 值的 Job 里,添加這兩個參數(shù):
- 并行數(shù)量為 2
- 至少完成的數(shù)量為 4
apiVersion: batch/v1
kind: Job
metadata:
name: pi
spec:
parallelism: 2
completions: 4
template:
spec:
containers:
- name: pi
image: resouer/ubuntu-bc
command: ["sh", "-c", "echo 'scale=5000; 4*a(1)' | bc -l "]
restartPolicy: Never
backoffLimit: 4
- 創(chuàng)建 Job:
[root@master01 yaml]# kubectl apply -f job.yaml
- 查看 Job:
- COMPLETIONS:需要完成的數(shù)量以及完成的數(shù)量,比如:2/4,已完成 2 個任務(wù),至少需要完成 4 個任務(wù)。
[root@master01 yaml]# kubectl get job
NAME COMPLETIONS DURATION AGE
pi 2/4 57s 57s
當一組 Pod 完成后,就會有新的一組 Pod 繼續(xù)執(zhí)行
[root@master01 yaml]# kubectl get pod
NAME READY STATUS RESTARTS AGE
pi-js98q 1/1 Running 0 25s
pi-mhfsl 1/1 Running 0 25s
pi-t2w8n 0/1 Completed 0 55s
pi-z7gqh 0/1 Completed 0 55s
當所有 Pod 任務(wù)完成之后,Job 的 COMPLETIONS 字段也就變成了 4/4
[root@master01 yaml]# kubectl get pod
NAME READY STATUS RESTARTS AGE
pi-js98q 0/1 Completed 0 8m56s
pi-mhfsl 0/1 Completed 0 8m56s
pi-t2w8n 0/1 Completed 0 9m26s
pi-z7gqh 0/1 Completed 0 9m26s
[root@master01 yaml]# kubectl get job
NAME COMPLETIONS DURATION AGE
pi 4/4 59s 3m59s
Job Controller 實際上控制了,作業(yè)執(zhí)行的并行度,以及總共需要完成的任務(wù)數(shù)這兩個重要參數(shù)。而在實際使用時,你需要根據(jù)作業(yè)的特性,來決定并行度(parallelism)和任務(wù)數(shù)(completions)的合理取值。
四、使用 Job 常用的方法
外部管理器 +Job 模板
這種模式的用法是:把 Job 的 YAML 文件當作一個模板,然后使用外部工具來控制生成 Job。如下:
apiVersion: batch/v1
kind: Job
metadata:
name: process-item-$ITEM
labels:
jobgroup: jobexample
spec:
template:
metadata:
name: job-example
labels:
jobgroup: jobexample
spec:
containers:
- name: busybox-job
image: busybox
command: ["sh", "-c", "echo Hello $ITEM && sleep 5"]
restartPolicy: Never
Job 的 YAML 中,定義了 $ITEM 變量,所以在控制這中 Job 時,需要注意兩個方面:
- 1. 創(chuàng)建 Job 時,替換掉 $ITEM 變量,為自己的信息;
- 2. 來自于同一個模板的 Job,這里都有一個
jobgroup: jobexample
標簽,也就是說這一組 Job 使用這樣一個相同的標識。
使用 Shell 把 $ITME 替換掉
[root@master01 yaml]# mkdir ./jobs
[root@master01 yaml]# for i in qyl-1 qyl-2 qyl-3
> do
> cat job-1.yaml | sed "s/\$ITEM/$i/g" > ./jobs/job-$i.yaml
> done
這樣通過 Shell 腳本的方式,同一個 Job 模板生成了不同的 Job 的 YAML 文件
[root@master01 yaml]# ll ./jobs
total 12
-rw-r--r-- 1 root root 372 Jun 25 17:31 job-qyl-1.yaml
-rw-r--r-- 1 root root 372 Jun 25 17:31 job-qyl-2.yaml
-rw-r--r-- 1 root root 372 Jun 25 17:31 job-qyl-3.yaml
[root@master01 yaml]# kubectl apply -f ./jobs
job.batch/process-item-qyl-1 created
job.batch/process-item-qyl-2 created
job.batch/process-item-qyl-3 created
[root@master01 yaml]# kubectl get pods -l jobgroup=jobexample
NAME READY STATUS RESTARTS AGE
process-item-qyl-1-tgr5k 0/1 Completed 0 53s
process-item-qyl-2-bftz4 0/1 Completed 0 53s
process-item-qyl-3-cgvwd 0/1 Completed 0 53s
五、CronJob
顧名思義,CronJob 描述的,是定時任務(wù)。
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: hello
spec:
schedule: "*/1 * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: hello
image: busybox
imagePullPolicy: IfNotPresent
args:
- /bin/sh
- -c
- date; echo Hello qyl-0
restartPolicy: OnFailure
CronJob 的 YAML 文件中,spec.jobTemplate
字段表示的是“Job模板”,所以 CronJob 是 Job 對象的控制器。CronJob 與 Job 之間的關(guān)系就與 Deployment 和 ReplicaSet 一樣的。不過它生命周期是由 schedule 字段控制的。
它也像我們 Linxu 里面的 CronTab,所以這里的 schedule 字段的格式是一個標準的 Cron 格式。比如:"*/1 * * * *"。
這個 Cron 表達式里 */1 中的 * 表示從 0 開始,/ 表示“每”,1 表示偏移量。所以,它的意思就是:從 0 開始,每 1 個時間單位執(zhí)行一次。
所以,上面的 CronJob 的 YAML 文件會一分鐘后創(chuàng)建 Job:
[root@master01 yaml]# kubectl get cronjob
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
hello */1 * * * * False 0 26s 58s
[root@master01 yaml]# kubectl get job
NAME COMPLETIONS DURATION AGE
hello-28128130 1/1 4s 27s
需要注意的是,由于定時任務(wù)的特殊性,很可能某個 Job 還沒有執(zhí)行完,另外一個新 Job 就產(chǎn)生了。這時候,你可以通過 spec.concurrencyPolicy
字段來定義具體的處理策略。比如:
-
concurrencyPolicy=Allow
:這也是默認情況,這意味著這些 Job 可以同時存在 -
concurrencyPolicy=Forbid
:這意味著不會創(chuàng)建新的 Pod,該創(chuàng)建周期被跳過; -
concurrencyPolicy=Replace
:這意味著新產(chǎn)生的 Job 會替換舊的、沒有執(zhí)行完的 Job。
而如果某一次 Job 創(chuàng)建失敗,這次創(chuàng)建就會被標記為“miss”。當在指定的時間窗口內(nèi),miss 的數(shù)目達到 100 時,那么 CronJob 會停止再創(chuàng)建這個 Job。
這個時間窗口,可以由 spec.startingDeadlineSeconds
字段指定。比如:
-
startingDeadlineSeconds=200
,意味著在過了 200 s 后,如果 miss 的數(shù)目達到了 100 次,那么這個 Job 就不會被創(chuàng)建執(zhí)行了。
總結(jié)
今天,主要講解了 Job 這種“離線業(yè)務(wù)”控制器的概率用法,并行控制的方法。文章來源:http://www.zghlxwxcb.cn/news/detail-517829.html
最后,解釋了 CronJob 的使用,CronJob 也體現(xiàn)了,用一個對象控制另一個對象,是 Kubernetes 編排的精髓所在。文章來源地址http://www.zghlxwxcb.cn/news/detail-517829.html
到了這里,關(guān)于【探索 Kubernetes|作業(yè)管理篇 系列 16】離線業(yè)務(wù) Job、CronJob的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!