跳到主要内容

运行一次性与定时任务

长期服务使用 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)独立子任务可调大加速
activeDeadlineSecondsJob 的总超时,超时后强制终止防止失控任务一直跑
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

  1. 创建一个 Job,运行 busybox 执行 echo "done" && exit 0,观察状态变为 Completed
  2. 再创建一个 Job,运行 exit 1,观察 backoffLimit 达到上限后状态变为 Failed
  3. 在 YAML 中添加 ttlSecondsAfterFinished: 60,等待 1 分钟后观察 Job 是否被自动清理

练习 B

  1. 创建一个 CronJob(每分钟一次),用 busybox 打印当前时间
  2. 运行 3 分钟后暂停该 CronJob(suspend: true),确认不再产生新的 Job
  3. 用 kubectl create job --from=cronjob/... 手动触发一次,验证任务逻辑

验收清单

  • 能区分长期服务、一次性 Job 与 CronJob
  • 会配置 backoffLimit、completions、parallelism 和 activeDeadlineSeconds
  • 知道 ttlSecondsAfterFinished 用于自动清理历史 Job
  • 会根据任务语义选择 CronJob 并发策略(Forbid / Replace / Allow)
  • 知道 CronJob 的 timeZone 和 suspend 用法
  • 知道迁移、备份任务需要幂等和可恢复设计

下一篇:自动扩缩容与可用性。