CFN Cloud
2025-10-10

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、权限、镜像与环境匹配。
  • 上线前具备健康探针与可观测日志。
  • 单副本存储容量规划充足。

收个尾:StatefulSet 的“麻烦”是正常的

有状态服务的升级和恢复,天然就比无状态慢。这不是你配置写错了,而是数据和卷的约束决定的。

上线前你可以简单记三件事:

  • PVC 不是备份:一定要有备份/恢复演练,不然出事只能祈祷。
  • 恢复会慢:卷重新 attach/mount 需要时间,readiness 也要反映真实可用。
  • 升级要分批:别一次滚全量,先从 0 号或小分区开始,观察再推进。

参考链接