一次性讲清 StatefulSet 的底层逻辑与实战技巧

288 阅读3分钟

一、为什么需要 StatefulSet?

Kubernetes 的 Deployment 非常适合无状态服务,Pod 可以随意重建、替换。但当我们面对以下场景时,它就显得力不从心了:

  • MySQL 主从部署,Pod 需要固定身份
  • Kafka、Zookeeper 等分布式系统,需要唯一标识和顺序启动
  • Redis Cluster、ElasticSearch 等组件,要求持久化存储和网络恒定性

这时候,就轮到 StatefulSet 上场了。


二、StatefulSet 到底解决了什么问题?

StatefulSet 是为有状态应用设计的控制器,它解决了以下关键问题:

问题StatefulSet 的解决方式
Pod 名称和身份不固定Pod 有固定序号(如 mysql-0, mysql-1)
网络地址不稳定每个 Pod 都有唯一 DNS(基于 Headless Service)
存储卷被重新绑定或覆盖每个 Pod 绑定一个持久化 PVC,删除 Pod 不会删数据卷
启动顺序与关闭顺序无法控制按编号有序创建、删除、终止(比如 0 → 1 → 2)

✅ StatefulSet = 有序编号 + 网络恒定 + 存储稳定


三、核心组件拆解

1. Pod 命名机制

metadata:
  name: mysql

最终生成的 Pod 名为:

mysql-0
mysql-1
mysql-2

Pod 顺序是稳定的,每次重建也不会变化。

2. Headless Service 必不可少

spec:
  serviceName: mysql-headless  # 必须绑定 Headless Service

搭配 Headless Service 后,Pod 的 DNS 形式如下:

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

3. 每个 Pod 都绑定唯一 PVC

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

最终生成的 PVC 如下:

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

每个 Pod 永久使用对应 PVC,Pod 删除时 PVC 不会丢失。


四、完整 YAML 示例

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

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

五、使用 StatefulSet 的注意事项

⚠️ 1. 删除顺序影响数据安全

StatefulSet 删除时,会按序逐个删除 Pod,并保留 PVC,这是为了数据安全。
如需连 PVC 一起清理,请手动删除对应的 PVC 资源。

⚠️ 2. 扩容建议逐步推进

扩容 StatefulSet 会新增 mysql-3、mysql-4 等 Pod。
由于状态相关,请保证应用支持新节点加入,如 Kafka 的 broker.id。

⚠️ 3. 禁止同时使用 RollingUpdate 和 Init Containers 执行数据库初始化

会导致多个 Pod 同时初始化数据,造成覆盖或数据冲突,建议通过 job+PVC 预写入。


六、StatefulSet vs Deployment 对比

特性DeploymentStatefulSet
Pod 命名随机有序、固定命名
网络地址动态DNS 恒定
存储卷可共享/动态挂载固定绑定 PVC
适用场景无状态微服务数据库、消息中间件

七、进阶技巧:如何与 Volume、Init、Affinity 结合使用?

  • 利用 volumeClaimTemplates 实现数据分片;
  • 结合 Pod Anti-Affinity 保证多个副本分布在不同节点上;
  • 加入 Init Container 执行启动前依赖检查;
  • 利用 readinessProbe 精细控制流量接入时机。

八、总结

StatefulSet 是 Kubernetes 中为有状态服务量身定做的解决方案。在你部署 MySQL、Redis Cluster、Kafka、Zookeeper、Elasticsearch 时,它都是你值得信赖的选择。

掌握 StatefulSet,意味着你迈出了从“用得起 Kubernetes”到“玩得转 Kubernetes”的关键一步。