本篇概述

在前面两篇中,我已经介绍了 Replicas 和 Deployment,这两种资源类型都是用于控制 Worklload 的。当你使用的时候,可以感受到,这两种类型的资源一般都是持续运行的,同时还有一些辅助的方式帮助在 Workload 出现异常时恢复,以及根据情况进行动态伸缩的特性。

那么,如果我不需要保持我的 workload 持续运行可不可以,例如,在一个 Web 应用真正运行之前,我希望有个 container 能够帮我初始化一下 DB;又或者,我希望有个定时任务可以帮助我定时地刷新一下 DB 的状态,这些场景都不需要 Pod 保持持续地运行,虽然我们了解 Pod 的运行并不会占用太多资源。

事实上,Kubernetes 充分地考虑了这些场景,并且给出了解决方案,那就是 Job 和 CronJob。

Job

在 Kubernetes 的定义中,Job 其实和前面介绍的 Replicas 和 Deployment 原理类似,都是通过定义 Pod 的模板,然后根据 Job 的定义创建出对应的 Pod,然后关注 Pod 的状态,直到满足定义,例如 Pod 执行成功了或者说执行失败了,并且达到了重试次数之类的。这里来看一个简单的 Pod 的例子:

  1. ---
  2. apiVersion: batch/v1
  3. kind: Job
  4. metadata:
  5. name: pi
  6. spec:
  7. template:
  8. spec:
  9. containers:
  10. - name: pi
  11. image: perl
  12. command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
  13. restartPolicy: Never
  14. backoffLimit: 4

这个 Job 的功能很简单,就是计算一下 Pi 的值,完成之后就退出了。我们先将它添加到 Kubernetes 中,然后再看看状态:

  1. [root@liqinag.io]# kubectl apply -f job00.yaml
  2. [root@liqiang.io]# kubectl get jobs
  3. NAME COMPLETIONS DURATION AGE
  4. pi 0/1 8m 8m

这个时候 Job 就在准备执行了,可以看到 COMPLETIONS 这一项,期望是 1,实际是 0,然后再看下 Pods 列表:

  1. [root@liqinag.io]# kubectl get pods
  2. k get pods
  3. NAME READY STATUS RESTARTS AGE
  4. pi-6rsxc 0/1 ContainerCreating 0 2m18s

可以发现确实有 Pod 在执行,并且还没有开始运行。我们等它执行完毕再看下效果:

  1. [root@liqiang.io]# kubectl get pods
  2. k get pods
  3. NAME READY STATUS RESTARTS AGE
  4. pi-6rsxc 0/1 Completed 0 4m47s
  5. [root@liqiang.io]# kubectl get jobs
  6. k get jobs
  7. NAME COMPLETIONS DURATION AGE
  8. pi 1/1 14m 17m

可以看到,这里的预期状态已经达成一致了。这是一个只执行一次的任务的 Job,它的操作方式就是创建一个 Pod,然后运行一遍(默认),然后就退出了。如果我们想要运行两遍呢?该怎么处理?其实,在 Job 的描述中加入一个配置项:

加上这一项之后,Kubernetes 就会创建分别创建两次 Pod,然后保证他们都执行成功之后才确认这个 Job 是完成的。

这里有一个注意的地方就是,我们在使用 Deployment 等 Workload 的时候,一般都会指定一个 restartPolicy,默认都是 RestartOnFail,那么在 Job 中,不能这么指定,因为这个逻辑应由 Job 来控制,而不应该让 Pod 来控制。

同时,Job 也不是说会无限期地执行下去,可以通过执行 backoffLimit 来限制失败重试的次数。

CronJob

Job 确实很有用,但是,很多时候我们更需要的是定时执行任务,例如,每小时统计一次商城的销售数据和趋势,类似这样周期性的任务,Kubernetes 在 Job 之上,又定义了 CronJob。之所以说是在 Job 之上,是因为 CronJob 就是在 Job 的基础上加上了周期定义的接口:

  1. ---
  2. apiVersion: batch/v1beta1
  3. kind: CronJob
  4. metadata:
  5. name: batch-job-pi
  6. spec:
  7. schedule: "0,15,30,45 * * * *"
  8. jobTemplate:
  9. spec:
  10. template:
  11. metadata:
  12. labels:
  13. app: pi-job
  14. spec:
  15. containers:
  16. - name: pi
  17. image: perl
  18. command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
  19. restartPolicy: Never

从这份定义中可以看到,除了在外层套了一层 CronJob 的 Meta 数据之外,还有一个 schedule,里面的其实就是一个 Job 的定义了。这份 CronJob 的功能就是每隔 15 分钟算一次 Pi(毫无意义的事情)。然后我们将这份申明应用到 Kubernetes 中之后,每隔 15 分钟就会出现一个 Job。

这里需要说明的一点是,CronJob 目前还不稳定,有诸多问题,例如:

Ref