StatefulSet 入门
为有状态应用提供稳定身份与存储。
StatefulSet 适合数据库、队列等有状态应用,核心是“稳定身份 + 稳定存储”。每个 Pod 都有固定名称,并绑定独立的 PVC,这让它适合需要持久化数据和稳定网络标识的系统。
本节在基础概念上补充 Headless Service、扩缩容行为、更新策略与运维要点。
适用场景
- 数据库、消息队列、有状态缓存。
- 依赖稳定主机名的服务。
- 每个副本需要独立存储的应用。
典型特性
- Pod 名称固定(如
mysql-0)。 - 与 PVC 一一绑定。
- 有序启动、扩缩容和滚动更新。
- 依赖 Headless Service 提供稳定 DNS。
Headless Service
StatefulSet 必须配合 Headless Service:
apiVersion: v1
kind: Service
metadata:
name: mysql
spec:
clusterIP: None
selector:
app: mysql
ports:
- port: 3306
targetPort: 3306
这样可以得到稳定 DNS,例如 mysql-0.mysql.default.svc.cluster.local。
核心片段
spec:
serviceName: mysql
replicas: 3
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
扩缩容行为
StatefulSet 按序扩容与缩容:扩容从 0 递增,缩容从最大序号开始。这对数据库更安全,但速度比 Deployment 慢。
滚动更新
默认从最大序号开始更新。可通过 updateStrategy 控制:
updateStrategy:
type: RollingUpdate
分区更新与灰度
当你不希望一次性更新所有副本时,可以使用分区策略。分区会让小于指定序号的 Pod 保持旧版本,其余副本更新。这个方式适合有主从拓扑的数据库,可以先更新从节点,验证无误后再推进到主节点。
稳定网络标识与访问方式
StatefulSet 的稳定 DNS 名称对于集群内部发现非常关键。典型模式是写请求走固定主节点,读请求走 Service 做负载均衡。对于需要直连副本的场景,可以通过 pod-ordinal.service.namespace.svc 直接访问指定实例,减少重连时的拓扑混乱。
PVC 命名与扩容
PVC 会按模板名称和序号拼接,例如 data-mysql-0。如果 StorageClass 允许扩容,通常可以在线扩容 PVC,但仍需确认文件系统是否需要额外的扩容步骤。建议在运维文档中记录扩容流程,避免在紧急情况下出错。
访问模式与共享存储
大多数有状态应用使用 ReadWriteOnce,因为每个副本独占一个卷。只有在明确需要共享存储时才考虑 ReadWriteMany,否则多个副本共享同一卷可能导致锁冲突、性能抖动或数据不一致。
Pod 管理策略
如果业务允许并行启动,可设置 podManagementPolicy: Parallel,但需确认应用能接受乱序启动。
存储规划
每个副本都会创建独立 PVC。数据库常用 SSD StorageClass,扩容前要计算总容量需求。
有序启动与就绪细节
StatefulSet 在默认策略下会等待前一个 Pod Ready 才启动下一个。readiness 探针应代表“真正可用”,但也要避免过度严格导致滚动更新卡住。对于需要初始化数据的场景,可以通过 init 容器完成引导,避免主容器在未准备好时接收流量。
探针与就绪
有状态服务的探针更要谨慎。readiness 要确保就绪后再接流量,liveness 不宜过于激进,避免恢复过程被反复重启。
示例说明
以 MySQL 为例,通常包括 Headless Service、Secret、以及 StatefulSet。本质区别是每个副本拥有独立存储和稳定身份。
备份与恢复
PVC 只能保证数据持久化,不能替代备份。建议配合快照、逻辑备份或运维工具定期导出数据,并演练恢复流程。对于有主从复制的系统,恢复顺序与主从切换策略要提前规划。
删除与回收策略
删除 StatefulSet 时 PVC 默认会保留,这是为了防止误删数据。若确实需要回收存储,应明确检查对应 PVC,并结合 StorageClass 的回收策略决定是否自动删除底层卷。
迁移与改造建议
从 Deployment 迁移到 StatefulSet 通常需要重新创建资源并迁移数据。可以先在新 StatefulSet 中创建空数据卷,再通过迁移工具同步数据,最后切换客户端到新的 Headless Service,尽量缩短不可用时间。
资源与性能
数据库等有状态应用对 CPU、内存和磁盘 IO 较为敏感。建议在测试环境压测后确定 requests 和 limits,避免因资源争抢引起延迟抖动。磁盘容量要预留扩容空间,防止满盘导致崩溃。
可观测与告警
监控不仅要看 Pod 状态,还要关注存储使用率、复制延迟、慢查询和磁盘延时。将这些指标与告警策略结合,可以更早发现隐患。
PDB 与维护窗口
通过 PodDisruptionBudget 限制同时被驱逐的副本数,可避免维护时造成服务不可用。维护前应评估副本数与业务承受能力,并在非高峰期执行升级或节点维护。
常见问题
- Pod Pending:PVC 未绑定或 StorageClass 缺失。
- 初始化卡住:应用需要有序启动或数据引导。
- 更新阻塞:readiness 探针失败。
排查命令
kubectl get pods
kubectl get pvc
kubectl describe pod <pod-name>
kubectl get events -A
实操建议
- 先单副本验证,再扩容。
- PVC 不是备份,仍需制定备份策略。
- 使用反亲和性将副本分散到不同节点。
快速检查清单
- 资源定义与业务意图一致。
- Namespace、权限、镜像与环境匹配。
- 上线前具备健康探针与可观测日志。
- 单副本存储容量规划充足。
实战补充
把快速入门应用到真实业务时,建议固定一套检查项:资源 requests、就绪探针、日志覆盖、告警阈值、回滚步骤。清单要短小、可重复,并随仓库一起维护,这样每次发布都能快速对齐标准。
排障路径
从现象入手,不要先猜原因。先看事件,再看日志,最后验证流量路径和配置版本是否一致。若访问异常,先确认 readiness 和 endpoints,再逐段排查入口到后端的链路。记录每一步改动,方便回滚和复盘。
小练习
在测试环境做几次常见操作:扩缩容、重启单个 Pod、调整一项配置并验证效果。通过这些小练习,你能更直观地感受到系统收敛速度和异常时的行为。
维护与责任
明确服务归属、值班人和升级窗口,准备常见故障的处理步骤。依赖服务也需要纳入监控和备份计划,确保问题出现时能快速定位和恢复。
交付提醒
发布后用用户视角快速验证一次:访问核心接口、观察延迟和错误率,确认新旧 Pod 的状态稳定。如果涉及存储或网络,顺手核对磁盘用量、DNS 和 endpoints 是否正常。
回滚预案
写下最小可行的回滚步骤,包括需要恢复的配置、镜像版本和校验方式。这样在出现异常时可以迅速还原,而不是现场临时拼步骤。