kubernetes - 控制器 - Job

网友投稿 842 2022-10-27

本站部分文章、图片属于网络上可搜索到的公开信息,均用于学习和交流用途,不能代表睿象云的观点、立场或意见。我们接受网民的监督,如发现任何违法内容或侵犯了您的权益,请第一时间联系小编邮箱jiasou666@gmail.com 处理。

kubernetes - 控制器 - Job

控制器 - Job目标介绍 Job创建 Job编写 Job 的定义Job 的终止和清理Job 的自动清理Job 的模式Job 的特殊操作小练习 - 使用扩展进行并行处理什么是控制器 -Jobkubernetes 中的 Job 控制器,可以创建一个或多个 Pod ,并且确保指定数量的 Pod 都可以执行到进程结束当 Job 创建的 Pod 执行完成并正常结束时,Job 会记录 Pod 成功结束的数量当成功结束的 Pod 达到了指定的实例,Job 将完成执行删除 Job 对象时,将清理掉 Job 创建的 Pod一个简单的例子是:创建一个 Job 对象用来确保一个 Pod 的成功执行并结束。在第一个 Pod 执行失败或者被删除(例如,节点硬件故障或机器重启)的情况下,该 Job 对象将创建一个新的 Pod 以重新执行当然,您也可以使用 Job 对象并行执行多个 Pod创建 Job下面举个 Job 的例子,Pod 执行了一个跟 π相关的计算,并打印最终结果apiVersion: batch/v1kind: Jobmetadata: name: pispec: template: spec: containers: - name: pi image: perl command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"] restartPolicy: Never backoffLimit: 4 执行下面命令创建 Job 对象kubectl apply -f pi-job.yaml执行下面命令查看结果kubectl describe jobs/pi输出结果Name: piNamespace: defaultSelector: controller-uid=7ba0b221-db44-427a-ae6b-3a6fc778c8caLabels: controller-uid=7ba0b221-db44-427a-ae6b-3a6fc778c8ca job-name=piAnnotations: kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"batch/v1","kind":"Job","metadata":{"annotations":{},"name":"pi","namespace":"default"},"spec":{"backoffLimit":4,"template":...Parallelism: 1Completions: 1Start Time: Mon, 25 May 2020 11:33:43 +0800Pods Statuses: 1 Running 0 Succeeded 0 FailedPod Template: Labels: controller-uid=7ba0b221-db44-427a-ae6b-3a6fc778c8ca job-name=pi Containers: pi: Image: perl Port: Host Port: Command: perl -Mbignum=bpi -wle print bpi(2000) Environment: Mounts: Volumes: Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal SuccessfulCreate 10s job-controller Created pod: pi-j8www执行下面命令查看所有的 Podkubectl get pods执行下面命令获取该 Pod 的名字kubectl get pods --selector=job-name=pi --output=jsonpath='{.items[*].metadata.name}'在这个命令中:selector 与 Job 中定义的 selector 相同--output=jsonpath 选项指定了一个表达式,该表达式从返回结果列表中的每一个 Pod 的信息中定位出 name 字段的取值执行下面的命令,查看 Pod 的日志输出kubectl logs 本实例的结果为3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858632788659361533818279682303019520353018529689957736225994138912497217752834791315155748572424541506959508295331168617278558890750983817546374649393192550604009277016711390098488240128583616035637076601047101819429555961989467678374494482553797747268471040475346462080466842590694912933136770289891521047521620569660240580381501935112533824300355876402474964732639141992726042699227967823547816360093417216412199245863150302861829745557067498385054945885869269956909272107975093029553211653449872027559602364806654991198818347977535663698074265425278625518184175746728909777727938000816470600161452491921732172147723501414419735685481613611573525521334757418494684385233239073941433345477624168625189835694855620992192221842725502542568876717904946016534668049886272327917860857843838279679766814541009538837863609506800642251252051173929848960841284886269456042419652850222106611863067442786220391949450471237137869609563643719172874677646575739624138908658326459958133904780275901编写 Job 的定义与所有的 kubernetes 对象一样,Job 对象的 YAML 文件中,都需要包括如下三个字段:.apiVersion.kind.metadataJob 对象的 YAML 文件,还需要一个 .spec字段Pod Template.spec.template 是必填字段:用于定义 Pod Template与 Pod 有相同的字段内容,但由于是内嵌的元素,pod template 不包括 apiVersion和kind字段除了 Pod 所需的字段之外,Job 中的 pod template 必须指定合适的标签.spec.template.spec.labels指定合适的重启策略 (restartPolicy).spec.template.spec.restartPolicy,此时只允许使用Never和OnFailure两个值Pod Selector.spec.selector字段是可选的,大多数情况下不需要指定,只有在极少的的特殊情况下使用Parallel Job有三种主要的任务适合使用 Job 运行Non-parallel jobs通常只启动一个 Pod 除非该 Pod 执行失败Pod 执行成功并结束后,Job也立刻进入完成 (completed) 状态parallel jobs with a fixed completion count.spec.completions为一个非零的整数Job 将创建至少.spec.completions个 Pod,编号为 1-.spec.completionsJob 记录了任务的整体执行情况,当1-.spec.competions中每个编号都有一个对应的 Pod 执行成功时,job 进入完成状态parallel jobs with a work queue不指定.spec.completions,使用.spec.parallelismPod 之间必须相互自行协调并发,或者使用一个外部服务决定每个 Pod 各自执行什么任务每个 Pod 都可以独立判断其他同僚(peers)是否完成,并确定整个 Job 是否完成当 Job 中任何一个成功结束,并不会在创建新的 Pod当所有的 Pod 都结束了,且至少有一个 Pod 执行成功后才结束,则 Job 判定为成功结束一旦任何一个 Pod 执行成功并退出,job 中的任何其他 Pod 都应停止工作和输出信息,并可以终止该 Pod 的进程completions 和 parallelism对于 non-parallel jobs, .spec.completions和.spec.parallelism可不填写,默认为 1对于 fixed completion count job 需要设置.spec.completions为你期待的个数,同时设置.spec.parallelism字段(默认为 1 )对于 work queue job 不能设置.spec.completions字段,其必须设置.spec.parallelism字段为0或者任何正整数并发控制 (Controlling Parallelism)并发数.spec.parallelism可以被设置为 0 或者任何整数,如果不设置,默认为 1 ,如果设置为 0 则 Job 被暂停,直到改数字调整为一个正整数实际的并发数(同一时刻正在运行的 Pod 数量)可能比设定的并发数 .spec.parallelism 要大一些或小一些,不一定严格相等,主要的原因有:对于 fixed completion count Job,实际并发运行的 Pod 数量不会超过剩余未完成的数量。如果 .spec.parallelism 比这个数字更大,将被忽略对于 work queue Job,任何一个 Pod 成功执行后,将不再创建新的 Pod (剩余的 Pod 将继续执行)Job 控制器可能没有足够的时间处理并发控制如果 Job 控制器创建 Pod 失败(例如,ResourceQuota 不够用,没有足够的权限等)同一个Job中,在已创建的 Pod 出现大量失败的情况下,Job 控制器可能限制 Pod 的创建当 Pod 被优雅地关闭时(gracefully shut down),需要等候一段时间才能结束

