Kubernetes:Job剖析

一. 简介

Deployment、StatefulSet,以及 DaemonSet 这三个主要编排的对象,都是“在线业务”,都属于Long Running Task(长作业)。
但是有一类作业显然不满足这样的条件,这就是“离线业务”,叫作 Batch Job(计算业务)。针对这种在计算完成后就直接退出的业务,可以使用我们今天的重点:Job来解决。

关于本文的项目的代码,都放于链接:GitHub资源

二. Job

2.1 案例

如下,我们创建一个计算pi后面100位的案例,需要执行10个这样的任务。
demo-job.yaml 文件如下:

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

2.2 检查Selector

运行完毕后,我们将看到如下的状态:

kubectl describe jobs/demo-job
# result
Name:                     demo-job
Namespace:                default
Selector:                 controller-uid=bde35f54-a1f8-4f1b-845f-d42e9c570f23
Labels:                   controller-uid=bde35f54-a1f8-4f1b-845f-d42e9c570f23
                          job-name=demo-job
Annotations:              <none>
Parallelism:              3
Completions:              10
Start Time:               Sat, 27 Mar 2021 23:58:51 +0000
Completed At:             Sat, 27 Mar 2021 23:59:11 +0000
Duration:                 20s
Active Deadline Seconds:  300s
Pods Statuses:            0 Running / 10 Succeeded / 0 Failed
result

可以看到,这个 Job 对象在创建后,它的 Pod 模板,被自动加上了一个 controller-uid=< 一个随机字符串 > 这样的 Label。而这个 Job 对象本身,则被自动加上了这个 Label 对应的 Selector,从而 保证了 Job 与它所管理的 Pod 之间的匹配关系。之所以要使用这种携带了 UID 的 Label,就是为了避免不同 Job 对象所管理的 Pod 发生重合。

2.3 参数

关于上面的YAML参数,详细分析如下:

  • spec.backoffLimit
    指定在标记此作业失败之前重试的次数,默认为6。并且,Job Controller 重新创建 Pod 的间隔是呈指数增加的,即下一次重新创建 Pod 的动作会分别发生在 10 s、20 s、40 s …后。
  • spec.activeDeadlineSeconds
    指定相对于startTime的持续时间(以秒为单位),在系统尝试终止该作业之前,该作业可能处于活动状态;值必须为正整数。例如,一旦运行超过了 300 s,这个 Job 的所有 Pod 都会被终止。并且,可以在 Pod 的状态里看到终止的原因是 reason: DeadlineExceeded
  • restartPolicy
    restartPolicy 在 Job 对象里只允许被设置为 Never 和 OnFailure,关于restartPolicy有如下俩种选项:
    • Never
      配置为当前参数后,那么离线作业失败后 Job Controller 就会不断地尝试创建一个新 Pod。
      当然,这个尝试肯定不能无限进行下去,这个与spec.backoffLimit参数是配合使用的。
    • OnFailure
      配置为当前参数后,那么离线作业失败后,Job Controller 就不会去创建新的 Pod,而是会不断地尝试重启 Pod 里的容器。

三. Job Controller

3.1 原理

Job Controller 控制的对象就是 Pod。
其次,Job Controller 在控制循环中进行的调谐(Reconcile)操作,是根据实际在 Running 状态 Pod 的数目、已经成功退出的 Pod 的数目,以及 parallelism、completions 参数的值共同计算出在这个周期里,应该创建或者删除的 Pod 数目,然后调用 Kubernetes API 来执行这个操作。

如果在这次调谐周期里,Job Controller 发现实际在 Running 状态的 Pod 数目,比 parallelism 还大,那么它就会删除一些 Pod,使两者相等。

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

3.2 参数

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

  • spec.parallelism
    指定作业在任何给定时间应运行的Pod的最大期望数目。
    ((.spec.completions-.status.successful)<.spec.parallelism),即当要做的工作小于最大并行度时,稳定状态下运行的Pod的实际数量将小于此数量。
  • spec.completion
    指定与作业一起运行所需的成功完成的Pod数量。
    设置为nil表示任何Pod的成功都表示所有Pod的成功,并允许并行性具有任何正值。设置为1意味着并行度被限制为1,并且pod的成功标志着工作的成功。

3.3 场景

3.3.1 parallelism和completions都确定

