Kubernetes StatefulSet 详细总结
1. StatefulSet 概述
StatefulSet 是 Kubernetes 中用于管理有状态应用的工作负载 API 对象。与 Deployment 不同,StatefulSet 为每个 Pod 维护一个粘性标识,确保 Pod 的有序部署、扩展、更新和删除。
主要特点:
- 稳定的网络标识:每个 Pod 有固定的主机名和 DNS 名称
- 稳定的持久化存储:使用 PersistentVolume 为每个 Pod 提供专用存储
- 有序的部署和扩展:按顺序创建/删除 Pod(从 0 到 N-1)
- 有序的滚动更新:按顺序更新 Pod(从 N-1 到 0)
2. StatefulSet 核心概念
2.1 Pod 标识
- 稳定的主机名:Pod 名称为
<statefulset-name>-<ordinal-index>
- 稳定的 DNS:
<pod-name>.<service-name>.<namespace>.svc.cluster.local
2.2 持久化存储
- 使用
volumeClaimTemplates
为每个 Pod 自动创建 PVC - 每个 Pod 获得自己独立的 PersistentVolume
2.3 有序性保证
- 创建、扩展、删除和更新都遵循严格的顺序
- 前一个 Pod 必须 Running & Ready 才会处理下一个
3. StatefulSet 典型使用场景
- 数据库集群:如 MySQL 主从、MongoDB 副本集等
- 分布式系统:如 ZooKeeper、etcd、Elasticsearch 等
- 需要持久化存储的应用:如消息队列、文件存储服务等
- 需要稳定网络标识的应用:如需要固定 IP/DNS 的服务
4. StatefulSet 配置详解
4.1 基本配置示例
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.19
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 1Gi
4.2 关键字段解释
- serviceName: 必须指定,用于 Pod 的网络标识
- volumeClaimTemplates: 定义 PVC 模板,为每个 Pod 创建独立的 PVC
- podManagementPolicy:
OrderedReady
(默认): 有序创建/删除Parallel
: 并行创建/删除 Pod
5. StatefulSet 操作
5.1 创建 StatefulSet
kubectl apply -f statefulset.yaml
5.2 查看 StatefulSet
kubectl get statefulset
kubectl describe statefulset <name>
5.3 扩缩容
kubectl scale statefulset <name> --replicas=5
5.4 更新 StatefulSet
kubectl edit statefulset <name>
# 或
kubectl apply -f updated-statefulset.yaml
5.5 删除 StatefulSet
kubectl delete statefulset <name>
# 可选择是否删除关联的 Pod
kubectl delete statefulset <name> --cascade=orphan
6. StatefulSet 网络与服务
6.1 Headless Service
StatefulSet 通常配合 Headless Service 使用:
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
clusterIP: None # 这是 Headless Service 的关键
selector:
app: nginx
ports:
- port: 80
name: web
6.2 DNS 记录
每个 Pod 会获得如下 DNS 记录:
web-0.nginx.default.svc.cluster.local
web-1.nginx.default.svc.cluster.local
- …
7. StatefulSet 存储管理
7.1 卷声明模板
volumeClaimTemplates
为每个 Pod 创建 PVC:
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
7.2 持久化存储生命周期
- StatefulSet 删除时,PVC 默认保留
- 需要手动删除 PVC 来释放 PV
8. StatefulSet 更新策略
8.1 更新类型
- RollingUpdate (默认): 顺序更新 Pod
- OnDelete: 手动删除 Pod 时触发更新
8.2 分区更新
可以指定分区进行金丝雀发布:
updateStrategy:
type: RollingUpdate
rollingUpdate:
partition: 2 # 只有序号 >=2 的 Pod 会被更新
9. StatefulSet 与 Deployment 对比
特性 | StatefulSet | Deployment |
---|---|---|
Pod 标识 | 稳定、有序 | 随机 |
存储 | 独立持久化存储 | 通常无或共享存储 |
网络 | 稳定 DNS 和主机名 | 不保证稳定 |
扩展顺序 | 有序扩展 (0→N-1) | 无序 |
更新策略 | 有序或分区更新 | 多种策略 (RollingUpdate等) |
使用场景 | 有状态应用 | 无状态应用 |
10. 最佳实践
- 始终定义 serviceName: 确保稳定的网络标识
- 合理设置资源请求和限制: 特别是数据库类应用
- 考虑使用反亲和性: 避免 Pod 集中在同一节点
- 备份持久化数据: StatefulSet 删除不会自动删除 PVC
- 监控就绪探针: 确保有序操作的正确性
- 考虑 Pod 中断预算: 保证最小可用实例数
11. 常见问题与解决方案
Q1: StatefulSet Pod 卡在 Terminating 状态
- 原因: 通常是由于 PV 无法卸载
- 解决: 检查存储插件或强制删除 Pod (
kubectl delete pod <name> --grace-period=0 --force
)
Q2: 扩展 StatefulSet 速度慢
- 原因: 有序创建,前一个 Pod 必须 Ready 才会创建下一个
- 解决: 确保应用快速启动,或考虑使用
podManagementPolicy: Parallel
Q3: 如何替换失败的 Pod
kubectl delete pod web-2
# StatefulSet 会自动创建同名 Pod 并挂载原有 PVC
12. 高级特性解析
12.1 初始化容器 (Init Containers)
作用: 初始化容器在主应用容器启动之前运行,用于准备应用运行所需的环境或配置。
典型用途:
- 等待依赖服务就绪(如数据库)
- 从远程仓库下载配置文件或密钥
- 设置文件系统权限
- 执行数据库迁移等初始化操作
示例中的用法:
initContainers:
- name: init
image: busybox
command: ['sh', '-c', '...']
这里使用 busybox 镜像运行一个 shell 命令来执行初始化任务。
12.2 拓扑分布约束 (Topology Spread Constraints)
作用: 控制 Pod 在集群中的分布策略,确保 Pod 在不同拓扑域(如节点、区域等)中均匀分布。
关键参数:
maxSkew
: 允许的不平衡程度(必须大于0)topologyKey
: 节点标签的键,用于定义拓扑域(如 “zone”、“hostname”)whenUnsatisfiable
: 无法满足约束时的行为(DoNotSchedule 或 ScheduleAnyway)labelSelector
: 用于匹配要约束的 Pod
示例中的用法:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app: nginx
这表示 nginx Pod 在不同 zone 之间的数量差异不超过 1,如果无法满足就不调度。
12.3 Pod 生命周期钩子 (Lifecycle Hooks)
作用: 允许在容器生命周期的特定阶段执行自定义操作。
两种钩子:
postStart
: 容器启动后立即执行preStop
: 容器终止前执行
示例中的用法:
lifecycle:
postStart:
exec:
command: ["/bin/sh", "-c", "echo Hello from postStart > /usr/share/message"]
preStop:
exec:
command: ["/bin/sh", "-c", "nginx -s quit"]
- postStart: 容器启动后写入欢迎消息
- preStop: 容器停止前优雅关闭 nginx
评论需开启科学上网!