跳到正文
复制成功
请遵守本站许可
报告
章节_文章 // 现场报告

文章编号: RL-STATEFUL

2026.07.20

StatefulSet:有状态应用管理

Chavy
Chavy
#Kubernetes#StatefulSet#有状态应用
档案

摘要:通过稳定网络身份、独立持久化存储和有序生命周期理解 StatefulSet,掌握更新策略、分区发布、扩缩容与常见故障排查。

本节学习 Kubernetes 中用于管理有状态应用的核心控制器——StatefulSet。

Deployment 主要用于管理无状态应用。

但在实际生产环境中,还有很多应用不能简单地通过删除旧 Pod、创建新 Pod 来替换。

例如:

  • MySQL 数据库
  • Redis 集群
  • Kafka 消息队列
  • ZooKeeper 集群
  • Elasticsearch 集群

这些应用通常需要稳定的网络身份、独立的数据存储,以及特定的启动和关闭顺序。

这就是 StatefulSet 存在的意义。


一、为什么需要 StatefulSet?#

1. Deployment 的局限性#

先回顾 Deployment。

假设我们部署一个有 3 个副本的 Web 应用:

flowchart TB
    N0["Deployment"]
    N1["ReplicaSet"]
    N2["Pod-A"]
    N3["Pod-B"]
    N4["Pod-C"]
    N0 --> N1
    N1 --> N2
    N1 --> N3
    N1 --> N4

这些 Pod 通常具有以下特点:

  • 可以被随时替换。
  • 不要求固定的 Pod 名称。
  • 不要求固定的网络身份。
  • 可以根据需要扩容和缩容。
  • 应用状态通常保存在外部数据库或共享存储中。

例如:

Pod-A 删除后,Deployment 创建的新 Pod 可能叫 Pod-D。

这对于无状态 Web 服务没有问题。

但是考虑数据库:

PRTCL // TEXT
MySQL 集群
mysql-0
mysql-1
mysql-2

假设 mysql-1 保存着某个节点特有的数据或承担固定的集群角色。

如果它被删除后,重新创建成一个完全不同身份的 Pod,就可能给集群成员识别、数据挂载和复制关系带来问题。

因此,有状态应用需要更加稳定的身份管理。

2. StatefulSet 的核心设计#

StatefulSet 是 Kubernetes 用于管理有状态应用的工作负载控制器。

它为每个 Pod 提供:

  1. 稳定的名称。
  2. 稳定的网络标识。
  3. 稳定的持久化存储关联。
  4. 有序的创建和删除机制(默认模式)。

例如:

flowchart TB
    N0["StatefulSet"]
    N1["Pod-0"]
    N2["Pod-1"]
    N3["Pod-2"]
    N4["PVC-0"]
    N5["PVC-1"]
    N6["PVC-2"]
    N7["PV-0"]
    N8["PV-1"]
    N9["PV-2"]
    N0 --> N1
    N0 --> N2
    N0 --> N3
    N1 --> N4
    N2 --> N5
    N3 --> N6
    N4 --> N7
    N5 --> N8
    N6 --> N9

注意:

每个 Pod 都可以拥有自己独立的 PVC,并关联自己的持久化卷。

这使得 Pod 被删除后,重新创建的同名 Pod 可以重新使用原来的 PVC。


二、StatefulSet 与 Deployment 的区别#

这是 CKA 必须掌握的知识点。

对比维度DeploymentStatefulSet
主要用途无状态应用有状态应用
Pod 名称通常不固定稳定、有序
Pod 身份可替换稳定
网络标识通常不固定稳定
存储关联通过 PVC 等方式配置可通过模板为每个 Pod 创建独立 PVC
创建顺序通常不保证默认有序
删除顺序不保证默认逆序
扩缩容支持支持

例如:

Deployment:

PRTCL // TEXT
nginx-7d8f9c-abc12
nginx-7d8f9c-def34
nginx-7d8f9c-ghi56

StatefulSet:

PRTCL // TEXT
mysql-0
mysql-1
mysql-2

StatefulSet 的名称由 StatefulSet 名称和序号组成。

序号默认从 0 开始。

重点:StatefulSet 并不是只能用于数据库,而是适合任何需要稳定身份或有序管理的应用。


三、StatefulSet 的稳定网络标识#

这是 StatefulSet 的核心知识之一。

1. 为什么需要 Headless Service?#

StatefulSet 通常需要配合 Headless Service 使用。

先了解普通 Service。

普通 ClusterIP Service:

