Kubernetes控制器Job和CronJob

Job 和 CronJob

Deployment, StatefuleSet以及DaemonSet这三个控制器主要编排的对象都是"在线业务",比如我们举例常用的Nginx,MySQL等。这些应用一旦运行起来,除非出错或者停止,它的容器进程会一直保持Running状态。

但是,有一类作业显然不满足这样的条件,这就是“离线业务”,或者叫作 Batch Job(计算业 务)。这种业务在计算完成后就直接退出了,而此时如果依然用 Deployment 来管理这种业务的话,就会发现 Pod 会在计算结束后退出,然后被 Deployment Controller 不断地重启;而像“滚动更新”这样的编排功能,更无从谈起了 。

所以在v1.4版本之后,社区设计出一个用来描述离线业务的API对象,他就是Job。

Job

我们用 Job 这个资源对象来创建一个任务,我们定义一个 Job 来执行一个倒计时的任务,对应的资源清单如下所示:(job-demo.yaml)

apiVersion: batch/v1
kind: Job
metadata:
  name: job-demo
spec:
  template:
    spec:
      restartPolicy: Never
      containers:
        - name: counter
          image: busybox:1.30
          command: ["/bin/sh","-c","for i in 9 8 7 6 5 4 3 2 1;do echo $i;sleep 3;done"]

我们可以看到 Job 中也是一个 Pod 模板,和之前的 Deployment、StatefulSet 之类的是一致的,只是 Pod 中的容器要求是一个任务,而不是一个常驻前台的进程了,因为需要退出,另外值得注意的是 Job 的 RestartPolicy 仅支持 Never 和 OnFailure 两种,不支持 Always,我们知道 Job 就相当于来执行一个批处理任务,执行完就结束了,如果支持 Always 的话是不是就陷入了死循环了?

创建后我们查看这个job对象:

# kubectl get job -o wide
NAME       COMPLETIONS   DURATION   AGE   CONTAINERS   IMAGES         SELECTOR
job-demo   1/1           30s        32s   counter      busybox:1.30   controller-uid=d6eecfa9-ac73-4a6a-8b33-03ffd1960e9b

# kubectl describe job job-demo
Name:           job-demo
Namespace:      default
Selector:       controller-uid=d6eecfa9-ac73-4a6a-8b33-03ffd1960e9b
Labels:         controller-uid=d6eecfa9-ac73-4a6a-8b33-03ffd1960e9b
                job-name=job-demo
......
Pod Template:
  Labels:  controller-uid=d6eecfa9-ac73-4a6a-8b33-03ffd1960e9b
......
Events:
  Type    Reason            Age    From            Message
  ----    ------            ----   ----            -------
  Normal  SuccessfulCreate  5m23s  job-controller  Created pod: job-demo-ktvbl
  Normal  Completed         4m53s  job-controller  Job completed

可以看到,Job 对象在创建后,它的 Pod 模板,被自动加上了一个 controller-uid=<一个随机字符串> 这样的 Label 标签,而这个 Job 对象本身,则被自动加上了这个 Label 对应的 Selector,从而保证了 Job 与它所管理的 Pod 之间的匹配关系。而 Job 控制器之所以要使用这种携带了 UID 的 Label,就是为了避免不同 Job 对象所管理的 Pod 发生重合。

我们也发现Pod状态很快变成了 Completed 状态,这是因为容器的任务执行完成正常退出了,我们可以查看对应的日志:

# kubectl logs job-demo-ktvbl
9
8
7
6
5
4
3
2
1

如果的任务执行失败了,我们这里定义了 restartPolicy=Never,那么任务在执行失败后 Job 控制器就会不断地尝试创建一个新 Pod,当然,这个尝试肯定不能无限进行下去。我们可以通过 Job 对象的 spec.backoffLimit 字段来定义重试次数,另外需要注意的是 Job 控制器重新创建 Pod 的间隔是呈指数增加的,即下一次重新创建 Pod 的动作会分别发生在 10s、20s、40s… 后。

如果我们定义的 restartPolicy=OnFailure,那么任务执行失败后,Job 控制器就不会去尝试创建新的 Pod了,它会不断地尝试重启 Pod 里的容器。

上面我们这里的 Job 任务对应的 Pod 在运行结束后,会变成 Completed 状态,但是如果执行任务的 Pod 因为某种原因一直没有结束怎么办呢?同样我们可以在 Job 对象中通过设置字段spec.activeDeadlineSeconds 来限制任务运行的最长时间,比如 :

spec:
 backoffLimit: 5
 activeDeadlineSeconds: 100

