【Kubernetes】K8s笔记(四):从 Job 和 CronJob 看 Kubernetes 的设计理念
0. 前言:在线业务和离线业务
Kubernetes 的业务可以分为两大类:在线业务和离线业务。
-
在线业务:像 Nginx 、MySQL 这样长时间运行的业务,这些应用一旦运行起来,除非出错或者停止,它的容器进程会一直保持在 Running 状态
-
离线业务:短时间运行的业务,或者是定时任务,这种业务在计算完成后就直接退出了;它们一般不直接服务于外部用户,只对内部用户有意义,比如日志分析、数据建模、视频转码等等,虽然计算量很大,但只会运行一段时间;也就是说,它们的特点是必定会退出,因此我们需要考虑运行超时、状态检查、失败重试、获取计算结果等管理事项
在上篇中我们也看到了,Kubernetes 基于 Pod 延伸出了很多表示各种业务的其他资源对象。那为什么不直接在 Pod 中添加功能来处理这些业务需求?
这篇笔记会简要阐述 Kubernetes 基于 Pod 的设计理念,也是上面问题的解答。下面先从 Kubernetes 最简单的两种对象 Job
和 CronJob
开始。
1. 不扩展 Pod 功能背后的理念和原则
Kubernetes 使用 YAML 来描述资源,把业务简化成了一个个的对象,内部有属性,外部有联系,也需要互相协作,只不过我们不需要编程,完全由 Kubernetes 自动处理。
面向对象的设计有许多基本原则,其中有两条比较恰当地描述了 Kubernetes 对象设计思路,一个是“单一职责”,另一个是“组合优于继承”。
-
单一职责:对象应该只专注于做好一件事情,保持足够小的粒度才更方便复用和管理
-
组合优于继承:尽量让对象在运行时产生联系,保持松耦合,而不要用硬编码的方式固定对象的关系
因为 Pod 已经是一个相对完善的对象,专门负责管理容器,那么我们就不应该再“画蛇添足”地盲目为它扩充功能,而是要保持它的独立性,容器之外的功能就需要定义其他的对象,把 Pod 作为它的一个成员“组合”进去。每种 Kubernetes 对象就可以只关注自己的业务领域,只做自己最擅长的事情,其他的工作交给其他对象来处理,既不“缺位”也不“越位”,既有分工又有协作。
2. Job 和 CronJob
“离线业务”也可以分为两种。一种是“临时任务”,运行完成就结束了,如果有需要可以再次安排;另一种是“定时任务”,可以按时按点周期运行,不需要过多干预。为了实现对离线业务的处理,Kubernetes 组合了 Pod 推出两种新的对象 Job
和 CronJob
,“临时任务”就是 API 对象 Job
,“定时任务”就是 API 对象 CronJob
,使用这两个对象women 就能够在 Kubernetes 里调度管理任意的离线业务了。
2.1 使用 YAML 描述 Job
YAML 文件的“头部”:
apiVersion
:batch/v1
kind
:Job
,这与对象的名字是一致的metadata
: 里面仍要有name
标记名字,也可以用labels
添加任意的标签
当然我们也可以用 kubectl create
来生成 YAML 模板:
$ kubectl create job echo-job --image=busybox --dry-run=client -o yaml
注意:想要生成 YAML 样板文件的话不能使用
kubectl run
,因为kubectl run
只能创建 Pod,要创建 Pod 以外的其他 API 对象,需要使用命令kubectl create
,再加上对象的类型名
下面是我们生成的 Job 对象的 YAML 文件(修改后的):
apiVersion: batch/v1
kind: Job
metadata:
creationTimestamp: null
name: echo-job
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- image: busybox
name: echo-job
imagePullPolicy: IfNotPresent
command: ["/bin/echo"]
args: ["hello", "world"]
可以看出,Job 与 Pod 主要的区别就在 spec
字段里,多了一个 template
字段,然后又是一个 spec
。
它其实就是在 Job 对象里应用了组合模式,template
字段定义了一个“应用模板”,里面嵌入了一个 Pod,这样 Job 就可以从这个模板来创建出 Pod。
而这个 Pod 因为受 Job 的管理控制,不直接和 apiServer
打交道,也就没必要重复 apiVersion
等“头字段”,只需要定义好关键的 spec
,描述清楚容器相关的信息就可以了,可以说是一个“无头部”的 Pod 对象。
apiVersion
字段是batch/v1
,表明它不属于核心对象组(core group),而是属于批处理对象组(batch group)
这个 Pod 工作非常简单,在 containers 里写好名字和镜像,command 执行 /bin/echo
,输出“hello world”。
因为 Job 业务的特殊性,所以我们还要在 spec
里多加一个字段 restartPolicy
,确定 Pod 运行失败时的策略,OnFailure
是失败原地重启容器,而 Never
则是不重启容器,让 Job 去重新调度生成一个新的 Pod。
2.2 在 Kubernetes 里面操作 Job
使用下面的命令来创建 Job:
$ kubectl apply -f job.yml
job.batch/echo-job created
然后我们可以查看 Job、Pod 的状态:
$ kubectl get jobs
NAME COMPLETIONS DURATION AGE
echo-job 1/1 13s 26s
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
echo-job-vr84n 0/1 Completed 0 29s
因为 Pod 被 Job 管理,它就不会反复重启报错了,而是会显示为 Completed 表示任务完成,而 Job 里也会列出运行成功的作业数量,这里只有一个作业,所以就是 1/1。Pod 被自动关联了一个名字,用的是 Job 的名字(echo-job)再加上一个随机字符串。
最后我们查看一下 Pod 的输出:
$ kubectl logs echo-job-vr84n
Job 在运行结束后,为了方便获取处理结果,不会立即删除。但是积累过多的已完成的 Job 也会消耗系统资源,我们可以使用 ttlSecondsAfterFinished
设置一个保留时限。参阅已完成 Job 的自动清理
2.3 几个离线作业的重要字段
上面我们操作了一个最简单的 Job,其实 Kubernetes 还支持在Job 级别、Pod 级别添加任意的字段来定制业务。
这里是几个控制离线作业的重要字段,其他更详细的信息可以参考 Job 文档
activeDeadlineSeconds
- 设置 Pod 运行的超时时间
backoffLimit
- 设置 Pod 的失败重试次数
completions
- Job 完成需要运行多少个 Pod,默认是 1 个
parallelism
- 它与 completions 相关,表示允许并发运行的 Pod 数量,避免过多占用资源
这 4 个字段并不在 template
字段下,而是在 spec
字段下,所以它们是属于 Job 级别的,用来控制模板里的 Pod 对象。
“声明式”的 Job 对象让离线业务的描述变得非常直观,简单的几个字段就可以很好地控制作业的并行度和完成数量,不需要我们去人工监控干预,Kubernetes 把这些都自动化实现了。
2.4 使用 YAML 描述 CronJob
CronJob 是定时任务,在 Kubernetes 中简称 CronJob 为 cj
(前面提到过可以通过 kubectl api-resources
命令查看)。下面我们使用命令来创建一个 CronJob 的 YAML 模板,因为是定时任务,在命令行里还需要指定参数 --schedule:
kubectl create cj echo-cj --image=busybox --schedule="" --dry-run=client -o yaml
然后稍微编辑一下,就生成一个描述 CronJob 对象的 YAML 文件:
apiVersion: batch/v1
kind: CronJob
metadata:
name: echo-cj
spec:
schedule: '*/1 * * * *'
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- image: busybox
name: echo-cj
imagePullPolicy: IfNotPresent
command: ["/bin/echo"]
args: ["hello", "world"]
这个 YAML 连续有三个 spec 嵌套层次:
-
第一个 spec 是 CronJob 自己的对象规格声明
-
第二个 spec 从属于“jobTemplate”,它定义了一个 Job 对象
-
第三个 spec 从属于“template”,它定义了 Job 里运行的 Pod
除了定义 Job 对象的“jobTemplate”字段之外,CronJob 还有一个新字段就是“schedule”,用来定义任务周期运行的规则。它使用的是标准的 Cron 语法,指定分钟、小时、天、月、周,和 Linux 上的 crontab 是一样的。
出于节约资源的考虑,CronJob 不会无限期地保留已经运行的 Job,它只会保留最近三个执行结果,当然我们也可以用 successfulJobsHistoryLimit
改变保留的数量。参阅 使用 CronJob 运行自动化任务
其余的用法可以参考 CronJob 文档
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 什么是nginx的强缓存和协商缓存
· 一文读懂知识蒸馏
· Manus爆火,是硬核还是营销?