【Docker-Day 33】掌握 K8s 任务调度:DaemonSet、Job、CronJob 实战指南
在 Kubernetes 的世界里,`Deployment` 是我们最熟悉的朋友,它负责管理无状态应用的部署、扩缩容和滚动更新。然而,并非所有任务都是这种“永远在线”的服务模式。有些任务需要在每个节点上安插一个“哨兵”,有些任务只需要执行一次便功成身退,还有些任务则需要像闹钟一样定时响起。为了应对这些特殊的场景,Kubernetes 提供了三位“特种兵”:`DaemonSet`、`Job` 和 `
Langchain系列文章目录
01-玩转LangChain:从模型调用到Prompt模板与输出解析的完整指南
02-玩转 LangChain Memory 模块:四种记忆类型详解及应用场景全覆盖
03-全面掌握 LangChain:从核心链条构建到动态任务分配的实战指南
04-玩转 LangChain:从文档加载到高效问答系统构建的全程实战
05-玩转 LangChain:深度评估问答系统的三种高效方法(示例生成、手动评估与LLM辅助评估)
06-从 0 到 1 掌握 LangChain Agents:自定义工具 + LLM 打造智能工作流!
07-【深度解析】从GPT-1到GPT-4:ChatGPT背后的核心原理全揭秘
08-【万字长文】MCP深度解析:打通AI与世界的“USB-C”,模型上下文协议原理、实践与未来
Python系列文章目录
PyTorch系列文章目录
机器学习系列文章目录
深度学习系列文章目录
Java系列文章目录
JavaScript系列文章目录
Python系列文章目录
Go语言系列文章目录
Docker系列文章目录
01-【Docker-Day 1】告别部署噩梦:为什么说 Docker 是每个开发者的必备技能?
02-【Docker-Day 2】从零开始:手把手教你在 Windows、macOS 和 Linux 上安装 Docker
03-【Docker-Day 3】深入浅出:彻底搞懂 Docker 的三大核心基石——镜像、容器与仓库
04-【Docker-Day 4】从创建到删除:一文精通 Docker 容器核心操作命令
05-【Docker-Day 5】玩转 Docker 镜像:search, pull, tag, rmi 四大金刚命令详解
06-【Docker-Day 6】从零到一:精通 Dockerfile 核心指令 (FROM, WORKDIR, COPY, RUN)
07-【Docker-Day 7】揭秘 Dockerfile 启动指令:CMD、ENTRYPOINT、ENV、ARG 与 EXPOSE 详解
08-【Docker-Day 8】高手进阶:构建更小、更快、更安全的 Docker 镜像
09-【Docker-Day 9】实战终极指南:手把手教你将 Node.js 应用容器化
10-【Docker-Day 10】容器的“持久化”记忆:深入解析 Docker 数据卷 (Volume)
11-【Docker-Day 11】Docker 绑定挂载 (Bind Mount) 实战:本地代码如何与容器实时同步?
12-【Docker-Day 12】揭秘容器网络:深入理解 Docker Bridge 模式与端口映射
13-【Docker-Day 13】超越默认Bridge:精通Docker Host、None与自定义网络模式
14-【Docker-Day 14】Docker Compose深度解析
15-【Docker-Day 15】一键部署 WordPress!Docker Compose 实战终极指南
16-【Docker-Day 16】告别单机时代:为什么 Docker Compose 不够用,而你需要 Kubernetes?
17-【Docker-Day 17】K8s 架构全解析:深入理解 Kubernetes 的大脑 (Master) 与四肢 (Node)
18-【Docker-Day 18】告别选择困难症:一文掌握 Minikube、kind、k3d,轻松搭建你的第一个 K8s 集群
19-【Docker-Day 19】万物皆 YAML:掌握 Kubernetes 声明式 API 的艺术
20-【Docker-Day 20】揭秘 Kubernetes 的原子单位:深入理解 Pod
21-【Docker-Day 21】Pod的守护神:ReplicaSet与ReplicationController,轻松实现应用高可用
22-【K8s-Day 22】深入解析 Kubernetes Deployment:现代应用部署的基石与滚动更新的艺术
23-【K8s-Day 23】从 Pod 的“失联”到 Service 的“牵线”:深入理解 ClusterIP 核心原理
24-【Docker-Day 24】K8s网络解密:深入NodePort与LoadBalancer,让你的应用走出集群
25-【Docker-Day 25】深入理解 Kubernetes Namespace:实现多租户与环境隔离的利器
26-【Docker-Day 26】K8s实战演练:从零开始部署一个完整的前后端分离Web应用
27-【K8s-Day 27】应用的“体检医生”:深入解析 Kubernetes 健康检查探针 (Probe)
28-【Docker-Day 28】K8s 核心配置管理:解密 ConfigMap,告别硬编码!
29-【Docker-Day 29】K8s 安全第一课:揭秘敏感信息管理器 Secret
30-【Docker-Day 30】解密 K8s 的“硬盘”:深入理解 PersistentVolume (PV) 与 PersistentVolumeClaim (PVC)
31-【Docker-Day 31】告别手动创建 PV!一文搞懂 Kubernetes StorageClass 工作原理与实战
32-【K8s-Day 32】StatefulSet 深度解析:为你的数据库和有状态应用保驾护航
33-【Docker-Day 33】掌握 K8s 任务调度:DaemonSet、Job、CronJob 实战指南
文章目录
摘要
在 Kubernetes 的世界里,Deployment 是我们最熟悉的朋友,它负责管理无状态应用的部署、扩缩容和滚动更新。然而,并非所有任务都是这种“永远在线”的服务模式。有些任务需要在每个节点上安插一个“哨兵”,有些任务只需要执行一次便功成身退,还有些任务则需要像闹钟一样定时响起。为了应对这些特殊的场景,Kubernetes 提供了三位“特种兵”:DaemonSet、Job 和 CronJob。本文将深入剖析这三种控制器的工作原理、核心应用场景,并通过丰富的实战案例,带你彻底掌握它们,让你的 K8s 集群任务调度能力再上一个台阶。
一、超越 Deployment:为什么需要特殊的 Pod 控制器?
在之前的文章中,我们已经熟练掌握了 Deployment,它非常适合部署像 Web 服务器、API 网关这类需要长期运行、并且可以被水平扩展的无状态服务。Deployment 的核心思想是维持期望数量的副本(Replica),并将它们均匀地调度到集群的各个节点上,不关心具体落在哪个节点。
但是,请思考以下几个常见需求:
- 节点级监控与日志收集:我希望在集群的每一个工作节点上都运行一个日志收集代理(如 Fluentd)或一个监控代理(如 Prometheus Node Exporter),以便收集该节点的系统日志和性能指标。如果使用
Deployment,我们无法保证每个节点都恰好有一个 Pod 实例。 - 一次性批处理任务:我需要对数据库进行一次性数据迁移,或者执行一个复杂的计算任务。这个任务执行完毕后就应该结束,不需要一直占用资源。
Deployment会在 Pod 结束后立即尝试重启它,这显然不符合我们的需求。 - 周期性定时任务:我需要每天凌晨 2 点对数据库进行备份,或者每小时清理一次临时文件。这就像 Linux 系统中的
crontab一样,需要定时触发。Deployment同样无法满足这种周期性执行的需求。
为了优雅地解决这些问题,Kubernetes 引入了专门的工作负载资源:
DaemonSet:节点守护者,确保每个(或部分)节点上都运行一个 Pod 副本。Job:一次性任务执行者,确保一个或多个 Pod 成功运行到结束。CronJob:定时任务调度器,基于Job并增加了定时触发的能力。
接下来,我们将逐一揭开它们神秘的面纱。
二、节点“守护神”:DaemonSet 详解
DaemonSet 就像是古代城池中派驻到每个城门(Node)的守护卫兵,确保每个关键位置都有人站岗。
2.1 什么是 DaemonSet?
DaemonSet(守护进程集)是一种 Kubernetes 控制器,它确保全部(或部分)节点上都运行一个 Pod 的副本。当有节点加入集群时,DaemonSet 会为它们新增一个 Pod;当有节点从集群中移除时,这些 Pod 也会被相应地回收。
核心目标:在指定的每个 Node 上都运行一个且仅一个 Pod 实例。
2.2 DaemonSet 的核心工作原理
DaemonSet 控制器会监听集群中的节点。对于每一个满足其调度要求的节点,它会确保该节点上存在一个由它管理的 Pod。它不使用 ReplicaSet,而是直接管理 Pod。
其工作流程可以简化为下图:
graph TD
subgraph Kubernetes Cluster
Master[Master Node]
Node1[Worker Node 1]
Node2[Worker Node 2]
Node3[Worker Node 3]
end
subgraph Control Plane
DSC[DaemonSet Controller]
end
DS_Def[DaemonSet YAML Definition] -->|kubectl apply| Master
Master -- informs --> DSC
DSC -- watches --> Node1
DSC -- watches --> Node2
DSC -- watches --> Node3
subgraph Node1
Pod_A[Pod A]
end
subgraph Node2
Pod_B[Pod B]
end
subgraph Node3
Pod_C[Pod C]
end
DSC -- Creates --> Pod_A
DSC -- Creates --> Pod_B
DSC -- Creates --> Pod_C
NewNode[New Node 4 Added] -->|joins| Master
Master -- informs --> DSC
DSC -- watches --> NewNode
subgraph NewNode
Pod_D[Pod D]
end
DSC -- Creates --> Pod_D
style DS_Def fill:#f9f,stroke:#333,stroke-width:2px
style DSC fill:#ccf,stroke:#333,stroke-width:2px
2.3 DaemonSet 的典型应用场景
DaemonSet 的应用场景非常广泛,几乎所有需要与节点底层交互的系统级应用都离不开它:
- 日志收集:在每个节点上运行一个日志收集代理,如
Fluentd、Filebeat或Logstash,用于收集该节点上所有容器的日志。 - 节点监控:在每个节点上运行一个监控代理,如
Prometheus Node Exporter、Datadog Agent或Zabbix Agent,用于暴露节点的硬件和操作系统指标。 - 网络插件:许多 CNI(容器网络接口)插件,如
Calico、Flannel等,会以DaemonSet的形式在每个节点上运行一个代理,负责该节点的网络配置和管理。 - 存储插件:分布式存储系统(如
Ceph、GlusterFS)的客户端或代理也常以DaemonSet形式部署,为节点提供存储服务。
2.4 实战:部署一个节点监控 Pod
让我们以部署 Prometheus Node Exporter 为例,它能暴露每个节点的硬件和 OS 指标。
(1) 编写 node-exporter-ds.yaml
# node-exporter-ds.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-exporter
labels:
app: node-exporter
spec:
# 1. Selector: 用于关联 DaemonSet 和它管理的 Pods
selector:
matchLabels:
app: node-exporter
# 2. Template: Pod 的定义模板
template:
metadata:
labels:
app: node-exporter
spec:
containers:
- name: node-exporter
image: prom/node-exporter:v1.3.1
ports:
- containerPort: 9100
protocol: TCP
# 3. Host Network: 允许 Pod 直接使用宿主机的网络,方便外部访问
hostNetwork: true
# 4. Host PID: 允许 Pod 访问宿主机的进程信息
hostPID: true
# 5. Tolerations: 容忍 master 节点的污点,使其也能被调度上去
# 这对于监控 master 节点本身也很重要
tolerations:
- effect: NoSchedule
key: node-role.kubernetes.io/master
- effect: NoSchedule
key: node-role.kubernetes.io/control-plane
(2) 部署与验证
-
应用 YAML 文件
kubectl apply -f node-exporter-ds.yaml -
查看 DaemonSet 状态
$ kubectl get ds node-exporter NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE node-exporter 3 3 3 3 3 <none> 60sDESIRED和CURRENT字段显示了期望和当前运行的 Pod 数量,它应该等于你集群中节点的数量。 -
查看 Pod 分布情况
使用-o wide参数可以清晰地看到每个 Pod 所在的节点。$ kubectl get pods -l app=node-exporter -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES node-exporter-abcde 1/1 Running 0 90s 192.168.1.11 k8s-worker-1 <none> <none> node-exporter-fghij 1/1 Running 0 90s 192.168.1.12 k8s-worker-2 <none> <none> node-exporter-klmno 1/1 Running 0 90s 192.168.1.10 k8s-master-1 <none> <none>可以看到,每个节点(包括 master 节点,因为我们加了容忍)上都运行了一个
node-exporterPod。
三、一次性与周期性任务:Job 与 CronJob
如果说 DaemonSet 关心的是“空间”(部署在哪些节点上),那么 Job 和 CronJob 关心的就是“时间”(何时执行,执行多久)。
3.1 从“一次性”开始:Job 控制器
3.1.1 什么是 Job?
Job 控制器会创建一个或多个 Pod,并确保指定数量的 Pod 成功运行到终止。一旦任务成功完成,Job 就完成了它的使命。如果 Pod 因任何原因(如节点故障、程序 bug)失败,Job 控制器会根据配置的重试策略重新创建一个新的 Pod,直到任务成功或达到重试上限。
核心目标:执行一个会“结束”的任务,并确保其成功完成。
3.1.2 Job 的行为模式
Job 的 spec 中有几个关键字段来控制其行为:
completions: 指定需要成功完成的 Pod 总数。默认为 1。parallelism: 指定并行运行的 Pod 数量。默认为 1。backoffLimit: 指定任务失败前可以重试的次数。默认为 6。activeDeadlineSeconds: 任务运行的最长时限,超时则标记为失败。
3.1.3 Job 应用场景
- 数据迁移:在应用新版本前,运行一个一次性的数据库 schema 迁移脚本。
- 批处理计算:对一批数据进行计算、转换或分析。
- 备份/恢复:执行一次性的数据备份或恢复操作。
- 测试:运行集成测试或端到端测试。
3.1.4 实战:运行一个计算 π 的 Job
这个经典的例子使用 perl 镜像来计算圆周率到 2000 位。
(1) 编写 pi-job.yaml
# pi-job.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: pi-calculation
spec:
# 1. Template: 定义了要运行的 Pod
template:
spec:
containers:
- name: pi
image: perl
# 2. Command: Pod 启动后执行的命令
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
# 3. Restart Policy: Job 的 Pod 必须设置为 OnFailure 或 Never
# 不能是 Always(这是 Deployment 的默认值)
restartPolicy: OnFailure
# 4. Backoff Limit: 如果失败,最多重试 4 次
backoffLimit: 4
(2) 部署与验证
-
应用 YAML 文件
kubectl apply -f pi-job.yaml -
查看 Job 状态
$ kubectl get jobs pi-calculation NAME COMPLETIONS DURATION AGE pi-calculation 1/1 15s 30sCOMPLETIONS显示1/1,表示任务已成功完成。 -
查看 Pod 状态
Job完成后,其创建的 Pod 不会被删除,以便你检查日志。$ kubectl get pods -l job-name=pi-calculation NAME READY STATUS RESTARTS AGE pi-calculation-xyz12 0/1 Completed 0 45sSTATUS为Completed表示 Pod 成功执行并退出。 -
查看任务输出(日志)
$ kubectl logs pi-calculation-xyz12 3.14159265358979323846... (后面跟着一长串数字)
3.2 定时任务的“闹钟”:CronJob 控制器
CronJob 是在 Job 之上构建的,它就像为 Job 配备了一个功能强大的定时闹钟。
3.2.1 什么是 CronJob?
CronJob 在给定的时间点(Cron 表达式)上创建一个 Job 对象。它非常适合执行周期性、重复性的任务。
核心目标:按预定的 cron 时间表周期性地创建 Job。
3.2.2 Cron 表达式详解
CronJob 的 schedule 字段使用标准的 Cron 表达式,格式如下:
# ┌───────────── 分钟 (0 - 59)
# │ ┌───────────── 小时 (0 - 23)
# │ │ ┌───────────── 一个月中的第几天 (1 - 31)
# │ │ │ ┌───────────── 月份 (1 - 12)
# │ │ │ │ ┌───────────── 星期几 (0 - 6) (Sunday to Saturday)
# │ │ │ │ │
# │ │ │ │ │
# * * * * *
常用示例:
*/1 * * * *: 每分钟执行一次。0 2 * * *: 每天凌晨 2 点执行。0 17 * * 1-5: 每周一至周五的下午 5 点执行。
3.2.3 CronJob 的关键配置
schedule: Cron 表达式,定义任务何时运行。jobTemplate:Job的模板,定义了每次要创建的Job的具体内容。concurrencyPolicy: 并发策略。如果上一个任务还没跑完,新的任务时间点又到了,该如何处理?Allow(默认): 允许并发运行Job。Forbid: 禁止并发,如果前一个Job还在运行,则跳过本次执行。Replace: 取消当前正在运行的Job,并用新的Job替换它。
successfulJobsHistoryLimit: 保留多少个成功的Job历史记录。默认为 3。failedJobsHistoryLimit: 保留多少个失败的Job历史记录。默认为 1。
3.2.4 实战:创建一个每分钟打印时间的 CronJob
(1) 编写 hello-cronjob.yaml
# hello-cronjob.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
name: hello-cronjob
spec:
# 1. Schedule: 每分钟执行一次
schedule: "*/1 * * * *"
# 2. Job Template: 定义了每次要创建的 Job
jobTemplate:
spec:
template:
spec:
containers:
- name: hello
image: busybox
args:
- /bin/sh
- -c
- date; echo "Hello from the Kubernetes CronJob"
restartPolicy: OnFailure
# 3. Concurrency Policy: 禁止并发
concurrencyPolicy: Forbid
# 4. History Limits: 保留最近 3 个成功和 1 个失败的 Job 记录
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 1
(2) 部署与验证
-
应用 YAML 文件
kubectl apply -f hello-cronjob.yaml -
查看 CronJob 状态
$ kubectl get cronjob hello-cronjob NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE hello-cronjob */1 * * * * False 0 30s 60sLAST SCHEDULE显示了上次调度的时间。 -
观察被创建的 Job 和 Pod
等待一两分钟后,你可以看到CronJob自动创建的Job。$ kubectl get jobs NAME COMPLETIONS DURATION AGE hello-cronjob-27757750 1/1 2s 110s hello-cronjob-27757751 1/1 2s 50s $ kubectl get pods NAME READY STATUS RESTARTS AGE hello-cronjob-27757750-abcde 0/1 Completed 0 112s hello-cronjob-27757751-fghij 0/1 Completed 0 52s你可以看到,
CronJob每次都会创建一个新的Job,而这个Job又会创建一个新的Pod来执行任务。
四、三者对比:如何选择合适的控制器?
为了帮助你快速区分和选择,下表总结了 Deployment、DaemonSet、Job 和 CronJob 的核心差异。
| 控制器类型 | 核心目标 | Pod 生命周期 | 典型应用场景 |
|---|---|---|---|
| Deployment | 维持指定数量的、长期运行的 Pod 副本 | 持续运行 (Always Restart) | 无状态 Web 服务、API 网关、微服务 |
| DaemonSet | 确保每个(或部分)节点上运行一个 Pod 副本 | 与节点生命周期绑定 | 日志收集、节点监控、网络/存储插件 |
| Job | 确保一个或多个 Pod 成功运行至结束 | 一次性,运行至完成 (Run-to-Completion) | 数据迁移、批处理计算、一次性备份、测试 |
| CronJob | 按预定时间表周期性地创建 Job | 周期性创建,运行至完成 | 定时备份、周期性报告生成、定时清理任务 |
五、总结
通过本文的学习,我们掌握了 Kubernetes 中除了 Deployment 之外的三种重要的工作负载控制器。它们使得 K8s 不仅能管理常规服务,还能灵活处理各种特殊任务,构成了完整而强大的应用调度体系。
核心要点回顾:
Deployment是通用选择:适用于需要长期运行、可随意扩展的无状态服务。它是最常用的控制器。DaemonSet关注“空间”:当你需要在集群的每个节点上部署一个代理或守护进程时,DaemonSet是不二之选。它保证了 Pod 在节点上的覆盖率。Job关注“一次性完成”:对于那些执行完即可丢弃的任务,如数据处理和批处理脚本,Job提供了可靠的执行和重试机制,确保任务最终成功。CronJob关注“周期性执行”:它为Job增加了定时调度能力,是 Kubernetes 内置的crontab,负责自动化执行周期性任务。
理解并熟练运用 DaemonSet、Job 和 CronJob,是衡量你是否真正迈入 Kubernetes 进阶大门的重要标志。在实际项目中,根据任务的特性选择最合适的控制器,才能构建出高效、健壮、自动化的云原生应用系统。
更多推荐
所有评论(0)