Job用途

容器按照持续运行的时间可分为两类:服务类容器和工作类容器
服务类容器通常持续提供服务,需要一直运行,比如HTTPServer、Daemon等。工作类容器则是一次性任务,比如批处理程序,完成后容器就退出
Kubernetes的Deployment、ReplicaSet和DaemonSet都用于管理服务类容器;对于工作类容器,我们使用Job

先看一个简单的Job配置文件myjob.yml

[k8s@server1 ~]$ cat myjob.yml 
apiVersion: batch/v1 (1)
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
kind指明当前资源的类型为Job
restartPolicy指定什么情况下需要重启容器。对于Job,只能设置为Never(启动容器失败了,会一直重新启动新的pod)或者OnFailure(启动容器失败,不会重新启动新的pod,节省资源)。对于其他controller(比如Deployment),

可以设置为Always

启动Job

[k8s@server1 ~]$ kubectl apply -f myjob.yml 
job.batch/myjob created

通过kubectl get job查看Job的状态

[k8s@server1 ~]$ kubectl get job
NAME    COMPLETIONS   DURATION   AGE
myjob   1/1           12s        14s

通过kubectl logs可以查看Pod的标准输出

[k8s@server1 ~]$ kubectl get pod
NAME                               READY   STATUS      RESTARTS   AGE
myjob-c87rp                        0/1     Completed   0          27s

[k8s@server1 ~]$ kubectl logs myjob-c87rp
hello k8s job !

以上是Pod成功执行的情况,如果Pod失败了会怎么样呢?
修改myjob.yml,故意引入一个错误

[k8s@server1 ~]$ cat myjob.yml 
apiVersion: batch/v1
kind: Job
metadata:
 name: myjob
spec:
 template:
  metadata:
    name: myjob
  spec:
   containers:
   - name: hello
     image: busybox
     command: ["invalid_command","hello k8s job !"]
   restartPolicy: Never

先删除之前的Job

[k8s@server1 ~]$ kubectl delete -f myjob.yml 
job.batch "myjob" deleted

运行新的Job并查看状态

[k8s@server1 ~]$ kubectl apply -f myjob.yml 
job.batch/myjob created

可以看到有多个Pod,状态均不正常

[k8s@server1 ~]$ kubectl get pod
NAME          READY   STATUS              RESTARTS   AGE
myjob-n5t26   0/1     ContainerCreating    0          9s
myjob-kvb67   0/1     ContainerCannotRun   0          38s
myjob-n5t26   0/1     ContainerCannotRun   0          59s


 通过kubectl describe podname查看某个Pod的启动日志
Events:
  Type     Reason     Age        From               Message
  ----     ------     ----       ----               -------
  Normal   Scheduled  <unknown>  default-scheduler  Successfully assigned default/myjob-n5t26 to server3
  Normal   Pulling    24s        kubelet, server3   Pulling image "busybox"
  Normal   Pulled     5s         kubelet, server3   Successfully pulled image "busybox"
  Normal   Created    5s         kubelet, server3   Created container hello
  Warning  Failed     5s         kubelet, server3   Error: failed to start container "hello": Error response from daemon: OCI runtime create failed: container_linux.go:345: starting container process caused "exec: \"invalid_command\": executable file not found in $PATH": unknown
# 日志显示没有可执行程序,符合我们的预期

下面解释一个现象:为什么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后重新启动

[k8s@server1 ~]$ cat myjob.yml 
apiVersion: batch/v1
kind: Job
metadata:
 name: myjob
spec:
 template:
  metadata:
    name: myjob
  spec:
   containers:
   - name: hello
     image: busybox
     command: ["invalid_command","hello k8s job !"]
   restartPolicy: OnFailure
[k8s@server1 ~]$ kubectl apply -f myjob.yml 
job.batch/myjob created