flowchart TB
    N0["Client"]
    N1["ClusterIP Service"]
    N2["Pod-0"]
    N3["Pod-1"]
    N4["Pod-2"]
    N0 --> N1
    N1 --> N2
    N1 --> N3
    N1 --> N4

普通 Service 提供一个稳定的虚拟 IP,客户端通过 Service 访问后端 Pod。

但是对于数据库集群,客户端可能需要直接定位某一个具体的 Pod。

例如:

  • mysql-0 是主节点。
  • mysql-1 是从节点。
  • mysql-2 是从节点。

这时仅有一个统一的 Service IP 不够方便。

因此可以使用 Headless Service。

2. Headless Service 是什么?#

Headless Service 是一种没有 ClusterIP 的 Service。

定义方式:

PRTCL // YAML
spec:
clusterIP: None

例如:

PRTCL // YAML
apiVersion: v1
kind: Service
metadata:
name: mysql
spec:
clusterIP: None
selector:
app: mysql
ports:
- port: 3306
targetPort: 3306

它的特点:

  • 不分配普通 ClusterIP。
  • 不提供普通 ClusterIP Service 的虚拟 IP 负载均衡入口。
  • DNS 可以返回符合条件的 Pod 地址。
  • 可以通过 DNS 直接定位具体 Pod。

3. StatefulSet 的 DNS 命名规则#

假设:

PRTCL // TEXT
StatefulSet 名称:mysql
Headless Service:mysql
Namespace:default
Cluster Domain:cluster.local

Pod 的稳定 DNS 名称:

PRTCL // TEXT
<Pod 名称 >.<Headless Service 名称 >.<Namespace>.svc.<Cluster Domain>

因此:

PRTCL // TEXT
mysql-0.mysql.default.svc.cluster.local
mysql-1.mysql.default.svc.cluster.local
mysql-2.mysql.default.svc.cluster.local

即使 mysql-1 被删除后重新创建,只要它重新加入同一个 StatefulSet,其稳定 DNS 名称仍然是:

PRTCL // TEXT
mysql-1.mysql.default.svc.cluster.local

注意:DNS 记录的实际可解析性还取决于 Pod 是否满足 DNS 发布条件、Service 配置以及集群 DNS 状态。


四、StatefulSet 的持久化存储#

这是 StatefulSet 最重要的功能之一。

  • PV(PersistentVolume):持久化存储资源。
  • PVC(PersistentVolumeClaim):存储申请。
  • StorageClass:动态创建存储资源的机制。

StatefulSet 可以通过 volumeClaimTemplates 自动为每个 Pod 创建独立 PVC。

1. 为什么每个 Pod 需要独立存储?#

假设有一个 MySQL 集群:

PRTCL // TEXT
mysql-0:保存数据 A
mysql-1:保存数据 B
mysql-2:保存数据 C

如果三个 Pod 共用同一个数据目录,可能造成数据冲突,甚至破坏数据库的数据一致性。

因此通常采用:

PRTCL // TEXT
mysql-0 ---- PVC-mysql-0 ---- PV-0
mysql-1 ---- PVC-mysql-1 ---- PV-1
mysql-2 ---- PVC-mysql-2 ---- PV-2

每个 Pod 都有自己的 PVC。

2. volumeClaimTemplates#

这是 StatefulSet 特有的重要字段。

示例:

PRTCL // YAML
volumeClaimTemplates:
- metadata:
name: mysql-data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: standard

含义:

  • name:PVC 模板名称。
  • accessModes:存储访问模式。
  • requests.storage:申请存储容量。
  • storageClassName:使用的存储类。

当 StatefulSet 创建 Pod 时,会自动创建对应 PVC。

例如:

PRTCL // TEXT
StatefulSet: mysql
Pod: mysql-0
PVC: mysql-data-mysql-0
Pod: mysql-1
PVC: mysql-data-mysql-1
Pod: mysql-2
PVC: mysql-data-mysql-2

注意 PVC 名称规则:

PRTCL // TEXT
<volumeClaimTemplates 名称 >-<StatefulSet 名称 >-<Pod 序号 >

3. Pod 删除后,PVC 会怎样?#

这是一个非常重要的生产知识点。

假设:

flowchart TB
    N0["mysql-0"]
    N1["mysql-data-mysql-0"]
    N2["PV-0"]
    N0 --> N1
    N1 --> N2

现在删除 Pod:

PRTCL // BASH
Terminal window
kubectl delete pod mysql-0

通常:

  • mysql-0 被删除。
  • mysql-data-mysql-0 保留。
  • PV-0 仍然保留,具体取决于存储及回收策略。
  • StatefulSet 创建新的 mysql-0。
  • 新的 mysql-0 重新挂载原来的 PVC。

