Job与CronJob

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

restartPolicy 在 Job 对象里只允许被设置为 Never OnFailure;而在 Deployment 对象里,restartPolicy 则只允许被设置为 Always。定义了 restartPolicy=Never,那么离线作业失败后 Job Controller 就会不断地尝试创建一个新 Pod。Job 对象的 spec.backoffLimit 字段里定义了重试次数为 4(即,backoffLimit=4),而这个字段的默认值是 6而如果你定义的 restartPolicy=OnFailure,那么离线作业失败后,Job Controller 就不会去尝试创建新的 Pod。但是,它会不断地尝试重启 Pod 里的容器。

当一个 Job 的 Pod 运行结束后,它会进入 Completed 状态。在 Job 的 API 对象里,有一个 spec.activeDeadlineSeconds 字段可以设置最长运行时间。一旦运行超过了 100 s,这个 Job 的所有 Pod 都会被终止。并且,你可以在 Pod 的状态里看到终止的原因是 reason: DeadlineExceeded。

Job Controller 对并行作业的控制方法,在 Job 对象中,负责并行控制的参数有两个:

1、spec.parallelism,它定义的是一个 Job 在任意时间最多可以启动多少个 Pod 同时运行;

2、spec.completions,它定义的是 Job 至少要完成的 Pod 数目,即 Job 的最小完成数。

首先,Job Controller 控制的对象,直接就是 Pod。

其次,Job Controller 在控制循环中进行的调谐(Reconcile)操作,是根据实际在 Running 状态 Pod 的数目、已经成功退出的 Pod 的数目,以及 parallelism、completions 参数的值共同计算出在这个周期里,应该创建或者删除的 Pod 数目,然后调用 Kubernetes API 来执行这个操作。

以创建 Pod 为例。在上面计算 Pi 值的这个例子中,当 Job 一开始创建出来时,实际处于 Running 状态的 Pod 数目 =0,已经成功退出的 Pod 数目 =0,而用户定义的 completions,也就是最终用户需要的 Pod 数目 =4。

所以,在这个时刻,需要创建的 Pod 数目 = 最终需要的 Pod 数目 - 实际在 Running 状态 Pod 数目 - 已经成功退出的 Pod 数目 = 4 - 0 - 0= 4。也就是说,Job Controller 需要创建 4 个 Pod 来纠正这个不一致状态。

可是,我们又定义了这个 Job 的 parallelism=2。也就是说,我们规定了每次并发创建的 Pod 个数不能超过 2 个。所以,Job Controller 会对前面的计算结果做一个修正,修正后的期望创建的 Pod 数目应该是:2 个。

这时候,Job Controller 就会并发地向 kube-apiserver 发起两个创建 Pod 的请求。

类似地,如果在这次调谐周期里,Job Controller 发现实际在 Running 状态的 Pod 数目,比 parallelism 还大,那么它就会删除一些 Pod,使两者相等。

综上所述,Job Controller 实际上控制了,作业执行的并行度,以及总共需要完成的任务数这两个重要参数。而在实际使用时,你需要根据作业的特性,来决定并行度(parallelism)和任务数(completions)的合理取值。

接下来,我再和你分享三种常用的、使用 Job 对象的方法。

第一种用法,也是最简单粗暴的用法:外部管理器 +Job 模板。

第二种用法:拥有固定任务数目的并行 Job。

第三种用法,也是很常用的一个用法:指定并行度(parallelism),但不设置固定的 completions 的值。

CronJob 是一个 Job 对象的控制器(Controller)。CronJob 与 Job 的关系,正如同 Deployment 与 Pod 的关系一样。CronJob 是一个专门用来管理 Job 对象的控制器。只不过,它创建和删除 Job 的依据,是 schedule 字段定义的、一个标准的Unix Cron格式的表达式。

比如,"*/1 * * * *"。

这个 Cron 表达式里 */1 中的 * 表示从 0 开始,/ 表示“每”,1 表示偏移量。所以,它的意思就是:从 0 开始,每 1 个时间单位执行一次。

那么,时间单位又是什么呢?

Cron 表达式中的五个部分分别代表:分钟、小时、日、月、星期。

所以,上面这句 Cron 表达式的意思是:从当前开始,每分钟执行一次。

需要注意的是,由于定时任务的特殊性,很可能某个 Job 还没有执行完,另外一个新 Job 就产生了。这时候,你可以通过 spec.concurrencyPolicy 字段来定义具体的处理策略。比如:

concurrencyPolicy=Allow,这也是默认情况,这意味着这些 Job 可以同时存在;

concurrencyPolicy=Forbid,这意味着不会创建新的 Pod,该创建周期被跳过;

concurrencyPolicy=Replace,这意味着新产生的 Job 会替换旧的、没有执行完的 Job。

而如果某一次 Job 创建失败,这次创建就会被标记为“miss”。当在指定的时间窗口内,miss 的数目达到 100 时,那么 CronJob 会停止再创建这个 Job。

这个时间窗口,可以由 spec.startingDeadlineSeconds 字段指定。比如 startingDeadlineSeconds=200,意味着在过去 200 s 里,如果 miss 的数目达到了 100 次,那么这个 Job 就不会被创建执行了。

job 执行结束,处于 completed 状态之后,还会占用系统资源吗?

需要删除掉,或者设置规则

你可能感兴趣的:(Job与CronJob)