暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Kubernetes系列12 一 Job 与 CronJob

栋总侃技术 2021-06-20
928

通过前面的文章大家已经对 Kubernetes 的控制对象的能力都有所了解了。

  • Deployment:控制无状态服务应用,例如大多数的Web服务;

  • StatefulSet:控制有状态服务应用,例如Mysql等有主从节点等拓扑结构的服务;

  • DaemonSet:控制在每个Node上有且仅运行单个实例的应用,例如日志采集、监控等服务。

这些被控制的对象都有个共同点,都是一直处于Running状态的服务。而在生产实践中也存在着大量的离线应用场景,例如执行一次就退出的脚本,或者是周期性执行的脚本,可以称这类应用为离线业务。Kubernetes 通过Job、CronJob 来实现离线业务应用场景。

首先我么看一个 Job 的定义yaml文件:

    apiVersion: batch/v1
    kind: Job
    metadata:
    name: job-example
    spec:
    template:
    spec:
    containers:
    - name: job-example
    image: alpine:latest
            command: ["sh", "-c", "echo Job is Running && sleep 10"]
    restartPolicy: Never
    backoffLimit: 4
      activeDeadlineSeconds: 60
      parallelism: 2
      completions: 4

    到现在,大家对 spec.template 部分是非常的熟悉了,是 Kubernetes 的最小调度单位 Pod 的定义。而在示例中我们使用的是一个linux的最小镜像alpine(常作为运行Go应用等无其他依赖的基础镜像),而容器运行起来会输出 Job is Running,同时 sleep 10秒后,容器进程退出。

    通过 kubectl get pods 命令可以看到 该 Pod 在Running状态后会变成 Completed 状态:

      kubectl get pods
      NAME READY STATUS RESTARTS AGE
      job-example-th9jc 0/1 Completed 0 107s

      在容器进程运行的时候是Running状态,当执行完sleep 10命令后容器进程退出。我们可以查看该 Pod 的日志查看容器输出:

        kubectl logs job-example-th9jc
        Job is Running

        通过 kubectl describe jobs/job-example 命令可以查看Job的详情:

          kubectl describe jobs/job-example
          Name: job-example
          Namespace: default
          Selector: controller-uid=f27533fa-3196-492a-af08-2c04c21ba642
          Labels: controller-uid=f27533fa-3196-492a-af08-2c04c21ba642
          job-name=job-example
          Annotations: <none>
          Parallelism: 1
          Completions: 1
          Start Time: Sat, 19 Jun 2021 14:19:12 +0800
          Completed At: Sat, 19 Jun 2021 14:19:49 +0800
          Duration: 37s
          Pods Statuses: 0 Running 1 Succeeded 0 Failed
          Pod Template:
          Labels: controller-uid=f27533fa-3196-492a-af08-2c04c21ba642
          job-name=job-example
          Containers:
          job-example:
          Image: alpine:latest
          Port: <none>
          Host Port: <none>
          Command:
          sh
          -c
          echo Job is Running && sleep 10
          Environment: <none>
          Mounts: <none>
          Volumes: <none>
          Events:
          Type Reason Age From Message
          ---- ------ ---- ---- -------
          Normal SuccessfulCreate 40s job-controller Created pod: job-example-th9jc

          可以看到在 Job 对象被创建后,Pod会被自动加上一个带有uid的label controller-uid=xxxxxx,而当前Job会带有一个Selector来保证当前Job与Pod的关系,避免了不同的Job管理了相同的Pod。

          我们再回过头来看看 Job 的定义文件中的字段。

          其中 restartPolicy=Never,表示Pod 正常退出后不再重启,实际上Job也不应该在正常退出后被重启,所以 Job 的restartPolicy只能设置为Never或者Onfailure。

          而 Never 和 Onfailure 表示在Pod的容器如果是异常退出后的处理不同。Never 表示会不断地重新创建 Pod,Onfailure 则不会创建新的 Pod,只会不停的重启 Pod 里的容器。

          但是Never 状态下也不会是无限的重启Pod,默认重试6次,可以通过backoffLimit 来指定重试次数,示例中定义的 backoffLimit 为4。Job重启Pod的时间间隔是指数增长的,10s、20s、40s ......

          spec.activeDeadlineSeconds 则是用来设置容器的最长运行时间的。当Job管理的Pod容器运行的脚本逻辑出现异常,一直卡着导致Pod一直无法为Completed状态时,一旦超过了 activeDeadlineSeconds定义的时间,当前Job管理的Pod会被终止,且 Events 中可以看到 Reason 为 DeadlineExceeded

          spec.parallelism控制Job 当前并行运行的Pod数量,spec.completions 控制Job需要完成的Pod数量。在示例中需要执行4次Pod且有2个Pod并行执行。Job管理并行运行Pod数和总数的过程与Pod的滚动升级策略是一样的,详情可以见Kubernetes系列9 一 终于聊到编排了

          但是在我们的生产实践中CronJob是最为常见的,通过名字就能猜想到其与Linux的Cron Job类似,提供周期性执行任务的能力。

          我们将上述yaml案例改造为一个每分钟执行一次的Cron Job:

            apiVersion: batch/v1beta1
            kind: CronJob
            metadata:
              name: cronjob-example
            spec:
            schedule: "*/1 * * * *"
              concurrencyPolicy: Allow
              startingDeadlineSeconds: 7200
            jobTemplate:
            spec:
                  template:
            containers:
            - name: cronjob-example
            image: alpine:latest
            command: ["sh", "-c", "echo Job is Running && sleep 10"]
            restartPolicy: Never
            backoffLimit: 4

            其中JobTemplate.spec.template 正是一个Pod 的定义与Job的 spec.template 对应。说明CronJob同Deployment、StatefulSet、DaemonSet是一类,都是控制器对象。而CronJob直接管理的对象是Job,即Job 的 ownerReference 为CronJob。这与 RelicaSet 同 Deployment 的关系是一样的。

            CronJob的 spec.schedule 与linux cron命令语法是一致的,不了解的同学可以自行查阅资料。

            我们还需要注意 spec.concurrencyPolicy 定义,定时任务难免会出现上一次任务还未结束,而到达当前任务执行时间的场景。concurrencyPolicy有如下三种类型:

            • Allow:表示不同周期的任务可以同时存在,这也是concurrency的默认值;

            • Forbid:表示上一周期的任务未退出则不会创建新的Pod,当前周期会被跳过;

            • Replacy:表示用新的周期任务代换上一周期任务。

            spec.startingDeadlineSeconds 表示在多长滑动窗口时间内,如果Job创建失败的次数达到100(这个100是kubernetes源码里写死的)则不再创建Pod,案例中为2小时内错误数达到100次则不再执行 Job任务。

            本系列回顾:

            Kubernetes系列1 一 容器是什么?

            Kubernetes系列2 一 小鲸鱼与船长的历险记

            Kubernetes系列3 一 docker隔离与限制的原理

            Kubernetes系列4 一 docker镜像

            Kubernetes系列5 一 实践课

            Kubernetes系列6 一 Kubernetes登场

            Kubernetes系列7 一 最小编排单位Pod

            Kubernetes系列8 一 Pod的生命周期

            Kubernetes系列9 一 终于聊到编排了

            Kubernetes系列10 一 容器编排之StatefulSet

            Kubernetes系列11 一 容器编排之DaemonSet

            文章转载自栋总侃技术,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

            评论