重点

删除 StatefulSet 管理的 Pod,默认不会删除其 PVC。

因此,Pod 重建后通常可以重新使用原有数据。

4. StatefulSet 删除后,PVC 会怎样?#

默认情况下,即使删除 StatefulSet,volumeClaimTemplates 创建的 PVC 也会保留。

例如:

PRTCL // BASH
Terminal window
kubectl delete statefulset mysql

StatefulSet 被删除,但 PVC 默认不会因此自动删除。

这样设计是为了保护有状态应用的数据。

如果希望管理 PVC 的保留和删除行为,可以使用:

PRTCL // YAML
spec:
persistentVolumeClaimRetentionPolicy:
whenDeleted: Retain
whenScaled: Retain

支持两种策略:

策略含义
Retain保留 PVC
Delete删除符合条件的 PVC

其中:

  • whenDeleted:删除 StatefulSet 时的 PVC 处理策略。
  • whenScaled:缩容时,被移除 Pod 对应 PVC 的处理策略。

默认两者都是 Retain。

注意:PVC 被删除不等于底层数据一定立即销毁。PV 的回收行为还取决于 PV 的 persistentVolumeReclaimPolicy,例如 Retain 或 Delete。


五、StatefulSet 的有序管理机制#

这是 StatefulSet 与 Deployment 的另一个重要区别。

StatefulSet 默认采用有序创建和删除机制。

1. OrderedReady(默认策略)#

配置:

PRTCL // YAML
spec:
podManagementPolicy: OrderedReady

创建时:

flowchart TB
    N0["创建 mysql-0"]
    N1["mysql-0 Ready"]
    N2["创建 mysql-1"]
    N3["mysql-1 Ready"]
    N4["创建 mysql-2"]
    N0 --> N1
    N1 --> N2
    N2 --> N3
    N3 --> N4

删除时:

flowchart TB
    N0["删除 mysql-2"]
    N1["删除 mysql-1"]
    N2["删除 mysql-0"]
    N0 --> N1
    N1 --> N2

也就是说:

  • 创建顺序:从小到大。
  • 删除顺序:从大到小。
  • 扩容时:从当前最大序号继续增加。
  • 缩容时:从最大序号开始移除。

例如,从 3 个副本扩容到 5 个:

PRTCL // TEXT
mysql-0
mysql-1
mysql-2
mysql-3
mysql-4

默认情况下,需要前一个 Pod 达到 Ready,才会继续创建下一个 Pod。

2. Parallel(并行策略)#

如果不希望 Pod 按顺序创建,可以使用:

PRTCL // YAML
spec:
podManagementPolicy: Parallel

这样:

  • 创建时可以并行创建 Pod。
  • 删除时也可以并行删除 Pod。
  • 不再要求前一个 Pod Ready 后才创建下一个 Pod。

对比:

特性OrderedReadyParallel
创建方式顺序创建并行创建
删除方式逆序删除并行删除
默认策略是否
适用场景有顺序要求的应用不依赖启动顺序的应用

注意:podManagementPolicy 主要影响扩缩容过程中的 Pod 创建和删除,不改变 StatefulSet 的稳定身份机制,也不改变其滚动更新策略。


六、StatefulSet 更新策略#

StatefulSet 也需要升级应用版本。

例如:

flowchart TB
    N0["nginx:1.27"]
    N1["nginx:1.28"]
    N0 --> N1

StatefulSet 主要有两种更新策略:

  1. RollingUpdate
  2. OnDelete

1. RollingUpdate#

默认更新策略。

PRTCL // YAML
spec:
updateStrategy:
type: RollingUpdate

假设当前有:

PRTCL // TEXT
mysql-0
mysql-1
mysql-2

升级时默认按照逆序更新:

flowchart TB
    N0["mysql-2"]
    N1["mysql-2 更新完成并 Ready"]
    N2["mysql-1 更新"]
    N3["mysql-1 更新完成并 Ready"]
    N4["mysql-0 更新"]
    N0 --> N1
    N1 --> N2
    N2 --> N3
    N3 --> N4

注意:

StatefulSet 默认滚动更新顺序是从最大序号到最小序号。

2. OnDelete#

配置:

PRTCL // YAML
spec:
updateStrategy:
type: OnDelete

含义:

修改 StatefulSet 的 Pod 模板后,不会自动删除旧 Pod。

需要手动删除旧 Pod:

PRTCL // BASH
Terminal window
kubectl delete pod mysql-2

