系列目錄html
對於ReplicaSet、ReplicationController等類型的控制器而言,它但願pod保持預期數目、持久運行下去,除非用戶明確刪除,不然這些對象一直存在,它們針對的是耐久性任務,如web服務等。對於非耐久性任務,好比壓縮文件,任務完成後,pod須要結束運行,不須要pod繼續保持在系統中,這個時候就要用到Job。所以說Job是對ReplicaSet、ReplicationController等持久性控制器的補充。python
Job定義方法與ReplicaSet等控制器類似,只有細微差異,以下:web
Job中的restart policy必需是"Never"或者"OnFailure",這個很好理解,由於pod要運行到結束,而不是反覆從新啓動。redis
Job不須要選擇器,其中的pod也不須要標籤,系統在建立Job時會自動添加相關內容。固然用戶也能夠出於資源組織的目的添加標籤,但這個與Job自己的實現沒有關係。json
Job新增長兩個字段:.spec.completions、.spec.parallelism。詳細用法在示例中說明api
backoffLimit字段:示例中說明bash
非併發Job的含義是,Job啓動後,只運行一個pod,pod運行結束後整個Job也就馬上結束。session
如下是簡單的Job配置文件,只包含一個pod,輸出圓周率小數點後2000位,運行時間大概爲10s:併發
apiVersion: batch/v1 kind: Job metadata: name: pi spec: template: spec: containers: - name: pi image: perl command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"] restartPolicy: Never backoffLimit: 4
以上示例無需設置選擇器、pod標籤。無需設置.spec.completions、.spec.parallelism,這兩個字段的默認值都是1。backoffLimit=4,表示容許pod失敗的次數。將以上內容保存成文件並建立Job:app
$ kubectl create -f https://k8s.io/examples/controllers/job.yaml job "pi" created
確認Job狀態:
$ kubectl describe jobs/pi Name: pi Namespace: default Selector: controller-uid=b1db589a-2c8d-11e6-b324-0209dc45a495 Labels: controller-uid=b1db589a-2c8d-11e6-b324-0209dc45a495 job-name=pi Annotations: <none> Parallelism: 1 Completions: 1 Start Time: Tue, 07 Jun 2016 10:56:16 +0200 Pods Statuses: 0 Running / 1 Succeeded / 0 Failed Pod Template: Labels: controller-uid=b1db589a-2c8d-11e6-b324-0209dc45a495 job-name=pi Containers: pi: Image: perl Port: Command: perl -Mbignum=bpi -wle print bpi(2000) Environment: <none> Mounts: <none> Volumes: <none> Events: FirstSeen LastSeen Count From SubobjectPath Type Reason Message --------- -------- ----- ---- ------------- -------- ------ ------- 1m 1m 1 {job-controller } Normal SuccessfulCreate Created pod: pi-dtn4q
從以上輸出能夠看到系統自動添加的Selector、Pod labels。注意Events的輸出,全程只建立了一個pod。
列出Job的全部pod:
$ pods=$(kubectl get pods --selector=job-name=pi --output=jsonpath={.items..metadata.name}) $ echo $pods pi-aiw0a
查看Pod的輸出
$ kubectl logs $pods 3.14159265358979323846264......
以上是最簡單的Job應用示例,輸出圓周率小數點後2000位。可是,考慮另一種狀況,假如咱們須要計算圓周率小數點後3000、4000、5000位怎麼辦?一種方案是先將上例中的2000改爲3000,建立並運行。而後再改爲4000,再建立並運行,一直到5000。顯然這種方案並不高明:麻煩、資源利用率低。另一種方法是同時建立4個Job,分別計算2000、3000、4000、5000。注意4個Job的name字段不能衝突分別是pi-2000、pi-3000、pi-4000、pi-5000,
文件名分別爲pi-2000.yaml、pi-3000.yaml、pi-4000.yaml、pi-5000.yaml,並保存在目錄/tmp/pi下。利用kubectl對目錄的支持一次性建立4個Job:
$ kubectl create -f /tmp/pi job "pi-2000" created job "pi-3000" created job "pi-4000" created job "pi-5000" created
以上方法是僞併發,只適用於任務量少的狀況。假如咱們須要處理的任務是從pi-1到pi-10000,那麼以上方法就不適用了:
須要同時建立太多的Job與pod,很差管理。
資源配額限制。
本例建立一個Job,但Job要建立多個pod。瞭解完示例後就明白爲何叫「粗併發」。
本示例須要一個消息隊列服務的配合,不詳細描述如何部署、填充消息隊列服務。假設咱們有一個RabbitMQ服務,集羣內訪問地址爲:amqp://guest:guest@rabbitmq-service:5672。其有一個名爲job1的隊列,隊列內有apple banana cherry date fig grape lemon melon共8個成員。
另外假設咱們有一個名爲gcr.io/
apiVersion: batch/v1 kind: Job metadata: name: job-wq-1 spec: completions: 8 parallelism: 2 template: metadata: name: job-wq-1 spec: containers: - name: c image: gcr.io/<project>/job-wq-1 env: - name: BROKER_URL value: amqp://guest:guest@rabbitmq-service:5672 - name: QUEUE value: job1 restartPolicy: OnFailure
上例中,completions的值爲8,等於job1隊列中元素的個數。由於每一個成功的pod處理一個元素,因此須要成功8次,job1中的全部成員就會被處理完成。在粗併發模式下,completions的值必需指定,不然其默認值爲1,整個Job只處理一個成員就結束了。
上例中,parallelism的值是2。雖然須要pod成功8次,但在同一時間,只容許有兩個pod併發。一個成功結束後,再啓動另外一個。這個參數的主要目的是控制併發pod的個數,可根據實際狀況調整。固然能夠不指定,那麼默認的併發個數就是1。
env中的內容告訴image如何訪問隊列。
將以上內容保存在job.yaml文件中,運行Job:
kubectl create -f ./job.yaml
稍等片刻Job運行完成,查看結果:
$ kubectl describe jobs/job-wq-1 Name: job-wq-1 Namespace: default Selector: controller-uid=41d75705-92df-11e7-b85e-fa163ee3c11f Labels: controller-uid=41d75705-92df-11e7-b85e-fa163ee3c11f job-name=job-wq-1 Annotations: <none> Parallelism: 2 Completions: 8 Start Time: Wed, 06 Sep 2017 16:42:02 +0800 Pods Statuses: 0 Running / 8 Succeeded / 0 Failed Pod Template: Labels: controller-uid=41d75705-92df-11e7-b85e-fa163ee3c11f job-name=job-wq-1 Containers: c: Image: gcr.io/causal-jigsaw-637/job-wq-1 Port: Environment: BROKER_URL: amqp://guest:guest@rabbitmq-service:5672 QUEUE: job1 Mounts: <none> Volumes: <none> Events: FirstSeen LastSeen Count From SubobjectPath Type Reason Message ───────── ──────── ───── ──── ───────────── ────── ────── ─────── 27s 27s 1 {job } Normal SuccessfulCreate Created pod: job-wq-1-hcobb 27s 27s 1 {job } Normal SuccessfulCreate Created pod: job-wq-1-weytj 27s 27s 1 {job } Normal SuccessfulCreate Created pod: job-wq-1-qaam5 27s 27s 1 {job } Normal SuccessfulCreate Created pod: job-wq-1-b67sr 26s 26s 1 {job } Normal SuccessfulCreate Created pod: job-wq-1-xe5hj 15s 15s 1 {job } Normal SuccessfulCreate Created pod: job-wq-1-w2zqe 14s 14s 1 {job } Normal SuccessfulCreate Created pod: job-wq-1-d6ppa 14s 14s 1 {job } Normal SuccessfulCreate Created pod: job-wq-1-p17e0
查看Events,能夠看到總共建立了8個pod。在本例中,每處理隊列中的一個成員都須要建立一個pod,開銷很大。若是隊列中的成員個數很是龐大,那麼這種處理方式就不適用。咱們但願少建立pod、每一個pod能處理多條記錄,請看下面示例
redis:6379> lrange job2 0 -1 1) "apple" 2) "banana" 3) "cherry" 4) "date" 5) "fig" 6) "grape" 7) "lemon" 8) "melon" 9) "orange"
接下來建立image,詳細過程不描述。只需肯定這個image運行以下名爲worker.py的python程序
#!/usr/bin/env python import time import rediswq host="redis" # Uncomment next two lines if you do not have Kube-DNS working. # import os # host = os.getenv("REDIS_SERVICE_HOST") q = rediswq.RedisWQ(name="job2", host="redis") print("Worker with sessionID: " + q.sessionID()) print("Initial queue state: empty=" + str(q.empty())) while not q.empty(): item = q.lease(lease_secs=10, block=True, timeout=2) if item is not None: itemstr = item.decode("utf=8") print("Working on " + itemstr) time.sleep(10) # Put your actual work here instead of sleep. q.complete(item) else: print("Waiting for work") print("Queue empty, exiting")
首先鏈接到redis的job2隊列。而後是一個while循環,每次讀job2中的一條記錄並輸出,而後sleep 10s。循環退出的條件是job2隊列爲空。這個image與示例2不一樣,示例2只處理一條記錄這就結束,而這個能夠處理多條一直到隊列爲空。
接下來定義Job:
apiVersion: batch/v1 kind: Job metadata: name: job-wq-2 spec: parallelism: 2 template: metadata: name: job-wq-2 spec: containers: - name: c image: gcr.io/myproject/job-wq-2 restartPolicy: OnFailure
上例中,無需像示例2同樣指定 completions的值,由於結束條件是job2爲空,已經內嵌在image的邏輯中。parallelism=2表示能夠併發兩個pod,不設置默認爲1,在實際應用中可據實際狀況自行調整。
運行Job:
kubectl create -f ./job.yaml
過一會查看Job運行情況:
$ kubectl describe jobs/job-wq-2 Name: job-wq-2 Namespace: default Selector: controller-uid=b1c7e4e3-92e1-11e7-b85e-fa163ee3c11f Labels: controller-uid=b1c7e4e3-92e1-11e7-b85e-fa163ee3c11f job-name=job-wq-2 Annotations: <none> Parallelism: 2 Completions: <unset> Start Time: Mon, 11 Jan 2016 17:07:59 -0800 Pods Statuses: 1 Running / 0 Succeeded / 0 Failed Pod Template: Labels: controller-uid=b1c7e4e3-92e1-11e7-b85e-fa163ee3c11f job-name=job-wq-2 Containers: c: Image: gcr.io/exampleproject/job-wq-2 Port: Environment: <none> Mounts: <none> Volumes: <none> Events: FirstSeen LastSeen Count From SubobjectPath Type Reason Message --------- -------- ----- ---- ------------- -------- ------ ------- 33s 33s 1 {job-controller } Normal SuccessfulCreate Created pod: job-wq-2-lglf8
雖然容許的最大併發數是2,但Events顯示只建立成功一個pod,這個是正常狀況,最大並不是必需,可能系統由於資源問題達不到最大。
查看pod輸出:
$ kubectl logs pods/job-wq-2-7r7b2 Worker with sessionID: bbd72d0a-9e5c-4dd6-abf6-416cc267991f Initial queue state: empty=False Working on banana Working on date Working on lemon
細併發相比與粗併發,減小了建立pod的開銷,使每一個pod能處理多條記錄,可是pod要本身決定退出條件,若是不退出,那麼Job永遠沒法結束。
Job建立的pod在結束運行後,不管是成功仍是失敗,不會默認刪除,仍然保留在系統中,這樣用戶才能夠查看其日誌、狀態信息、排除錯誤。用戶須要手動運行kubectl delete刪除全部運行結束的pod,爲了方便組織資源,一次性刪除會部pod,能夠被pod自定義標籤。Job在運行完成後也仍然保留在系統中,由用戶刪除。因此使用Job,用戶應注意資源回收,避免資源被耗盡。