4. StatefulSet 与有状态数据库:StatefulSet 原理、稳定网络标识、有序部署与滚动更新策略

在 Kubernetes 中部署有状态数据库(如 MySQL、PostgreSQL、MongoDB、Redis 集群)时,StatefulSet 是唯一能够提供稳定标识与有序生命周期的原生工作负载。与 Deployment 不同,StatefulSet 为每个 Pod 分配一个持久的身份标识,确保数据库节点在重启、迁移或扩缩容后仍能保持原有的网络名称和存储绑定。

4.1 StatefulSet 核心原理

StatefulSet 通过以下三个机制实现有状态应用的可靠运行:

机制 说明 数据库场景价值
稳定网络标识 每个 Pod 拥有固定的 DNS 名称(如 mysql-0.mysql-svc.ns.svc.cluster.local) 主从复制、集群发现无需动态更新连接字符串
有序部署与终止 Pod 按序号从 0 到 N-1 依次创建,反向顺序终止 确保主节点先启动、从节点后加入;避免脑裂
持久存储绑定 每个 Pod 绑定独立的 PVC,Pod 重建后自动挂载同一卷 数据库数据不丢失,节点恢复后直接加载本地数据
关键区别: Deployment 创建的 Pod 名称是随机的(如 app-7d8f9c6b4-abcde),而 StatefulSet 创建的 Pod 名称固定为 <statefulset-name>-<ordinal>(如 mysql-0、mysql-1)。这个序号就是 Pod 的“身份指纹”。

4.2 稳定网络标识:有状态数据库的通信基石

StatefulSet 与 Headless Service(ClusterIP: None)配合使用,为每个 Pod 生成可预测的 DNS 记录。数据库集群内部通过 SRV 记录或 A 记录直接定位每个节点。

apiVersion: v1
kind: Service
metadata:
  name: mysql-svc
spec:
  clusterIP: None          # Headless Service
  selector:
    app: mysql
  ports:
  - port: 3306
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
spec:
  serviceName: mysql-svc   # 必须关联 Headless Service
  replicas: 3
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:8.0
        ports:
        - containerPort: 3306
          name: mysql
        volumeMounts:
        - name: data
          mountPath: /var/lib/mysql
  volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 50Gi

创建后,三个 Pod 的 DNS 解析结果如下:

  • mysql-0.mysql-svc.default.svc.cluster.local → Pod IP
  • mysql-1.mysql-svc.default.svc.cluster.local → Pod IP
  • mysql-2.mysql-svc.default.svc.cluster.local → Pod IP
数据库配置实践: MySQL Group Replication 或 PostgreSQL Patroni 可直接使用 mysql-0.mysql-svc 作为种子节点地址,无需服务发现中间件。
StatefulSet 稳定网络标识与存储绑定架构 StatefulSet 稳定网络标识与存储绑定架构 Headless Service mysql-svc (ClusterIP: None) Pod: mysql-0 DNS: mysql-0.mysql-svc PVC: data-mysql-0 角色: Primary Pod: mysql-1 DNS: mysql-1.mysql-svc PVC: data-mysql-1 角色: Replica Pod: mysql-2 DNS: mysql-2.mysql-svc PVC: data-mysql-2 角色: Replica PV: pvc-data-mysql-0 PV: pvc-data-mysql-1 PV: pvc-data-mysql-2 核心特性 Pod 重建后 DNS 名称不变,PVC 自动重新挂载 → 数据库节点身份与数据持久化

4.3 有序部署与滚动更新策略

StatefulSet 的 Pod 管理策略分为两种模式,直接影响数据库集群的升级与扩缩容行为:

策略 创建顺序 更新顺序 终止顺序 适用场景
OrderedReady(默认) 0 → 1 → 2 从序号最大开始,逐个更新 2 → 1 → 0 主从复制、有主节点选举的数据库
Parallel 同时创建所有 Pod 同时更新所有 Pod 同时删除所有 Pod 无状态或对启动顺序不敏感的组件

4.4 滚动更新策略配置

StatefulSet 的 updateStrategy 支持两种方式:

  • RollingUpdate(默认):按序号从大到小逐个更新 Pod,每个 Pod 更新前会等待前一个 Pod 进入 Ready 状态。
  • OnDelete:手动删除 Pod 后才触发重建,适用于需要精确控制升级节奏的数据库场景。
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
spec:
  updateStrategy:
    type: RollingUpdate
    rollingUpdate:
      partition: 2          # 只更新序号 >= 2 的 Pod
  podManagementPolicy: OrderedReady
  ...
数据库升级避坑: 使用 partition 字段可以实现金丝雀更新。例如设置 partition: 2,则只有 mysql-2 会被更新,mysql-0 和 mysql-1 保持不变。验证新版本稳定后再逐步降低 partition 值,完成全量升级。
StatefulSet 有序滚动更新流程 StatefulSet 有序滚动更新流程(3 副本) 阶段 1:更新前 mysql-0 (v1) mysql-1 (v1) mysql-2 (v1) 阶段 2:更新 mysql-2 mysql-0 (v1) mysql-1 (v1) mysql-2 (v2) ← 正在更新 阶段 3:更新 mysql-1 mysql-0 (v1) mysql-1 (v2) ← 正在更新 mysql-2 (v2) 阶段 4:更新完成 mysql-0 (v2) mysql-1 (v2) mysql-2 (v2)

4.5 数据库迁移中的 StatefulSet 最佳实践

迁移清单:
  1. 始终使用 Headless Service:确保数据库节点间通过固定 DNS 通信,避免 IP 漂移导致复制中断。
  2. 设置 podManagementPolicy: OrderedReady:保证主节点先启动,从节点后加入,防止从节点竞选为主导致数据不一致。
  3. 利用 partition 做灰度升级:先升级一个从节点,验证查询性能与复制延迟,再逐步推进。
  4. 为每个节点配置独立的资源请求与限制:数据库对 CPU/内存敏感,避免因资源竞争导致 OOM 或性能抖动。
  5. 启用 terminationGracePeriodSeconds:给数据库进程足够时间完成事务提交与 binlog 刷新(建议 60s+)。
性能优化提示: 对于高并发写入的数据库,建议将 StatefulSet 的 minReadySeconds 设置为 30-60 秒,确保新 Pod 在加入流量前已完成 WAL 恢复和缓存预热。