StatefulSet 详解:有状态应用的编排与管理
稳定网络标识:固定 Pod 名与 DNS有序部署扩缩:按序创建与逆序删除持久化存储:每 Pod 独立 PVC需要配合 Headless Service 使用。典型场景:数据库(MySQL、PostgreSQL)、缓存集群(Redis)、消息队列(Kafka、RabbitMQ)、分布式协调(ZooKeeper、etcd)等。特性说明网络标识Headless Service + 固定 Pod 名有序性
摘要:数据库、消息队列等有状态应用需要稳定的网络标识和持久存储。StatefulSet 为这类应用提供有序部署、稳定标识和持久存储能力。本文详解 StatefulSet 的三大保证、Pod 管理策略、更新策略、volumeClaimTemplates 机制及与 Deployment 的对比。
一、Deployment vs StatefulSet
Deployment 管理的 Pod 彼此等价、可任意替换,适合无状态服务。StatefulSet 管理的 Pod 具有固定标识和独立存储,适合有状态服务。
上图为 Deployment 与 StatefulSet 的差异。StatefulSet 的 Pod 名称格式为 <name>-<序号>,如 mysql-0、mysql-1、mysql-2,且每个 Pod 绑定独立的 PVC。
二、StatefulSet 的三大保证详解
2.1 稳定的网络标识
Pod 名称格式:<statefulset-name>-<序号>。配合 Headless Service 后,每个 Pod 拥有固定 DNS:<pod-name>.<service-name>.<namespace>.svc.cluster.local。Pod 重建后名称和 DNS 不变。即使 Pod IP 变化,通过 DNS 仍可稳定访问。
2.2 有序的部署和扩缩容
创建顺序:0 → 1 → 2。扩容时需等待前一个 Pod Ready 后再创建下一个。
删除顺序:2 → 1 → 0。缩容时逆序删除,先删除序号最大的 Pod。
该机制确保主从类应用(如 MySQL 主从)能按序建立复制关系。
2.3 持久化存储绑定
每个 Pod 通过 volumeClaimTemplates 绑定独立 PVC。Pod 删除重建后仍绑定同一 PVC,数据得以保留。PVC 命名规则:<volumeClaimTemplate-name>-<statefulset-name>-<序号>。
三、StatefulSet 完整示例
3.1 Headless Service(必须)
apiVersion: v1
kind: Service
metadata:
name: mysql-svc
spec:
clusterIP: None # Headless Service
selector:
app: mysql
ports:
- port: 3306
| 字段 | 说明 |
|---|---|
| clusterIP: None | 声明为 Headless Service,不分配 ClusterIP |
| selector | 与 StatefulSet Pod 标签匹配,用于 DNS 解析 |
3.2 StatefulSet 完整 YAML
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
spec:
serviceName: mysql-svc # 关联 Headless Service
replicas: 3
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:8.0
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: password
volumeMounts:
- name: data
mountPath: /var/lib/mysql
# 卷声明模板 — 自动为每个 Pod 创建独立 PVC
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: fast-ssd
resources:
requests:
storage: 10Gi
| 字段 | 说明 |
|---|---|
| serviceName | 必须,关联 Headless Service |
| volumeClaimTemplates | 为每个 Pod 自动创建 PVC,命名格式为 <name>-<statefulset>-<序号> |
| template | Pod 模板,与 Deployment 类似 |
3.3 验证命令
# 创建 Secret
kubectl create secret generic mysql-secret --from-literal=password=yourpassword
# 部署
kubectl apply -f headless-svc.yaml
kubectl apply -f statefulset.yaml
# 观察有序创建
kubectl get pods -w
# 查看 PVC
kubectl get pvc
# 验证 DNS
kubectl run -it --rm debug --image=busybox -- nslookup mysql-0.mysql-svc
四、Pod 管理策略
| 策略 | 说明 |
|---|---|
| OrderedReady(默认) | 有序创建/删除,前一个 Ready 后才处理下一个 |
| Parallel | 并行创建/删除,不保证顺序 |
spec:
podManagementPolicy: Parallel
Parallel 适用于可独立启动的有状态应用,可加快部署速度;主从类应用建议使用 OrderedReady。
五、更新策略
5.1 RollingUpdate 与 partition
spec:
updateStrategy:
type: RollingUpdate
rollingUpdate:
partition: 1 # 分区更新:只更新序号 >= 1 的 Pod
partition 用于金丝雀发布:partition=2 时,仅 mysql-2 及之后的 Pod 会更新;验证无误后可将 partition 设为 0,完成全部 Pod 的更新。
5.2 OnDelete
spec:
updateStrategy:
type: OnDelete
OnDelete 下,只有 Pod 被手动删除后才会用新镜像重建,适用于需要严格人工控制的场景。
六、volumeClaimTemplates 详解
volumeClaimTemplates 在 StatefulSet 创建时,为每个副本生成一个 PVC。命名规则:<volumeClaimTemplate-name>-<statefulset-name>-<序号>。
| 行为 | 说明 |
|---|---|
| 扩容 | 新 Pod 创建时,自动创建对应 PVC |
| 缩容 | Pod 删除后,PVC 不会自动删除,需手动清理 |
| 重建 | Pod 重建后自动绑定同一 PVC,数据保留 |
七、扩缩容行为
扩容:按序创建,mysql-0 Ready → mysql-1 创建 → mysql-1 Ready → mysql-2 创建。
缩容:逆序删除,先删除 mysql-2,再 mysql-1,最后 mysql-0。缩容不会自动删除 PVC。
上图为 replicas=3 时的部署顺序。每个 Pod 创建前会先创建对应的 PVC(data-mysql-0、data-mysql-1、data-mysql-2)。
八、网络标识详解
Headless Service(clusterIP: None)会为每个 Pod 创建 DNS 记录,格式为 <pod-name>.<service-name>.<namespace>.svc.cluster.local。即使 Pod 重建导致 IP 变化,通过 DNS 仍可稳定访问。
适用于 MySQL 主从等场景:mysql-0 作为主节点,mysql-1、mysql-2 作为从节点,通过固定 DNS 建立复制关系。
九、与 Deployment 的详细对比
| 对比项 | Deployment | StatefulSet |
|---|---|---|
| Pod 名称 | 随机后缀(如 app-abc123) | 固定格式(如 mysql-0) |
| 网络标识 | 通过 Service 负载均衡 | 固定 DNS,每 Pod 可独立访问 |
| 存储 | 共享或无 | 每 Pod 独立 PVC |
| 创建顺序 | 并行 | 有序(可配置 Parallel) |
| 删除顺序 | 无保证 | 逆序 |
| 更新策略 | RollingUpdate / Recreate | RollingUpdate(支持 partition)/ OnDelete |
| 典型场景 | 无状态 Web、API | 数据库、消息队列、分布式协调 |
十、生产环境建议
- Headless Service:必须配置,否则无法获得稳定 DNS
- volumeClaimTemplates:为每个 Pod 分配独立存储,避免数据混用
- 优雅关闭:设置
terminationGracePeriodSeconds,确保应用处理 SIGTERM 并完成复制同步 - 备份策略:StatefulSet 不负责数据备份,需通过 CSI 快照或应用层备份
- 缩容前确认:手动删除 PVC 前务必确认数据已迁移或不需要保留
十一、FAQ
Q1:StatefulSet 扩容时 PVC 不自动创建?
检查 StorageClass 是否存在且 provisioner 正常;查看 StatefulSet controller 日志;确认 volumeClaimTemplates 的 storageClassName 与集群中 StorageClass 名称一致。
Q2:Pod 卡在 Terminating 怎么办?
常见原因:finalizers 未完成、存储未卸载、节点异常。可 kubectl describe pod <name> 查看 Events;若确认可强制删除:kubectl delete pod <name> --force --grace-period=0,注意数据一致性风险。
Q3:StatefulSet 是否必须使用 Headless Service?
是的。Headless Service 提供 Pod 的 DNS 解析,是 StatefulSet 稳定网络标识的前提。
Q4:缩容时 PVC 会被删除吗?数据如何保证持久性?
不会。为保护数据,K8s 不会自动删除 StatefulSet 的 PVC。需手动删除不再使用的 PVC。数据持久性由底层 PV 的回收策略和备份策略保证。
Q5:如何实现 StatefulSet 的零停机滚动更新?
需应用支持优雅关闭和滚动更新。设置 terminationGracePeriodSeconds,确保应用正确处理 SIGTERM;主从类应用还需在断开前完成复制同步。可使用 partition 进行金丝雀发布:先更新从节点,验证无误后再更新主节点。
十二、零停机滚动更新实践
实现 StatefulSet 的零停机滚动更新需满足:
- 应用支持优雅关闭:正确处理 SIGTERM,在
terminationGracePeriodSeconds内完成收尾 - 主从类应用:从节点在断开前完成复制同步
- partition 金丝雀:先更新从节点,验证无误后再更新主节点
spec:
template:
spec:
terminationGracePeriodSeconds: 30
updateStrategy:
type: RollingUpdate
rollingUpdate:
partition: 1 # 先更新 mysql-1、mysql-2,保留 mysql-0
12.1 更新流程示例
- 设置
partition: 2,仅 mysql-2 更新为新镜像 - 验证 mysql-2 运行正常
- 设置
partition: 1,更新 mysql-1 - 验证后设置
partition: 0,更新 mysql-0(主节点)
十三、常用命令
# 查看 StatefulSet
kubectl get statefulset
kubectl get sts
# 扩缩容
kubectl scale statefulset mysql --replicas=5
# 滚动更新(修改镜像)
kubectl set image statefulset/mysql mysql=mysql:8.0.33
# 分区更新
kubectl patch statefulset mysql -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":1}}}}'
# 查看 Pod 顺序
kubectl get pods -l app=mysql
十四、典型应用场景配置
14.1 Redis 集群
Redis 集群需固定节点标识,StatefulSet 可为每个节点分配独立存储与 DNS:
volumeClaimTemplates:
- metadata:
name: redis-data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: standard
resources:
requests:
storage: 5Gi
14.2 Kafka
Kafka Broker 需持久化 topic 分区数据,每 Pod 独立存储,通过固定 DNS 建立 Broker 间通信。
14.3 与 Headless Service 的读写分离
可为 StatefulSet 同时创建普通 Service(负载均衡)和 Headless Service(直接访问):
# 普通 Service:用于读负载均衡
apiVersion: v1
kind: Service
metadata:
name: mysql-read
spec:
selector:
app: mysql
ports:
- port: 3306
---
# Headless Service:用于主从复制等直接访问
apiVersion: v1
kind: Service
metadata:
name: mysql-svc
spec:
clusterIP: None
selector:
app: mysql
ports:
- port: 3306
14.4 terminationGracePeriodSeconds 配置
主从类应用在关闭前需完成复制同步,需设置足够的优雅关闭时间:
spec:
template:
spec:
terminationGracePeriodSeconds: 60
默认 30 秒,MySQL 等应用建议 60 秒以上。应用需在收到 SIGTERM 后停止接受新连接、完成复制同步再退出。
14.5 扩缩容注意事项
- 扩容:新 Pod 会按序创建,每个 Pod 会创建新的 PVC;需确保 StorageClass 的 provisioner 可用
- 缩容:逆序删除 Pod,PVC 保留;若需释放存储,需手动删除 PVC,删除前务必确认数据已备份或不需要
14.6 删除顺序与数据安全
缩容时,StatefulSet 按逆序删除 Pod(先删除序号最大的)。若需缩容时保留某 Pod 的数据,可先备份对应 PVC 的数据,再执行缩容。删除 StatefulSet 时,Pod 会按逆序删除,但 PVC 不会被删除;需手动删除 PVC 才能释放存储。
十五、总结
StatefulSet 适用于有状态应用的编排,主要能力包括:
- 稳定网络标识:固定 Pod 名与 DNS
- 有序部署扩缩:按序创建与逆序删除
- 持久化存储:每 Pod 独立 PVC
需要配合 Headless Service 使用。典型场景:数据库(MySQL、PostgreSQL)、缓存集群(Redis)、消息队列(Kafka、RabbitMQ)、分布式协调(ZooKeeper、etcd)等。
| 特性 | 说明 |
|---|---|
| 网络标识 | Headless Service + 固定 Pod 名 |
| 有序性 | OrderedReady(默认)或 Parallel |
| 更新 | RollingUpdate + partition 金丝雀 |
| 存储 | volumeClaimTemplates 每 Pod 独立 PVC |
更多推荐



所有评论(0)