StatefulSet 有状态应用
StatefulSet 用于管理有状态应用——每个副本都"有身份、有名字、有独立存储",重启后仍然认得自己是谁。数据库、消息队列、注册中心这类需要稳定标识的中间件,通常用它来部署。
与 Deployment 的差异
| 对比点 | Deployment | StatefulSet |
|---|---|---|
| Pod 名称 | 随机后缀,如 app-7d9c5d | 有序编号,如 web-0、web-1 |
| 网络标识 | 无固定 DNS 名 | 有稳定 DNS 名(配合 headless Service) |
| 存储 | 副本共享同一份模板 | 每个副本有独立 PVC |
| 启停顺序 | 无顺序要求 | 按编号顺序启动、逆序优雅删除 |
| 适用 | 无状态应用 | 有状态应用(数据库、注册中心) |
稳定网络标识:序号与 headless Service
StatefulSet 的每个 Pod 名字固定为"控制器名-序号"(从 0 递增),Pod 重建后名字不变,IP 却可能变化,所以再配一个 clusterIP 为 None 的 headless Service,为每个 Pod 提供稳定的 DNS 名:
kubectl get pods -l app=web
# NAME READY STATUS RESTARTS AGE
# web-0 1/1 Running 0 5m
# web-1 1/1 Running 0 4m
kubectl exec web-0 -- hostname
# web-0
# 集群内可用 web-0.web-svc.default.svc 之类域名直连某个实例
YAML 示例:headless Service + StatefulSet
apiVersion: v1
kind: Service
metadata:
name: web-svc
spec:
clusterIP: None # headless:不分配虚拟 IP
selector:
app: web
ports:
- port: 80
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
serviceName: web-svc # 必须绑定 headless Service
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: nginx
image: nginx:1.27
ports:
- containerPort: 80
volumeMounts:
- name: data
mountPath: /usr/share/nginx/html
volumeClaimTemplates: # 为每个副本生成独立 PVC
- metadata:
name: data
spec:
accessModes: [ReadWriteOnce]
resources:
requests:
storage: 1Gi
serviceName 把 StatefulSet 与 headless Service 绑定;volumeClaimTemplates 按模板为每个副本自动创建 PVC(本例生成 data-web-0、data-web-1、data-web-2),写坏的数据不会因为 Pod 重建而丢失。
启动与下线顺序
默认 OrderedReady 策略下,Pod 严格按 0、1、2……顺序启动,前一个 Ready 才启动下一个;缩容或删除时则逆序进行,保证同一时刻只有少数副本在变化:
kubectl scale statefulset web --replicas=5 # 扩容:web-3、web-4 依次就绪
kubectl delete pod web-1 # 重建后名字仍是 web-1,PVC 仍挂回原数据
适用场景
- 需要稳定成员名单与编号的:MySQL 主从、Redis、MongoDB 等数据库集群。
- 需要选举与有序加入的:ZooKeeper、etcd、Consul 等注册与协调服务。
- 每个实例必须有独享存储的应用。
如果应用完全无状态(任何副本可互换、数据放外部存储),Deployment 更简单;只有"实例必须认识自己、数据不能混用"时才上 StatefulSet。
小结:StatefulSet 用"固定序号名字 + headless Service + volumeClaimTemplates"换来三个稳定:稳定标识、稳定 DNS、稳定存储。代价是没有 Deployment 那么随意——启停有序、缩容逆序,适合把数据库这类敏感应用搬上集群的场景。