当前位置: 首页 > news >正文

kubernetes中离线业务编排详解JobCronJob之Job 应用

在 Kubernetes 中编排离线业务(如批处理任务、定时任务或计算密集型作业)通常需要结合 JobCronJob 等资源对象,同时合理管理资源分配、任务调度和依赖关系。

Job用来管理一次性任务,确保任务成功完成;CronJob则类似于Linux的Cron,定时执行任务

1.在线业务和离线业务

在线业务

Deployment、StatefulSet以及 DaemonSet 这三个编排概念的共同之处是:它们主要编排的对象,都是"在线业务",即:Long Running Task(长作业)。比如常用的 Nginx、Tomcat,以及 MySQL 等等。这些应用一旦运行起来,除非出错或者停止,它的容器进程会一直保持在 Running 状态。

离线业务

指的是批处理任务、定时任务或者计算密集型但不需要实时响应的作业,比如数据分析、机器学习训练、视频渲染等。这类任务的特点是运行时间较长,不需要一直运行,一旦完成就会终止。

1.1. Job 的核心概念

  • 一次性执行:确保任务运行到完成(完成后 Pod 不会重启)。
  • 失败自动重试:通过 backoffLimit 控制重试次数。
  • 并行控制:支持指定并行运行的 Pod 数量(parallelism)和总完成数(completions)。
  • 适用场景:数据处理、定时任务(结合 CronJob)、测试任务等。

2.Job 的核心定义

2.1.YAML 结构示例

apiVersion: batch/v1
kind: Job
metadata:name: example-job
spec:completions: 3       # 需要成功完成的任务总次数(默认 1)parallelism: 2       # 允许同时运行的 Pod 数量(默认 1)backoffLimit: 4      # 失败后重试的最大次数(默认 6)template:spec:containers:- name: taskimage: busyboxcommand: ["sh", "-c", "echo Processing item $ITEM && exit 0"]env:- name: ITEMvalue: "123"restartPolicy: OnFailure  # 必须为 OnFailure 或 Never
关键字段说明
  • completions:任务需要成功完成的总次数(适用于需要多次执行的任务)。
  • parallelism:允许同时运行的 Pod 数量(控制并发)。
  • backoffLimit:任务失败后的最大重试次数。
  • restartPolicy:仅支持 OnFailureNever(确保任务完成后不再重启)。

2.2. 实战场景与操作

场景 1:单次任务

运行一个简单的 Job,打印消息后退出。

[root@master ~]# mkdir job
[root@master ~]# cd job/
[root@master job]# vim test_jobs.yml
apiVersion: batch/v1
kind: Job
metadata:name: test-task
spec:template:spec:containers:- name: helloimage: busyboxcommand: ["sh", "-c", "echo 'Hello Kubernetes Job!' && exit 0"]restartPolicy: OnFailure[root@master job]# kubectl apply -f test_jobs.yml 
job.batch/test-task created[root@master job]# kubectl describe jobs test-task #查看job的详细信息
Name:             test-task
Namespace:        default
Selector:         batch.kubernetes.io/controller-uid=8ac0999b-59ea-4f64-b8c3-8a19803985a3
Labels:           batch.kubernetes.io/controller-uid=8ac0999b-59ea-4f64-b8c3-8a19803985a3batch.kubernetes.io/job-name=test-taskcontroller-uid=8ac0999b-59ea-4f64-b8c3-8a19803985a3job-name=test-task
Annotations:      <none>
Parallelism:      1
Completions:      1
Completion Mode:  NonIndexed
Suspend:          false
Backoff Limit:    6
Start Time:       Fri, 02 May 2025 16:28:03 +0800
Completed At:     Fri, 02 May 2025 16:28:29 +0800
Duration:         26s
Pods Statuses:    0 Active (0 Ready) / 1 Succeeded / 0 Failed
Pod Template:Labels:  batch.kubernetes.io/controller-uid=8ac0999b-59ea-4f64-b8c3-8a19803985a3batch.kubernetes.io/job-name=test-taskcontroller-uid=8ac0999b-59ea-4f64-b8c3-8a19803985a3job-name=test-taskContainers:hello:Image:      busyboxPort:       <none>Host Port:  <none>Command:sh-cecho 'Hello Kubernetes Job!' && exit 0Environment:   <none>Mounts:        <none>Volumes:         <none>Node-Selectors:  <none>Tolerations:     <none>
Events:Type    Reason            Age    From            Message----    ------            ----   ----            -------Normal  SuccessfulCreate  4m36s  job-controller  Created pod: test-task-9mmsnNormal  Completed         4m10s  job-controller  Job completed