[k8s@server1 ~]$ kubectl get pod
NAME          READY   STATUS              RESTARTS   AGE
myjob-b28g7   0/1     ContainerCreating   0          4s
[k8s@server1 ~]$ kubectl get pod
NAME          READY   STATUS              RESTARTS   AGE
myjob-b28g7   0/1     ContainerCreating   0          6s
[k8s@server1 ~]$ kubectl get pod
NAME          READY   STATUS              RESTARTS   AGE
myjob-b28g7   0/1     ContainerCreating   0          7s
[k8s@server1 ~]$ kubectl get pod
NAME          READY   STATUS              RESTARTS   AGE
myjob-b28g7   0/1     RunContainerError   1          38s
[k8s@server1 ~]$ kubectl get pod
NAME          READY   STATUS              RESTARTS   AGE
myjob-b28g7   0/1     RunContainerError   1          38s
[k8s@server1 ~]$ kubectl get pod
NAME          READY   STATUS              RESTARTS   AGE
myjob-b28g7   0/1     RunContainerError   2          39s
[k8s@server1 ~]$ kubectl get pod
NAME          READY   STATUS              RESTARTS   AGE
myjob-b28g7   0/1     RunContainerError   2          86s
# RESTARTS为2,而且不断增加,说明OnFailure生效,容器失败后会自动重启,不会创建新的pod

[k8s@server1 ~]$ kubectl delete -f myjob.yml 
job.batch "myjob" deleted

Job的并行性

有时我们希望能同时运行多个Pod,提高Job的执行效率。这个可以通过parallelism设置

[k8s@server1 ~]$ cat myjob.yml 
apiVersion: batch/v1
kind: Job
metadata:
 name: myjob
spec:
 parallelism: 2 ##同时运行两个pod
 template:
  metadata:
    name: myjob
  spec:
   containers:
   - name: hello
     image: busybox
     command: ["echo","hello k8s job !"]
   restartPolicy: OnFailure
#这里我们将并行的Pod数量设置为2,实践一下,Job一共启动了两个Pod,而且AGE相同,可见是并行运行的

[k8s@server1 ~]$ kubectl apply -f myjob.yml 
job.batch/myjob created

[k8s@server1 ~]$ kubectl get pod
NAME          READY   STATUS              RESTARTS   AGE
myjob-plh9q   0/1     RunContainerError   0          19s
myjob-x4f4v   0/1     RunContainerError   0          19s
[k8s@server1 ~]$ kubectl get jobs.batch 
NAME    COMPLETIONS   DURATION   AGE
myjob   0/1 of 2      7s         7s
[k8s@server1 ~]$ kubectl get job
NAME    COMPLETIONS   DURATION   AGE
myjob   0/1 of 2      11s        11s

我们还可以通过completions设置Job成功完成Pod的总数

[k8s@server1 ~]$ cat myjob.yml 
apiVersion: batch/v1
kind: Job
metadata:
 name: myjob
spec:
 completions: 6
 parallelism: 2
 template:
  metadata:
    name: myjob
  spec:
   containers:
   - name: hello
     image: busybox
     command: ["echo","hello k8s job !"]
   restartPolicy: OnFailure
# 上面配置的含义是:每次运行两个Pod,直到总共有6个Pod成功完成

[k8s@server1 ~]$ kubectl apply -f myjob.yml 
job.batch/myjob created


[k8s@server1 ~]$ kubectl get job
NAME    COMPLETIONS   DURATION   AGE
myjob   6/6           57s        2m6s
[k8s@server1 ~]$ kubectl get pod
NAME          READY   STATUS      RESTARTS   AGE
myjob-5n7sz   0/1     Completed   0          74s
myjob-rp2sx   0/1     Completed   0          41s
myjob-v5thn   0/1     Completed   0          55s
myjob-vkww5   0/1     Completed   0          74s
myjob-w9cvx   0/1     Completed   0          33s
myjob-wlh4j   0/1     Completed   0          54s

上面的例子只是为了演示Job的并行特性,实际用途不大。不过现实中确实存在很多需要并行处理的场景。比如批处理程序,每个副本(Pod)都会从任务池中读取任务并执行,副本越多,执行时间就越短,效率就越高。这种类似的场景都可以用Job来实现

