Kubernetes

K8s StatefulSet 详解

·12 分钟阅读·4548 字

说明 Kubernetes StatefulSet 的稳定身份、Headless Service、独立存储、顺序发布和更新策略

📋 目录

K8s StatefulSet 详解

核心定义 StatefulSet 是 Kubernetes 用于管理有状态应用的工作负载控制器。它为每个 Pod 提供稳定的名称、稳定的网络身份、独立的持久化存储和有序的创建、更新、删除语义,常用于数据库、消息队列、协调服务等有状态系统。

1. StatefulSet 解决什么问题

Deployment 适合无状态应用,Pod 可以任意替换;但有状态应用通常需要固定身份和稳定数据。

典型需求:

  1. 每个副本都有固定名称,例如 mysql-0、mysql-1。
  2. 每个副本都有稳定 DNS,例如 mysql-0.mysql.default.svc.cluster.local。
  3. 每个副本绑定自己的 PVC,重建后仍挂载原数据。
  4. 启动、扩容、缩容和更新需要按顺序执行。
  5. 应用内部可能依赖成员序号进行主从、分片或选主。

StatefulSet 正是为这些需求设计的。

2. StatefulSet 与 Deployment 对比

对比项DeploymentStatefulSet
适用应用无状态应用有状态应用
Pod 名称随机后缀,例如 web-7d8b9有序编号,例如 mysql-0、mysql-1
网络身份Pod IP 变化,名称不稳定基于 Headless Service 的稳定 DNS
存储通常共享或无状态每个 Pod 独立 PVC
启动顺序通常并行默认按 0、1、2 顺序启动
删除顺序通常无严格顺序默认按最大序号到最小序号删除
更新策略RollingUpdateRollingUpdate、OnDelete、Partition
典型场景Web、API、无状态服务MySQL、Kafka、ZooKeeper、Redis Cluster

3. 三个核心稳定性

3.1. 稳定 Pod 名称

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

<StatefulSet 名称>-<序号>

例如副本数为 3:

mysql-0
mysql-1
mysql-2

即使 mysql-1 被删除,控制器重建后仍然叫 mysql-1。

3.2. 稳定网络身份

StatefulSet 通常配合 Headless Service 使用。Headless Service 设置:

clusterIP: None

Pod 的稳定 DNS 形式:

<pod-name>.<service-name>.<namespace>.svc.cluster.local

示例:

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

这对主从复制、分片成员发现和集群选主非常重要。

3.3. 稳定存储

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

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

Pod 删除后,PVC 默认不会自动删除。Pod 重建后会重新挂载原 PVC,从而保留数据。

4. 基本 YAML 示例

Headless Service:

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

StatefulSet:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
spec:
  serviceName: mysql
  replicas: 3
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
        - name: mysql
          image: mysql:8
          ports:
            - containerPort: 3306
          volumeMounts:
            - name: data
              mountPath: /var/lib/mysql
  volumeClaimTemplates:
    - metadata:
        name: data
      spec:
        accessModes:
          - ReadWriteOnce
        resources:
          requests:
            storage: 20Gi

关键字段:

字段作用
serviceName指向 Headless Service,用于生成稳定 DNS
replicas副本数量
selector匹配被管理的 Pod
volumeClaimTemplates为每个 Pod 创建独立 PVC

5. 创建、扩容与缩容顺序

5.1. 创建顺序

默认情况下,StatefulSet 会按序号从小到大创建:

mysql-0 → mysql-1 → mysql-2

前一个 Pod Ready 后,才继续创建下一个 Pod。

5.2. 缩容顺序

缩容时按序号从大到小删除:

mysql-2 → mysql-1 → mysql-0

这对有主从关系或成员顺序依赖的应用更安全。

5.3. podManagementPolicy

podManagementPolicy 控制 Pod 管理顺序。

策略含义
OrderedReady默认,按顺序创建和删除
Parallel并行创建或删除 Pod

