Skip to main content
Documents
Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

Kubernetes StatefulSet

StatefulSet 是 Kubernetes 中用于 有状态应用(Stateful Application) 的 Workload 类型,解决以下问题:

Pod 的身份保持(Identity) + 稳定一致的存储(Stable Storage) + 顺序化部署、更新、删除(Ordered Operation)

典型业务场景包括:

  • 数据库集群(MySQL、PostgreSQL、MongoDB)
  • 分布式协调服务(ZooKeeper、Etcd)
  • 存储系统(Ceph、HDFS)
  • 需要固定主机名访问的服务(Kafka、RabbitMQ)

🧩 1. 为什么需要 StatefulSet?(核心价值)

Deployment 设计用于无状态应用:

  • ❌ Pod 名称随机
  • ❌ 存储不固定
  • ❌ Pod 会被替换,无法稳定绑定数据
  • ❌ 无法保证先启动/先关闭顺序

StatefulSet 则提供:

| 特性 | Deployment | StatefulSet | | Pod 名称稳定 | ❌ | ✅ | | Pod DNS 稳定 | ❌ | ✅ | | Pod 顺序部署 | ❌ | ✅ | | Pod 顺序更新 | ❌ | ✅ | | 固定持久卷 | ❌ | ✅(PVC 自动创建) | | 适合数据库 | ❌ | ✅ |

总结一句话:

StatefulSet 让每个 Pod 都有身份(Identity)+ 数据持久化(Persistence)。

🧩 2. StatefulSet 的核心特性

2.1 Pod 稳定身份(Stable Identity)

Pod 名字固定:

<statefulset-name>-0
<statefulset-name>-1
<statefulset-name>-2

例如:

mysql-0
mysql-1
mysql-2

重启也不会改变。

2.2 稳定网络标识(Stable Network Identity)

借助 Headless Service(必须):

serviceName: mysql

Pod 会有稳定的 DNS:

mysql-0.mysql.default.svc.cluster.local
mysql-1.mysql.default.svc.cluster.local

每个实例都有可直连的域名(数据库非常依赖)。

2.3 稳定持久化卷(Stable Storage)

StatefulSet + volumeClaimTemplates -> 自动生成 PVC:

data-mysql-0
data-mysql-1
data-mysql-2

删除 Pod 不会删除 PVC

  • 数据不丢
  • Pod 可以恢复
  • 节点不可用时依旧能重建 Pod

2.4 严格顺序化的行为(Ordered Operations)

StatefulSet 提供:

📌 顺序部署(Create)

  • mysql-0 -> mysql-1 -> mysql-2

📌 顺序更新(Update)

  • 滚更时逐个更新 Pod
  • 新 Pod 必须 Ready 才能继续

📌 顺序删除(Delete)

  • mysql-2 -> mysql-1 -> mysql-0

数据库主从切换非常依赖此特性。

🧩 3. StatefulSet YAML 解析(最干净版本)

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
spec:
  serviceName: mysql
  replicas: 3

  selector:
    matchLabels:
      app: mysql

  updateStrategy:
    type: RollingUpdate

  podManagementPolicy: OrderedReady  # 默认行为

  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:8
        volumeMounts:
        - name: data
          mountPath: /var/lib/mysql

  volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 20Gi

🧩 4. StatefulSet 的关键字段解释

⭐ serviceName(必须)

用于为每个 Pod 创建稳定 DNS:

serviceName: mysql

要求绑定一个:

Headless Service:

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

否则 Pod DNS 无法生成。

⭐ podManagementPolicy

默认:OrderedReady

  • 按顺序启动、更新、删除
  • 适合数据库

选项:Parallel

  • 并行启动所有 Pod
  • 适合 Kafka、RabbitMQ 这种节点间独立性较强的服务

⭐ updateStrategy

RollingUpdate(默认)

逐个更新 Pod(安全)

OnDelete