定时Job

Linux中有cron程序定时执行任务,Kubernetes的CronJob提供了,类似的功能,可以定时执行Job

[k8s@server1 ~]$ cat cron.yml 
apiVersion: batch/v1beta1 
kind: CronJob
metadata:
 name: hello
spec:
 schedule: "*/1 * * * *" 
 jobTemplate:
  spec:
   template:
    spec:
     containers:
     - name: hello
       image: busybox
       command: ["echo","hello k8s job !"]
     restartPolicy: OnFailure
(1) batch/v1beta1当前CronJob的apiVersion
kind指明当前资源的类型为CronJob
schedule指定什么时候运行Job,其格式与Linux cron一致。这里*/1 * * * *的含义是每一分钟启动一次
[k8s@server1 ~]$ kubectl api-versions
admissionregistration.k8s.io/v1
admissionregistration.k8s.io/v1beta1
apiextensions.k8s.io/v1
apiextensions.k8s.io/v1beta1
apiregistration.k8s.io/v1
apiregistration.k8s.io/v1beta1
apps/v1
authentication.k8s.io/v1
authentication.k8s.io/v1beta1
authorization.k8s.io/v1
authorization.k8s.io/v1beta1
autoscaling/v1
autoscaling/v2beta1
autoscaling/v2beta2
batch/v1
batch/v1beta1
certificates.k8s.io/v1beta1
coordination.k8s.io/v1
coordination.k8s.io/v1beta1
events.k8s.io/v1beta1
extensions/v1beta1
networking.k8s.io/v1
networking.k8s.io/v1beta1
node.k8s.io/v1beta1
policy/v1beta1
rbac.authorization.k8s.io/v1
rbac.authorization.k8s.io/v1beta1
scheduling.k8s.io/v1
scheduling.k8s.io/v1beta1
storage.k8s.io/v1
storage.k8s.io/v1beta1
v1

通过kubectl apply创建CronJob

[k8s@server1 ~]$ kubectl apply -f cron.yml 
cronjob.batch/hello created

通过kubectl get cronjob查看CronJob的状态

[k8s@server1 ~]$ kubectl get cronjob
NAME    SCHEDULE      SUSPEND   ACTIVE   LAST SCHEDULE   AGE
hello   */1 * * * *   False     0        <none>          20s

等待几分钟,然后通过kubectl get jobs查看Job的执行情况

[k8s@server1 ~]$ kubectl get jobs
NAME               COMPLETIONS   DURATION   AGE
hello-1573011120   0/1           3m41s      3m41s
hello-1573011180   0/1           2m41s      2m41s
hello-1573011240   0/1           101s       101s
hello-1573011300   0/1           41s        41s

可以看到每隔一分钟就会启动一个Job。执行kubectl logs可查看某个Job的运行日志

[k8s@server1 ~]$ kubectl get pod
NAME                     READY   STATUS              RESTARTS   AGE
hello-1573011120-68kp9   0/1     ImagePullBackOff    0          4m21s
hello-1573011180-lmwvv   0/1     ImagePullBackOff    0          3m21s
hello-1573011240-v4h77   0/1     ImagePullBackOff    0          2m21s
hello-1573011300-l4v9v   0/1     ImagePullBackOff    0          81s
hello-1573011360-tk64h   0/1     ContainerCreating   0          21s
myjob-5n7sz              0/1     Completed           0          19h
myjob-rp2sx              0/1     Completed           0          19h
myjob-v5thn              0/1     Completed           0          19h
myjob-vkww5              0/1     Completed           0          19h
myjob-w9cvx              0/1     Completed           0          19h
myjob-wlh4j              0/1     Completed           0          19h
[k8s@server1 ~]$ kubectl logs hello-1573011120-68kp9
hello k8s job !
Logo

开源、云原生的融合云平台

更多推荐