外观
第七节 多类型控制器编排
约 2691 字大约 9 分钟
KubernetesDaemonSetStatefulSetJob
2026-07-28
项目目标
根据业务运行语义选择适当的控制器:编写 long-running.yaml 部署 DaemonSet 与配合 Headless Service 的 StatefulSet,体验每节点守护进程与稳定网络身份;编写 batch.yaml 部署 Job 与 CronJob,掌握批处理完成语义、restartPolicy 约束与 concurrencyPolicy 并发控制策略,建立结构化的工作负载选型决策表。
7.1 控制器选型:为什么不能所有工作负载都用 Deployment
在前一课中,我们学习了 Deployment,它假设所有的 Pod 都是无状态且完全可互换的(Stateless & Interchangeable)。
然而,在生产环境和复杂业务系统中,并非所有组件都符合无状态假设。不同业务具备截然不同的运行语义(Operational Semantics):
- 每个节点都需要运行一份日志/监控采集代理:无法用固定副本数的 Deployment 表达,需随节点增减自动扩缩。
- 数据库主从节点需要固定名称与有序启动:Pod 副本不能完全互换,必须拥有固定的序号与 DNS 域名。
- 数据初始化脚本运行一次成功后即可退出:要求 Pod 成功退出后终止,不能自动重启。
- 定时巡检与数据备份任务:要求按 Cron 时间计划周期性创建和调度任务。
根据业务运行语义,Kubernetes 提供了多类型工作负载控制器(Workload Controllers):
从业务约束选择控制器
按运行范围、身份和完成语义做选择。
1 / 5
| 业务诉求与运行语义 | 控制器类型 | 核心行为特征 |
|---|---|---|
| 每节点守护进程 | DaemonSet | 保证集群中每一个(或符合选择条件的)节点上都运行且仅运行一个 Pod 副本。 |
| 有状态有序应用 | StatefulSet | 为每个 Pod 提供稳定递增的网络序号(如 pod-0)、固定 DNS 域名和持久化存储绑定。 |
| 一次性批处理任务 | Job | 运行一个或多个 Pod,直到指定数量的 Pod 成功执行并退出(Exit Code 0)。 |
| 周期性定时任务 | CronJob | 按照 Cron 时间表达式,在指定时间点周期性创建 Job 对象。 |
7.2 长期运行控制器:DaemonSet 与 StatefulSet
7.2.1 DaemonSet 与 StatefulSet 配置文件:long-running.yaml
在项目根目录下直接创建配置文件 long-running.yaml:
long-running.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-agent
namespace: yunfan-shop
spec:
selector:
matchLabels:
app: node-agent
template:
metadata:
labels:
app: node-agent
spec:
containers:
- name: agent
image: busybox:1.36.1
command: ["sh", "-c", "while true; do echo node-agent; sleep 60; done"]
resources:
requests:
cpu: 10m
memory: 8Mi
limits:
cpu: 50m
memory: 32Mi
---
apiVersion: v1
kind: Service
metadata:
name: catalog-headless
namespace: yunfan-shop
spec:
clusterIP: None
selector:
app: catalog-state
ports:
- name: http
port: 80
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: catalog-state
namespace: yunfan-shop
spec:
serviceName: catalog-headless
replicas: 2
selector:
matchLabels:
app: catalog-state
template:
metadata:
labels:
app: catalog-state
spec:
containers:
- name: nginx
image: nginx:1.27-alpine
resources:
requests:
cpu: 20m
memory: 24Mi
limits:
cpu: 100m
memory: 64Mi在终端中部署该配置文件:
kubectl apply -f long-running.yaml
kubectl rollout status daemonset/node-agent -n yunfan-shop --timeout=120s
kubectl rollout status statefulset/catalog-state -n yunfan-shop --timeout=120s7.2.2 底层机制与关键语法拆解
- DaemonSet 的节点自动关联机制:
- 不需要配置
replicas属性。DaemonSet 控制器会自动监听集群节点变化:当新工作节点加入集群时,自动在该节点拉起一个node-agentPod;当节点从集群中移除时,Pod 被自动清理。 - DaemonSet 默认能容忍节点的
unschedulable等控制平面污点,确保系统级代理在所有节点均能覆盖。
- 不需要配置
- StatefulSet 与 Headless Service (无头服务):
clusterIP: None(Headless Service):指定该 Service 不分配虚拟 ClusterIP。CoreDNS 不会为该 Service 返回单个 IP,而是会为 StatefulSet 中的每一个 Pod 分配一条固定的全限定域名 (FQDN):catalog-state-0.catalog-headless.yunfan-shop.svc.cluster.local- 稳定递增序号:查看创建的 Pod,名称必定为
catalog-state-0和catalog-state-1。即使catalog-state-0发生崩溃重建,新 Pod 的名称依然保持为catalog-state-0! - 有序部署机制:StatefulSet 默认按照
0 -> N-1的顺序依次创建 Pod,前一个 Pod 达到 Ready 后才会创建下一个;销毁时按照N-1 -> 0的逆序依次优雅终止。
运行以下命令,验证 DaemonSet 与 StatefulSet 的实际 Pod 名称:
kubectl get daemonset,statefulset,pod -n yunfan-shop -o wide7.3 批处理与定时控制器:Job 与 CronJob
观察下面的批处理任务生命周期动画,理解有状态应用与批处理任务在运行时间与完成语义上的差异:
稳定身份与完成语义
比较 StatefulSet、Job 与 CronJob 的时间关系。
1 / 5
7.3.1 Job 与 CronJob 配置文件:batch.yaml
在项目根目录下直接创建配置文件 batch.yaml:
batch.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: catalog-bootstrap
namespace: yunfan-shop
spec:
backoffLimit: 2
template:
spec:
restartPolicy: Never
containers:
- name: task
image: busybox:1.36.1
command: ["sh", "-c", "echo catalog bootstrap completed"]
---
apiVersion: batch/v1
kind: CronJob
metadata:
name: catalog-audit
namespace: yunfan-shop
spec:
schedule: "*/5 * * * *"
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 2
failedJobsHistoryLimit: 1
jobTemplate:
spec:
backoffLimit: 1
template:
spec:
restartPolicy: Never
containers:
- name: audit
image: busybox:1.36.1
command: ["sh", "-c", "date; echo catalog audit completed"]在终端中应用该批处理配置文件:
kubectl apply -f batch.yaml
kubectl wait -n yunfan-shop --for=condition=Complete job/catalog-bootstrap --timeout=120s7.3.2 完成语义与定时并发参数详解
- Job 的
restartPolicy硬性约束:- 在 Job 中,Pod 模板的
restartPolicy绝不能写为Always(否则容器成功退出后又会自动无限重启,违反了 Job 运行至完成的语义)。必须显式设置为Never(容器失败时创建新 Pod 重试)或OnFailure(容器失败时在原 Pod 内重启容器)。
- 在 Job 中,Pod 模板的
backoffLimit: 2(失败重试上限):- 如果批处理任务命令退出码非 0,Job 控制器最多重试 2 次。超越重试上限后,Job 状态将被标记为
Failed并停止重试。
- 如果批处理任务命令退出码非 0,Job 控制器最多重试 2 次。超越重试上限后,Job 状态将被标记为
- CronJob 时间表达式与
concurrencyPolicy:schedule: "*/5 * * * *":标准 5 字段 Cron 表达式(依次为:分 时 日 月 周)。*/5 * * * *表示每隔 5 分钟触发一次。concurrencyPolicy(并发策略):Allow(默认):允许新 Job 与尚未运行完毕的旧 Job 重叠并发运行。Forbid:禁止并发。如果上一个 5 分钟触发的 Job 尚未运行完,跳过本次触发。Replace:强行替代。用新创建的 Job 终止并替换尚未运行完的旧 Job。
- 历史清理限制:
successfulJobsHistoryLimit: 2自动保留最近 2 次成功的 Job 记录,避免垃圾对象无限堆积。
7.3.3 验证 Job 与手动触发 CronJob
查看 Job 运行完成日志:
kubectl logs -n yunfan-shop job/catalog-bootstrap预期输出:catalog bootstrap completed。
运行以下命令查看 CronJob 调度状态:
kubectl get cronjob,job,pod -n yunfan-shop若不想等待 5 分钟的 Cron 触发点,可以命令式从 CronJob 模板手动派生生成一个测试 Job:
# 手动从 CronJob 派生创建一个单次 Job 资源进行测试
kubectl create job -n yunfan-shop --from=cronjob/catalog-audit catalog-audit-manual
kubectl wait -n yunfan-shop --for=condition=Complete job/catalog-audit-manual --timeout=120s
kubectl logs -n yunfan-shop job/catalog-audit-manual7.4 控制器架构对比决策矩阵
在进行 Kubernetes 架构设计时,应当根据业务运行语义选择最契合的控制器:
| 评价维度 | Deployment | DaemonSet | StatefulSet | Job | CronJob |
|---|---|---|---|---|---|
| 运行时间语义 | 长期持续运行 | 长期持续运行 | 长期持续运行 | 运行至成功即终止 | 周期性创建 Job |
| 副本扩展依据 | 显式指定 replicas | 自动适配集群节点数 | 显式指定 replicas | 指定完成数 completions | 依时间计划触发 |
| Pod 身份与名称 | 随机 Hash 无状态 | 与节点主机名关联 | 固定递增序号 (-0, -1) | 临时随机任务名称 | 按时间派生新名称 |
| 网络标识 | 共享入口 (ClusterIP) | 节点端口/HostPort | 固定 DNS FQDN 域名 | 无需稳定网络入口 | 无需稳定网络入口 |
| 典型应用场景 | Web API、微服务 | 日志采集、监控 Agent | Redis, MySQL, Kafka | 数据初始化、SQL 迁移 | 数据库备份、定时巡检 |
7.5 阶段验收与排错速查
7.5.1 本课提交成果清单
完成本课实训后,提交以下四项成果即可:
- 长期运行配置文件:项目根目录下的
long-running.yaml。 - 批处理配置文件:项目根目录下的
batch.yaml。 - 第一张截图
07-daemonset-statefulset.png:同一终端画面中包含kubectl get daemonset,statefulset,pod -n yunfan-shop -o wide。 - 第二张截图
07-job-cronjob.png:同一终端画面中包含kubectl get cronjob,job,pod以及手动派生 Job 成功的日志输出。
7.5.2 常见错误与排错矩阵
| 故障现象 | 可能原因 | 修复排查路径 |
|---|---|---|
| DaemonSet 数量少于集群节点数 | 节点存在污点(Taint)或设置了 nodeSelector | 运行 kubectl describe daemonset 查看 Events,确认节点匹配条件或补充 Tolerations。 |
StatefulSet 第二个 Pod 卡在 Pending | 前一个 Pod 尚未达到 Ready 状态 | StatefulSet 默认采用顺序更新,前一个 Pod 成功就绪后才会启动下一个。查看 pod-0 的日志。 |
| Job 不断重复创建新的 Pod | 容器内部命令退出码非 0 报错 | 运行 kubectl describe job 确认 FailuresNum;用 kubectl logs 查看容器失败的具体错误堆栈。 |
| CronJob 到时间未触发 Job | Cron 时间表达式语法错误或时区偏差 | 运行 kubectl get cronjob 查看 SCHEDULE 列与 LAST SCHEDULE 时间戳;检查 concurrencyPolicy 设置。 |
挑战任务:探秘 Job 的失败退避机制
尝试修改 batch.yaml 中的 Job 命令,将其改为 command: ["sh", "-c", "exit 1"] 并重新应用。观察 Pod 的创建频率与重试过程,记录 backoffLimit 是如何拉长重试间隔时间的。验证完成后恢复原 YAML。
7.5.3 清理练习资源
完成验收后,清理本课创建的练习对象(保留第 6 课的 yunfan-web 供下一课使用):
kubectl delete -f batch.yaml
kubectl delete -f long-running.yaml本章小测
本章小结
完成本课后,你已经掌握了:
- 五大控制器选型逻辑:理解了根据运行时间语义、副本扩展依据与身份要求选择不同控制器的必要性。
- DaemonSet 节点守护原理:掌握了 DaemonSet 随节点增减自动维护 Pod 副本的机制。
- StatefulSet 稳定身份:理清了 StatefulSet 的递增序号名称、顺序部署/销毁规则以及配合 Headless Service 产生固定 DNS 域名的原理。
- Job 完成语义与约束:理解了 Job 运行至成功退出的规则,以及
restartPolicy绝不能设为Always的硬性约束。 - CronJob 周期控制:掌握了标准 5 字段 Cron 时间表达式、
concurrencyPolicy3 种并发策略以及手动派生 Job 的调试技巧。
下一课中,我们将为 yunfan-web 构建 Service 服务发现与访问暴露,深入 ClusterIP、NodePort 与 EndpointSlice 的数据包转发全路径!
