date
related_level
slug
type
relate_date
summary
status
tags
category
last_updated
Dec 8, 2025 10:18 AM
是否已更新
orginal_page
是否推荐
参考资料
KubernetesJob
Job
Job 表示一次性任务,运行完成后就会停止。
Job 会创建一个或者多个 Pod,并将继续重试 Pod 的执行,直到指定数量的 Pod 成功终止
- 删除 Job 的操作会清除所创建的全部 Pod
- 挂起 Job 的操作会删除 Job 的所有活跃 Pod,直到 Job 被再次恢复执行
- 可以使用 Job 以并行的方式运行多个 Pod
- CronJob 按计划调度启动一次性 Job,用于执行排期操作,例如备份、生成报告等
CronJob 创建 Job 的行为
- CronJob 只负责创建 Job,Job 自身负责管理 Pod
Job 创建行为不是严格一次,因此 CronJob 的 Job 必须是幂等的
- 理论上 CronJob 每个触发点创建一个 Job,但可能:
- 创建两个
- 或者一个都不创建
- 试图使这些情况尽量少发生,但不能完全杜绝
- v1.32 以后创建的 Job 会带注解记录计划创建时间
batch.kubernetes.io/cronjob-scheduled-timestamp(计划时间)
- 若未设置或设置了较大的
startingDeadlineSeconds,且concurrencyPolicy: Allow,Job 至少会运行一次 - 注意:
startingDeadlineSeconds < 10可能导致调度失败(因控制器每 10 秒检查一次)
如果错过的调度次数超过上限(100 次),CronJob 将不再创建 Job 并报错。
- 未能在调度时间内创建 CronJob,则计为错过
- 并发限制也可能导致错过调度:并发策略为 Forbid 但上一个 Job 还在运行,新的调度被算作错过
- 默认情况下,错过次数从上一次应调度时间开始计算;
- 若设置了
startingDeadlineSeconds,则只统计该时间段内的错过次数。
CronJob 限制
不支持在 schedule 中写 TZ/CRON_TZ
spec.schedule不能使用TZ=或CRON_TZ=,必须使用专门的.spec.timezone字段 来指定时区,否则会验证失败
- 修改 CronJob 不会影响已运行的 Job,只影响未来新创建的 Job
kubectl 手动调度 cronjob
kubectl create -n <namespace> job --from=cronjob/<cronjob-name>
Job 三种执行模式:非并行 Job,具有固定完成数的并行 Job,带工作队列的并行 Job
非并行 Job:单个 Pod 完成 → Job 完成
- 不设置
.spec.completions/.spec.completionMode
固定完成数的并行 Job:运行直到成功的 Pod 数达到 N
.spec.completions=N- 同时可设置
.spec.parallelism
.spec.completionMode- (默认)NonIndexed:Pod 无索引
Indexed:每个 Pod 有唯一 index(0~N-1),可用于静态任务分片
工作队列类型 Job:Pod 之间需自行协调或通过外部服务(如工作队列)分配任务,每个 Pod 可领取若干工作项
- 不设置
completions但设置.spec.parallelism
- 任一 Pod 成功完成任务后,Job 即视为成功,不再创建新 Pod
- 所有 Pod 在任一 Pod 成功后应停止处理、退出,且不得再产生输出
- 当至少一个 Pod 成功且所有 Pod 均终止时,Job 被标记为成功完成
如何选择 Job 执行模式
- Job 可用于处理一组独立但相关的“工作条目”(如邮件、视频帧、文件等)
在设计批处理作业时,需权衡以下模式
- Job 粒度:每个工作条目对应一个 Job(管理开销大) vs. 所有条目共用一个 Job(适合大规模任务)。
- Pod 粒度:每个 Pod 处理一个条目(改动小) vs. 每个 Pod 处理多个条目(更高效,适合大量任务)。
- 协调机制:可使用外部工作队列(需修改应用)或无头 Service 实现 Pod 间通信协作。
- 任务一致性:当设置
.spec.completions时,所有 Pod 使用完全相同的配置,需通过其他方式(如外部队列或参数)让各 Pod 执行不同工作
权衡模式汇总
模式 | 单个 Job 对象 | Pod 数少于工作条目数? | 直接使用应用无需修改? |
每工作条目一 Pod 的队列 | ✓ | ㅤ | 有时 |
Pod 数量可变的队列 | ✓ | ✓ | ㅤ |
静态任务分派的带索引的 Job | ✓ | ㅤ | ✓ |
带 Pod 间通信的 Job | ✓ | 有时 | 有时 |
Job 模板扩展 | ㅤ | ㅤ | ✓ |
每种模式下 .spec.parallelism 和 .spec.completions 所需要的设置
W表示的是工作条目的个数
模式 | .spec.completions | .spec.parallelism |
每工作条目一 Pod 的队列 | W | 任意值 |
Pod 数量可变的队列 | 1 | 任意值 |
静态任务分派的带索引的 Job | W | ㅤ |
带 Pod 间通信的 Job | W | W |
Job 模板扩展 | 1 | 应该为 1 |
适用于 Indexed Job 的成功策略
- Job 默认规则:成功 Pod 数量 =
.spec.completions→ Job 成功
有时候不需要所有索引都成功
- 模拟任务中只需要部分成功即可
- 主从结构(如 MPI / PyTorch)中,只有“领导者”成功就算成功
spec.successPolicy.rules三种规则类型- 仅设置
succeededIndexes:当指定的索引列表(范围)全部成功 → Job 成功 - 仅设置
succeededCount:成功索引数量达到指定数值 → Job 成功 - 同时设置两者:当指定索引集合中,成功数量达到
succeededCount→ Job 成功
- 多条规则按顺序执行,匹配任意一条规则即视为 Job 成功,剩余规则不再检查
Job 终止
完成后的 Job 与 Pod 默认会保留
- Job 完成后不会再创建新 Pod,但 已完成的 Pod 不会自动删除(方便看日志)
- Job 对象本身也不会删除,需要用户手动
kubectl delete job
- 删除 Job 会 级联删除其 Pod
终止 Job 的两种方式:.spec.backoffLimit 和 .spec.activeDeadlineSeconds
.spec.backoffLimit设置重试次数上限restartPolicy = Never→ Pod 失败直接算一次失败restartPolicy = OnFailure→ 容器失败才算失败- 失败次数超过
.spec.backoffLimit→ Job 失败(Failed),Pod 停止创建
.spec.activeDeadlineSeconds设置活跃期限(秒),适用于 Job 的整个生命期- Job 运行总时间超过
.spec.activeDeadlineSeconds→ Job 标记失败(DeadlineExceeded),所有 Pod 被终止
.spec.activeDeadlineSeconds优先级高于.spec.backoffLimit
1.31 起,控制器仅在所有 Pod 都终止之后才会添加 Job 的终止 conditions
- 通过
JobManagedBy和JobPodReplacementPolicy特性门控来控制这一行为 - 均默认启用
Job 状态的终止 conditions 类型:complete, failed
- Complete:
- Pod 成功数量达到了
.spec.completions .spec.successPolicy中指定的标准已满足
- Failed:
- Pod 失败数量超过
.spec.backoffLimit - Job 运行时间超过
.spec.activeDeadlineSeconds - Job 失败的索引数量超过
.spec.maxFailedIndexes - 失败的 Pod 匹配
.spec.podFailurePolicy指定的条件 - (v1.30+)满足失败条件后被 Job 控制器终止
Job 提前触发 Pod 的终止
- 早于 Job 状态的 Failed 或 Complete 状态,控制器会先给 Job 添加:
- SuccessCriteriaMet(满足成功条件)
- FailureTarget(满足失败条件)
- 可提前判断 Job 结果后触发 Pod 终止,无需等待所有 Pod 完全终止
- 若在出现 Pod 状态为 FailureTarget 时立即创建替换 Job,启动更快,但可能导致新旧 Pod 并存、增加资源消耗
- 若等到 Job 状态为 Failed 再替换,则启动更晚,但能确保旧 Pod 已清理,节省资源
自动清理完成的 Job
- Job 状态为
Complete或Failed视为已完成
- 两种方式
- CronJob 会自动依据其策略清理旧 Job
- 使用由 TTL 控制器所提供的 TTL 机制
- 设置
.spec.ttlSecondsAfterFinished字段,让 TTL 控制器清理掉已结束的资源 - TTL 控制器清理 Job 时,会级联式地删除 Job 对象
Job 标签键为 batch.kubernetes.io/job-name 和 batch.kubernetes.io/controller-uid
Job 规范
- 只有
.spec.template是必需的字段
.spec.template 为 Job 创建的 Pod 定义模板
- 无需设置 metadata
- Job 中的 Pod 模板必须设置合适的 Labels 和 restartPolicy
- Job 中的 Pod 的 restartPolicy 只能为
Never或者OnFailure
- (可选)
.spec.selector大多数时候都不需要手动赋值
(可选).spec.parallelism 指定 Job 应在任何给定时刻预期运行的 Pod 个数上限
- 未设置则默认为 1
- 如果设置为 0 则 Job 相当于启动之后便被暂停,直到此值被增加
(可选).spec.completions 指定 Job 应该运行并预期成功完成的 Pod 个数
- 未设置则默认为 1
(可选).spec.backoffLimit 标记此任务失败之前的重试次数
- 默认值为 6
(可选,建议设置).spec.ttlSecondsAfterFinished 限制已完成的 Job 的生命周期
- 到期后 TTL 控制器会删除 Job 及所有 Pod(级联删除)
- 设置
0→ 立即删除
- 不设置 → Job 永不自动清理
- 强烈建议设置 TTL,否则被 orphan 的 Pod 会长期占用资源,影响集群性能
(可选).spec.completionMode 如何跟踪 Pod 完成情况
NonIndexed(默认):Pod 无索引
Indexed:每个 Pod 有唯一 index(0~N-1),可用于静态任务分片
Job 的 Pod 的 index 可通过以下方式获取
- 注解
batch.kubernetes.io/job-completion-index
- 标签
batch.kubernetes.io/job-completion-index(1.28+) - 必须启用
PodIndexLabel特性门控才能使用此标签,默认启用
- Pod 主机名
$(job-name)-$(index)
- 环境变量
JOB_COMPLETION_INDEX
(可选).spec.successPolicy 判定何时可以声明 Job 为成功,适用于 Indexed Job
spec.successPolicy.rules三种规则类型- 仅设置
succeededIndexes:当指定的索引列表(范围)全部成功 → Job 成功 - 仅设置
succeededCount:成功索引数量达到指定数值 → Job 成功 - 同时设置两者:当指定索引集合中,成功数量达到
succeededCount→ Job 成功
CronJob 规范
.spec.schedule 遵循 Cron 语法,也包含了扩展的 “Vixie cron” 步长值
.spec.jobTemplate为 CronJob 创建的 Job 定义模板,内容和 Job 的.spec一样
- (可选)
.spec.timeZone为 CronJob 指定一个时区,设置为一个有效的时区名称
(可选).spec.startingDeadlineSeconds 限定 Job 错过调度后允许的最大延迟时间
- 超过这个时间则视为错过,Job 不会被创建(算失败)
- 不设置则表示没有最后期限
(可选).spec.concurrencyPolicy 控制同一个 CronJob 生成的 Job 是否可以并发运行
- 仅适用于相同 CronJob 创建的 Job。如果有多个 CronJob,它们相应的 Job 总是允许并发执行的
可选值,默认值为 Allow
Allow:允许多个 Job 并发执行
Forbid:不允许并发;旧 Job 未完成时忽略新 Job- 注意,当老 Job 执行完成时,仍然会考虑
.spec.startingDeadlineSeconds,可能会导致新的 Job 执行失败
Replace:新 Job 到点时直接替换掉正在运行的旧 Job
(可选).spec.suspend 挂起 Job 调度
- 设为
true→ 暂停后续 Job 创建(已运行的 Job 不受影响)
- 恢复后(suspend=false),如果没有 startingDeadlineSeconds,所有错过的任务会立即补跑
(可选).spec.successfulJobsHistoryLimit 限制保留成功的 Job 数
- 默认值为
3
- 设置为
0意味着不会保留任何成功的 Job。
(可选).spec.failedJobsHistoryLimit 限制保留失败的 Job 数
- 默认值为
1
- 将此字段设置为
0意味着不会保留任何失败的 Job
Job 高级用法
手动设置 Job 的 .spec.selector
- 默认情况下,Job 的 selector 由系统自动生成,确保唯一性
- 可手动指定相同的
selector并设置manualSelector: true使新 Job 控制旧 Pod - 用于接管已有 Pod(如迁移 Job)
- 错误的选择器可能导致 Pod 被错误归属、删除或 Job 无法完成,Kubernetes 不会阻止此类操作
- 典型场景:通过
kubectl delete --cascade=orphan删除旧 Job 但保留其 Pod,再创建新 Job 并复用相同 selector 接管这些 Pod,实现无缝迁移或模板更新
通过 .spec.suspend 字段暂停和恢复 Job 的执行
设置 .spec.suspend 字段为 true 挂起一个 Job
- 挂起时,Job 会立即停止创建新 Pod,并终止所有正在运行且未完成的 Pod
- 发送 SIGTERM,尊重
terminationGracePeriodSeconds
- Pod 以这种形式终止时,不会被记入 Job 的
completions计数
更新 .spec.suspend 字段为 false 恢复 Job 执行
.status.startTime字段会被重置为当前的时间.status.conditions[].lastTransitionTime字段可被用来确定 Job 被挂起的时长
.spec.activeDeadlineSeconds计时器随之重新开始
- 挂起状态判断:可通过 Job 的
status.conditions中类型为Suspended的条件判断当前是否挂起(status: "True")或是否曾被挂起("False"或条件不存在)
- 挂起和恢复操作会分别触发
Suspended和Resumed事件,便于审计和监控
更改从未被激活过的已挂起 Job 的 Pod 调度策略
- 在 Job 开始之前更新调度指令,从而为定制队列提供影响 Pod 放置
- 允许自定义队列控制器在 Job 启动前调整调度策略
- 标签、注解
- 节点亲和性(nodeAffinity)
- 节点选择器(nodeSelector)
- 容忍(tolerations)
- 调度门控(schedulingGates)
kubectl patch 挂起和恢复 Job
kubectl patch job/myjob --type=strategic --patch '{"spec":{"suspend":true}}'
kubectl patch job/myjob --type=strategic --patch '{"spec":{"suspend":false}}'
Job 和 Cronjob 样例
Job 样例:计算 π 到小数点后 2000 位,并将结果打印出来
Cronjob 样例:每分钟打印出当前时间和问候消息
successPolicy Indexed Job 样例
使用工作队列进行粗粒度的并行处理 Job 样例
创建镜像
docker build -t job-wq-1 .
使用工作队列进行精细的并行处理 Job 样例
创建镜像
docker build -t job-wq-2 .
使用索引作业完成静态工作分配下的并行处理 Job 样例
基于一个公共的模板运行多个 Jobs 样例
模板
创建清单
基于清单创建 Job
kubectl create -f ./jobs
- Author:白鸟3
- URL:https://blog.kun2peng.top/operation/k8s_job_cronjob
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!