为了避免不同 Job 对象所管理的 Pod 发生重合,Job 对象在创建后,它的 Pod 模板,被自动加上了一个 controller-uid=< 一个随机字符串 > 这样的 Label。而这个 Job 对象本身,则被自动加上了这个 Label 对应的 Selector,保证了 Job 与它所管理的 Pod 之间的匹配关系。

[root@master job]# kubectl get jobs # 查看 Job 状态(COMPLETIONS 应为 1/1)
NAME        STATUS     COMPLETIONS   DURATION   AGE
test-task   Complete   1/1           26s        28s[root@master job]# kubectl get pods --selector=job-name=test-task # 查看关联的 Pod
NAME              READY   STATUS      RESTARTS   AGE
test-task-9mmsn   0/1     Completed   0          66s

Pod 进入了 Running 状态说明它正在打印消息,打印完了之后这个 Pod 就会进入 Completed 状态。

[root@master job]# kubectl logs test-task-9mmsn  # 查看输出日志(应显示 "Hello Kubernetes Job!")
Hello Kubernetes Job!

离线任务的 Pod 永远都不应该被重启

实现方式是在 Pod 模板中定义 restartPolicy=Never

事实上restartPolicy 在 Job 对象里只允许被设置为 Never 和 OnFailure;而在 Deployment 对象里,restartPolicy 则只允许被设置为 Always。

场景2:并行任务

运行一个并行处理任务的 Job,模拟批量处理数据

离线业务之所以被称为 Batch Job,是因为它们可以以"Batch",也就是并行的方式去运行。

负责并行控制的参数有两个:

spec.parallelism:

​ 定义一个 Job 在任意时间最多可以启动多少个 Pod 同时运行;

spec.completions:

​ 定义 Job 至少要完成的 Pod 数目,即 Job 的最小完成数。

[root@master job]# cat test_jobs2.yml 
apiVersion: batch/v1
kind: Job
metadata:name: task-job2
spec:completions: 6     # 总共需要完成 6 个任务parallelism: 2     # 同时运行 2 个 Podtemplate:spec:containers:- name: workerimage: busyboxcommand: ["sh", "-c", "echo Processing item $ITEM && sleep 5 && exit 0"]env:- name: ITEMvalueFrom:fieldRef:fieldPath: metadata.name  # 使用 Pod 名称作为参数restartPolicy: OnFailure[root@master job]# kubectl apply -f test_jobs2.yml 
job.batch/task-job2 created

这个 Job 首先创建了两个并行运行的 Pod 来执行任务:

[root@master job]# kubectl get pod 
NAME              READY   STATUS              RESTARTS   AGE
task-job2-8n4xk   0/1     ContainerCreating   0          4s
task-job2-w4kkh   0/1     ContainerCreating   0          4s

这时可以看到,每当有一个 Pod 完成计算进入 Completed 状态时,就会有一个新的 Pod 被自动创建出来,并且快速地从 Pending 状态进入到 ContainerCreating 状态:

[root@master job]# kubectl get pod 
NAME              READY   STATUS              RESTARTS   AGE
task-job2-8n4xk   1/1     Running             0          47s
task-job2-jwjkd   0/1     ContainerCreating   0          17s
task-job2-w4kkh   0/1     Completed           0          47s[root@master job]# kubectl get pod 
NAME              READY   STATUS              RESTARTS   AGE
task-job2-8n4xk   0/1     Completed           0          84s
task-job2-ds5jq   0/1     ContainerCreating   0          31s
task-job2-jwjkd   0/1     Completed           0          54s
task-job2-pn7lc   0/1     ContainerCreating   0          9s
task-job2-w4kkh   0/1     Completed           0          84s

也可以实时查看