处理 Pod 和容器的失败Pod 中的容器可能会因为多种原因执行失败,例如:容器中的进程退出了,且退出码不为 0容器因为超出内存限制而被 kill其他原因如果 Pod 中的容器执行失败,且.spec.template.spec.restartPolicy = "OnFailur",则 Pod 将停留在该节点上,但是容器将被重新执行,此时,你的应用程序需要处理在原节点(失败的节点)上重启的情况,或者你可以设置为.spec.template.spec.restartPolicy = "Never"整个 Pod 也会出现多种原因执行失败,例如:Pod 从节点上被驱逐Pod 的容器执行失败,且 .spec.template.spec.restartPolicy = "Never"当 Pod 执行失败后,Job 控制器会新建一个 Pod,此时,你的应用程序需要处理一个新的 Pod 中重启的情况,具体来说,需要处理临时文件,锁,未完成的输出信息以及前一次执行可能留下来的其他东西即使你指定 .spec.parallelism = 1、 .spec.completions = 1 以及 .spec.template.spec.restartPolicy = "Never",同一个应用程序仍然可能被启动多次如果指定 .spec.parallelism 和 .spec.completions 的值都大于 1,则,将可能有多个 Pod 同时执行。此时,你的 Pod 还必须能够处理并发的情况Pod 的重试某些情况下(例如,配置错误),你可能期望在 Job 重试仍然失败的情况下停止 Job,此时,你可以通过.spec.backoffLimit来设定 Job 的最大重试次数,默认是 6Job 中的 Pod 执行失败后,Job 控制器将按照一个指数增大的时间延迟(10s,20s,40s ... 最大为 6 分钟)来多次重新创建 Pod,如果没有新的 Pod 执行失败,则重试次数的计数将被重置如果 restartPolicy = "OnFailure",执行该 Job 的容器在 job 重试次数达到以后将被终止。这种情况使得 Job 程序的 debug 工作变得较为困难。建议在 debug 时,设置 restartPolicy = "Never",或者使用日志系统确保失败的 Job 的日志不会丢失Job 的终止和清理当 Job 完成后:将不会创建新的 Pod已经创建的 Pod 也不会被清理,此时,你仍然可以查看已结束 Pod 的日志Job 也会被保留,以便查看该 Job 的状态由用户决定是否删除已完成 Job 或 Pod可以通过 kubectl delete jobs/或者kubectl delete -f 删除 Job 对象时,由该 Job 创建的 Pod 也将一并删除Job 通常会顺利的执行下去,但是也会有如下情况非正常终止:某一个 Pod 执行失败 (且restartPolicy="Never")或者某一个容器执行出错(且restartPolicy="OnFailure")此时,Job 按照.spec.backoffLimit字段描述的方式进行处理一旦重试次数达到了.spec.backoffLimit中的值,Job 将被标记为失败,且由其创建的所有 Pod 将被终止Job 中设置了 .spec.activeDeadlineSeconds,该字段限定了 Job 对象在集群中存活的时长,一旦达到.spec.activeDeadlineSeconds指定的时长,该 Job 创建的所有 Pod 都将被终止,Job 的 Status 将变为 type.Failed、reason:DeadlineExceededJob 中 .spec.activeDeadlineSeconds 字段的优先级高于 .spec.backoffLimit。因此,正在重试失败 Pod 的 Job,在达到 .spec.activeDeadlineSecondes 时,将立刻停止重试,即使 .spec.backoffLimit 还未达到例如:apiVersion: batch/v1kind: Jobmetadata: name: pi-with-timeoutspec: backoffLimit: 5 # 指定了重启次数 activeDeadlineSeconds: 100 # 限定了存活时间 template: spec: contaners: - name: pi image: perl command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"] restartPolicy: NeverJob 中有两个 activeDeadlineSeconds:.spec.activeDeadlineSeconds 和 .spec.template.spec.activeDeadlineSeconds请不要混淆了Job 的自动清理系统中已经完成的 Job 通常是不在需要的,长期在系统里保留着,会对 apiserver 产生极大的压力,可以使用更高级别的 CronJob 控制器管理 Job,则 CronJob 可以根据定义的基于容量的清理策略 (capacity-based cleanup policy) 自动清理JobTTL 机制除了使用 CronJob 之外,TTL机制是另一种自动清理已结束 Job (Completed 或 Finished) 的方式TTL机制由 TTL 控制器提供在 Job 对象中指定.spec.ttlSecondsAfterFinished字段可激活该特性在 TTL 控制器清理 Job 时,TTL控制器将删除 Job 对象,以及改对象创建的所有 Pod参考例子:apiVersion: batch/v1kind: Jobmetadata: name: pi-with-ttlspec: ttlSecondsAfterFinished: 100 # 指定自动清理100秒之后 template: spec: containers: - name: pi image: perl command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"] restartPolicy: Never字段解释 ttlSecondsAfterFinished:Job pi-with-ttl 的 ttlSecondsAfterFinished 值为 100,则,在其结束 100 秒之后,将可以被自动删除如果 ttlSecondsAfterFinished 被设置为 0,则 TTL 控制器在 Job 执行结束后,立刻就可以清理该 Job 及其 Pod如果 ttlSecondsAfterFinished 值未设置,则 TTL 控制器不会清理该 JobJob 的模式kubernetes Job 对象可以用来支持 Pod 的并发执行,但是:Job 对象并非设计为支持需要紧密相连相互通信的 Pod 的并发执行,例如科学计算Job 对象不支持并发处理一系列相互独立又相互关联的工作任务,例如:发送邮件渲染页面转码文件扫描 NoSQL数据库中的主键其他在一个复杂的系统中,可能存在多种类型的工作任务,这里只考虑批处理任务对于批处理任务的并行计算,存在着几种模式,它们各自有自己的优缺点:每个工作任务一个 Job 对象 对比 一个 Job 对象负责所有的工作任务当工作任务特别多时,第二种选择(一个 Job 对象负责所有的工作任务)更合适一些第一种选择(每个工作任务一个 Job 对象)将为管理员和系统带来很大的额外开销,因为要管理很多数量的 Job 对象Pod的数量与工作任务的数量相等 对比  每个Pod可以处理多个工作任务第一种选择(Pod的数量与工作任务的数量相等)通常只需要对现有的代码或容器做少量的修改第二种选择(每个Pod可以处理多个工作任务)更适合工作任务的数量特别多的情况,相较于第一种选择可以降低系统开销使用工作队列,此时:需要运行一个队列服务需要对已有的程序或者容器做修改,以便其可以配合队列工作如果是一个已有的程序,改造时可能存在难度

