【Kubernetes】离线业务:Job与CronJob
Deployment、StatefulSet和DaemonSet這三個編排概念編排的對象主要都是在線業務(Long Running Task,這些應用一旦運行起來,除非出錯或者停止,它的容器進程會一直保持在Running狀態)。
但是對于離線業務(Batch Job,計算業務)在計算完成后就直接退出了,如果依然使用Deployment來管理,就會發現Pod會在計算結束后退出,然后被Deployment Controller不斷重啟。
在Kubernetes v1.4版本之后,設計出來一個用來描述離線業務的API對象:Job。
舉個Job的栗子
apiVersion: batch/v1 kind: Job metadata:name: pi spec:template:spec:containers:- name: piimage: resouer/ubuntu-bc #安裝了ba明了的Ubuntu鏡像command: ["sh", "-c", "echo 'scale=10000; 4*a(1)' | bc -l "] #bc命令是Linux里的計算器,; -l表示使用標準數學課; a(1)調用arctangent函數,scale指定小數點后的位數restartPolicy: NeverbackoffLimit: 4創建這個Pod
$ kubectl create -f job.yaml $ kubectl describe jobs/pi Name: pi Namespace: default Selector: controller-uid=c2db599a-2c9d-11e6-b324-0209dc45a495 Labels: controller-uid=c2db599a-2c9d-11e6-b324-0209dc45a495job-name=pi Annotations: <none> Parallelism: 1 Completions: 1 .. Pods Statuses: 0 Running / 1 Succeeded / 0 Failed Pod Template:Labels: controller-uid=c2db599a-2c9d-11e6-b324-0209dc45a495job-name=piContainers:...Volumes: <none> Events:FirstSeen LastSeen Count From SubobjectPath Type Reason Message--------- -------- ----- ---- ------------- -------- ------ -------1m 1m 1 {job-controller } Normal SuccessfulCreate Created pod: pi-rq5rl可以看大這個Job對象在創建后,它的Pod模板被自動加上了一個Labels,?controller-uid=<一個隨機的字符串>。而Job對象本身,則被自動加上了這個Label對應的Selector,從而保證了Job與它所管理的Pod之間的匹配關系。
? Job Controller之所以要使用這種攜帶了UID的Label,就是為了避免不同Job對象管理的Pod重合
### 接下來可以看到這個Job創建的Pod進入了Running狀態,這意味著它正在計算Pi的值$ kubectl get pods NAME READY STATUS RESTARTS AGE pi-rq5rl 1/1 Running 0 10s###計算結束后,Pod會進入Completed狀態,這也是需要在Pod模板中定義restartPolicy=Never的原因:離線計算的Pod永遠不應該被重啟$ kubectl get pods NAME READY STATUS RESTARTS AGE pi-rq5rl 0/1 Completed 0 4m### 通過查看log可以看到計算的值
? $ kubectl logs pi-rq5rl
? 3.141592653589793238462643383279...
那如果這個離線作業失敗了怎么辦?因為這個例子中定義了restartPolicy=Never,那離線作業失敗后Job Controller就會不斷地嘗試創建一個新Pod
Job對象的spec.backoffLimit字段限制嘗試的次數,在例子中定義為4,默認值為6。Job Controller重新創建Pod的間隔是呈倍數增加的,即下一次重新創建Pod的動作會分別發生在10s,20s,40s……
那如果定義的restartPolicy=OnFailure呢?離線作業失敗后,Job Controller就不會去嘗試創建新的Pod,但是它會不斷嘗試重啟Pod里的容器。
那如果這個Pod一直不肯結束呢?spec.activeDeadlineSeconds字段可以設置最長運行時間
spec:backoffLimit: 5activeDeadlineSeconds: 100 # 運行超過100s,這個Job的所有Pod都會被終止
?Job Controller 對并行作業的控制方法
在Job對象中,負責并行控制的參數有兩個:
spec.parallelism:定義一個Job在任意時間最多可以啟動多少個Pod同時運行
spec.completions:定義Job至少要玩的Pod的數目
再舉個栗子
apiVersion: batch/v1 kind: Job metadata:name: pi spec:parallelism: 2completions: 4template:spec:containers:- name: piimage: resouer/ubuntu-bccommand: ["sh", "-c", "echo 'scale=5000; 4*a(1)' | bc -l "]restartPolicy: NeverbackoffLimit: 4指定了最大并行數是2,最小完成數是4
### 創建Job對象 $ kubectl create -f job.yaml### Job維護兩個字段,DESIRED即最小完成數 $ kubectl get job NAME DESIRED SUCCESSFUL AGE pi 4 0 3s### Job首先創建兩個并行運行的Pod計算PI $ kubectl get pods NAME READY STATUS RESTARTS AGE pi-5mt88 1/1 Running 0 6s pi-gmcq5 1/1 Running 0 6s### 當一個Pod完成計算會進入Completed狀態,就會有一個新的Pod被創建出來,并且快速地從Pending狀態進入ContainerCreating狀態,再到Running狀態,最后完成 $ kubectl get pods NAME READY STATUS RESTARTS AGE pi-gmcq5 0/1 Completed 0 40s pi-84ww8 0/1 Pending 0 0s pi-5mt88 0/1 Completed 0 41s pi-62rbt 0/1 Pending 0 0s$ kubectl get pods NAME READY STATUS RESTARTS AGE pi-gmcq5 0/1 Completed 0 40s pi-84ww8 0/1 ContainerCreating 0 0s pi-5mt88 0/1 Completed 0 41s pi-62rbt 0/1 ContainerCreating 0 0s$ kubectl get pods NAME READY STATUS RESTARTS AGE pi-5mt88 0/1 Completed 0 54s pi-62rbt 1/1 Running 0 13s pi-84ww8 1/1 Running 0 14s pi-gmcq5 0/1 Completed 0 54s$ kubectl get pods NAME READY STATUS RESTARTS AGE pi-5mt88 0/1 Completed 0 5m pi-62rbt 0/1 Completed 0 4m pi-84ww8 0/1 Completed 0 4m pi-gmcq5 0/1 Completed 0 5m### 所有Pod均已成功退出,SUCCESSFUL字段值變成4 $ kubectl get job NAME DESIRED SUCCESSFUL AGE pi 4 4 5m通過上述DESIRED和SUCCESSFUL字段的關系,可以看出Job Controller控制的直接對象是Pod,Job Controller在控制循環中進行的調諧(Reconcile)操作,是根據實際在Running狀態Pod數目、已經成功推出的Pod數目,以及parallelism、completions參數的值共同計算在這個周期里,應該創建或刪除的Pod數目,然后調用Kubernetes API來執行這個操作?
?
Job對象使用方法
1、外部管理器 + Job模板
把Job的YAML文件定義為一個模板,然后用一個外部工具控制這些模板來生成Job 。Job的定義方式如下所示:
apiVersion: batch/v1 kind: Job metadata:name: process-item-$ITEMlabels:jobgroup: jobexample spec:template:metadata:name: jobexamplelabels:jobgroup: jobexamplespec:containers:- name: cimage: busyboxcommand: ["sh", "-c", "echo Processing item $ITEM && sleep 5"] ### 定義了$ITEM變量restartPolicy: Never在控制這種Job時,只要注意如下兩個方面即可
-
- 創建Job時,替換掉$ITEM這樣的變量
- 所有來自同一個目標的Job,都有一個jobgroup: jobexample標簽,也就是說這一組Job使用這樣一個相同的標識
這種模式雖然看起很傻,但卻很普遍,因為大多數用戶在需要管理Batch Job時,都已經有自家的一套方案,需要做的往往就是集成工作。這時候Kubernetes對這些方案最有價值的就是Job這個API對象,因此只需要編寫一個外部工具(如上面for循環)來管理這些Job即可。
這種模式下使用Job對象,completions和parallelism這兩個字段都應該使用默認值1,作業Pod的并行控制,應該完全交由外部工具來進行管理
?
2、擁有固定任務數目的并行Job
? 只關心最后是否有指定數目(spec.completions)個任務成功推出,不關心執行時的并行度多少。
比如上面計算pi的例子,或者可以不指定parallelism
?
?3、指定并行度(parallelism),不設置固定的completions的值
任務總數未知,需要決定什么時候啟動Pod,什么時候Job才算執行完成。因此需要一個工作隊列來負責任務分發,還需要能夠判斷工作隊列已經為空(所有工作已經結束)
apiVersion: batch/v1 kind: Job metadata:name: job-wq-2 spec:parallelism: 2template:metadata:name: job-wq-2spec:containers:- name: cimage: gcr.io/myproject/job-wq-2env:- name: BROKER_URLvalue: amqp://guest:guest@rabbitmq-service:5672 ##工作隊列采用RabbitMQ- name: QUEUEvalue: job2restartPolicy: OnFailure?
這個Pod執行邏輯為
/* job-wq-2 的偽代碼 */ for !queue.IsEmpty($BROKER_URL, $QUEUE) {task := queue.Pop()process(task) } print("Queue empty, exiting") exit?
?
CronJob
CronJob描述的是定時任務,舉個栗子
apiVersion: batch/v1beta1 kind: CronJob metadata:name: hello spec:schedule: "*/1 * * * *"jobTemplate:spec:template:spec:containers:- name: helloimage: busyboxargs:- /bin/sh- -c- date; echo Hello from the Kubernetes clusterrestartPolicy: OnFailure在這個YAML文件中,最重要的關鍵詞就是jobTemplate,即一個Job對象的控制器(Controller)。如Deployment和Pod的關系一樣,CronJob是一個專門用來管理Job對象的控制器。
CronJob創建和刪除Job的依據是schedule字段定義的、一個標準的Unix Cron格式的表達式
如,“*/1****”,這個Cron表達式里*/1中的*表示從0開始,/表示每,1表示偏移量,它的意思就是從零開始,每1個時間單位執行一次
那時間單位又是什么意思?Cron表達式中的五個部分分別代表:分鐘、小時、日、月、星期。因此上面的意思就是每分鐘執行一次。
$ kubectl create -f ./cronjob.yaml cronjob "hello" created# 一分鐘后 $ kubectl get jobs NAME DESIRED SUCCESSFUL AGE hello-4111706356 1 1 2s##CronJob對象會記錄下這次Job的執行時間 $ kubectl get cronjob hello NAME SCHEDULE SUSPEND ACTIVE LAST-SCHEDULE hello */1 * * * * False 0 Thu, 6 Sep 2018 14:34:00 -070另外由于定時任務的特殊性,很可能某個Job還沒有執行完,另外一個新的Job就產生了,這時候可以通過spec.concurrencyPolicy字段來定義具體的處理策略
-
- concurrencyPolicy=Allow:默認情況,Job可以同時存在;
- concurrencyPolicy=Forbid:不會創建新的Jod,該創建周期被跳過
- concurrencyPolicy=Replace:新產生的Job會替換舊的、沒有執行完的Job
如果一個Job創建失敗,這次創建就會被標記為“miss”,當在指定的時間窗口內,miss的數目達到100時,那么CronJob會停止創建這個Job。這個時間窗口可以由spec.startingDeadlineSeconds字段指定。
例如,startingDeadlineSeconds=200,意味著在過去的200s里,如果miss的數目到達了100次,那么這個Job就不會被創建執行了。
?
轉載于:https://www.cnblogs.com/yuxiaoba/p/9797331.html
總結
以上是生活随笔為你收集整理的【Kubernetes】离线业务:Job与CronJob的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 了解一下ES6: 函数简述深浅拷贝
- 下一篇: 如何让hybris启动加快