Lazy loaded image
运维管理
k8s 使用 Job 和 CronJob 一次性或定期运行 Pod
Words 4259Read Time 11 min
2025-12-8
2025-12-8
date
related_level
slug
type
relate_date
summary
status
tags
category
last_updated
Dec 8, 2025 10:18 AM
是否已更新
orginal_page
是否推荐
参考资料
  • KubernetesKubernetesJob
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 状态的 FailedComplete 状态,控制器会先给 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 样例
使用工作队列进行精细的并行处理 Job 样例
使用索引作业完成静态工作分配下的并行处理 Job 样例
带 Pod 间通信的 Job 样例
基于一个公共的模板运行多个 Jobs 样例
模板
创建清单
基于清单创建 Job
  • kubectl create -f ./jobs
上一篇
k8s 集群故障排查和备份恢复
下一篇
Zsh 与 zinit 终端包管理

Comments
Loading...