在这种模式下使用 Job 对象,completionsparallelism 这两个字段都应该使用默认值 1,而不应该由我们自行设置。
一般实际落地方案就是:外部管理器 +Job 模板。作业 Pod 的并行控制,应该完全交由外部工具来进行管理(比如,KubeFlow)。

3.3.2 parallelism不确定,completions确定

当只关心最后是否有指定数目(spec.completions)个任务成功退出,而不关系任务并行度时。
一般采用:外部MQ+Job。利用确定的Pod数,主动去消费MQ里面的消息达到目标数量即可。
例如,每个 Pod 只需要将任务信息读取出来,处理完成,然后退出即可。而作为用户,只关心最终一共有 10 个计算任务启动并且退出,只要这个目标达到,就认为整个 Job 处理完成了。

3.3.3 parallelism确定,completions不确定

由于任务数目的总数不固定,所以每一个 Pod 必须能够知道,什么时候可以退出。比如,借助上面例子,简单地以“队列为空”,作为任务全部完成的标志。
在这种情况下,难点在于任务的总数是未知的,所以不仅需要一个工作队列来负责任务分发,还需要能够判断工作队列已经为空。

四. Cron Job

4.1 原理

此处先看demo-cronjob.yaml文件:

apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: demo-cronjob
spec:
  schedule: "*/5 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: hello
            image: busybox
            args:
            - /bin/sh
            - -c
            - date; echo Hello World
          restartPolicy: OnFailure
  concurrencyPolicy: Replace
  startingDeadlineSeconds: 500

在这个 YAML 文件中,最重要的关键词就是 jobTemplateCronJob 是一个 Job 对象的控制器。CronJob 与 Job 的关系,正如同 Deployment 与 ReplicaSet 的关系一样。

4.2 Unix Cron

CronJob 是一个专门用来管理 Job 对象的控制器。只不过,它创建和删除 Job 的依据,是 schedule 字段定义的、一个标准的Unix Cron格式的表达式。
Cron 表达式中的五个部分分别代表:分钟、小时、日、月、星期。

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

关于上面的任务,执行如下俩条指令可以查看结果(等待5min):

kubectl get jobs
kubectl get cronjob demo-cronjob

结果如下:


cron job

4.3 并发策略

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

  • Allow
    允许CronJobs并发运行,默认值。
  • Forbid
    禁止同时运行,如果前一个运行尚未完成,则跳过下一个运行。
  • Replace
    取消当前正在运行的作业,并将其替换为新作业。

如果由于任何原因错过了计划的时间,则以秒为单位的可选截止期限,用于开始工作。当在指定的时间窗口内,miss 的数目达到 100 时,那么 CronJob 会停止再创建这个 Job。这个时间窗口,可以由 spec.startingDeadlineSeconds 字段指定。
在上面例子中, startingDeadlineSeconds=500,意味着在过去 500 s 里,如果 miss 的数目达到了 100 次,那么这个 Job 就不会被创建执行了。

四. 总结

关于Job,Cron Job 和 Job Controller 这三者,都是采用了控制器模式设计,利用对象管理对象,是一种树状的层级管理。这点与Deployment,ReplicaSet和Deployment Controller之间的设计理念一致。
用一个对象控制另一个对象,是 Kubernetes 编排的精髓所在!

欢迎收藏个人博客: Wyatt's Blog ,非常感谢~

Reference

https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349

推荐阅读更多精彩内容

  • “离线业务”,或者叫作 Batch Job(计算业务)。这种业务在计算完成后就直接退出了,而此时如果你依然用 De...
    xuxw阅读 818评论 0 0
  • 前言 Pod的分类 自助式pod 只要pod退出了,此类型的pod不会被重建,该pod没有管理者,死亡后不会被拉起...
    小波同学阅读 683评论 0 0
  • 容器技术概念入门篇 从进程说开去 容器本身没有价值,有价值的是“容器编排”。 容器其实是一种沙盒技术。顾名思义,沙...
    白板时钟阅读 2,508评论 0 2
  • 一、Kubernetes介绍 核心功能 Kubernetes抽象了数据中心的硬件设施,使得对外暴露的只是一个巨大的...
    睡不醒的大橘阅读 1,139评论 0 5
  • MySQL集群的流程迁移到 Kubernetes Master 节点和 Slave 节点需要有不同的配置文件(即:...
    小王的平凡生活_jerome阅读 445评论 0 0