StatefulSet 才会根据最新模板重新创建 mysql-2。

这种方式适合需要人工控制每个实例升级时间的场景。

3. RollingUpdate 与 OnDelete 对比#

对比RollingUpdateOnDelete
自动更新是否
更新顺序默认逆序手动控制
适用场景常规升级人工控制升级
是否需要手动删除 Pod不需要需要

七、StatefulSet 高级更新:Partition(分区更新)#

这是 StatefulSet 的进阶知识点,也是生产环境中实用的灰度升级机制。

1. 什么是 Partition?#

Partition 可以控制 StatefulSet 滚动更新时,哪些 Pod 需要升级。

例如:

当前有 5 个副本:

PRTCL // TEXT
mysql-0
mysql-1
mysql-2
mysql-3
mysql-4

配置:

PRTCL // YAML
spec:
updateStrategy:
type: RollingUpdate
rollingUpdate:
partition: 3

含义:

只更新序号大于或等于 3 的 Pod。

因此:

PRTCL // TEXT
mysql-0 旧版本
mysql-1 旧版本
mysql-2 旧版本
mysql-3 新版本
mysql-4 新版本

这实际上是一种按照 Pod 序号控制更新范围的机制。

2. Partition 的工作原理#

假设:

PRTCL // YAML
replicas: 5
updateStrategy:
type: RollingUpdate
rollingUpdate:
partition: 3

更新镜像:

PRTCL // BASH
Terminal window
kubectl set image statefulset/mysql nginx=nginx:1.28

结果:

Pod是否更新
mysql-0否
mysql-1否
mysql-2否
mysql-3是
mysql-4是

如果后续将 Partition 修改为 0:

PRTCL // YAML
partition: 0

那么所有 Pod 都会逐步更新到新版本。

3. Partition 的应用场景#

例如:

数据库集群有 5 个节点。

你不想一次性升级所有节点,而是:

  1. 先升级部分节点。
  2. 验证应用运行情况。
  3. 确认没有问题。
  4. 再逐步升级剩余节点。

这就是 Partition 的价值。

注意:Partition 只控制 StatefulSet 的 Pod 更新范围,不会自动判断数据库主从角色,也不等同于完整的金丝雀发布系统。


八、StatefulSet 扩容与缩容#

1. 扩容#

假设当前有三个副本:

PRTCL // TEXT
mysql-0
mysql-1
mysql-2

扩容到五个:

PRTCL // BASH
Terminal window
kubectl scale statefulset mysql --replicas=5

默认 OrderedReady 策略下:

PRTCL // TEXT
mysql-0
mysql-1
mysql-2
mysql-3
mysql-4

新增两个 Pod,并为其创建独立 PVC。

2. 缩容#

缩容到两个:

PRTCL // BASH
Terminal window
kubectl scale statefulset mysql --replicas=2

默认有序策略下:

PRTCL // TEXT
删除 mysql-4
删除 mysql-3

最终保留:

PRTCL // TEXT
mysql-0
mysql-1

注意:默认情况下,mysql-3 和 mysql-4 对应的 PVC 会保留。

3. 为什么缩容不会自动删除 PVC?#

因为 StatefulSet 默认优先保护数据。

例如:

flowchart TB
    N0["mysql-2"]
    N1["mysql-data-mysql-2"]
    N0 --> N1

缩容时 Pod 被删除,但 PVC 保留。

以后再次扩容到三个副本时:

flowchart TB
    N0["重新创建 mysql-2"]
    N1["重新挂载 mysql-data-mysql-2"]
    N0 --> N1

这样可以避免因为缩容而直接丢失数据库数据。

生产环境特别注意:缩容数据库 StatefulSet 之前,必须先确认数据库集群成员退出、数据复制状态和存储安全。Kubernetes 删除 Pod 并不等于数据库节点已经安全退群。


九、StatefulSet 的删除机制#

StatefulSet 的删除和普通 Deployment 有一个重要区别。

1. 删除 StatefulSet#

PRTCL // BASH
Terminal window
kubectl delete statefulset mysql

默认级联删除其管理的 Pod。

但是不会自动删除 volumeClaimTemplates 创建的 PVC。

2. 只删除 Pod,不删除 StatefulSet#

PRTCL // BASH
Terminal window
kubectl delete pod mysql-0

StatefulSet 会重新创建 mysql-0。

3. 缩容 StatefulSet#

PRTCL // BASH
Terminal window
kubectl scale statefulset mysql --replicas=0

所有 Pod 被删除,但默认保留 PVC。

4. 删除 StatefulSet 时保留 Pod#

