运行一次性与定时任务
长期服务使用 Deployment,完成后退出的工作使用 Job,按计划反复执行的工作使用 CronJob。选错对象会造成任务重复执行、永不重试或不必要的常驻资源。
本篇目标:能写出幂等的 Job、配置合理的重试与清理策略,并正确使用 CronJob 的并发控制和时区。
1. Job:直到成功为止
Job 创建 Pod 执行任务,直到达到成功次数或超过失败重试上限:
apiVersion: batch/v1
kind: Job
metadata:
name: schema-migrate
namespace: learning
spec:
backoffLimit: 3
ttlSecondsAfterFinished: 86400
template:
spec:
restartPolicy: OnFailure
containers:
- name: migrate
image: registry.example.com/app:1.4.2
command: ["./bin/migrate"]
1.1 Job 的关键参数
| 参数 | 作用 | 建议 |
|---|---|---|
backoffLimit | 失败重试次数上限(默认 6) | 迁移类设 3,幂等重试设更高 |
completions | 需要成功完成的 Pod 次数(默认 1) | 批量任务设 >1 |
parallelism | 同时运行的最大 Pod 数(默认 1) | 独立子任务可调大加速 |
activeDeadlineSeconds | Job 的总超时,超时后强制终止 | 防止失控任务一直跑 |
ttlSecondsAfterFinished | 完成后多少秒自动清理 Job 和 Pod | 生产必须设,否则历史 Job 堆积 |
1.2 并行 Job
当一批子任务相互独立时,用 completions + parallelism 加速:
spec:
completions: 10 # 总共需要 10 次成功
parallelism: 3 # 同时跑 3 个 Pod
backoffLimit: 2
template:
spec:
restartPolicy: OnFailure
containers:
- name: worker
image: registry.example.com/worker:2.1.0
# 观察并行执行进度
kubectl get job -n learning -w
1.3 幂等性:任务可能被执行多次
数据库迁移、数据导入这类任务必须具备幂等性:
- 迁移脚本用
IF NOT EXISTS/CREATE TABLE IF NOT EXISTS; - 备份任务按时间戳写入,避免覆盖已有备份;
- 不假设"上次成功、这次不需要跑"——Job 重试或人工重新创建时,任务逻辑可能再次执行。
2. CronJob:按时间触发 Job
apiVersion: batch/v1
kind: CronJob
metadata:
name: daily-backup
namespace: learning
spec:
schedule: "0 2 * * *"
timeZone: "Asia/Shanghai" # 1.24 GA,指定时区
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 3
startingDeadlineSeconds: 300 # 若调度错过 5 分钟以上则跳过
suspend: false # 设为 true 可临时暂停
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: backup
image: registry.example.com/backup:2.1.0
2.1 并发策略
concurrencyPolicy | 行为 |
|---|---|
Forbid | 上一次没跑完就跳过本次(适合备份、报表,不能并发) |
Replace | 终止旧任务再启动新任务(适合"只要最新一次结果"的场景) |
Allow | 允许重叠执行(适合完全独立的短任务) |
2.2 常见陷阱
- CronJob 调度存在控制器延迟,不能用于毫秒级精确调度。
startingDeadlineSeconds尽量设大一些(如 300),避免控制面短暂不可用导致任务丢失; - 历史 Job 会堆积,必须设
successfulJobsHistoryLimit和failedJobsHistoryLimit(Kubernetes 1.25 起默认分别为 3 和 1,之前默认不清理); - 夏令时/闰秒:如果
schedule的触发时间在夏令时切换中不存在或出现两次,CronJob 行为取决于实现版本。用timeZone明确指定时区; - 分布式 Cron 替代方案:需要"集群中只有一个实例执行"的定时任务,考察 Leader Election 或外部调度(Airflow、Argo Workflows)。
2.3 CronJob 暂停
# 临时停掉 CronJob(如数据库维护窗口)
kubectl patch cronjob daily-backup -n learning -p '{"spec":{"suspend":true}}'
# 恢复
kubectl patch cronjob daily-backup -n learning -p '{"spec":{"suspend":false}}'
3. 观察与人工触发
kubectl get jobs,cronjobs -n learning
kubectl describe job schema-migrate -n learning
kubectl logs job/schema-migrate -n learning
# 从现有 CronJob 创建一次临时 Job(用于补跑或测试)
kubectl create job --from=cronjob/daily-backup daily-backup-manual -n learning
失败时保留 Job 和 Pod,先导出日志、事件和退出码,再决定重试或删除:
# 看退出码
kubectl get pod -n learning -l job-name=schema-migrate \
-o jsonpath='{.items[*].status.containerStatuses[*].state.terminated.exitCode}'
# 导出日志备查
kubectl logs job/schema-migrate -n learning > /tmp/migrate-failure.log
4. 练习
练习 A
- 创建一个 Job,运行
busybox执行echo "done" && exit 0,观察状态变为Completed - 再创建一个 Job,运行
exit 1,观察backoffLimit达到上限后状态变为Failed - 在 YAML 中添加
ttlSecondsAfterFinished: 60,等待 1 分钟后观察 Job 是否被自动清理
练习 B
- 创建一个 CronJob(每分钟一次),用
busybox打印当前时间 - 运行 3 分钟后暂停该 CronJob(
suspend: true),确认不再产生新的 Job - 用
kubectl create job --from=cronjob/...手动触发一次,验证任务逻辑
验收清单
- 能区分长期服务、一次性 Job 与 CronJob
- 会配置
backoffLimit、completions、parallelism和activeDeadlineSeconds - 知道
ttlSecondsAfterFinished用于自动清理历史 Job - 会根据任务语义选择 CronJob 并发策略(Forbid / Replace / Allow)
- 知道 CronJob 的
timeZone和suspend用法 - 知道迁移、备份任务需要幂等和可恢复设计
下一篇:自动扩缩容与可用性。