那么当我们的任务 Pod 运行超过了 100s 后,这个 Job 的所有 Pod 都会被终止,并且, Pod 的终止原因会变成 DeadlineExceeded

除此之外,我们还可以通过设置 spec.parallelism 参数来进行并行控制,该参数定义了一个 Job 在任意时间最多可以有多少个 Pod 同时运行。spec.completions 参数可以定义 Job 至少要完成的 Pod 数目。

apiVersion: batch/v1
kind: Job
metadata:
  name: job-demo
spec:
  parallelism: 2
  completions: 4
  backoffLimit: 4
  template:
    spec:
      restartPolicy: Never
      containers:
        - name: counter
          image: busybox:1.30
          command: ["/bin/sh","-c","for i in 9 8 7 6 5 4 3 2 1;do echo $i;sleep 3;done"]

接下来我们创建这个Job对象,可以看到 COMPLETIONS正是我们定义的最小完成数。

# kubectl get job
NAME       COMPLETIONS   DURATION   AGE
job-demo   4/4           61s        3m35s

CronJob

CronJob 其实就是在 Job 的基础上加上了时间调度,我们可以在给定的时间点运行一个任务,也可以周期性地在给定时间点运行。这个实际上和我们 Linux 中的 crontab 就非常类似了。

一个 CronJob 对象其实就对应 crontab 文件中的一行,它根据配置的时间格式周期性地运行一个Job,格式和 crontab 也是一样的。

crontab 的格式为:分 时 日 月 星期 要运行的命令

  • 第1列分钟0~59
  • 第2列小时0~23
  • 第3列日1~31
  • 第4列月1~12
  • 第5列星期0~7(0和7表示星期天)
  • 第6列要运行的命令

现在,我们用 CronJob 来管理我们上面的 Job 任务,定义如下所示的资源清单:(cronjob-demo.yaml)

apiVersion: batch/v1beta1 # 版本号
kind: CronJob # 类型
metadata: # 元数据
  name: cronjob-demo # 名称
spec: # 详情描述
  schedule: "*/1 * * * * " # cron格式的作业调度运行时间点,用于控制任务任务时间执行
  jobTemplate: # job控制器模板,用于为cronjob控制器生成job对象,下面其实就是job的定义
    spec:
      template: # 模板,当副本数量不足时,会根据下面的模板创建Pod模板
        spec:
          restartPolicy: Never # 重启策略只能设置为Never或OnFailure
          containers:
            - name: counter
              image: busybox:1.30
              command: [ "/bin/sh","-c","for i in 9 8 7 6 5 4 3 2 1;do echo $i;sleep 2;done" ]

这里的 Kind 变成了 CronJob 了,要注意的是.spec.schedule字段是必须填写的,用来指定任务运行的周期,格式就和 crontab 一样,另外一个字段是.spec.jobTemplate, 用来指定需要运行的任务,格式当然和 Job 是一致的。

还有一些值得我们关注的字段 .spec.successfulJobsHistoryLimit 和 .spec.failedJobsHistoryLimit,表示历史限制,是可选的字段,指定可以保留多少完成和失败的 Job,默认没有限制,所有成功和失败的 Job 都会被保留。然而,当运行一个 CronJob 时,Job 可以很快就堆积很多,所以一般推荐设置这两个字段的值。如果设置限制的值为 0,那么相关类型的 Job 完成后将不会被保留。

我们直接新建上面的资源对象 ,查看对应的CronJob资源对象:

# kubectl get cj
NAME           SCHEDULE       SUSPEND   ACTIVE   LAST SCHEDULE   AGE
cronjob-demo   */1 * * * *    False     0        <none>          31s

稍微等一会儿查看可以发现多了几个 Job 资源对象,这个就是因为上面我们设置的 CronJob 资源对象,每1分钟执行一个新的 Job:

# kubectl get pods
NAME                            READY   STATUS      RESTARTS   AGE
cronjob-demo-1640085660-9j9nx   0/1     Completed   0          3m11s
cronjob-demo-1640085720-j5wtr   0/1     Completed   0          2m11s
cronjob-demo-1640085780-hw72x   0/1     Completed   0          71s
cronjob-demo-1640085840-nlshn   1/1     Running     0          11s

这个就是 CronJob 的基本用法,一旦不再需要 CronJob,我们可以使用 kubectl delete命令删除它:

# kubectl delete cronjob cronjob-demo
cronjob.batch "cronjob-demo" deleted
原文地址:https://www.cnblogs.com/huiyichanmian/p/15716693.html