StatefulSet 有状态应用
Deployment 解决了无状态应用的部署问题。但对于有状态应用呢?
- 数据库:MySQL 主从集群,需要固定的 hostnames
- 消息队列:Kafka 分区与消费者的对应关系需要稳定
- 分布式存储:Ceph、MinIO 的节点需要有持久化的身份
StatefulSet 就是为这些场景设计的。
StatefulSet vs Deployment
创建 StatefulSet
statefulset.yaml
StatefulSet 核心特性
稳定网络标识
StatefulSet Pod 的主机名格式为:{statefulset-name}-{ordinal}。
例如,名为 mysql 的 StatefulSet,其 Pod 名称为 mysql-0、mysql-1、mysql-2。
Headless Service
StatefulSet 通常需要配合 Headless Service 使用:
headless-service.yaml
Headless Service 的 DNS 解析会直接返回 Pod IP:
稳定存储
StatefulSet 使用 volumeClaimTemplates 为每个 Pod 创建独立的 PVC:
即使 Pod 被删除并重新调度,相同的 PVC 会被重新绑定(如果存在):
有序部署与扩缩容
Pod 管理策略
OrderedReady(默认)
Pod 按照 ordinal 顺序创建/删除,每个 Pod 必须 Ready 后才能进行下一个操作。
Parallel
Pod 并行创建/删除,不等待前一个 Pod Ready。适用于可以容忍乱序的场景。
更新策略
StatefulSet 支持三种更新策略:
扩缩容
Danger
缩容 StatefulSet 不会删除 PVC,数据仍然保留。但如果扩容时原来的 PVC 已被其他应用使用,可能导致问题。
分步缩容
对于有状态应用,建议手动分步缩容:
常见使用场景
MySQL 主从复制
mysql-statefulset.yaml
Kafka 集群
kafka-statefulset.yaml
常见问题
Pod 无法启动
PVC 无法绑定
数据丢失
缩容 StatefulSet 时:
- 确保数据已备份:缩容前备份重要数据
- 手动缩容:逐个删除 Pod,确保数据安全
- 保留 PVC:缩容后 PVC 不会自动删除,数据仍然保留
最佳实践
1. 使用合理的副本数
- 最小化部署:1 个副本(测试环境)
- 高可用部署:至少 3 个副本
2. 配置持久存储
3. 设置合适的终止gracePeriod
4. 配置健康检查
延伸思考
StatefulSet 是 Kubernetes 处理有状态应用的基础抽象。它的设计哲学是:
- 稳定性优先:网络标识和存储的稳定比什么都重要
- 有序操作:确保数据一致性的关键
- 独立存储:每个 Pod 都有自己的存储空间
但 StatefulSet 也有局限性:
- 不支持自动故障转移:如果某个 Pod 崩溃,不会自动在新节点上创建
- 不支持分片:需要应用自己处理数据分片
- 运维复杂:备份、恢复、升级都需要额外考虑
对于更复杂的有状态应用,可以考虑 Operator 模式,如 Prometheus Operator、Cassandra Operator 等。
延伸阅读
- Deployment 与 ReplicaSet:无状态应用的部署
- Volume 与 PVC/PV:持久化存储
- Operator 模式深度解析:如何管理复杂的有状态应用