【Kubernetes】离线业务:Job与CronJob
Deployment、StatefulSet和DaemonSet这三个编排概念编排的对象主要都是在线业务(Long Running Task,这些应用一旦运行起来,除非出错或者停止,它的容器进程会一直保持在Running状态)。
但是对于离线业务(Batch Job,计算业务)在计算完成后就直接退出了,如果依然使用Deployment来管理,就会发现Pod会在计算结束后退出,然后被Deployment Controller不断重启。
在Kubernetes v1.4版本之后,设计出来一个用来描述离线业务的API对象:Job。
举个Job的栗子
- apiVersion: batch/v1
- kind: Job
- metadata:
- name: pi
- spec:
- template:
- spec:
- containers:
- - name: pi
- image: resouer/ubuntu-bc #安装了ba明了的Ubuntu镜像
- command: ["sh", "-c", "echo 'scale=10000; 4*a(1)' | bc -l "] #bc命令是Linux里的计算器,; -l表示使用标准数学课; a()调用arctangent函数,scale指定小数点后的位数
- restartPolicy: Never
- backoffLimit:
创建这个Pod
- $ kubectl create -f job.yaml
- $ kubectl describe jobs/pi
- Name: pi
- Namespace: default
- Selector: controller-uid=c2db599a-2c9d-11e6-b324-0209dc45a495
- Labels: controller-uid=c2db599a-2c9d-11e6-b324-0209dc45a495
- job-name=pi
- Annotations: <none>
- Parallelism:
- Completions:
- ..
- Pods Statuses: Running / Succeeded / Failed
- Pod Template:
- Labels: controller-uid=c2db599a-2c9d-11e6-b324-0209dc45a495
- job-name=pi
- Containers:
- ...
- Volumes: <none>
- Events:
- FirstSeen LastSeen Count From SubobjectPath Type Reason Message
- --------- -------- ----- ---- ------------- -------- ------ -------
- 1m 1m {job-controller } Normal SuccessfulCreate Created pod: pi-rq5rl
可以看大这个Job对象在创建后,它的Pod模板被自动加上了一个Labels, controller-uid=<一个随机的字符串>。而Job对象本身,则被自动加上了这个Label对应的Selector,从而保证了Job与它所管理的Pod之间的匹配关系。
Job Controller之所以要使用这种携带了UID的Label,就是为了避免不同Job对象管理的Pod重合
- ### 接下来可以看到这个Job创建的Pod进入了Running状态,这意味着它正在计算Pi的值
- $ kubectl get pods
- NAME READY STATUS RESTARTS AGE
- pi-rq5rl / Running 10s
- ###计算结束后,Pod会进入Completed状态,这也是需要在Pod模板中定义restartPolicy=Never的原因:离线计算的Pod永远不应该被重启
- $ kubectl get pods
- NAME READY STATUS RESTARTS AGE
- pi-rq5rl / Completed 4m
- ### 通过查看log可以看到计算的值
$ kubectl logs pi-rq5rl
3.141592653589793238462643383279...
那如果这个离线作业失败了怎么办?因为这个例子中定义了restartPolicy=Never,那离线作业失败后Job Controller就会不断地尝试创建一个新Pod
Job对象的spec.backoffLimit字段限制尝试的次数,在例子中定义为4,默认值为6。Job Controller重新创建Pod的间隔是呈倍数增加的,即下一次重新创建Pod的动作会分别发生在10s,20s,40s……
那如果定义的restartPolicy=OnFailure呢?离线作业失败后,Job Controller就不会去尝试创建新的Pod,但是它会不断尝试重启Pod里的容器。
那如果这个Pod一直不肯结束呢?spec.activeDeadlineSeconds字段可以设置最长运行时间
- spec:
- backoffLimit:
- activeDeadlineSeconds: 100 # 运行超过100s,这个Job的所有Pod都会被终止
Job Controller 对并行作业的控制方法
在Job对象中,负责并行控制的参数有两个:
spec.parallelism:定义一个Job在任意时间最多可以启动多少个Pod同时运行
spec.completions:定义Job至少要玩的Pod的数目
再举个栗子
- apiVersion: batch/v1
- kind: Job
- metadata:
- name: pi
- spec:
- parallelism:
- completions:
- template:
- spec:
- containers:
- - name: pi
- image: resouer/ubuntu-bc
- command: ["sh", "-c", "echo 'scale=5000; 4*a(1)' | bc -l "]
- restartPolicy: Never
- backoffLimit:
指定了最大并行数是2,最小完成数是4
- ### 创建Job对象
- $ kubectl create -f job.yaml
- ### Job维护两个字段,DESIRED即最小完成数
- $ kubectl get job
- NAME DESIRED SUCCESSFUL AGE
- pi 3s
- ### Job首先创建两个并行运行的Pod计算PI
- $ kubectl get pods
- NAME READY STATUS RESTARTS AGE
- pi-5mt88 / Running 6s
- pi-gmcq5 / Running 6s
- ### 当一个Pod完成计算会进入Completed状态,就会有一个新的Pod被创建出来,并且快速地从Pending状态进入ContainerCreating状态,再到Running状态,最后完成
- $ kubectl get pods
- NAME READY STATUS RESTARTS AGE
- pi-gmcq5 / Completed 40s
- pi-84ww8 / Pending 0s
- pi-5mt88 / Completed 41s
- pi-62rbt / Pending 0s
- $ kubectl get pods
- NAME READY STATUS RESTARTS AGE
- pi-gmcq5 / Completed 40s
- pi-84ww8 / ContainerCreating 0s
- pi-5mt88 / Completed 41s
- pi-62rbt / ContainerCreating 0s
- $ kubectl get pods
- NAME READY STATUS RESTARTS AGE
- pi-5mt88 / Completed 54s
- pi-62rbt / Running 13s
- pi-84ww8 / Running 14s
- pi-gmcq5 / Completed 54s
- $ kubectl get pods
- NAME READY STATUS RESTARTS AGE
- pi-5mt88 / Completed 5m
- pi-62rbt / Completed 4m
- pi-84ww8 / Completed 4m
- pi-gmcq5 / Completed 5m
- ### 所有Pod均已成功退出,SUCCESSFUL字段值变成4
- $ kubectl get job
- NAME DESIRED SUCCESSFUL AGE
- pi 5m
通过上述DESIRED和SUCCESSFUL字段的关系,可以看出Job Controller控制的直接对象是Pod,Job Controller在控制循环中进行的调谐(Reconcile)操作,是根据实际在Running状态Pod数目、已经成功推出的Pod数目,以及parallelism、completions参数的值共同计算在这个周期里,应该创建或删除的Pod数目,然后调用Kubernetes API来执行这个操作
Job对象使用方法
1、外部管理器 + Job模板
把Job的YAML文件定义为一个模板,然后用一个外部工具控制这些模板来生成Job 。Job的定义方式如下所示:
- apiVersion: batch/v1
- kind: Job
- metadata:
- name: process-item-$ITEM
- labels:
- jobgroup: jobexample
- spec:
- template:
- metadata:
- name: jobexample
- labels:
- jobgroup: jobexample
- spec:
- containers:
- - name: c
- image: busybox
- command: ["sh", "-c", "echo Processing item $ITEM && sleep 5"] ### 定义了$ITEM变量
- restartPolicy: Never
在控制这种Job时,只要注意如下两个方面即可
- 创建Job时,替换掉$ITEM这样的变量
- 所有来自同一个目标的Job,都有一个jobgroup: jobexample标签,也就是说这一组Job使用这样一个相同的标识
- ### 第一点可以通过shell把¥ITEM替换掉
- $ mkdir ./jobs
- $ for i in apple banana cherry
- do
- cat job-tmpl.yaml | sed "s/\$ITEM/$i/" > ./jobs/job-$i.yaml
- done
- ### 创建Job
- $ kubectl create -f ./jobs
- $ kubectl get pods -l jobgroup=jobexample
- NAME READY STATUS RESTARTS AGE
- process-item-apple-kixwv / Completed 4m
- process-item-banana-wrsf7 / Completed 4m
- process-item-cherry-dnfu9 / Completed 4m
这种模式虽然看起很傻,但却很普遍,因为大多数用户在需要管理Batch Job时,都已经有自家的一套方案,需要做的往往就是集成工作。这时候Kubernetes对这些方案最有价值的就是Job这个API对象,因此只需要编写一个外部工具(如上面for循环)来管理这些Job即可。
这种模式下使用Job对象,completions和parallelism这两个字段都应该使用默认值1,作业Pod的并行控制,应该完全交由外部工具来进行管理
2、拥有固定任务数目的并行Job
只关心最后是否有指定数目(spec.completions)个任务成功推出,不关心执行时的并行度多少。
比如上面计算pi的例子,或者可以不指定parallelism
3、指定并行度(parallelism),不设置固定的completions的值
任务总数未知,需要决定什么时候启动Pod,什么时候Job才算执行完成。因此需要一个工作队列来负责任务分发,还需要能够判断工作队列已经为空(所有工作已经结束)
- apiVersion: batch/v1
- kind: Job
- metadata:
- name: job-wq-
- spec:
- parallelism:
- template:
- metadata:
- name: job-wq-
- spec:
- containers:
- - name: c
- image: gcr.io/myproject/job-wq-
- env:
- - name: BROKER_URL
- value: amqp://guest:guest@rabbitmq-service:5672 ##工作队列采用RabbitMQ
- - name: QUEUE
- value: job2
- restartPolicy: OnFailure
这个Pod执行逻辑为
- /* job-wq-2 的伪代码 */
- for !queue.IsEmpty($BROKER_URL, $QUEUE) {
- task := queue.Pop()
- process(task)
- }
- print("Queue empty, exiting")
- exit
CronJob
CronJob描述的是定时任务,举个栗子
- apiVersion: batch/v1beta1
- kind: CronJob
- metadata:
- name: hello
- spec:
- schedule: "*/1 * * * *"
- jobTemplate:
- spec:
- template:
- spec:
- containers:
- - name: hello
- image: busybox
- args:
- - /bin/sh
- - -c
- - date; echo Hello from the Kubernetes cluster
- restartPolicy: OnFailure
在这个YAML文件中,最重要的关键词就是jobTemplate,即一个Job对象的控制器(Controller)。如Deployment和Pod的关系一样,CronJob是一个专门用来管理Job对象的控制器。
CronJob创建和删除Job的依据是schedule字段定义的、一个标准的Unix Cron格式的表达式
如,“*/1****”,这个Cron表达式里*/1中的*表示从0开始,/表示每,1表示偏移量,它的意思就是从零开始,每1个时间单位执行一次
那时间单位又是什么意思?Cron表达式中的五个部分分别代表:分钟、小时、日、月、星期。因此上面的意思就是每分钟执行一次。
- $ kubectl create -f ./cronjob.yaml
- cronjob "hello" created
- # 一分钟后
- $ kubectl get jobs
- NAME DESIRED SUCCESSFUL AGE
- hello- 2s
- ##CronJob对象会记录下这次Job的执行时间
- $ kubectl get cronjob hello
- NAME SCHEDULE SUSPEND ACTIVE LAST-SCHEDULE
- hello */ * * * * False Thu, Sep :: -
另外由于定时任务的特殊性,很可能某个Job还没有执行完,另外一个新的Job就产生了,这时候可以通过spec.concurrencyPolicy字段来定义具体的处理策略
- concurrencyPolicy=Allow:默认情况,Job可以同时存在;
- concurrencyPolicy=Forbid:不会创建新的Jod,该创建周期被跳过
- concurrencyPolicy=Replace:新产生的Job会替换旧的、没有执行完的Job
如果一个Job创建失败,这次创建就会被标记为“miss”,当在指定的时间窗口内,miss的数目达到100时,那么CronJob会停止创建这个Job。这个时间窗口可以由spec.startingDeadlineSeconds字段指定。
例如,startingDeadlineSeconds=200,意味着在过去的200s里,如果miss的数目到达了100次,那么这个Job就不会被创建执行了。
【Kubernetes】离线业务:Job与CronJob的更多相关文章
- Kubernetes Job与CronJob(离线业务)
Kubernetes Job与CronJob(离线业务) Job Job分为普通任务(Job) 一次性执行 应用场景:离线数据处理,视频解码等业务 官方文档:https://kubernetes.i ...
- [转帖]在 Kubernetes 离线部署 KubeSphere
在 Kubernetes 离线部署 KubeSphere https://kubesphere.io/docs/v2.0/zh-CN/installation/install-ks-offline/ ...
- linux运维、架构之路-Kubernetes离线、二进制部署集群
一.Kubernetes对应Docker的版本支持列表 Kubernetes 1.9 <--Docker 1.11.2 to 1.13.1 and 17.03.x Kubernetes 1.8 ...
- linux运维、架构之路-Kubernetes离线集群部署-无坑
一.部署环境介绍 1.服务器规划 系统 IP地址 主机名 CPU 内存 CentOS 7.5 192.168.56.11 k8s-node1 2C 2G CentOS 7.5 192.168.56 ...
- 从零开始了解kubernetes
kubernetes 已经成为容器编排领域的王者,它是基于容器的集群编排引擎,具备扩展集群.滚动升级回滚.弹性伸缩.自动治愈.服务发现等多种特性能力. 本文将带着大家快速了解 kubernetes , ...
- Kubernetes的基本概念和术语
Kubernetes中的大部分概念如Node.Pod.Replication Controller. Service等都可以被看作一种资源对象,几乎所有资源对象都可以通过 Kubernetes提供的k ...
- Kubernetes 的这些原理,你一定要了解
点击上方"开源Linux",选择"设为星标" 回复"学习"获取独家整理的学习资料! 作者:fredalxin地址:https://freda ...
- Docker与k8s的恩怨情仇(六)—— “容器编排”上演“终结者”大片
转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 在上节中,我们为大家介绍了Pod的基础内容,Kubernetes如何站在上帝视角上处理容器和容器之间的关系. ...
- Kubernetes — Job与CronJob
有一类作业显然不满足这样的条件,这就是“离线业务”,或者叫作 Batch Job(计算业务). 这 种业务在计算完成后就直接退出了,而此时如果你依然用 Deployment 来管理这种业务的话,就会 ...
随机推荐
- 盒子模型--IE与标准
从上图可以看到标准 W3C 盒子模型的范围包括 margin.border.padding.content,并且 content 部分不包含其他部分. 从上图可以看到 IE 盒子模型的范围也包括 ma ...
- Java类的静态块の二
在上一篇Java类的静态块の一中介绍到:类的静态块在类加载时候执行,执行早于构造函数,并且只执行一次. 但是在下面的例子中却发现JVM并不是把把所有的static模块都执行完成再执行其他(Java果然 ...
- mount_cd9660:/dev/acd0: Input/output error
mount -t cd9660 /dev/acd0 /cdrom g_vfs_done():acd0[READ(offset32768, length=204]error =5 mount_cd966 ...
- nmon安装和使用介绍
使用参考地址:百度中搜索 nmon 博客园 使用文档参考地址:http://nmon.sourceforge.net/pmwiki.php?n=Site.Documentation nmmon地址:h ...
- 如何计算CDS view里两个时间戳之间的天数间隔
ABAP透明表里的时间戳,数据类型为dec: 有个需求:计算这两个时间戳之间的天数间隔,丢弃时间戳年-月-日8位后面的小时:分钟:秒. 举个例子:如果时间戳是20180918173132,丢弃1731 ...
- 【算法基础】欧几里得gcd求最大公约数
package Basic; import java.util.Scanner; public class Gcd { public static void main(String[] args) { ...
- 测试类执行报错:AttributeError: 'Testlei' object has no attribute 'test_cases' 和data,unpack用法解析
a=[{"}] import unittest from ddt import ddt,data,unpack @ddt class Testlei(unittest.TestCase): ...
- k8s学习目录
目录 K8S基础部分 基础部分 5 秒创建 k8s 集群[转] k8s 核心功能[转] k8s 重要概念[转] 部署 k8s Cluster(上)[转] 部署 k8s Cluster(下)[转] Ku ...
- chrom控制台常用方法
console.assert对输入的表达式进行断言,只有表达式为false时,才输出相应的信息到控制台 . console.count(这个方法非常实用哦)当你想统计代码被执行的次数 console. ...
- 剑指offer44 扑克牌顺序
注意一个边界条件:必须是连续的,如果前后两个数是一样的也不满足条件 class Solution { public: bool IsContinuous( vector<int> numb ...