手动删除旧 Pod 才更新 用于非常敏感的数据库升级,例如 etcd。

⭐ volumeClaimTemplates

每个 Pod 自动生成独立 PVC:

data-mysql-0
data-mysql-1
data-mysql-2

卷不会随 StatefulSet 删除。

🧩 5. StatefulSet + Persistent Volume 挂载流程

流程图:

创建 StatefulSet
创建 Pod-0
自动创建 PVC-0
调度到 Node
挂载 PV(动态/静态)
Pod 启动

特点:

  • Pod 与 PVC 永久绑定
  • Pod 重建不影响数据
  • 换节点仍会挂回同一 PVC(使用网络存储时)

🧩 6. StatefulSet 常见使用场景

MySQL 主从、MySQL InnoDB Cluster

数据必须固定,Pod 顺序要求强。

PostgreSQL Patroni 集群

Leader/Follower 依赖固定主机名。

Redis Sentinel

每个节点身份不同。

ZooKeeper

只有 0 号 Pod 可以初始化集群。

Kafka、RabbitMQ

每个 broker 有独立日志目录。

Ceph OSD

每个节点绑定特定磁盘或数据目录。

🧩 7. StatefulSet 常见问题与排查

❗ 1. 为什么 StatefulSet Pod 无法启动?

检查是否缺少 Headless Service:

clusterIP: None

检查存储:

kubectl get pvc
kubectl describe pvc <name>

❗ 2. 为什么 StatefulSet 不能自动扩缩容?

因为:

  • 扩容:新 Pod 如 3->4 会自动创建 PVC
  • 缩容:Pod 删除,但 PVC 不会删除
  • 再次扩容 -> 绑定回原 PVC

❗ 3. PVC 如何清理?

你必须手动删除:

kubectl delete pvc data-mysql-2

防止误删数据。

🧩 8. StatefulSet vs Deployment vs DaemonSet(总结对比)

| 特性 | Deployment | StatefulSet | DaemonSet | | 适用场景 | 无状态应用 | 有状态服务 | 节点 Agent | | Pod 身份 | 无 | 有(固定) | 与节点绑定 | | DNS 稳定 | ❌ | ✅ | ✅ | | 存储 | 可选,非稳定 | 绑定 PVC | 通常使用 hostPath | | 顺序启动 | ❌ | ✅ | ❌ | | 适合数据库 | ❌ | ✅ | ❌ |

🧩 9. StatefulSet 最佳实践(生产环境)

必须配合 Headless Service

clusterIP: None

必须使用 volumeClaimTemplates(不要手写 PVC)

因为:

  • 自动创建
  • 自动绑定命名规范
  • 不用担心漏写

对数据库请使用 RollingUpdate + PodDisruptionBudget + readinessProbe

强烈建议不要给 StatefulSet Pod 设置 hostNetwork: true

会导致:

  • ❌ 不同 Pod DNS 冲突
  • ❌ 端口冲突
  • ❌ ClusterIP 无法访问

StatefulSet 不适合这些场景

  • 高并发横向扩展型 Web 服务 -> Deployment
  • 节点级插件 -> DaemonSet
  • 批处理 -> Job
  • 定时任务 -> CronJob

🧩 10. 一张图理解 StatefulSet(超清晰)

StatefulSet
Pod 0 -- PVC-0 -- DNS: mysql-0.mysql
Pod 1 -- PVC-1 -- DNS: mysql-1.mysql
Pod 2 -- PVC-2 -- DNS: mysql-2.mysql

顺序:

创建: 0 -> 1 -> 2
更新: 0 -> 1 -> 2
删除: 2 -> 1 -> 0

每个 Pod 就像有自己 身份证号码独立硬盘

🎯 最终总结(掌握 StatefulSet 的关键一句话)

StatefulSet = 有身份的 Pod + 稳定 DNS + 稳定存储 + 顺序化运维。

用于数据库、队列、协调系统等所有有状态应用。