在前面的文章中,我们重点学习了 Kubernetes 中最常见的无状态工作负载 Deployment,它凭借 ReplicaSet 与滚动更新机制,成为了绝大多数 Web 应用部署的首选。然而真实的生产环境远比”无状态服务”复杂得多:数据库需要稳定的网络标识与持久化存储,日志采集组件需要每个节点都运行一份,而批量任务则需要”跑完即退出”的一次性执行语义。这些场景下,单纯使用 Deployment 会显得捉襟见肘。
今天我们就来学习 Kubernetes 中另外三类进阶工作负载:StatefulSet(有状态应用)、DaemonSet(节点级守护进程) 与 Job/CronJob(一次性与定时任务)。掌握这三类对象之后,你将能够覆盖生产环境中绝大多数的应用编排形态,真正具备”用什么、怎么选”的判断能力。

一、认识三类进阶工作负载
1.1 StatefulSet:为有状态应用而生
Deployment 管理的 Pod 是无状态的,它们共享同一个 Pod 模板,可以随意销毁重建,Pod 名称也是随机后缀。但对于 MySQL、Redis、Kafka、ZooKeeper 这类有状态应用来说,稳定身份、稳定存储、有序部署是刚需。StatefulSet 正是为此设计,它保证:
- 稳定的网络标识:Pod 名称固定为
<statefulset-name>-<序号>,例如mysql-0、mysql-1,即使 Pod 重建名称也不会变。 - 稳定的存储:每个 Pod 对应一个独立的 PVC(PersistentVolumeClaim),Pod 重建后依然绑定同一块存储卷。
- 有序的部署与扩缩容:Pod 严格按照序号顺序创建与删除,
mysql-0就绪后才会创建mysql-1。
1.2 DaemonSet:每个节点运行一份
有些组件需要在集群的每一个节点上都运行一个副本,例如日志采集器 Fluentd、监控探针 Node Exporter、网络插件 Calico 的 calico-node。DaemonSet 会自动在新加入的节点上创建 Pod,并在节点下线时清理对应 Pod。它与 Deployment 的本质区别在于:副本数量不是由 replicas 指定,而是由节点数量决定。
1.3 Job 与 CronJob:一次性与定时任务
Job 用于运行一次性任务,任务完成后 Pod 退出并保持完成状态,例如数据迁移、模型训练、备份脚本。CronJob 则在 Job 之上增加了类似 Linux crontab 的定时调度能力,适合周期性的清理、报表生成、快照备份等场景。
二、实战步骤
2.1 部署一个 StatefulSet
下面以 Nginx 为例演示 StatefulSet 的稳定身份与存储。首先创建一个 Headless Service(无头服务),它是 StatefulSet 稳定网络标识的基础:
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: nginx
接着定义 StatefulSet,通过 volumeClaimTemplates 为每个 Pod 动态创建独立 PVC:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
serviceName: "nginx"
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.25
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 1Gi
应用上述 YAML 并观察 Pod 的有序创建过程:
kubectl apply -f statefulset.yaml
kubectl get pods -w -l app=nginx
# 输出会看到 web-0、web-1、web-2 依次进入 Running 状态
kubectl get pvc
# 每个 Pod 都生成了独立的 PVC:www-web-0、www-web-1、www-web-2
2.2 部署一个 DaemonSet
下面部署一个使用 BusyBox 的 DaemonSet,它会自动在每个节点上运行一个 Pod:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-logger
labels:
app: node-logger
spec:
selector:
matchLabels:
app: node-logger
template:
metadata:
labels:
app: node-logger
spec:
tolerations:
- key: node-role.kubernetes.io/control-plane
operator: Exists
effect: NoSchedule
containers:
- name: logger
image: busybox:1.36
args: ["sh", "-c", "while true; do echo $(hostname) $(date); sleep 60; done"]
注意上面的 tolerations 配置,它让 DaemonSet 也能调度到带有控制面污点的 master 节点上。查看部署结果:
kubectl apply -f daemonset.yaml
kubectl get ds node-logger
kubectl get pods -o wide -l app=node-logger
# 观察 DESIRED 与 READY 数量是否等于节点数量
2.3 运行 Job 与 CronJob
先运行一个简单的一次性 Job,用于计算圆周率并输出结果:
apiVersion: batch/v1
kind: Job
metadata:
name: pi
spec:
backoffLimit: 4
template:
spec:
restartPolicy: Never
containers:
- name: pi
image: perl:5.34
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
再创建一个 CronJob,每天凌晨 2 点执行一次数据备份任务:
apiVersion: batch/v1
kind: CronJob
metadata:
name: daily-backup
spec:
schedule: "0 2 * * *"
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: backup
image: alpine:3.18
command: ["/bin/sh", "-c", "echo running backup; sleep 30"]
查看 Job 与 CronJob 的执行状态:
kubectl apply -f job.yaml -f cronjob.yaml
kubectl get jobs
kubectl get cronjobs
kubectl logs job/pi
三、常见问题
Q1:StatefulSet 的 Pod 删除了,数据会丢吗?
不会。StatefulSet 的 PVC 与 Pod 生命周期解耦,即使 Pod 被删除重建,它依然会重新绑定到原来那块 PVC,数据得以保留。只有当 PVC 本身被删除时,底层存储才会被回收(取决于 StorageClass 的回收策略)。
Q2:为什么 StatefulSet 必须配合 Headless Service?
Headless Service(clusterIP: None)不会做负载均衡,而是为每个 Pod 提供独立的 DNS 记录(如 web-0.nginx.default.svc.cluster.local),这是有状态应用实现主从复制、数据分片时互相定位的关键。
Q3:DaemonSet 可以只部署到部分节点吗?
可以,通过 nodeSelector 或 nodeAffinity 来限定目标节点,例如只让日志采集器运行在标记了 logging=true 的节点上。
Q4:Job 的 restartPolicy 为什么不能设为 Always?
因为 Job 需要”任务完成后 Pod 退出”,而 Always 策略会导致容器失败时无限重启,任务永远无法判定完成。Job 的 Pod 只能使用 Never 或 OnFailure。
四、总结
今天我们从”无状态”走向了”有状态、节点级、批处理”三类更复杂的编排形态。StatefulSet 用稳定身份与稳定存储支撑数据库等有状态服务;DaemonSet 保证守护组件覆盖集群每一个节点;Job 与 CronJob 则补齐了一次性与定时任务的能力。理解这三类对象与 Deployment 的差异,是判断”某个应用该用什么控制器部署”的基础,也是进阶到有状态应用运维与定时任务体系的关键一步。
下期预告:第 17 天我们将进入高可用集群的世界,深入剖析 etcd 集群与控制平面(kube-apiserver、kube-controller-manager、kube-scheduler)的 HA 部署方案,让你的集群告别单点故障。敬请期待!


















暂无评论内容