Job
容器按照持續運行的時間可分為兩類:服務類容器和工作類容器。
服務類容器通常持續提供服務,需要一直運行,比如 http server,daemon 等。
工作類容器則是一次性任務,比如批處理程序,完成后容器就退出。
Kubernetes 的 Deployment、ReplicaSet 和 DaemonSet 都用於管理服務類容器;
對於工作類容器,我們用 Job。
先看一個簡單的 Job 配置文件 myjob.yml:
apiVersion: batch/v1
kind: Job
metadata:
name: myjob
spec:
template:
metadata:
name: myjob
spec:
containers:
- name: hello
image: busybox
command: ["echo", "hello k8s job! "]
restartPolicy: Never

① batch/v1 是當前 Job 的 apiVersion。kubectl api-versions查看可用apiVersion
② 指明當前資源的類型為 Job。
③ restartPolicy 指定什么情況下需要重啟容器。對於 Job,只能設置為 Never 或者 OnFailure。
對於其他 controller(比如 Deployment)可以設置為 Always 。
通過 kubectl apply -f myjob.yml 啟動 Job。並kubectl get job 查看 Job 的狀態:
daweij@master:~/stady01/nginx$ kubectl apply -f myjob.yml job "myjob" created daweij@master:~/stady01/nginx$ kubectl get job NAME DESIRED SUCCESSFUL AGE myjob 1 1 2m daweij@master:~/stady01/nginx$ kubectl get pod --show-all NAME READY STATUS RESTARTS AGE myjob-72j2r 0/1 Completed 0 3m
DESIRED 和 SUCCESSFUL 都為 1,表示按照預期啟動了一個 Pod,並且已經成功執行。kubectl get pod 查看 Pod 的狀態:
因為 Pod 執行完畢后容器已經退出,需要用 --show-all 才能查看 Completed 狀態的 Pod。
kubectl logs 可以查看 Pod 的標准輸出:
daweij@master:~/stady01/nginx$ kubectl logs myjob-72j2r hello k8s job!
以上是 Pod 成功執行的情況。
如果 Pod 失敗了會怎么樣呢?
修改 myjob.yml,故意引入一個錯誤。
如果將 restartPolicy 設置為 OnFailure 會怎么樣?下面我們實踐一下,修改 myjob.yml 后重新啟動。
運行新的 Job 並查看狀態,當前 SUCCESSFUL 的 Pod 數量為 0,查看 Pod 的狀態.
可以看到有多個 Pod,狀態均不正常。kubectl describe pod 查看某個 Pod 的啟動日志:

日志顯示沒有可執行程序,符合我們的預期。
為什么 kubectl get pod 會看到這么多個失敗的 Pod?
原因是:當第一個 Pod 啟動時,容器失敗退出,根據 restartPolicy: Never,此失敗容器不會被重啟,但 Job DESIRED 的 Pod 是 1,目前 SUCCESSFUL 為 0,不滿足.
所以 Job controller 會啟動新的 Pod,直到 SUCCESSFUL 為 1。
對於我們這個例子,SUCCESSFUL 永遠也到不了 1,所以 Job controller 會一直創建新的 Pod。為了終止這個行為,只能刪除 Job。
如果將 restartPolicy 設置為 OnFailure 會怎么樣?下面我們實踐一下,修改 myjob.yml 后重新啟動。
Job 的 SUCCESSFUL Pod 數量還是為 0,看看 Pod 的情況。
這里只有一個 Pod,不過 RESTARTS 為 3,而且不斷增加,說明 OnFailure 生效,容器失敗后會自動重啟。
有時,我們希望能同時運行多個 Pod,提高 Job 的執行效率。這個可以通過 parallelism 設置。

這里我們將並行的 Pod 數量設置為 2,實踐一下:

Job 一共啟動了兩個 Pod,而且 AGE 相同,可見是並行運行的。
我們還可以通過 completions 設置 Job 成功完成 Pod 的總數:

上面配置的含義是:每次運行兩個 Pod,直到總共有 6 個 Pod 成功完成。實踐一下:

DESIRED 和 SUCCESSFUL 均為 6,符合預期。如果不指定 completions 和 parallelism,默認值均為 1。
上面的例子只是為了演示 Job 的並行特性,實際用途不大。
不過現實中確實存在很多需要並行處理的場景。
比如批處理程序,每個副本(Pod)都會從任務池中讀取任務並執行,副本越多,執行時間就越短,效率就越高。這種類似的場景都可以用 Job 來實現。
如何定時執行 Job。
Linux 中有 cron 程序定時執行任務,Kubernetes 的 CronJob 提供了類似的功能,可以定時執行 Job。CronJob 配置文件示例如下:

① batch/v2alpha1 是當前 CronJob 的 apiVersion。
② 指明當前資源的類型為 CronJob。
③ schedule 指定什么時候運行 Job,其格式與 Linux cron 一致。這里 */1 * * * * 的含義是每一分鍾啟動一次。
④ jobTemplate 定義 Job 的模板,格式與前面 Job 一致。
接下來通過 kubectl apply 創建 CronJob。

失敗了。這是因為 Kubernetes 默認沒有 enable CronJob 功能,需要在 kube-apiserver 中加入這個功能。方法很簡單,修改 kube-apiserver 的配置文件 /etc/kubernetes/manifests/kube-apiserver.yaml:

kube-apiserver 本身也是個 Pod,在啟動參數中加上 --runtime-config=batch/v2alpha1=true 即可。
然后重啟 kubelet 服務:
systemctl restart kubelet.service
kubelet 會重啟 kube-apiserver Pod。通過 kubectl api-versions 確認 kube-apiserver 現在已經支持 batch/v2alpha1:

再次創建CronJob:

這次成功了。通過 kubectl get cronjob 查看 CronJob 的狀態:

等待幾分鍾,然后通過 kubectl get jobs 查看 Job 的執行情況:

可以看到每隔一分鍾就會啟動一個 Job。執行 kubectl logs 可查看某個 Job 的運行日志:

小結
運行容器化應用是 Kubernetes 最重要的核心功能。
為滿足不同的業務需要,Kubernetes 提供了多種 Controller,包括 Deployment、DaemonSet、Job、CronJob 等。
