前言

本文主要会介绍笔者在学习Kubernetes Job Controller的实现原理时所总结的知识点,其中会涉及到Job Controller的使用场景、实现原理以及控制循环等方面的相关内容。 笔者也会将自己的理解在文中进行阐述,这也算是在和大家交流心得的一个过程。若文中有错误的理解和概念,请大家及时纠正;吸纳大家的建议,对于我来说也是很重要的学习过程之一。


(目录)


1.使用场景

Job对象主要用来解决离线业务或是Batch Job(计算业务)类型的相关业务需求。Job对象可以并行的处理多个任务来满足各种离线业务的需求。


2.实现原理

2.1 Pod管理

在定义Job对象时是无需在定义中声明Label selector,以来描述其所管理的Pod特征/范围。因为Job对象在创建后,它内部的Pod template会被自动加上了一个Label,格式为controller-uid=< random string >。而这个Job对象本身则会被自动加上了这个 Label对应的Selector,从而保证了Job与它所管理的Pod之间的匹配关系。即Job本身会自己维护Pod的Label以及自身的Label selector。Job Controller之所以Label的内容中加入自身的UID是为了避免不同Job对象所管理的Pod发生重合。

Tips: 这种自动生成的 Label 对用户来说并不友好,所以不太适合推广到Deployment等长作业编排对象上。

2.2 任务结果处理

在定义Job对象时需要在Pod template定义中加上restartPolicy=Never的定义。因为Job中执行的业务成功完成后Pod就会进入Completed状态;此时如果使用其他的Pod重启策略就会导致pod无限重启运。

Tips: restartPolicy 在 Job 对象里只允许被设置为 Never 和 OnFailure。而在 Deployment 对象里,restartPolicy 则只允许被设置为 Always。这样的设置差异实际上体现出了两种控制器对象的功能区别:Deployment需要保证Pod一直满足用户的期望态,Job则是按用户需求有限次的完成相应的任务。

如果restartPolicy=Never,则需要配合spec.backoffLimit字段来限制任务重试的次数;如果restartPolicy=OnFailure,那么离线作业失败后Job Controller就不会去尝试创建新的Pod。但是,它会不断地尝试重启Pod里的容器;因为这就是OnFailure的定义。对于因bug而永不停止的Pod,使用spec.activeDeadlineSeconds字段可以设置最长运行时间。

2.3 控制循环

Job Controller是直接管理Pod对象的

2019-03-05-Job-Topology.png

Job Controller根据实际在 Running 状态 Pod 的数目、已经成功退出的 Pod 的数目以及 parallelism、completions参数的值共同计算出在这个周期里应该创建或者删除的 Pod 数目。最后调用 Kubernetes API 来执行这个操作。 Job Controller 实际上控制了作业执行的并行度以及总共需要完成的任务数这两个重要参数。

2.4 并行作业

在Job对象中,负责并行控制的参数有两个:

  1. spec.parallelism 定义了一个Job在任意时间最多可以并行启动多少个Pod
  2. spec.completions 定义了Job至少要完成的Pod数目,即Job的最小完成数

Pod最大并行运行数量的计算方法如下:

需创建Pod数目 = 最大并行Pod数量 - 实际处于Running状态Pod数量 - 已经成功退出的Pod数量

其中:

  1. 最大并行Pod数量 即spec.completions。
  2. 实际处于Running状态Pod数量 即spec.parallelism。
  3. 已经成功退出的Pod数量 按实际情况而定。

3.使用方式

3.1 Job模板

这种方法的核心思路是:把Job的YAML文件定义为一个模板,然后用一个外部工具控制这些模板来建立Job对象

在模版中,completions和parallelism为主要需要渲染的两个数据。这两个字段都应该使用默认值1。在实现模版后,还需要编写一个外部工具管理Job对象。这个工具的主要职责有两部分,一是根据用户提供的数据和Job模版来渲染出一个真正的Job对象定义文件;二则是使用渲染生成的Job对象定义文件调用Kubernetes API创建出相应的Job对象。

这样设计好处在于:

  1. 特征性 所有来自于同一个模板的Job对象都会有同一个标签。
  2. 并行控制管理 对Job的并行配制由外部来控制,而不是由Kubernetes内部的控制器来进行控制。即同时有多少个Job对象在运行,完全是由外部因素来进行管控。

这种使用方式可以更加灵活的控制Job对象的并行作业。因为不再使用原本的控制单元(Job Controller)来控制并发度,而是在外部环境来控制。即在这种方式下,Kubernetes只负责创建Job对象,但不会过多的去维护Job对象。

3.2 拥有固定任务数目的并行Job

这种模式下只关心最后是否有指定数量的Job对象成功退出,即只需要指定spec.completions字段的值即可。

这种模式可以配合外部的消息队列来进行使用,即将Job中运行的Pod作为消费者来使用。但这种模式往往需要知道任务的准确执行数


4.CronJob Controller

CronJob是一个专门用来管理Job对象的控制器,主要用途为定时触发相应的Job。

1*AjvOBmVKNmx2SKKX-DhkXw.webp

CronJob 与 Job 的关系如同 Deployment 与 ReplicaSet 的关系一样。这一设计是通过在CronJob对象中定义的jobTemplate字段来实现的。CronJob创建和删除 Job 的依据是schedule字段定义的一个标准的Unix Cron格式的表达式。

由于定时任务的特殊性,有可能会发生某个Job还没有执行完而另外一个新Job就开始的现象。可以通过 spec.concurrencyPolicy字段来定义处理这种现象的策略:

  1. concurrencyPolicy=Allow(默认情况) 表示Job可以同时存在。
  2. concurrencyPolicy=Forbid 表示不会创建新的Pod,该创建周期被跳过。
  3. concurrencyPolicy=Replace 新产生的Job会替换旧的、没有执行完的Job。

如果某一次Job创建失败,这次创建就会被标记为miss。当在指定的时间窗口内,miss的数目达到100时,那么 CronJob会停止再创建这个Job。这个时间窗口可以由spec.startingDeadlineSeconds字段指定。