【探索 Kubernetes|作业管理篇 系列 16】离线业务 Job、CronJob

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: 大家好,我是秋意零。在上一篇中,我们讲解了 DaemonSet 控制器,相信你以及理解了其的工作过程,分为三部。一是,获取所有 Node 节点中的 Pod;二是,判断是否有符合 DaemonSet 管理的 Pod;三是,通过“亲和性”和“容忍”来精确控制并保证 Pod 在目标节点运行。今天的内容是 Job 与 CronJob 离线业务控制器。

 前言

大家好,我是秋意零。

在上一篇中,我们讲解了 DaemonSet 控制器,相信你以及理解了其的工作过程,分为三部。一是,获取所有 Node 节点中的 Pod;二是,判断是否有符合 DaemonSet 管理的 Pod;三是,通过“亲和性”和“容忍”来精确控制并保证 Pod 在目标节点运行。

今天的内容是 Job 与 CronJob 离线业务控制器。

👿 简介

    • 🏠 个人主页秋意零
    • 🔥 账号:全平台同名, 秋意零 账号创作者、 云社区 创建者
    • 🧑 个人介绍:在校期间参与众多云计算相关比赛,如:🌟 “省赛”、“国赛”,并斩获多项奖项荣誉证书
    • 🎉 目前状况:24 届毕业生,拿到一家私有云(IAAS)公司 offer,暑假开始实习
    • 💕欢迎大家:欢迎大家一起学习云计算,走向年薪 30 万
    • 💕推广:CSDN 主页左侧,是个人扣扣群推广。方便大家技术交流、技术博客互助

    image.gif编辑

    系列文章目录


    【云原生|探索 Kubernetes-1】容器的本质是进程

    【云原生|探索 Kubernetes-2】容器 Linux Cgroups 限制

    【云原生|探索 Kubernetes 系列 3】深入理解容器进程的文件系统

    【云原生|探索 Kubernetes 系列 4】现代云原生时代的引擎

    【云原生|探索 Kubernetes 系列 5】简化 Kubernetes 的部署,深入解析其工作流程


    更多点击专栏查看深入探索 Kubernetes

    正文开始

      • 快速上船,马上开始掌舵了(Kubernetes),距离开船还有 3s,2s,1s...

      image.gif


      目录

      前言

      系列文章目录

      一、离线业务

      二、Job 基本概念与用法

      三、Job Controller 并行作业的控制方法

      四、使用 Job 常用的方法

      外部管理器 +Job 模板

      五、CronJob

      总结



      一、离线业务

      通过前面篇章中的学习的控制器,如:Deployment、StatefulSet、DaemonSet 这三个编排控制器,它们所部署的服务都有什么共同点吗?

      答案是:有的。

        • 其实,它们主要编排的对象业务,都是“在线业务”,即:Long Running Task(长作业)。比如:Nginx、Tomcat、Apache、MySQL 等等,这部分业务只要一运行起来,如果不出现错误或手动停止删除,这些服务的容器(进程)会一直运行(Running)下去。

        既然有了这种“在线业务”,那是不是就一定有“离线业务”呢?

        答案:是的。

          • “离线业务”对比“在线业务”是相反的概率,就是服务不会一直运行下去,而是服务自己的任务完成之后就会自动退出。

          如果使用控制“在线业务”的控制器,来编排“离线业务”会是怎么样呢?

            • 离线业务”或者叫作 Batch Job(计算业务):这种情况下是没有意义的,比如:使用 Deployment 来编排一个“离线业务”,“离线业务”完成后就会自动退出,而因为 Deployment 的缘故会实际状态的 Pod 个数保持在期望状态的 Pod 个数,也就会重新创建这个“离线业务”。
            • 咋一看,好像也没什么,如果将“离线业务”任务是用来计算 1+1 的这种运行结果时,不断重建“离线业务”是不是就失去了意义了呢?
            • 因为完全没有必要。而使用 Deployment 的“滚动更新”功能也是一样的道理,无意义。

            二、Job 基本概念与用法

            现在,我们来看一个 Job 计算 π 后 10000 位小数的例子:

            apiVersion: batch/v1
            kind: Job
            metadata:
              name: pi
            spec:
              template:
                spec:
                  containers:
                  - name: pi
                    image: resouer/ubuntu-bc 
                    command: ["sh", "-c", "echo 'scale=10000; 4*a(1)' | bc -l "]
                  restartPolicy: Never
              backoffLimit: 4

            image.gif

            可以看到,这个例子的 spec.template字段可谓是非常熟悉了吧(Pod 模板)。但是,跟其他控制器不同的是,Job 对象并不要求你定义一个 spec.selector 来绑定要控制哪些 Pod。

            这个 Job 使用的一个 ubuntu 镜像 ,安装有 bc 精度的计算命令,并运行了一条计算 π 后 10000 位小数的命令:

            echo 'scale=10000; 4*a(1)' | bc -l

              • scale:定义某些操作如何使用小数点后的数字,默认为 0;
              • 4*a(1):a(1),是调用数学库中的 arctangent 函数,4*atan(1) 正好就是 π,也就是 3.1415926…;
              • -l 参数:定义使用的标准数学库。
                1. 运行这个 Job:
                [root@master01 yaml]# kubectl apply -f job.yaml
                job.batch/pi created
                [root@master01 yaml]# kubectl describe job/pi

                image.gif

                我们来查看一下这个 Job 对象详细信息:

                  • 可以看到创建 Job 之后,Job 自动为 Pod Template 添加了一个标签,格式为:controller-uid=<一个随机字符串>。Job 本身也添加了对应的 Selector,从而保证了 Job 与它所管理的 Pod 之间的匹配关系。
                  • 而 Job 控制器使用这种 UID 的标签,就是为了避免不同 Job 对象所管理的 Pod 发生重合。因为它不需要对特定的副本进行选择或管理,Job 仅负责执行一次性任务,而不需要与其他副本进行交互或进行标签选择。
                  • Job 中也没有 replicas 字段。因为, Job 的主要目的是确保任务的完成,不是保持一定数量的副本运行。当 Job 中定义的任务成功完成后,Job 会认为任务已经完成,并且不会重新创建新的任务。因此,replicas 字段在 Job 中没有意义。

                  image.gif编辑

                    1. 创建 Job 后,查看 Pod 的状态:
                    [root@master01 yaml]# kubectl get pod
                    NAME       READY   STATUS    RESTARTS   AGE
                    pi-nxplz   1/1     Running   0          31s

                    image.gif

                    几分钟后 Pod 进入 Completed 状态,说明它的任务已经完成。不重启的原因:我们在 Pod 模板中定义过了 restartPolicy=Never 策略。

                    Job 中的重启策略 restartPolicy,只能被设置为 Never 和 OnFailure;

                    [root@master01 yaml]# kubectl get pod
                    NAME       READY   STATUS      RESTARTS   AGE
                    pi-nxplz   0/1     Completed   0          4m
                    [root@master01 yaml]# kubectl get job
                    NAME   COMPLETIONS   DURATION   AGE
                    pi     0/1           3s         3s

                    image.gif

                      1. kubectl logs 命令,查看运行结果:
                      [root@master01 ~]# kubectl logs pod/pi-nxplz
                      3.141592653589793238462643383279502884197169399375105820974944592307\
                      81640628620899862803482534211706798214808651328230664709384460955058\
                      22317253594081284811174502841027019385211055596446229489549303819644\
                      28810975665933446128475648233786783165271201909145648566923460348610\
                      ....

                      image.gif

                        1. 离线作业失败了要怎么办?

                        由于,定义了 restartPolicy=Never,那么离线作业失败后 Job Controller 就会不断地尝试创建一个新 Pod,如:

                        $ kubectl get pods
                        NAME                                READY     STATUS              RESTARTS   AGE
                        pi-55h89                            0/1       ContainerCreating   0          2s
                        pi-tqbcz                            0/1       Error               0          5s

                        image.gif

                        不过,为了不让这个 Pod 一直创建下去,因为一直创建下去说明我们程序就有问题,这个时候我们使用 spec.backoffLimit字段来设置重试次数,这个 Job 为 4,这个字段的默认值是 6。

                        需要注意的是:Job Controller 重新创建 Pod 的间隔是呈指数增加的,即:下一次重新创建 Pod 的动作会分别发生在 10 s、20 s、40 s …后。

                        而如果你定义的 restartPolicy=OnFailure,那么离线作业失败后,Job Controller 就不会去尝试创建新的 Pod。但是,它会不断地尝试重启 Pod 里的容器。

                          1. 如果这个 Pod 因为某种原因一直不肯结束呢?

                          spec.activeDeadlineSeconds字段可以设置最长运行时间,比如:

                          spec:
                           backoffLimit: 4
                           activeDeadlineSeconds: 100

                          image.gif

                          这个程序运行一旦超过 100 s,那 Pod 会被终止。

                          以上,就是一个 Job API 对象最主要的概念和用法了。不过,离线业务之所以被称为 Batch Job,当然是因为它们可以以“Batch”(批处理),也就是并行的方式去运行。

                          三、Job Controller 并行作业的控制方法

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

                            • 1. spec.parallelism:Job 最多可以启动多少个 Pod 同时运行;
                            • 2.spec.completions:Job 至少要完成的 Pod 数目,即 Job 的最小完成数。

                            在之前计算 Pi 值的 Job 里,添加这两个参数:

                              • 并行数量为 2
                              • 至少完成的数量为 4
                              apiVersion: batch/v1
                              kind: Job
                              metadata:
                                name: pi
                              spec:
                                parallelism: 2
                                completions: 4
                                template:
                                  spec:
                                    containers:
                                    - name: pi
                                      image: resouer/ubuntu-bc
                                      command: ["sh", "-c", "echo 'scale=5000; 4*a(1)' | bc -l "]
                                    restartPolicy: Never
                                backoffLimit: 4

                              image.gif

                                1. 创建 Job:
                                [root@master01 yaml]# kubectl apply -f job.yaml

                                image.gif

                                  1. 查看 Job:
                                    • COMPLETIONS:需要完成的数量以及完成的数量,比如:2/4,已完成 2 个任务,至少需要完成 4 个任务。
                                    [root@master01 yaml]# kubectl get job
                                    NAME   COMPLETIONS   DURATION   AGE
                                    pi     2/4           57s        57s

                                    image.gif

                                    当一组 Pod 完成后,就会有新的一组 Pod 继续执行

                                    [root@master01 yaml]# kubectl get pod
                                    NAME       READY   STATUS      RESTARTS   AGE
                                    pi-js98q   1/1     Running     0          25s
                                    pi-mhfsl   1/1     Running     0          25s
                                    pi-t2w8n   0/1     Completed   0          55s
                                    pi-z7gqh   0/1     Completed   0          55s

                                    image.gif

                                    当所有 Pod 任务完成之后,Job 的 COMPLETIONS 字段也就变成了 4/4

                                    [root@master01 yaml]# kubectl get pod
                                    NAME       READY   STATUS      RESTARTS   AGE
                                    pi-js98q   0/1     Completed   0          8m56s
                                    pi-mhfsl   0/1     Completed   0          8m56s
                                    pi-t2w8n   0/1     Completed   0          9m26s
                                    pi-z7gqh   0/1     Completed   0          9m26s
                                    [root@master01 yaml]# kubectl get job
                                    NAME   COMPLETIONS   DURATION   AGE
                                    pi     4/4           59s        3m59s

                                    image.gif

                                    Job Controller 实际上控制了,作业执行的并行度,以及总共需要完成的任务数这两个重要参数。而在实际使用时,你需要根据作业的特性,来决定并行度(parallelism)和任务数(completions)的合理取值。

                                    四、使用 Job 常用的方法

                                    外部管理器 +Job 模板

                                    这种模式的用法是:把 Job 的 YAML 文件当作一个模板,然后使用外部工具来控制生成 Job。如下:

                                    apiVersion: batch/v1
                                    kind: Job
                                    metadata:
                                      name: process-item-$ITEM
                                      labels:    
                                        jobgroup: jobexample
                                    spec:
                                      template:
                                        metadata:
                                          name: job-example
                                          labels: 
                                            jobgroup: jobexample
                                        spec:
                                          containers:
                                          - name: busybox-job
                                            image: busybox
                                            command: ["sh", "-c", "echo Hello $ITEM && sleep 5"]
                                          restartPolicy: Never

                                    image.gif

                                    Job 的 YAML 中,定义了 $ITEM 变量,所以在控制这中 Job 时,需要注意两个方面:

                                      • 1. 创建 Job 时,替换掉 $ITEM 变量,为自己的信息;
                                      • 2. 来自于同一个模板的 Job,这里都有一个 jobgroup: jobexample标签,也就是说这一组 Job 使用这样一个相同的标识。

                                      使用 Shell 把 $ITME 替换掉

                                      [root@master01 yaml]# mkdir ./jobs
                                      [root@master01 yaml]# for i in qyl-1 qyl-2 qyl-3
                                      > do
                                      >   cat job-1.yaml | sed "s/\$ITEM/$i/g" > ./jobs/job-$i.yaml
                                      > done

                                      image.gif

                                      这样通过 Shell 脚本的方式,同一个 Job 模板生成了不同的 Job 的 YAML 文件

                                      [root@master01 yaml]# ll ./jobs
                                      total 12
                                      -rw-r--r-- 1 root root 372 Jun 25 17:31 job-qyl-1.yaml
                                      -rw-r--r-- 1 root root 372 Jun 25 17:31 job-qyl-2.yaml
                                      -rw-r--r-- 1 root root 372 Jun 25 17:31 job-qyl-3.yaml
                                      [root@master01 yaml]# kubectl apply -f ./jobs
                                      job.batch/process-item-qyl-1 created
                                      job.batch/process-item-qyl-2 created
                                      job.batch/process-item-qyl-3 created
                                      [root@master01 yaml]# kubectl get pods -l jobgroup=jobexample
                                      NAME                       READY   STATUS      RESTARTS   AGE
                                      process-item-qyl-1-tgr5k   0/1     Completed   0          53s
                                      process-item-qyl-2-bftz4   0/1     Completed   0          53s
                                      process-item-qyl-3-cgvwd   0/1     Completed   0          53s

                                      image.gif

                                      image.gif编辑

                                      五、CronJob

                                      顾名思义,CronJob 描述的,是定时任务。

                                      apiVersion: batch/v1beta1
                                      kind: CronJob
                                      metadata:
                                        name: hello
                                      spec:
                                        schedule: "*/1 * * * *"
                                        jobTemplate:
                                          spec:
                                            template:
                                              spec:
                                                containers:
                                                - name: hello
                                                  image: busybox
                                                  imagePullPolicy: IfNotPresent
                                                  args:
                                                  - /bin/sh
                                                  - -c
                                                  - date; echo Hello qyl-0
                                                restartPolicy: OnFailure

                                      image.gif

                                      CronJob 的 YAML 文件中,spec.jobTemplate字段表示的是“Job模板”,所以 CronJob 是 Job 对象的控制器。CronJob 与 Job 之间的关系就与 Deployment 和 ReplicaSet 一样的。不过它生命周期是由 schedule 字段控制的。

                                      它也像我们 Linxu 里面的 CronTab,所以这里的 schedule 字段的格式是一个标准的 Cron 格式。比如:"*/1 * * * *"

                                      这个 Cron 表达式里 */1 中的 * 表示从 0 开始,/ 表示“每”,1 表示偏移量。所以,它的意思就是:从 0 开始,每 1 个时间单位执行一次。

                                      image.gif编辑

                                      所以,上面的 CronJob 的 YAML 文件会一分钟后创建 Job:

                                      [root@master01 yaml]# kubectl get cronjob
                                      NAME    SCHEDULE      SUSPEND   ACTIVE   LAST SCHEDULE   AGE
                                      hello   */1 * * * *   False     0        26s             58s
                                      [root@master01 yaml]# kubectl get job
                                      NAME             COMPLETIONS   DURATION   AGE
                                      hello-28128130   1/1           4s         27s

                                      image.gif

                                      需要注意的是,由于定时任务的特殊性,很可能某个 Job 还没有执行完,另外一个新 Job 就产生了。这时候,你可以通过 spec.concurrencyPolicy字段来定义具体的处理策略。比如:

                                        • concurrencyPolicy=Allow:这也是默认情况,这意味着这些 Job 可以同时存在
                                        • concurrencyPolicy=Forbid:这意味着不会创建新的 Pod,该创建周期被跳过;
                                        • concurrencyPolicy=Replace:这意味着新产生的 Job 会替换旧的、没有执行完的 Job。

                                        而如果某一次 Job 创建失败,这次创建就会被标记为“miss”。当在指定的时间窗口内,miss 的数目达到 100 时,那么 CronJob 会停止再创建这个 Job。

                                        这个时间窗口,可以由 spec.startingDeadlineSeconds字段指定。比如:

                                          • startingDeadlineSeconds=200,意味着在过了 200 s 后,如果 miss 的数目达到了 100 次,那么这个 Job 就不会被创建执行了。

                                          总结

                                          今天,主要讲解了 Job 这种“离线业务”控制器的概率用法,并行控制的方法。

                                          最后,解释了 CronJob 的使用,CronJob 也体现了,用一个对象控制另一个对象,是 Kubernetes 编排的精髓所在。

                                          相关实践学习
                                          通过Ingress进行灰度发布
                                          本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
                                          容器应用与集群管理
                                          欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
                                          目录
                                          相关文章
                                          |
                                          7月前
                                          |
                                          Kubernetes Perl 容器
                                          kubernetes 的Job 的并行执行 配置
                                          在Kubernetes中,Job是一种用于批处理任务的Controller对象。如果你想要配置Job以支持并行执行,可以使用Job的`.spec.parallelism`字段。这个字段定义了Job中可以并行运行的Pod的最大数量。 下面是一个简单的Job定义,其中包含了`.spec.parallelism`字段: ```yaml apiVersion: batch/v1 kind: Job metadata: name: example-job spec: parallelism: 3 # 这里定义了并行运行的Pod的数量 completions: 5 # 定义了成功完成的
                                          120 1
                                          |
                                          28天前
                                          |
                                          Kubernetes 调度 容器
                                          【赵渝强老师】K8s中Job控制器单工作队列的串行方式
                                          Kubernetes中的Job控制器用于管理一次性任务,确保任务完成后不再重启。本文介绍了Job的工作原理、运行方式及示例,包括创建Job、查看Job和Pod信息等步骤,并附有视频讲解。
                                          |
                                          28天前
                                          |
                                          Kubernetes Linux 调度
                                          【赵渝强老师】K8s的周期性任务控制器CronJob
                                          本文介绍了K8s中的CronJob控制器,它类似于Linux的crontab命令,用于管理和调度定时作业。CronJob可以设置在未来某一时间运行作业一次或在指定时间点重复运行作业。文章通过一个示例展示了如何创建和使用CronJob控制器,包括创建配置文件、应用配置、查看Pod信息和日志等步骤。同时,还解释了CronJob的时间表示方式及其限制。
                                          |
                                          28天前
                                          |
                                          Kubernetes 调度 容器
                                          【赵渝强老师】K8s的Job控制器多工作队列的并行方式
                                          Kubernetes Job 是一次性任务控制器,用于控制 Pod 中的容器执行特定任务。本文介绍了 Job 控制器的工作原理、运行方式及多工作队列并行执行的示例。示例中创建了 5 个作业,以 3 个队列并行执行,整个过程需 2 分钟。文中还提供了详细的 YAML 文件配置和执行命令。
                                          |
                                          7月前
                                          |
                                          存储 数据采集 Kubernetes
                                          一文详解K8s环境下Job类日志采集方案
                                          本文介绍了K8s中Job和Cronjob控制器用于非常驻容器编排的场景,以及Job容器的特点:增删频率高、生命周期短和突发并发大。文章重点讨论了Job日志采集的关键考虑点,包括容器发现速度、开始采集延时和弹性支持,并对比了5种采集方案:DaemonSet采集、Sidecar采集、ECI采集、同容器采集和独立存储采集。对于短生命周期Job,建议使用Sidecar或ECI采集,通过调整参数确保数据完整性。对于突发大量Job,需要关注服务端资源限制和采集容器的资源调整。文章总结了不同场景下的推荐采集方案,并指出iLogtail和SLS未来可能的优化方向。
                                          |
                                          6月前
                                          |
                                          SQL 关系型数据库 MySQL
                                          实时计算 Flink版产品使用问题之运行run-application --target kubernetes-application执行,通过进程的返回码来决定作业是否成功,任务返回码都是0,该怎么办
                                          实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
                                          |
                                          6月前
                                          |
                                          Kubernetes Oracle 关系型数据库
                                          实时计算 Flink版操作报错合集之用dinky在k8s上提交作业,会报错:Caused by: org.apache.flink.table.api.ValidationException:,是什么原因
                                          在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
                                          273 0
                                          |
                                          7月前
                                          |
                                          Kubernetes Linux 调度
                                          k8s-高级调度-CronJob 计划任务
                                          k8s-高级调度-CronJob 计划任务
                                          133 0
                                          |
                                          7月前
                                          |
                                          Kubernetes Java 流计算
                                          在Kubernetes上运行Flink应用程序时,你可以使用Flink Kubernetes Client提供的命令来提交作业
                                          在Kubernetes上运行Flink应用程序时,你可以使用Flink Kubernetes Client提供的命令来提交作业
                                          104 6
                                          |
                                          7月前
                                          |
                                          Kubernetes Cloud Native Linux
                                          云原生|kubernetes|kubernetes集群部署神器kubekey安装部署高可用k8s集群(半离线形式)
                                          云原生|kubernetes|kubernetes集群部署神器kubekey安装部署高可用k8s集群(半离线形式)
                                          329 1

                                          相关产品

                                        • 容器服务Kubernetes版