Kubernetes StatefulSet
StatefulSet 是 Kubernetes 中用于 有状态应用(Stateful Application) 的 Workload 类型,解决以下问题:
Pod 的身份保持(Identity) + 稳定一致的存储(Stable Storage) + 顺序化部署、更新、删除(Ordered Operation)
典型业务场景包括:
- 数据库集群(MySQL、PostgreSQL、MongoDB)
- 分布式协调服务(ZooKeeper、Etcd)
- 存储系统(Ceph、HDFS)
- 需要固定主机名访问的服务(Kafka、RabbitMQ)
Deployment 设计用于无状态应用:
- ❌ Pod 名称随机
- ❌ 存储不固定
- ❌ Pod 会被替换,无法稳定绑定数据
- ❌ 无法保证先启动/先关闭顺序
StatefulSet 则提供:
| 特性 | Deployment | StatefulSet | | Pod 名称稳定 | ❌ | ✅ | | Pod DNS 稳定 | ❌ | ✅ | | Pod 顺序部署 | ❌ | ✅ | | Pod 顺序更新 | ❌ | ✅ | | 固定持久卷 | ❌ | ✅(PVC 自动创建) | | 适合数据库 | ❌ | ✅ |
总结一句话:
StatefulSet 让每个 Pod 都有身份(Identity)+ 数据持久化(Persistence)。
Pod 名字固定:
<statefulset-name>-0
<statefulset-name>-1
<statefulset-name>-2
例如:
mysql-0
mysql-1
mysql-2
重启也不会改变。
借助 Headless Service(必须):
serviceName: mysql
Pod 会有稳定的 DNS:
mysql-0.mysql.default.svc.cluster.local
mysql-1.mysql.default.svc.cluster.local
每个实例都有可直连的域名(数据库非常依赖)。
StatefulSet + volumeClaimTemplates -> 自动生成 PVC:
data-mysql-0
data-mysql-1
data-mysql-2
删除 Pod 不会删除 PVC:
- 数据不丢
- Pod 可以恢复
- 节点不可用时依旧能重建 Pod
StatefulSet 提供:
📌 顺序部署(Create)
- mysql-0 -> mysql-1 -> mysql-2
📌 顺序更新(Update)
- 滚更时逐个更新 Pod
- 新 Pod 必须 Ready 才能继续
📌 顺序删除(Delete)
- mysql-2 -> mysql-1 -> mysql-0
数据库主从切换非常依赖此特性。
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
spec:
serviceName: mysql
replicas: 3
selector:
matchLabels:
app: mysql
updateStrategy:
type: RollingUpdate
podManagementPolicy: OrderedReady # 默认行为
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:8
volumeMounts:
- name: data
mountPath: /var/lib/mysql
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 20Gi
用于为每个 Pod 创建稳定 DNS:
serviceName: mysql
要求绑定一个:
Headless Service:
apiVersion: v1
kind: Service
metadata:
name: mysql
spec:
clusterIP: None
selector:
app: mysql
ports:
- port: 3306
否则 Pod DNS 无法生成。
默认:OrderedReady
- 按顺序启动、更新、删除
- 适合数据库
选项:Parallel
- 并行启动所有 Pod
- 适合 Kafka、RabbitMQ 这种节点间独立性较强的服务
RollingUpdate(默认)
逐个更新 Pod(安全)
OnDelete
手动删除旧 Pod 才更新 用于非常敏感的数据库升级,例如 etcd。
每个 Pod 自动生成独立 PVC:
data-mysql-0
data-mysql-1
data-mysql-2
卷不会随 StatefulSet 删除。
流程图:
创建 StatefulSet
↓
创建 Pod-0
↓
自动创建 PVC-0
↓
调度到 Node
↓
挂载 PV(动态/静态)
↓
Pod 启动
特点:
- Pod 与 PVC 永久绑定
- Pod 重建不影响数据
- 换节点仍会挂回同一 PVC(使用网络存储时)
数据必须固定,Pod 顺序要求强。
Leader/Follower 依赖固定主机名。
每个节点身份不同。
只有 0 号 Pod 可以初始化集群。
每个 broker 有独立日志目录。
每个节点绑定特定磁盘或数据目录。
检查是否缺少 Headless Service:
clusterIP: None
检查存储:
kubectl get pvc
kubectl describe pvc <name>
因为:
- 扩容:新 Pod 如 3->4 会自动创建 PVC
- 缩容:Pod 删除,但 PVC 不会删除
- 再次扩容 -> 绑定回原 PVC
你必须手动删除:
kubectl delete pvc data-mysql-2
防止误删数据。
| 特性 | Deployment | StatefulSet | DaemonSet | | 适用场景 | 无状态应用 | 有状态服务 | 节点 Agent | | Pod 身份 | 无 | 有(固定) | 与节点绑定 | | DNS 稳定 | ❌ | ✅ | ✅ | | 存储 | 可选,非稳定 | 绑定 PVC | 通常使用 hostPath | | 顺序启动 | ❌ | ✅ | ❌ | | 适合数据库 | ❌ | ✅ | ❌ |
clusterIP: None
因为:
- 自动创建
- 自动绑定命名规范
- 不用担心漏写
会导致:
- ❌ 不同 Pod DNS 冲突
- ❌ 端口冲突
- ❌ ClusterIP 无法访问
- 高并发横向扩展型 Web 服务 -> Deployment
- 节点级插件 -> DaemonSet
- 批处理 -> Job
- 定时任务 -> CronJob
StatefulSet
↓
Pod 0 -- PVC-0 -- DNS: mysql-0.mysql
Pod 1 -- PVC-1 -- DNS: mysql-1.mysql
Pod 2 -- PVC-2 -- DNS: mysql-2.mysql
顺序:
创建: 0 -> 1 -> 2
更新: 0 -> 1 -> 2
删除: 2 -> 1 -> 0
每个 Pod 就像有自己 身份证号码 和 独立硬盘。
StatefulSet = 有身份的 Pod + 稳定 DNS + 稳定存储 + 顺序化运维。
用于数据库、队列、协调系统等所有有状态应用。