[root@master job]# kubectl get pods -w  # 实时观察 Pod 的创建和完成情况
NAME              READY   STATUS      RESTARTS   AGE
task-job2-dhljh   1/1     Running     0          6s
task-job2-wvzl7   1/1     Running     0          6s
test-task-9mmsn   0/1     Completed   0          28m
task-job2-wvzl7   0/1     Completed   0          8s
task-job2-dhljh   0/1     Completed   0          9s
task-job2-wvzl7   0/1     Completed   0          9s
task-job2-wvzl7   0/1     Completed   0          9s
task-job2-pxnjw   0/1     Pending     0          0s
task-job2-pxnjw   0/1     Pending     0          0s
task-job2-wvzl7   0/1     Completed   0          10s
task-job2-pxnjw   0/1     ContainerCreating   0          0s
task-job2-dhljh   0/1     Completed           0          10s
task-job2-dhljh   0/1     Completed           0          10s
task-job2-pxnjw   0/1     ContainerCreating   0          1s
task-job2-lplw2   0/1     Pending             0          0s
task-job2-lplw2   0/1     Pending             0          0s
task-job2-lplw2   0/1     ContainerCreating   0          0s
task-job2-dhljh   0/1     Completed           0          11s
task-job2-lplw2   0/1     ContainerCreating   0          0s
task-job2-pxnjw   1/1     Running             0          3s
task-job2-lplw2   1/1     Running             0          3s
task-job2-pxnjw   0/1     Completed           0          8s
task-job2-lplw2   0/1     Completed           0          8s
task-job2-pxnjw   0/1     Completed           0          9s
task-job2-pxnjw   0/1     Completed           0          9s
task-job2-r8bn5   0/1     Pending             0          0s
task-job2-r8bn5   0/1     Pending             0          0s
task-job2-pxnjw   0/1     Completed           0          10s
task-job2-r8bn5   0/1     ContainerCreating   0          0s
task-job2-lplw2   0/1     Completed           0          9s
task-job2-lplw2   0/1     Completed           0          9s
task-job2-r8bn5   0/1     ContainerCreating   0          1s
task-job2-s5k4g   0/1     Pending             0          0s
task-job2-s5k4g   0/1     Pending             0          0s
task-job2-lplw2   0/1     Completed           0          10s
task-job2-s5k4g   0/1     ContainerCreating   0          0s
task-job2-s5k4g   0/1     ContainerCreating   0          1s
task-job2-r8bn5   1/1     Running             0          3s
task-job2-s5k4g   1/1     Running             0          3s
task-job2-r8bn5   0/1     Completed           0          8s
task-job2-s5k4g   0/1     Completed           0          8s
task-job2-r8bn5   0/1     Completed           0          9s
task-job2-r8bn5   0/1     Completed           0          9s
task-job2-r8bn5   0/1     Completed           0          10s
task-job2-s5k4g   0/1     Completed           0          9s
task-job2-s5k4g   0/1     Completed           0          9s
task-job2-s5k4g   0/1     Completed           0          10s

查看jobs的完成状态

[root@master job]# kubectl get jobs  # COMPLETIONS 应为 6/6
NAME        STATUS     COMPLETIONS   DURATION   AGE
task-job2   Complete   6/6           31s        103s

查看生成的pod

[root@master job]# kubectl get pod 
NAME              READY   STATUS      RESTARTS   AGE
task-job2-dhljh   0/1     Completed   0          2m43s
task-job2-lplw2   0/1     Completed   0          2m32s
task-job2-pxnjw   0/1     Completed   0          2m33s
task-job2-r8bn5   0/1     Completed   0          2m23s
task-job2-s5k4g   0/1     Completed   0          2m22s
task-job2-wvzl7   0/1     Completed   0          2m43s[root@master job]# kubectl logs task-job2-lplw2
Processing item task-job2-lplw2
[root@master job]# kubectl logs task-job2-s5k4g
Processing item task-job2-s5k4g

Job Controller工作原理总结

  1. Job Controller 控制的对象,直接就是 Pod。

  2. Job Controller 在控制循环中进行的调谐(Reconcile)操作,是根据实际在 Running 状态 Pod 的数目、已经成功退出的 Pod 的数目,以及 parallelism、completions 参数的值共同计算出在这个周期里,应该创建或者删除的 Pod 数目,然后调用 Kubernetes API 来执行这个操作。

场景3:失败重试

离线作业失败处理方式

离线作业失败后 Job Controller 就会不断地尝试创建一个新 Pod,这个尝试肯定不能无限进行下去。所以,在 Job 对象的 spec.backoffLimit 字段里定义了重试次数为 3(即,backoffLimit=3,默认值是 6)

如果restartPolicy=OnFailure,离线作业失败后,Job Controller 就不会去尝试创建新的 Pod。但是,它会不断地尝试重启 Pod 里的容器。

模拟任务失败并观察 Job 的重试机制。

[root@master job]# cat test_jobs3.yml 
apiVersion: batch/v1
kind: Job
metadata:name: task-job3
spec:backoffLimit: 3     # 最多重试 3 次template:spec:containers:- name: task-3image: busyboxcommand: ["sh", "-c", "echo 'Attempting...' && exit 1"]  # 故意失败restartPolicy: OnFailure[root@master job]# kubectl apply -f test_jobs3.yml 
job.batch/task-job3 created

观察 Pod 的重启次数(RESTARTS 列)

[root@master job]# kubectl get pods -w 
NAME              READY   STATUS              RESTARTS   AGE
task-job3-tbhst   0/1     ContainerCreating   0          2s
task-job3-tbhst   0/1     Error               0          24s
task-job3-tbhst   0/1     Error               1 (23s ago)   46s
task-job3-tbhst   0/1     CrashLoopBackOff    1 (1s ago)    47s
task-job3-tbhst   0/1     Error               2 (37s ago)   83s
task-job3-tbhst   0/1     CrashLoopBackOff    2 (12s ago)   95s
task-job3-tbhst   0/1     Error               3 (48s ago)   2m11s
task-job3-tbhst   0/1     Terminating         3 (49s ago)   2m12s
task-job3-tbhst   0/1     Terminating         3             2m12s
task-job3-tbhst   0/1     Terminating         3             2m12s
task-job3-tbhst   0/1     Terminating         3             2m13s
task-job3-tbhst   0/1     Error               3             2m13s
task-job3-tbhst   0/1     Error               3             2m13s
task-job3-tbhst   0/1     Error               3             2m13s[root@master job]# kubectl get jobs
NAME        STATUS   COMPLETIONS   DURATION   AGE
task-job3   Failed   0/1           2m49s      2m49s

