前言
在 Kubernetes 中,容器应用大体可以分为两类:服务类容器和工作类容器。服务类容器需要长时间持续运行,对外提供服务(如 Nginx、MySQL);而工作类容器通常执行一次性任务,任务完成后容器便退出(如批处理程序、数据计算、测试脚本等)。
对于服务类容器,Kubernetes 提供了 Deployment、ReplicaSet、DaemonSet 等控制器来管理;对于工作类容器,则需要使用Job这种原生控制器。Job 能够确保指定数量的 Pod 成功完成任务并退出,非常适合运行一次性作业。
本文将从 Job 的使用场景入手,通过实际 YAML 配置、失败重试策略分析以及 CronJob 定时任务等方面,系统讲解 Kubernetes Job 的用法与原理,帮助读者在生产环境中正确使用 Job 来完成批处理任务。
一、Job使用场景
容器按照持续运行的时间可分为两类:
| 类型 | 描述 | 示例 | 对应K8s控制器 |
|---|---|---|---|
| 服务类容器 | 持续提供服务,需要一直运行 | http server, mysql db | Deployment, ReplicaSet, DaemonSet |
| 工作类容器 | 一次性任务,完成后容器就退出 | 批处理程序、数据导入、计算任务 | Job |
Kubernetes 中的 Deployment、ReplicaSet 和 DaemonSet 都用于管理服务类容器;而对于工作类容器,Job是最佳选择。
二、Job应用介绍
1. 一个简单的 Job 配置文件
下面是一个基于busybox执行简单 echo 任务的 Job YAML 示例:
apiVersion: batch/v1 kind: Job metadata: name: myjob spec: template: spec: containers: - name: job image: busybox command: ["echo", "hello k8s"] restartPolicy: Never2. 关键字段解释
| 字段 | 说明 |
|---|---|
apiVersion | Job 的 API 版本,当前稳定版为batch/v1 |
kind | 资源类型,这里为Job |
metadata.name | Job 的名称 |
spec.template | Pod 模板,定义要运行的 Pod |
spec.template.spec.containers | 容器定义,image和command指定要执行的命令 |
restartPolicy | 重要:Pod 内容器的重启策略。对于 Job,只能设置为Never或OnFailure,不能设为Always |
restartPolicy 的含义:
Never:无论容器退出状态如何,kubelet 都不重启该容器。OnFailure:当容器终止运行且退出码不为 0 时,重启容器。Always:容器失效时自动重启(仅用于服务类控制器)。
3. 创建并查看 Job
[root@master k8s]# kubectl apply -f myjob.yml job.batch/myjob created [root@master k8s]# kubectl get job NAME COMPLETIONS DURATION AGE myjob 1/1 2s 10s [root@master k8s]# kubectl get pod NAME READY STATUS RESTARTS AGE myjob-xxxxx 0/1 Completed 0 15s [root@master k8s]# kubectl logs myjob-xxxxx hello k8s成功执行后,Pod 的状态变为Completed,Job 的COMPLETIONS显示为1/1,表示成功完成 1 个 Pod。
三、Job失败策略分析
上面介绍的是 Job 成功执行的情况。如果任务失败会怎样?下面通过一个故意出错的示例来观察 Job 的失败处理行为。
1. 制造失败场景
修改myjob.yml,将 command 改为一个不存在的命令:
command: ["easasacho", "hello k8s"] # 故意写错命令然后重新创建 Job:
[root@master k8s]# kubectl delete -f myjob.yml [root@master k8s]# kubectl apply -f myjob.yml2. 观察 Pod 状态
[root@master k8s]# kubectl get pod NAME READY STATUS RESTARTS AGE myjob-mq7sd 0/1 ContainerCannotRun 0 88s myjob-ngpxc 0/1 ContainerCannotRun 0 2m48s myjob-qs2sb 0/1 ContainerCannotRun 0 3m36s myjob-w7gmgf 0/1 ContainerCannotRun 0 3m53s myjob-x2jp9 0/1 ContainerCannotRun 0 3m8s会看到大量失败的 Pod 被不断创建!为什么会出现这种情况?
3. 原因分析
当restartPolicy: Never时:
第一个 Pod 启动,容器因“命令不存在”错误退出。
根据策略,
Never表示不重启该容器,Pod 保持在失败状态(如ContainerCannotRun)。Job 控制器检查当前状态:期望成功数为 1,实际成功数为 0。
不满足期望,于是 Job controller 不断创建新的 Pod 来尝试达到成功目标。
由于命令始终错误,永远不会成功,因此 Job controller 会无限循环创建 Pod,直到用户手动删除该 Job。
当restartPolicy: OnFailure时:
第一个 Pod 启动失败,容器退出。
根据策略,
OnFailure会重启容器(而不是重建 Pod)。因此只会看到一个 Pod,但
RESTARTS次数会不断增加。
4. 查看失败原因
使用kubectl describe pod可以查看具体错误:
[root@master k8s]# kubectl describe pod myjob-w7gmf ... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled <unknown> default-scheduler Successfully assigned default/myjob-w7gmf to node1 Normal Pulling 26s kubelet, node1 Pulling image "busybox" Normal Pulled 10s kubelet, node1 Successfully pulled image "busybox" Normal Created 10s kubelet, node1 Created container job Warning Failed 10s kubelet, node1 Error: failed to start container "job": ... executable file not found in $PATH错误信息executable file not found in $PATH明确指出了问题所在。
5. 如何终止失败的 Job
对于restartPolicy: Never且一直失败的 Job,必须手动删除它:
[root@master k8s]# kubectl delete job myjob删除 Job 时,由其创建的所有 Pod 也会被一并删除。
四、定时执行Job:CronJob
Linux 系统中有crontab可以定时执行任务,Kubernetes 也提供了CronJob来实现定时触发 Job 的功能。
1. CronJob 配置文件示例
apiVersion: batch/v1beta1 kind: CronJob metadata: name: hellojob spec: schedule: "*/2 * * * *" # 每2分钟执行一次 jobTemplate: spec: template: spec: containers: - name: hello image: busybox command: ["echo", "hello k8s cron_job!"] restartPolicy: OnFailure2. 关键字段说明
| 字段 | 说明 |
|---|---|
apiVersion | CronJob 的 API 版本,较新集群推荐batch/v1(旧版为batch/v1beta1) |
kind | CronJob |
schedule | 与 Linux crontab 格式一致:分 时 日 月 周。*/2 * * * *表示每 2 分钟执行一次 |
jobTemplate | Job 模板,内部结构与普通的 Job 完全相同 |
restartPolicy | 对于 CronJob 产生的 Job,通常设置为OnFailure或Never |
3. 操作示例
# 创建 CronJob [root@master k8s]# kubectl apply -f cronjob.yml cronjob.batch/hellojob created # 查看 CronJob 状态 [root@master k8s]# kubectl get cronjob NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE hellojob */2 * * * * False 0 <none> 5s # 等待几分钟后,查看由此创建的 Job [root@master k8s]# kubectl get job NAME COMPLETIONS DURATION AGE hellojob-1596513900 1/1 2s 2m # 查看产生的 Pod [root@master k8s]# kubectl get pod NAME READY STATUS RESTARTS AGE hellojob-1596513900-hl7nv 0/1 Completed 0 2m # 查看 Pod 日志 [root@master k8s]# kubectl logs hellojob-1596513900-hl7nv hello k8s cron_job! # 删除 CronJob(会自动删除关联的 Job 和 Pod) [root@master k8s]# kubectl delete -f cronjob.yml4. CronJob 常用调度格式
| 表达式 | 含义 |
|---|---|
*/1 * * * * | 每分钟执行一次 |
0 */2 * * * | 每2小时整点执行 |
0 8 * * * | 每天早上8点执行 |
0 0 * * 0 | 每周日午夜执行 |
0 0 1 * * | 每月1号午夜执行 |
注意:CronJob 的时区默认使用 kube-controller-manager 的时区,通常是 UTC。如需指定时区,可参考官方文档设置
timezone字段(v1.25+ 支持)。
结语
Kubernetes Job 为运行一次性批处理任务提供了完整的生命周期管理能力。通过本文的学习,我们掌握了:
使用场景:区分服务类容器与工作类容器,明确 Job 的定位。
基本配置:YAML 文件的各个字段含义,特别是
restartPolicy在 Job 中的限制。失败处理策略:
Never会导致无限创建新 Pod,OnFailure会在同一 Pod 内重启容器。生产环境中应根据任务性质选择合适的策略,避免资源浪费。定时任务:利用 CronJob 可以轻松实现周期性任务调度,其语法与 Linux crontab 完全一致。
在实际使用中,建议为 Job 设置backoffLimit(默认为6)来限制重试次数,避免错误任务无限循环;对于运行时间较长的批处理任务,还可以结合activeDeadlineSeconds设置任务超时时间。
Job 与 CronJob 是 Kubernetes 中处理任务型负载的利器,掌握它们之后,你可以将更多的运维和数据处理任务无缝接入到容器化平台中,实现统一调度与管理。