kubernete编排技术四:Job和CronJob

gq_design
发布于 2022-5-1 09:19
浏览
0收藏

作者 |  朱晋君
来源 | 君哥聊技术(ID:gh_1f109b82d301)

这篇文章我们学习一下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中的应用起了很好的支持。

分类
收藏
回复
举报
回复
    相关推荐