到此只是重启了3次之后即停止重启。

修改restartPolicy为Never,再次查看

[root@master job]# kubectl delete -f test_jobs3.yml
[root@master job]# vim test_jobs3.yml 
apiVersion: batch/v1
kind: Job
metadata:name: task-job3
spec:backoffLimit: 3     # 最多重试 3 次template:spec:containers:- name: task-3image: busyboxcommand: ["sh", "-c", "echo 'Attempting...' && exit 1"]  # 故意失败restartPolicy: Never[root@master job]# kubectl apply -f test_jobs3.yml

重新创建3次pod

[root@master job]# kubectl get pods -w  #实时查看
NAME              READY   STATUS              RESTARTS   AGE
task-job3-pjxzt   0/1     ContainerCreating   0          2s
task-job3-pjxzt   0/1     Error               0          23s
task-job3-pjxzt   0/1     Error               0          24s
task-job3-pjxzt   0/1     Error               0          24s
task-job3-pjxzt   0/1     Error               0          25s
task-job3-l6b45   0/1     Pending             0          0s
task-job3-l6b45   0/1     Pending             0          0s
task-job3-l6b45   0/1     ContainerCreating   0          0s
task-job3-l6b45   0/1     ContainerCreating   0          0s
task-job3-l6b45   0/1     Error               0          23s
task-job3-l6b45   0/1     Error               0          24s
task-job3-l6b45   0/1     Error               0          24s
task-job3-l6b45   0/1     Error               0          25s
task-job3-dh8xp   0/1     Pending             0          0s
task-job3-dh8xp   0/1     Pending             0          0s
task-job3-dh8xp   0/1     ContainerCreating   0          0s
task-job3-dh8xp   0/1     ContainerCreating   0          0s
task-job3-dh8xp   0/1     Error               0          2s
task-job3-dh8xp   0/1     Error               0          3s
task-job3-dh8xp   0/1     Error               0          4s
task-job3-dh8xp   0/1     Error               0          4s
task-job3-xkwjc   0/1     Pending             0          0s
task-job3-xkwjc   0/1     Pending             0          0s
task-job3-xkwjc   0/1     ContainerCreating   0          0s
task-job3-xkwjc   0/1     ContainerCreating   0          0s
task-job3-xkwjc   0/1     Error               0          23s
task-job3-xkwjc   0/1     Error               0          24s
task-job3-xkwjc   0/1     Error               0          25s
task-job3-xkwjc   0/1     Error               0          26s

以上,就是一个 Job API 对象最主要的概念和用法

相关文章:

  • 字符串的相关方法
  • 5.2刷题
  • shell(6)
  • btrace1.0使用方法
  • 超预期!淘宝闪购提前开放全国全量,联合饿了么扭转外卖战局
  • ARConv的复现流程
  • 算法笔记.分解质因数
  • 值此五一劳动节来临之际,
  • 【Java IO流】字符输入流FileReader、字符输出流FileWriter
  • CMake separate_arguments用法详解
  • 全国信息素养大赛 图形化挑战赛~复赛练习-在正方形内吗?
  • 软件第三方测试:关键部分、意义、流程及方法全解析?
  • 数字智慧方案5876丨智慧交通枢纽智能化系统建设方案(56页PPT)(文末有下载方式)
  • 对解微分方程分离变量法本质的思考
  • 进程与线程:05 内核级线程实现
  • 综合案例:使用vuex对购物车的商品数量和价格等公共数据进行状态管理
  • GNOME扩展:ArcMenu的Brisk布局左右调换
  • C语言与指针3——基本数据类型
  • 大语言模型能力评定探讨
  • AI实现制作logo的网站添加可选颜色模板
  • 澎湃读报丨央媒头版头条集中刊发:大国应有的样子
  • 乌美矿产协议文本公布,明确乌收益及协议优先级
  • 两部门发布“五一”假期全国森林草原火险形势预测
  • 视频丨中国海警位中国黄岩岛领海及周边区域执法巡查
  • 国台办:台商台企有信心与国家一起打赢这场关税战
  • 零食连锁鸣鸣很忙递表港交所:去年营收393亿元,门店超1.4万家,净利润率2.1%