目录
这篇文章我们学习一下kubernete对Job的编排。不同于前面讲的Deployment、StatefulSet的编排,Job是一个执行一次就结束的pod,并不会滚动更新。
Job
定义job非常简单,只要在yaml文件中把kind字段定义成Job就可以了。如下kubejob.yaml:
apiVersion: batch/v1
kind: Job
metadata:
name: kubejob
spec:
parallelism: 2
completions: 4
template:
spec:
containers:
- name: myjob
image: zjj2006forever/kubejob:1.0
imagePullPolicy: IfNotPresent
restartPolicy: Never
backoffLimit: 4
activeDeadlineSeconds: 600
这个yaml文件中,我们定义了如下几个重要的参数:
restartPolicy:重启策略,这儿我们定义是Never,就是如果任务失败后不会重启,而是会创建一个新pod出来,直到创建次数超过了backoffLimit。如果设置成OnFailure,则失败后不会重新创建pod而是会重启。
backoffLimit:默认是6,我们定义失败次数是4
activeDeadlineSeconds:控制pod重新创建时间,防止失败后无限制的重新创建,Job运行结束后就会进入Completed状态,如果Job一直没有执行成功,就会反复地重新创建,直到时间超过activeDeadlineSeconds的值,上面我设置了600s如果Job在600s后还没有完成,那就会结束。
parallelism:任务并行度,上面设置是2个,这样就会生成2个pod并行执行
completions:期望有多少个pod执行完成后整个任务结束,上面设置是4
注意:上面的Job中,需要创建pod的数量 = 期望总共完成的pod数量(completions参数) - Completed状态的pod数量(已完成) - running状态的pod数量(运行中)
下面我们写一段java代码,这段代码很简单,每隔12s一次依次输出0到9的数,我把它打成一个镜像,提交到我的dockerhub,名称:zjj2006forever/kubejob:1.0
public class JobTest {
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 10; i++){
System.out.println(i);
Thread.sleep(12000);
}
}
}
上面的镜像打包好后,执行如下命令创建Job
[root@master kubejob]# kubectl create -f kubejob.yaml
job.batch/kubejob created
这时我们看一下Job的描述
[root@master kubejob]# kubectl describe jobs/kubejob
Name: kubejob
Namespace: default
Selector: controller-uid=190e811d-4d89-4d1d-9911-144499413c3a
Labels: controller-uid=190e811d-4d89-4d1d-9911-144499413c3a
job-name=kubejob
Annotations: <none>
Parallelism: 2
Completions: 4
Start Time: Thu, 30 Jul 2020 07:14:53 -0400
Active Deadline Seconds: 600s
Pods Statuses: 2 Running / 0 Succeeded / 0 Failed
Pod Template:
Labels: controller-uid=190e811d-4d89-4d1d-9911-144499413c3a
job-name=kubejob
Containers:
myjob:
Image: zjj2006forever/kubejob:1.0
Port: <none>
Host Port: <none>
Environment: <none>
Mounts: <none>
Volumes: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulCreate 105s job-controller Created pod: kubejob-vxgzg
Normal SuccessfulCreate 105s job-controller Created pod: kubejob-tbgqj
上面的输出我要说明一下,我们看到有一个Selector,是给了controller一个uid,这个uid的作用是匹配job和它管理的pod的对应关系,也就是通过这个uid,Job才可以管理它创建的pod。
然后查看pod数量,2个pod都已经进入了running状态。
[root@master kubejob]# kubectl get pods
NAME READY STATUS RESTARTS AGE
kubejob-tbgqj 1/1 Running 0 5s
kubejob-vxgzg 1/1 Running 0 5s
上面的输出我们看到当前有2个pod正在并行执行,4分钟以后,我们查看所有的pod,都已经完成
[root@master kubejob]# kubectl get pods
NAME READY STATUS RESTARTS AGE
kubejob-fnx6b 0/1 Completed 0 3m9s
kubejob-tbgqj 0/1 Completed 0 5m13s
kubejob-vxgzg 0/1 Completed 0 5m13s
kubejob-w7zlb 0/1 Completed 0 3m9s
而我们这时再查看pod的状态,COMPLETIONS说明期望4个任务都已经完成
[root@master kubejob]# kubectl get Job
NAME COMPLETIONS DURATION AGE
kubejob 4/4 4m8s 19m
我们查看其中一个pod的日志,输出正确,如下图:
[root@master kubejob]# kubectl logs kubejob-fnx6b
0
1
2
3
4
5
6
7
8
9
CronJob
从名字中我们也可以看出,这是一个定时任务控制器,事实上,它也是用标准的Unix cron表达式来控制任务的执行。它的定义也非常简单,把kind定义成CronJob。我们先定义一个yaml文件cronjob.yaml如下:
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: mycronjob
spec:
schedule: "*/1 * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: mycronjob
image: zjj2006forever/kubejob:1.0
imagePullPolicy: IfNotPresent
restartPolicy: OnFailure
concurrencyPolicy: Replace
从上面的yaml定义中我们看到有一个jobTemplate属性,他是一个job的模板,用来控制Job对象。所以,CronJob其实是一个Job对象的控制器。还记得之前文章《kubernete编排技术二:deployment》中用deployment来控制ReplicaSet对象吗,其实是一个道理。
CronJob对Job的控制,是通过参数schedule来进行的,这个参数的表达式就跟我们在linux下创建定时任务配置的cron时间格式一样。
这儿要注意,我上面定义的cron表达式是每分钟执行一次,但是上面我写的java应用是每2分钟才能执行,那是不是会有时间段内同时存在2个任务呢?
我们可以用这个字段来控制spec.concurrencyPolicy, 它有3个属性值:默认是Allow,允许job同时存在;Forbid表示上一个任务没有执行完成这个任务不允许创建;Replace表示新产生的任务pod会替换调旧的。
接下来我们创建这个CronJob,执行下面命令:
kubectl create -f cronjob.yaml
查看创建的任务:
[root@master kubejob]# kubectl get CronJob
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
mycronjob */1 * * * * False 1 21s 4m14s
再看一下pod和日志打印:
[root@master kubejob]# kubectl get pods
NAME READY STATUS RESTARTS AGE
mycronjob-1596280800-9xnpm 1/1 Running 0 52s
[root@master kubejob]# kubectl logs mycronjob-1596280800-9xnpm
0
1
2
3
4
这时我们看到其中一个pod打印出5个数之后(用了一分钟),就消失了,出现了新的Pod,这也印证了我们yaml文件中的spec.concurrencyPolicy=Replace
[root@master kubejob]# kubectl logs mycronjob-1596280800-9xnpm
Error from server (NotFound): pods "mycronjob-1596280800-9xnpm" not found
下面的输出我们还看到了pod被Replace的过程
[root@master kubejob]# kubectl get pods
NAME READY STATUS RESTARTS AGE
mycronjob-1596280920-2vlhr 1/1 Terminating 0 60s
mycronjob-1596280980-gvqqd 0/1 ContainerCreating 0 0s
[root@master kubejob]# kubectl get pods
NAME READY STATUS RESTARTS AGE
mycronjob-1596280980-gvqqd 1/1 Running 0 14s
最后说明一下,如果一个Job创建失败,这个Job就标记为miss,一旦指定时间内miss次数达到100,CronJob会停止再创建这个Job。这个时间可以由spec.startingDeadlineSeconds参数指定,单位是s。这里我就不再实验了。
总结
相对于之前讲的编排技术,Job和CronJob是相对比较简单的编排技术,但是也非常重要,包括怎么控制并发任务(parallelism),怎么控制完成数量(completions),还有定时任务配置(schedule)。这些对kubernete中的应用起了很好的支持。
微信公众号,欢迎关注,共同学习进步