Job的特殊模式在创建 Job 时,系统默认将为其指定一个.spec.selector的取值,并确保其不会与任何其他 Job 重叠在少数情况下,你仍然可能需要覆盖这个自动设置的.spec.selecor的取值,在做此操作时,一定要小心如果指定的 .spec.selector不能确定性的标识出该 Job 的 Pod,并可能选中无关的 Pod (例如,selector 可能选中其他控制器创建的 Pod),则:与该 Job 不相关的 Pod 可能被删除该 Job 可能将不相关的 Pod 纳入到 .spec.completions 的计数一个或多个 Job 可能不能够创建 Pod,或者不能够正常结束如果指定的 .spec.selector 不是唯一的,则其他控制器(例如,Deployment、StatefulSet 等)及其 Pod 的行为也将难以预测在 Kubernetes 中,系统并不能帮助你避免此类型的错误,你需要自己关注所指定的 .spec.selector 的取值是否合理让我们来看一个实际使用 .spec.selector 的例子:假设 Job old 已经运行,你希望已经创建的 Pod 继续运行,但是你又想要修改该 Job 的 名字,同时想要使该 Job 新建的 Pod 使用新的 template。此时你不能够修改已有的 Job 对象,因为这些字段都是不可修改的。此时,你可以执行命令 kubectl delete jobs/old --cascade=false,以删除 Job old 但是保留其创建的 Pod在删除之前先记录 Job old 的 selector,执行命令如下:kubectl get jos/old -o yaml输出结果kind: Jobmetadata: name: old ...spec: selector: matchLabels: controller-uid: a8f3d00d-c6d2-11e5-9f87-42010af00002 ...创建新的 Job new,并使用已有的 selector。由于已创建的 Pod 带有标签 controller-uid=a8f3d00d-c6d2-11e5-9f87-42010af00002,这些 Pod 也将被新的 Job new 所管理。使用类似如下的 yaml 文件创建 Job new:kind: Jobmetadata: name: new ...spec: manualSelector: true # 手动指定Selector selector: matchLabels: controller-uid: a8f3d00d-c6d2-11e5-9f87-42010af00002 # old 的Selector的值 ...当你不使用系统自动创建的 .spec.selector 时,需要在 Job new 中指定 .spec.manualSelector: true新建的 Job new 其 uid 将不同于 a8f3d00d-c6d2-11e5-9f87-42010af00002。设置 .spec.manualSelector: true 意味着,你知道这个设定是有意为之,系统将使用你指定的 .spec.selector,而不是使用 Job new 的 uid 作为 .spec.selector 的取值小练习 - 使用扩展进行并行处理在下面的例子中,我们将使用用一个模板创建多个 kubernetes Job基于模板扩展多模板参数基于模板扩展下面有个 Job 的模板文件:apiVersion: batch/v1kind: Jobmetadata: name: process-item-$ITEM labels: jobgroup: jobexamplespec: template: metadata: name: jobexample labels: jobgroup: jobexample spec: containers: - name: c image: busybox command: ["sh", "-c", "echo Processing item $ITEM && sleep 5"] restartPolicy: Never与 pod template 不同,此处的 job template 并不是一个 Kubernetes API 对象,而仅仅是 Job 对象的 yaml 文件(其中包含一些占位符)。例子文件中的 $ITEM 对 Kubernetes 并没有任何意义,仅仅是一个占位符,必须在使用时用实际数值替换。在此例子中,容器唯一做的事情就是 echo 一个字符串,并等待一小段时间。在实际使用中,应该是某种有意义的计算,例如渲染视频的某一帧图片,或处理数据库中某些记录。模板中的 $ITEM 占位符可用来指定视频的帧数,或者数据库记录的行数。此 Job 及其 Pod template 包含标签 jobgroup=jobexample。对系统来说此标签并没有任何特别之处。该标签可以用来方便地操作这一组 Job。Pod 上也包含该标签,以便我们可以使用一条命令即可检查这些 Job 的所有 Pod。在 Job 创建以后,系统将添加更多的标签以区分不同的 Job 创建的 Pod。jobgroup 并不是 Kubernetes 特殊要求的标签,你可以使用任何标签达到此目的。接下来,下载该模板文件,并将其扩展为多个文件:# 将上面的模板文件保存为 job-tmpl.yaml 文件# 将模板文件扩展为多个文件,并存到一个临时的文件夹mkdir ./jobsfor i in apple banana cherrydo cat job-tmpl.yaml | sed "s/\$ITEM/$i/" > ./jobs/job-$i.yamldone检查输出结果# 执行命令ll jobs/# 输出结果-rw-r--r-- 1 root root 366 May 25 17:13 job-apple.yaml-rw-r--r-- 1 root root 368 May 25 17:13 job-banana.yaml-rw-r--r-- 1 root root 368 May 25 17:13 job-cherry.yaml此处,我们使用 sed 将占位符 $ITEM 替换为循环变量的值。你可以使用任意模板语言(jinja2,erb等)或编写一个程序来生成 Job 对象。接下来,创建这些 Job:kubectl apply -f ./jobs输出结果job.batch/process-item-apple createdjob.batch/process-item-banana createdjob.batch/process-item-cherry created执行命令,检查 Pod 的状态:kubectl get jobs -l jobgroup=jobexample输出结果NAME COMPLETIONS DURATION AGEprocess-item-apple 1/1 37s 37sprocess-item-banana 1/1 26s 37sprocess-item-cherry 1/1 15s 37s此处,我们使用 -l 选项选择这一组 Job。执行如下命令可查看这组 Job 所有的 Pod:kubectl get pods -l jobgroup=jobexample输出结果NAME READY STATUS RESTARTS AGEprocess-item-apple-pn9tv 0/1 Completed 0 78sprocess-item-banana-4f8rg 0/1 Completed 0 78sprocess-item-cherry-m64dm 0/1 Completed 0 78s目前还不能直接使用一个命令去检查所有 Pod 的输出,但是,可以通过一个循环来检查所有 Pod 的输出:for p in $(kubectl get pods -l jobgroup=jobexample -o name)do kubectl logs $pdone输出结果Processing item appleProcessing item bananaProcessing item cherry多模板参数在前面的例子中,每一个模板的实例包含一个参数,同时,此参数也被用作标签。然而,标签的主键是受限于 句法和字符集 的下面这个例子稍微复杂一些,使用了 jinja2 模板语言来生成 Job 对象。我们将使用 python 脚本将模板转换为一个文件。首先,创建一个文件 job.yaml.jinja2,其内容如下所示:{%- set params = [{ "name": "apple", "url": "http://orangepippin.com/apples", }, { "name": "banana", "url": "https://en.wikipedia.org/wiki/Banana", }, { "name": "raspberry", "url": "https://raspberrypi.org/" }]%}{%- for p in params %}{%- set name = p["name"] %}{%- set url = p["url"] %}apiVersion: batch/v1kind: Jobmetadata: name: jobexample-{{ name }} labels: jobgroup: jobexamplespec: template: metadata: name: jobexample labels: jobgroup: jobexample spec: containers: - name: c image: busybox command: ["sh", "-c", "echo Processing URL {{ url }} && sleep 5"] restartPolicy: Never---{%- endfor %}此模板中,使用 python 字典表(1-4行)为每个 Job 对象定义了参数。然后通过一个循环遍历这些参数,并生成 Job 的 yaml 对象文件。多个 yaml 对象可以合并到一个 yaml 文件,使用 --- 分隔即可在运行时,你的环境中需要由 jinja2 包,如果没有,可以通过 pip install --user jinja2 命令安装执行 Python 脚本,以将模板扩展为多个 yaml 文件alias reder_template='python -c "from jinja2 import Template; import sys; print(Template(sys.stdin.read()).render());"'输出的结果保存到一个文件中,例如:cat job.yaml.jinja2 > reder_template > jobs.yaml或者直接通过 kubectl 执行,例如:cat job.yaml.jinja2 | reder_template | kubectl apply -f -

上一篇:在Jenklns中集成Selenium测试
下一篇:自动化GUI测试有很多可取的特点
相关文章

 发表评论

暂时没有评论,来抢沙发吧~