16.5.4 StatefulSet与持久化应用
StatefulSet用于管理有状态工作负载,提供稳定网络标识、持久化存储绑定与有序部署/扩缩容能力,适合数据库、消息队列、配置中心等需要稳定身份和数据一致性的场景。
原理草图(StatefulSet + Headless Service + PVC):
核心特性与行为:
- 稳定标识:Pod名称固定为<sts-name>-<ordinal>,重建后名称不变。
- 稳定网络:结合Headless Service提供固定DNS,如mysql-0.mysql-hl.default.svc.cluster.local。
- 稳定存储:volumeClaimTemplates为每个Pod创建独立PVC。
- 有序操作:默认顺序创建/删除,按序滚动更新,保障依赖关系。
关键配置要点(含解释):
- serviceName必须指向Headless Service,确保DNS解析。
- volumeClaimTemplates定义存储规格与访问模式,建议明确storageClassName与容量。
- podManagementPolicy可选OrderedReady或Parallel,影响扩缩容时序。
- updateStrategy建议生产使用RollingUpdate并配置partition做灰度更新。
- readinessProbe与livenessProbe确保仅健康实例对外服务。
示例:部署MySQL StatefulSet(含PVC与Headless Service)
# 文件: /opt/k8s/mysql-hl.yaml
apiVersion: v1
kind: Service
metadata:
name: mysql-hl
spec:
clusterIP: None
selector:
app: mysql
ports:
- port: 3306
name: mysql
---
# 文件: /opt/k8s/mysql-sts.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
spec:
serviceName: mysql-hl
replicas: 2
podManagementPolicy: OrderedReady
updateStrategy:
type: RollingUpdate
rollingUpdate:
partition: 0
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
initContainers:
- name: init-mysql
image: busybox:1.36
command: ["sh","-c","chown -R 999:999 /var/lib/mysql"]
volumeMounts:
- name: data
mountPath: /var/lib/mysql
containers:
- name: mysql
image: mysql:8.0
env:
- name: MYSQL_ROOT_PASSWORD
value: "Root@123"
ports:
- containerPort: 3306
name: mysql
readinessProbe:
exec:
command: ["sh","-c","mysqladmin ping -uroot -pRoot@123"]
initialDelaySeconds: 10
periodSeconds: 5
livenessProbe:
tcpSocket:
port: 3306
initialDelaySeconds: 30
periodSeconds: 10
volumeMounts:
- name: data
mountPath: /var/lib/mysql
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: "standard"
resources:
requests:
storage: 10Gi
部署与验证(命令说明清晰):
# 1) 创建Headless Service
kubectl apply -f /opt/k8s/mysql-hl.yaml
# 2) 创建StatefulSet
kubectl apply -f /opt/k8s/mysql-sts.yaml
# 3) 查看Pod与PVC绑定关系(预期每个Pod对应一个PVC)
kubectl get pods -l app=mysql -o wide
kubectl get pvc -l app=mysql -o wide
# 4) 验证DNS解析(从集群内访问)
kubectl run -it --rm dns-test --image=busybox:1.36 -- sh
# 在容器内执行:
nslookup mysql-0.mysql-hl
扩缩容与有序性验证:
# 将副本扩容到3,观察创建顺序 mysql-2
kubectl scale sts/mysql --replicas=3
kubectl get pods -l app=mysql -w
# 缩容回2,按序删除 mysql-2
kubectl scale sts/mysql --replicas=2
滚动更新与灰度发布示例:
# 将partition设为1,仅更新序号>=1的Pod
kubectl patch sts/mysql -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":1}}}}'
# 更新镜像
kubectl set image sts/mysql mysql=mysql:8.0.36
# 查看更新进度
kubectl rollout status sts/mysql
kubectl get pods -l app=mysql -o wide
排错清单与命令(问题->排查命令->结论):
- PVC Pending:
kubectl get pvc
kubectl describe pvc data-mysql-0
kubectl get sc
结论:检查StorageClass是否存在、Provisioner是否就绪、配额是否充足。
- Pod无法挂载卷:
kubectl describe pod mysql-0
kubectl get events --sort-by=.metadata.creationTimestamp | tail -n 20
结论:查看CSI节点插件日志、节点是否可达、存储后端权限。
- 有序更新过慢:
kubectl get pod mysql-0 -o jsonpath='{.status.containerStatuses[0].ready}{"\n"}'
kubectl describe pod mysql-0 | sed -n '/Readiness probe/,+5p'
结论:优化探针、启动耗时或调整podManagementPolicy为Parallel。
持久化应用实践要点(简明可执行):
- 应用内部复制优先:MySQL主从、Redis哨兵/集群与RWO卷组合。
- 避免多副本写入同一RWX存储,降低写入冲突风险。
- 初始化数据使用initContainers,确保目录权限与基础数据一致。
- 配合Pod反亲和与拓扑约束提升可用性。
练习(含目标与验证):
1) 将上例MySQL从2扩容到3并验证mysql-2的PVC独立性。
验证命令:
kubectl get pvc | grep data-mysql
kubectl exec -it mysql-2 -- sh -c "ls -l /var/lib/mysql | head"
2) 模拟Pod删除并验证数据持久性。
步骤:
kubectl delete pod mysql-0
kubectl wait --for=condition=Ready pod/mysql-0 --timeout=120s
kubectl exec -it mysql-0 -- sh -c "ls -l /var/lib/mysql | head"
预期:数据目录仍存在,PVC未变化。
3) 将podManagementPolicy改为Parallel并观察扩容时序。
验证命令:
kubectl patch sts/mysql -p '{"spec":{"podManagementPolicy":"Parallel"}}'
kubectl scale sts/mysql --replicas=4
kubectl get pods -l app=mysql -w