9.1. 有状态服务 Operator:PostgreSQL、Kafka 与 Redis

StatefulSet 只保证「有稳定名字和 PVC 的 Pod」,但数据库真正难的是主从切换、备份恢复、版本升级、扩缩容和故障自愈。Operator 把这些运维知识写成控制器,让「一个 CR 创建一个高可用集群」成为可能。

层级:

L3 · 平台

难度:

进阶

预计:

50 分钟

前置:

StatefulSet、PVC、CRD/Operator 基础

9.1.1. Operator 在做什么

Operator = CRD + 控制器 + 领域知识。你提交一个 Cluster 或 Kafka 对象,控制器负责:

  • 创建 StatefulSet、Service、PVC、ConfigMap、Secret;

  • 初始化集群、配置复制与仲裁;

  • 处理主从切换、成员变更、滚动升级;

  • 执行备份、恢复、快照与版本迁移;

  • 暴露状态与事件,供监控和告警使用。

Operator

管理对象

典型能力

CloudNativePG

PostgreSQL

主备、PITR、备份到 S3、故障切换

Strimzi

Kafka

KRaft/ZooKeeper、Topic、User、镜像

Vitess

MySQL 分片

分库分表、在线扩缩容

Redis Operator

Redis

哨兵/集群、主从切换

Elastic/OpenSearch Operator

搜索集群

节点角色、快照、升级

9.1.2. CloudNativePG 最小实验

helm repo add cnpg https://cloudnative-pg.github.io/charts
helm install cnpg cnpg/cloudnative-pg -n cnpg-system --create-namespace
kubectl -n cnpg-system get pods
pg-cluster.yaml
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: demo-pg
  namespace: default
spec:
  instances: 3
  storage:
    size: 5Gi
  bootstrap:
    initdb:
      database: app
      owner: app
  backup:
    barmanObjectStore:
      destinationPath: s3://demo-pg-backup/
      s3Credentials:
        accessKeyId:
          name: backup-creds
          key: ACCESS_KEY_ID
        secretAccessKey:
          name: backup-creds
          key: SECRET_ACCESS_KEY
kubectl apply -f pg-cluster.yaml
kubectl get cluster demo-pg -w
kubectl get pods -l cnpg.io/cluster=demo-pg
kubectl get secrets demo-pg-app -o jsonpath='{.data.password}' | base64 -d

CloudNativePG 会创建一个主实例和两个备实例,并生成 demo-pg-rw(读写)、demo-pg-ro(只读)Service。应用应连接 -rw,不要把主实例地址写死。

9.1.3. 故障切换与备份

kubectl cnpg status demo-pg
kubectl cnpg promote demo-pg demo-pg-2
kubectl cnpg backup demo-pg
  • 故障切换:主实例不可用时,Operator 依据仲裁提升一个备实例;应用通过 -rw Service 自动跟随。

  • PITR:基于基础备份 + WAL 归档恢复到某个时间点;必须提前配置对象存储和保留策略。

  • 升级:先升级 Operator,再修改 imageName;Operator 按顺序重启实例,保持仲裁。

不要只验证「Pod 变成 Running」。真正的验收是:杀掉主实例后应用能自动重连,备份能恢复到一个新集群。

9.1.4. Strimzi/Kafka 的差异

Kafka 的难点在 KRaft/ZooKeeper 仲裁、分区副本、Topic 配置与磁盘。Strimzi 用 Kafka、KafkaTopic、KafkaUser 等 CR 管理,升级时要关注 inter.broker.protocol.version 与滚动顺序。

kubectl apply -f https://strimzi.io/install/latest?namespace=kafka
kubectl -n kafka get pods

生产环境至少 3 个 broker,副本因子 3,min.insync.replicas=2;磁盘用本地 NVMe 或高性能云盘,不要用 NFS。

9.1.5. 验证清单

  • Operator 与 CRD 已安装,控制器 Pod 健康。

  • 集群 CR 进入 Ready,实例数与期望一致。

  • 读写/只读 Service 可连接,应用使用 -rw 而非 Pod IP。

  • 手动删除主实例后,故障切换在可接受时间内完成。

  • 备份成功,并能恢复到新集群或指定时间点。

  • 升级路径已演练,回滚方案明确。

9.1.6. 排错表

现象

原因

处理

CR 一直 Creating

存储类不满足 / 镜像拉取失败

describe cluster、看 Operator 日志

主实例反复重启

资源不足 / PVC 满

查 events、扩容 PVC、调 resources

应用连不上 -rw

Service 未就绪 / 网络策略

get endpoints、检查 NetworkPolicy

备份失败

S3 凭证/桶权限/网络

查 Backup CR 状态与 Operator 日志

升级卡住

副本不健康 / 版本不兼容

先修复副本,再继续滚动

9.1.7. 进阶挑战

  1. 用 CloudNativePG 创建一个 3 实例集群,杀掉主实例并观察应用重连。

  2. 配置 S3 备份与 PITR,恢复到一个 5 分钟前的时间点。

  3. 用 Strimzi 创建 3 broker Kafka,生产/消费一个 Topic。

  4. 给 Operator 管理的集群加 NetworkPolicy,只允许应用命名空间访问。

9.1.8. 小结

  • Operator 把数据库运维知识编码进控制器,但不会替你做容量规划与演练。

  • 有状态服务的验收标准是故障切换、备份恢复、升级回滚,而不是 Pod Running。

  • 优先使用成熟 Operator;自研 Operator 只覆盖组织特有的运维逻辑。

  • 数据服务要独立节点池/存储类,避免和在线业务抢资源。

9.1.9. 延伸阅读