深色模式
Job 与 CronJob 批处理任务
摘要:本文面向需要在 K8s 中运行一次性或周期性批处理任务的 SRE,讲解 Job 的完成/并行模型、重试与清理,以及 CronJob 的调度与并发控制。覆盖 Kubernetes v1.28+。
适用版本与前提
- Kubernetes:v1.28+(
ttlSecondsAfterFinished仍受特性门控、suspend已稳定;Pod Failure Policy 自 v1.26 稳定) - 工具:
kubectl - 前提:理解 Pod 与
restartPolicy
背景与问题
长跑服务用 Deployment,但“算完就走”的任务——数据库备份、报表生成、批量迁移——需要不同的原语:能追踪成功完成、能在失败时重试、能在超时后放弃、能在历史堆积时清理。Job 与 CronJob 正是为这类“运行到完成(run-to-completion)”语义设计。
Job:运行到完成
Job 创建一个或多个 Pod,持续重试直到指定数量成功终止。Pod 模板中 restartPolicy 只允许 Never 或 OnFailure(不能 Always)。
yaml
apiVersion: batch/v1
kind: Job
metadata:
name: pi
spec:
backoffLimit: 4 # 最大重试次数
activeDeadlineSeconds: 300 # 整个 Job 的最长存活时间,超时即失败
ttlSecondsAfterFinished: 300 # 完成后 300s 自动清理(需特性门控,[版本相关])
template:
spec:
restartPolicy: Never
containers:
- name: pi
image: perl:5.34.0
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
三种并行模型
| 类型 | 配置 | 适用 |
|---|---|---|
| 非并行 | completions/parallelism 均不设置(默认 1) | 单任务,失败重试 |
| 固定完成数 | completions=N,可选 parallelism | 批量作业,需 N 次成功 |
| 工作队列 | 不设 completions,设 parallelism>1 | 多 Pod 自行协调队列消费 |
parallelism:同时运行的 Pod 上限;设为 0 等效暂停。completions:需要成功完成的 Pod 数(Indexed 模式下每个 Pod 拿到 0~N-1 索引)。
版本相关
ttlSecondsAfterFinished 用于自动清理已完成 Job,但长期以特性门控 TTLAfterFinished 提供,部分发行版默认未开启。若不可用,需用 kubectl delete job 或 CronJob 的 successfulJobsHistoryLimit 间接管理。Pod Failure Policy(v1.26 稳定)可按失败原因决定是否计入 backoffLimit。
CronJob:定时触发 Job
CronJob 按 schedule(标准 cron 表达式)周期性创建 Job。
yaml
apiVersion: batch/v1
kind: CronJob
metadata:
name: nightly-backup
spec:
schedule: "0 2 * * *" # 每天 02:00
startingDeadlineSeconds: 300 # 错过开始时间 300s 内仍可补跑
concurrencyPolicy: Forbid # Allow / Forbid / Replace
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 1
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: backup
image: busybox:1.28
command: ["sh", "-c", "echo backup at $(date)"]1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
关键字段
concurrencyPolicy:Allow(允许并发)、Forbid(本次跳过)、Replace(替换上一次未完成的)。startingDeadlineSeconds:控制器错过调度点的容忍窗口,超时不补。successfulJobsHistoryLimit/failedJobsHistoryLimit:保留的历史 Job 数量,防止 etcd 膨胀。suspend: true:暂停所有后续执行(已稳定)。
注意
CronJob 的 schedule 使用集群时区(默认 UTC,部分发行版可用 CRON_TZ 或 .spec.timeZone)。生产定时任务务必确认时区,避免“半夜跑成白天跑”。.spec.timeZone 自 v1.27 起支持。
生产实践
- 备份/迁移类任务设
activeDeadlineSeconds:防止任务卡死占用资源无限期。 - 批量作业优先 Idx'd 模式:
completionMode: Indexed让每个 Pod 知道自己的序号,便于分片。 - CronJob 务必设历史限制:否则每次执行都留一个 Job+Pod,长期拖垮 etcd。
concurrencyPolicy: Forbid适合“不能重叠”的报表/备份;可重叠的用Allow。- 敏感任务加
backoffLimit与告警:避免无限重试刷日志。
生产危险
CronJob 失败的 Job/Pod 若未被 failedJobsHistoryLimit 或 ttlSecondsAfterFinished 清理,且任务反复失败,会在集群中堆积大量失败 Pod,挤占资源并污染 etcd。上线前确认清理策略生效。
故障排查
| 现象 | 原因 | 处理 |
|---|---|---|
Job 一直 Running | 任务未退出 / 死循环 | 查 kubectl logs;设 activeDeadlineSeconds |
反复 BackoffLimitExceeded | 应用持续失败 | 查日志;修正命令/依赖 |
| CronJob 没触发 | 时区/调度表达式错误、suspend | kubectl describe cronjob 看 Last Schedule |
| 历史堆积 | 未设 history limit | 清理并设置限制 |
常见坑
- Job 的 Pod 模板
restartPolicy用Always会被 API 拒绝(校验失败)。 - 依赖“恰好一次”语义的任务,CronJob 不保证(可能重叠或重复执行)——需业务幂等。
ttlSecondsAfterFinished未开启时,手动清理是必须的运维动作。
替代方案与权衡
- 更高可靠/可观测的定时任务可用 Argo Workflows、Tekton,适合复杂 DAG。
- 极简一次性任务也可用 bare Pod +
restartPolicy: OnFailure,但缺少重试计数与完成追踪。
FAQ
Q:Job 失败会一直重试吗? A:最多重试 backoffLimit 次(退避递增),超过后 Job 标记失败。但退避上限时间由控制器决定,非立即。
Q:CronJob 能“恰好一次”执行吗? A:不能严格保证。用 concurrencyPolicy: Forbid 减少重叠,但任务本身需幂等以应对偶尔的重复/补跑。
参考资料
- Jobs - Kubernetes 官方文档,访问日期:2026-10-08。
- CronJob - Kubernetes 官方文档,访问日期:2026-10-08。
- Fine Parallel Processing using a Work Queue - Kubernetes 官方文档,访问日期:2026-10-08。