本节摘要:Job 负责跑完即走的一次性任务,控制完成数、并行度与失败重试;CronJob 在 Job 之上加了一本历法,按周期表自动派活。两者让"批处理"成为集群的一等公民。本节为书屋安排夜间备份与逾期提醒两件农活,讲清 completions、parallelism、backoffLimit 与并发策略的用法。
书屋有两件活很特别:每天凌晨把数据库备份到对象存储;每小时扫一遍借阅记录给逾期读者发提醒。它们不是服务,没有"活着"这个状态,只有"干完了"或"没干完"。用 Deployment 常驻苗伺候这种活是灾难:程序大部分时间在空转,还得自己写"到点了没"的判断逻辑。
Job 为"干完就走"而生:种下一个 Job,园丁看着它跑到成功为止;失败自动重试,重试到上限标记失败。CronJob 再加一本历法:到点自动创建 Job,错过或重叠都有章法。手册里 Job 是农忙活,CronJob 是节气活。
# 农忙活:备份数据库到对象存储 apiVersion: batch/v1 kind: Job metadata: name: db-backup-manual namespace: greenlib-prod spec: backoffLimit: 3 # 失败最多重试三次 三次都败就认栽 activeDeadlineSeconds: 1800 # 整活最多半小时 超时判死(防呆) template: metadata: labels: app: db-backup spec: restartPolicy: Never # Job 的苗不许常驻 重启交给 Job 层管 containers: - name: backup image: greenlib/db-tools:1.2 command: ["sh", "-c", "pg_dump $(DB_HOST) | gzip | upload-to-store backup-$(date +%F).sql.gz"] envFrom: - secretRef: name: api-db-cred # 口令照旧来自农药柜
kubectl apply -f backup-job.yaml -n greenlib-prod # job.batch/db-backup-manual created kubectl get jobs -n greenlib-prod # NAME COMPLETIONS DURATION AGE # db-backup-manual 1/1 42s 1m # 完成度一一:一个任务 成功跑完 kubectl logs -n greenlib-prod job/db-backup-manual | tail -n 3 # dump 完成 812MB 上传 backup-2026-09-01.sql.gz 成功 # Job 的日志照常可查 苗退役了 档案还在
注意 restartPolicy: Never——Job 模板里这是必写项,且只允许 Never 或 OnFailure。原因想一下就通:常驻苗的重启归 kubelet 管,Job 苗的重启归 Job 园丁管(它要数着重试次数),两权不能旁落。
手工派备份当然不行,套上历法:
# 节气活:每天凌晨两点半备份(服务器时区) apiVersion: batch/v1 kind: CronJob metadata: name: db-backup-nightly namespace: greenlib-prod spec: schedule: "30 2 * * *" # 分 时 日 月 周:每天的两点三十分 concurrencyPolicy: Forbid # 上一场没干完 不许开下一场 successfulJobsHistoryLimit: 3 # 成功档案留三份够查了 failedJobsHistoryLimit: 1 # 失败档案留一份 便于排查 jobTemplate: spec: backoffLimit: 2 template: spec: restartPolicy: Never containers: - name: backup image: greenlib/db-tools:1.2 command: ["sh", "-c", "pg_dump $(DB_HOST) | gzip | upload-to-store backup-nightly.sql.gz"] envFrom: - secretRef: name: api-db-cred
kubectl apply -f backup-cronjob.yaml -n greenlib-prod # cronjob.batch/db-backup-nightly created kubectl get cronjobs -n greenlib-prod # NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE # db-backup-nightly 30 2 * * * False 0 9h # 挂历在墙 到点派工 kubectl get jobs -n greenlib-prod # NAME COMPLETIONS AGE # db-backup-nightly-28701450 1/1 9h # 每场的 Job 名自动带时间编号 便于对账
schedule 那串就是经典的五段表达式(分、时、日、月、周),与 Linux 的 crontab 同文。concurrencyPolicy 管重叠:Forbid 禁止并发(上次的没跑完就跳过这次,备份类默认选它)、Allow 放任并发、Replace 取消旧的换新的。历史条数限制则是防台账膨胀:每场 Job 留下的档案默认会一直堆着,设个上限让园丁自动清旧档。
备份是"一株苗干一件活",还有些活要"一群苗分头干"——比如把三年积压的封面图批量转格式。Job 的两个参数这时上场:
# 分头干活:三十份任务 五路并行 spec: completions: 30 # 总共要完成三十份 parallelism: 5 # 同时最多五株苗在干
kubectl get jobs -n greenlib-dev # NAME COMPLETIONS DURATION # cover-convert 30/30 6m # 三十份全部完成 并行五路用时六分钟 kubectl get pods -n greenlib-dev -l job-name=cover-convert | wc -l # 数一下在册的苗(含已完成的)会发现远少于三十: # Job 用"苗干完活再领下一份"的方式复用苗 而不是一份活配一株苗
原理:Job 园丁按 parallelism 维持在岗苗数,每株苗完成后由工作队列领下一项,直到凑满 completions。想要的是总完成量,付的是并行峰值,这两个旋钮把批处理的经济学调得明明白白。
⚠️ 常见坑:CronJob 的时区。schedule 默认按 kube-controller-manager 的时区解释(常见为协调世界时),写"凌晨两点半"前先确认集群时区,否则备份会在你最忙的白天准点开跑。另一个坑是任务脚本必须可重入:Forbid 只防同时跑,不防上一场的收尾没做完,脚本里要自己处理"文件传了一半"的续传。
restartPolicy: Never 或 OnFailure,重启权归 Job 园丁