Parallel 适合不依赖顺序的有状态服务,但使用前需要确认应用自身能处理并发启动。

6. 更新策略

6.1. RollingUpdate

默认策略。StatefulSet 会按序号从大到小更新 Pod。

mysql-2 → mysql-1 → mysql-0

这样可以避免低序号节点在某些有状态系统中被过早更新。

6.2. OnDelete

OnDelete 表示 StatefulSet 模板更新后,不会自动重建 Pod。只有手动删除 Pod 时,才会按新模板重建。

适合需要人工控制更新节奏的数据库或中间件。

6.3. Partition 灰度更新

partition 可用于灰度更新,只更新序号大于等于 partition 的 Pod。

例如副本数为 5,partition 为 3:

更新 mysql-3、mysql-4
保留 mysql-0、mysql-1、mysql-2

示例:

updateStrategy:
  type: RollingUpdate
  rollingUpdate:
    partition: 3

7. PVC 生命周期注意点

StatefulSet 删除 Pod 或缩容时,PVC 默认保留。这是为了避免误删数据。

常见现象:

删除 mysql-1 Pod → PVC data-mysql-1 仍保留
重建 mysql-1 Pod → 重新挂载 data-mysql-1

删除 StatefulSet 不等于删除数据 删除 StatefulSet 或缩容副本不会自动删除 PVC。需要清理数据时,应明确确认 PVC 和 PV 的回收策略,避免误删生产数据。

8. 常见应用场景

场景为什么适合 StatefulSet
MySQL 主从每个节点需要固定身份和独立数据目录
KafkaBroker ID、日志目录和网络身份需要稳定
ZooKeeper节点 myid 和成员 DNS 需要稳定
Redis Cluster分片节点和持久化数据需要绑定
Elasticsearch数据节点需要独立存储和稳定拓扑

9. 常见排查命令

查看 StatefulSet:

kubectl get statefulset -n <namespace>
kubectl describe statefulset <name> -n <namespace>

查看 Pod 顺序和状态:

kubectl get pod -n <namespace> -o wide

查看 PVC:

kubectl get pvc -n <namespace>
kubectl describe pvc <pvc_name> -n <namespace>

查看 Headless Service:

kubectl get svc -n <namespace>
kubectl describe svc <service_name> -n <namespace>

测试 DNS:

kubectl exec -it <pod> -n <namespace> -- nslookup mysql-0.mysql.default.svc.cluster.local

10. 常见问题

10.1. Pod 卡在创建阶段

常见原因:

  • PVC 无法绑定。
  • StorageClass 不存在或 CSI 异常。
  • 前一个序号 Pod 未 Ready,导致后续 Pod 不创建。
  • 镜像拉取失败或探针配置错误。

10.2. DNS 无法解析

排查方向:

  • Headless Service 是否存在。
  • StatefulSet 的 serviceName 是否正确。
  • Pod labels 是否匹配 Service selector。
  • CoreDNS 是否正常。

10.3. 更新卡住

常见原因:

  • 高序号 Pod 更新后未 Ready。
  • readinessProbe 配置过严。
  • 新版本应用启动失败。
  • PVC 挂载或权限异常。

11. 面试回答模板

标准回答 StatefulSet 是 Kubernetes 用于管理有状态应用的控制器。它和 Deployment 最大的区别是提供稳定 Pod 名称、稳定 DNS、独立 PVC 和有序创建、更新、删除语义。StatefulSet 通常配合 Headless Service 生成固定域名,并通过 volumeClaimTemplates 为每个 Pod 创建独立 PVC。默认创建顺序是从 0 到 N,删除和滚动更新通常从最大序号开始。它适合 MySQL、Kafka、ZooKeeper、Redis Cluster 等依赖稳定身份和持久化数据的服务。


关联文档

Yanche Blog

记录云原生、Linux、数据库等技术领域的学习心得,以及日常生活的思考与感悟。

© 2026 Yanche Blog. All rights reserved.

Powered by Astro