如果想删除 StatefulSet 但保留 Pod,可以:

PRTCL // BASH
Terminal window
kubectl delete statefulset mysql --cascade=orphan

这种操作需要谨慎。

因为此时 Pod 不再由原来的 StatefulSet 自动管理。

如果之后重新创建同名 StatefulSet,还需要注意 Pod 的认领和管理关系。


十、StatefulSet 故障排查#

实际生产环境中,StatefulSet 常见问题主要有以下几类。

1. Pod 一直 Pending#

例如:

PRTCL // TEXT
mysql-0 Pending
mysql-1 Pending

常见原因:

  • PVC 无法绑定。
  • StorageClass 不存在。
  • PV 容量不足。
  • 节点资源不足。
  • 存储拓扑不匹配。

排查:

PRTCL // BASH
Terminal window
kubectl describe pod mysql-0

查看 PVC:

PRTCL // BASH
Terminal window
kubectl get pvc

查看 PV:

PRTCL // BASH
Terminal window
kubectl get pv

查看 StorageClass:

PRTCL // BASH
Terminal window
kubectl get storageclass

2. StatefulSet 只有第一个 Pod 正常运行#

例如:

PRTCL // TEXT
mysql-0 Running
mysql-1 Pending
mysql-2 Pending

默认 OrderedReady 策略下,后续 Pod 必须等待前一个 Pod 达到 Ready 才能继续创建。

所以需要重点检查 mysql-0 是否 Ready。

PRTCL // BASH
Terminal window
kubectl describe pod mysql-0

可能原因:

  • Readiness Probe 失败。
  • 容器启动异常。
  • 数据库初始化失败。
  • 依赖服务不可用。

3. StatefulSet 无法完成滚动更新#

查看:

PRTCL // BASH
Terminal window
kubectl rollout status statefulset/mysql

查看:

PRTCL // BASH
Terminal window
kubectl describe statefulset mysql

重点检查:

  • 新版本 Pod 是否启动失败。
  • Readiness Probe 是否通过。
  • 镜像是否能够正常拉取。
  • Partition 是否限制了更新范围。
  • 是否有较低序号 Pod 阻塞更新过程。

特别注意:StatefulSet 的滚动更新默认从最大序号向最小序号执行,较高序号的 Pod 更新不成功时,可能阻止更低序号的 Pod 继续更新。


十一、StatefulSet 必须掌握的命令#

操作命令
查看 StatefulSetkubectl get sts
查看详细信息kubectl describe sts mysql
创建 StatefulSetkubectl apply -f sts.yaml
扩容kubectl scale sts mysql --replicas=5
缩容kubectl scale sts mysql --replicas=2
查看 Podkubectl get pods
查看 PVCkubectl get pvc
更新镜像kubectl set image sts/mysql nginx=nginx:1.28
查看更新状态kubectl rollout status sts/mysql
查看更新历史kubectl rollout history sts/mysql
回滚kubectl rollout undo sts/mysql
删除 StatefulSetkubectl delete sts mysql

十二、StatefulSet 与 Deployment 综合对比#

到这里,我们已经学习了两种最重要的工作负载控制器。

建议重点掌握下面这张表:

知识点DeploymentStatefulSet
应用类型无状态有状态
Pod 名称通常不固定固定序号
网络身份通常通过 Service 统一访问支持稳定 Pod DNS
独立 PVC需要自行配置支持自动创建
启动顺序不保证默认有序
删除顺序不保证默认逆序
滚动更新支持支持
版本回滚支持支持
分区更新不支持该机制支持 Partition
并行创建通常并行支持 Parallel

典型应用场景#

Web 应用

Deployment Nginx、Spring Boot、Go Web 服务。

数据库集群

StatefulSet MySQL、PostgreSQL 等有状态实例。

消息队列集群

StatefulSet Kafka、ZooKeeper 等需要稳定节点身份的集群。

缓存服务

视架构选择 Redis 单实例、主从或集群部署,需要根据状态管理方式选择控制器。

注意:StatefulSet 只提供 Kubernetes 层面的稳定身份、存储关联和生命周期管理,不会自动实现 MySQL 主从复制、Redis 数据同步或 Kafka 集群成员管理。这些仍需要应用自身的集群机制或 Operator 配合。


归档于 2026.07.20
// 档案结束
Classified
章节_06
协议编号: CC-BY-NC-SA-4.0

StatefulSet:有状态应用管理

作者:Chavy发布日期:2026.07.20

基于 CC BY-NC-SA 4.0

© 2026 Chavy
Powered by Astro