讲解

到目前为止的 workload 都是「长期在线」型(Deployment 要保证副本一直活着)。另一类需求是「跑一次就结束」:数据迁移、批量处理、报表生成、定时备份。Job 就是为这种「跑到完成」的任务设计的控制器:它启动 Pod,等到容器以退出码 0 结束就算成功;容器失败了按 backoffLimit 重试;完成后的 Pod 和日志保留下来供查看(restartPolicy 必须是 Never 或 OnFailure,不能是 Always——「永远重启」和「跑完即止」是矛盾的)。

Job 有几个控制并行与可靠性的字段:completions(要成功跑完几次,默认 1)、parallelism(同时跑几个 Pod,做大批量并行任务时用)、backoffLimit(失败重试上限,默认 6,超过则 Job 标记失败)、activeDeadlineSeconds(总时长硬限制,超时强杀)、ttlSecondsAfterFinished(完成后自动清理,不让完成的 Pod 越积越多)。手动触发「立刻跑一次」也有标准手法:kubectl create job --from=cronjob/名字 新名,从 CronJob 的模板直接克隆一个 Job。

CronJob 是 Job 的定时器:spec.schedule 填标准 cron 表达式(分 时 日 月 周,注意时区——老版本恒为控制面时区,新版本支持 timeZone 字段),到点就按 jobTemplate 克隆一个 Job 出来跑。concurrencyPolicy 控制上次没跑完这次又到点怎么办:Allow(默认,并行跑)、Forbid(跳过这次)、Replace(杀掉旧的换新的)——定时任务设计时要想清楚重入问题,幂等性(同一任务跑两遍结果正确)是定时任务的基本修养。

示例

一个简单 Job:处理三批数据然后功成身退(backoffLimit 允许失败重试 2 次):

# wait: job/ohmydocs-verify-batch
apiVersion: batch/v1
kind: Job
metadata:
  name: ohmydocs-verify-batch
spec:
  backoffLimit: 2
  template:
    spec:
      restartPolicy: Never
      containers:
        - name: worker
          image: busybox:1.36
          command:
            - sh
            - -c
            - |
              for i in 1 2 3; do echo "处理第 $i 批数据"; sleep 1; done
              echo "批处理完成"

Job 已完成(COMPLETIONS 1/1),日志里能看到完整处理过程:

kubectl get job ohmydocs-verify-batch
kubectl logs job/ohmydocs-verify-batch

每分钟跑一次的 CronJob(报表任务模板;jobTemplate 上打标签,方便之后按标签清理它产生的 Job):

apiVersion: batch/v1
kind: CronJob
metadata:
  name: ohmydocs-verify-report
spec:
  schedule: "* * * * *"
  concurrencyPolicy: Forbid
  jobTemplate:
    metadata:
      labels:
        app: ohmydocs-verify-report
    spec:
      backoffLimit: 1
      template:
        metadata:
          labels:
            app: ohmydocs-verify-report
        spec:
          restartPolicy: Never
          containers:
            - name: report
              image: busybox:1.36
              command:
                - sh
                - -c
                - echo "生成报表 $(date)"

不等整点,直接从 CronJob 手动触发一次验证(create job --from=cronjob 克隆模板),跑完看日志;随后清理 CronJob 和它产生的所有 Job:

kubectl get cronjob ohmydocs-verify-report
kubectl create job --from=cronjob/ohmydocs-verify-report ohmydocs-verify-report-manual
kubectl wait --for=condition=complete job/ohmydocs-verify-report-manual --timeout=120s
kubectl logs job/ohmydocs-verify-report-manual
kubectl delete cronjob ohmydocs-verify-report --wait=false
kubectl delete job -l app=ohmydocs-verify-report --wait=false

常见坑

  • restartPolicy 写了 Always:Job 的 Pod 模板不允许 Always(永远重启 = 永远完不成),apply 直接报错;用 Never 或 OnFailure。
  • 任务不幂等:CronJob 重试、并发策略 Allow、手动补跑都会让任务执行多次——写文件、发通知、扣款类任务必须自己保证幂等。
  • 完成的 Job 无限堆积:每次执行都留下 Pod 和 Job 对象,久了拖垮 etcd;配 ttlSecondsAfterFinished 或 successfulJobsHistoryLimit 自动清理。
  • cron 时区踩坑:控制面在 UTC 而业务按北京时间,定时任务漂移 8 小时;新版本用 spec.timeZone 显式指定。

小结

Job 跑一次性任务(backoffLimit 重试、完成后留痕),CronJob 按 cron 表达式定时克隆 Job;concurrencyPolicy 控制重入,幂等性是定时任务的底线;create job --from=cronjob 是手动验证的标准手法。下一章回到长期负载的特殊形态:StatefulSet。