跳到内容

11.2 Kubernetes 有状态工作负载:身份、存储与恢复

把数据库 YAML 改成 StatefulSet 不等于获得了高可用数据库。Kubernetes 能维护 Pod 身份、挂载声明和编排顺序;复制协议、一致性、备份校验和故障切换仍由应用、operator 或托管服务负责。

PV、PVC 与 StorageClass 分工

text
Pod → PersistentVolumeClaim → PersistentVolume → 存储系统

                   StorageClass 动态供应策略
  • PVC 表达工作负载需要多大的卷、访问模式和存储类;
  • PV 表示集群中可绑定的存储资源;
  • StorageClass 描述 provisioner、参数、回收策略和绑定方式。

访问模式如 ReadWriteOnce 描述卷的挂载约束,不等同于应用级并发写安全,也不直接说明底层存储的故障域和性能保证。

对拓扑受限的块存储,volumeBindingMode: WaitForFirstConsumer 可以等调度器选定节点区域后再供应卷,减少“Pod 在 A 区、卷在 B 区”造成的不可调度。

StatefulSet 提供稳定身份

yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: ledger
spec:
  serviceName: ledger-headless
  replicas: 3
  selector:
    matchLabels:
      app: ledger
  template:
    metadata:
      labels:
        app: ledger
    spec:
      terminationGracePeriodSeconds: 60
      containers:
        - name: ledger
          image: registry.example/ledger@sha256:REPLACE_ME
          ports:
            - name: peer
              containerPort: 7000
          volumeMounts:
            - name: data
              mountPath: /var/lib/ledger
  volumeClaimTemplates:
    - metadata:
        name: data
      spec:
        accessModes: [ReadWriteOnce]
        storageClassName: fast-zonal
        resources:
          requests:
            storage: 100Gi

Pod 会获得 ledger-0ledger-1 这样的稳定序号,并在重新调度后重新关联自己的 PVC。默认 OrderedReady 按序创建和终止;只有应用不依赖顺序时才考虑 Parallel

StatefulSet 需要 headless Service 提供网络身份,但 DNS 名称稳定不代表进程一定健康。集群成员发现还要处理 readiness、脑裂防护和失联成员重加入。

PVC 生命周期默认偏向保数据

缩容或删除 StatefulSet 时,关联卷通常不会自动删除,这是有意的数据安全取舍。新项目应明确 persistentVolumeClaimRetentionPolicy、StorageClass 的 reclaimPolicy,以及删除 namespace 时谁负责最终确认。

扩容前先验证应用是否支持增加成员;缩容前先让应用层安全移除副本,再改变 replicas。直接把三副本数据库缩成一副本,控制器不会替你维护 quorum。

探针不能只检查端口打开

有状态服务常需要区分:

  • startup:恢复日志、重放 WAL 或加入集群是否完成;
  • readiness:该副本此刻能否安全接收目标类型的流量;
  • liveness:进程是否已进入只能重启恢复的状态。

把“暂时落后”写成 liveness 失败会触发重启循环,反而永远追不上。把主库专属写能力与普通存活混在一个 readiness 中,也会让读流量无端中断。

快照不是完整备份策略

CSI VolumeSnapshot 可以快速捕获卷状态,但是否应用一致取决于存储实现和应用冻结流程。生产恢复方案要回答:

  1. 是 crash-consistent 还是 application-consistent?
  2. 数据库日志和多卷如何获得同一恢复点?
  3. 备份是否复制到独立账户、区域或故障域?
  4. 加密密钥、schema、配置和 operator 版本是否一起保留?
  5. 最近一次从空集群恢复演练花了多久,恢复到哪个时间点?

没有成功恢复记录的备份,只是尚未验证的一组对象。RPO 决定允许丢多少数据,RTO 决定服务多久必须恢复,两者共同推导备份频率、复制方式和演练周期。

Operator 的价值与边界

成熟数据库 operator 可以编码成员变更、滚动升级、备份和故障切换知识,但它也引入 CRD、webhook、controller 和版本兼容风险。采用前应检查:

  • operator 与数据库版本升级矩阵;
  • controller 不可用时数据面是否继续服务;
  • CRD 删除和 finalizer 卡住时如何处置;
  • 自动故障切换在网络分区下的 fencing 机制;
  • 备份能否脱离原集群恢复。

若团队无法承担这些操作责任,托管数据库往往比“把数据库塞进 Kubernetes”更可靠。

上线检查

  • 每个副本的身份和卷绑定是否可预测?
  • 节点、可用区和存储是否共享同一故障域?
  • 资源不足时是否会同时驱逐多数副本?
  • 升级、缩容、节点 drain 和区域故障是否演练?
  • PVC、快照、备份与密钥的删除权限是否分离?
  • RPO/RTO 是否通过真实恢复数据验证?

下一课把资源、调度、扩缩容和中断预算组合起来,控制共享集群中的容量与故障半径。

参考资料

Built with VitePress | Software Systems Atlas