Ceph+K8s 中间件实战系列 · 第 6/15 天

引言
在前一天的实战中,我们使用 bitnami/redis-cluster 部署了 Redis Cluster 分片集群,解决了水平扩展与多分片数据分布的问题。然而,在很多业务场景下——比如缓存、会话管理、排行榜——单分片 Redis 已经足够,真正需要的是高可用(HA)而非分片。这时,Redis Sentinel 哨兵模式就是更轻量、更成熟的选择。
Redis Sentinel 是 Redis 官方提供的高可用解决方案,通过一组独立的 Sentinel 进程持续监控 Redis 主从集群,在主节点故障时自动执行故障检测 → 选举领导者 → 提升从节点为新主的完整故障转移流程。相较于 Redis Cluster,Sentinel 模式架构更简单、运维心智负担更低,适合不需要水平分片但又要求服务连续性的场景。
本篇将在 K8s 上通过 Bitnami 官方 bitnami/redis Chart 部署 Redis Sentinel 哨兵集群,持久化底层对接 Ceph RBD StorageClass,完整覆盖架构设计、部署实战、登录验证与日常巡检。
设计架构
组件拓扑
Redis Sentinel 模式的核心拓扑由三类角色构成:
| 组件 | 数量 | 职责 | 存储需求 |
|---|---|---|---|
| Redis Master | 1 | 读写主节点,接收所有写请求 | Ceph RBD PVC(8Gi) |
| Redis Replica | 2 | 只读从节点,异步复制 Master 数据 | Ceph RBD PVC(8Gi) |
| Sentinel | 3 | 监控 + 故障判定 + 自动故障转移 | 无状态,无需持久化 |
整体拓扑如下:
┌─────────────────┐
│ Client / App │
└────────┬────────┘
│
┌────────▼────────┐
│ redis Service │ ← Sentinel 自动更新 Service 指向新 Master
│ (ClusterIP) │
└────────┬────────┘
│
┌─────────────────┼─────────────────┐
│ │ │
┌──────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐
│ Redis Node0│ │ Redis Node1 │ │ Redis Node2 │
│ (Master) │ │ (Replica) │ │ (Replica) │
│ + Sentinel │ │ + Sentinel │ │ + Sentinel │
│ Ceph PVC │ │ Ceph PVC │ │ Ceph PVC │
└─────────────┘ └─────────────┘ └─────────────┘
│ ▲ ▲
└─────────────────┴─────────────────┘
异步复制 (replication)
在 Bitnami Chart 的实现中,每个 Pod 内运行两个容器:Redis Server 和 Sentinel,通过共享网络命名空间通信。这种 Sidecar 模式使得 Sentinel 与所监控的 Redis 实例部署在同一节点,减少网络延迟对故障检测的干扰。
数据流向
- 写入路径:客户端通过
redisService 连接当前 Master → Master 处理写请求 → 异步复制到 2 个 Replica - 读取路径:客户端可通过
redisService 读 Master,也可直连 Replica 读取(读写分离) - 故障检测:3 个 Sentinel 每秒向 Master/Replica/其他 Sentinel 发送 PING → 超过
down-after-milliseconds无响应则标记为主观下线(SDOWN)→ 达到quorum个 Sentinel 同意则升级为客观下线(ODOWN) - 故障转移:Sentinel 集群选举 Leader → Leader 选择最优 Replica 提升为新 Master → 通知其他 Replica 复制新 Master → 更新 Service 端点
高可用机制
| 机制 | 参数 | 说明 |
|---|---|---|
| 主观下线 (SDOWN) | sentinel.downAfterMilliseconds |
单个 Sentinel 判定实例不可达的超时时间 |
| 客观下线 (ODOWN) | sentinel.quorum |
需 N 个 Sentinel 同意才确认故障,防止误判 |
| 故障转移 | sentinel.failoverTimeout |
故障转移超时,超时则中止并重试 |
| 选举算法 | Raft | Sentinel 之间通过 Raft 协议选举 Leader 执行转移 |
关键设计原则:Sentinel 节点数应为奇数(3 或 5),quorum 设为
(N/2)+1。3 个 Sentinel 设 quorum=2,允许 1 个 Sentinel 不可用仍能正常运作。
存储规划
| 存储类型 | 用途 | StorageClass | 卷模式 |
|---|---|---|---|
| Ceph RBD | Redis 数据持久化 | ceph-rbd-sc |
ReadWriteOnce(每 Pod 独占卷) |
| CephFS | 不适用 | — | Sentinel 模式不使用共享文件存储 |
每个 Redis Pod 绑定一块独立的 Ceph RBD 卷。Master 故障转移后,旧 Master 的 PVC 不会迁移到新 Master——新 Master 从自身 Replica 数据继续提供服务,旧 Master 恢复后自动降级为 Replica 并从新 Master 全量同步。这是 Redis 哨兵模式与数据库集群的一个重要区别:数据持久化的目的是防数据丢失,而非跨节点数据迁移。
部署实战
前置条件确认
确保已按第 2 天完成了 Ceph RBD CSI Driver 部署,并拥有可用的 StorageClass:
# 确认 Ceph RBD StorageClass 存在
kubectl get sc ceph-rbd-sc
# 确认 CSI Driver 正常运行
kubectl get pods -n ceph-csi-rbd -l app=ceph-csi-rbd
预期输出类似:
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE
ceph-rbd-sc rbd.csi.ceph.com Delete Immediate
NAME READY STATUS RESTARTS
csi-rbdplugin-provisioner 4/4 Running 0
csi-rbdplugin-xxxxx 2/2 Running 0
添加 Bitnami Helm 仓库
# 添加 Bitnami 官方 Chart 仓库
helm repo add bitnami https://charts.bitnami.com/bitnami
# 更新本地索引
helm repo update
# 搜索 Redis Chart 确认可用
helm search repo bitnami/redis –versions | head -10
编写 values.yaml 自定义配置
创建 redis-sentinel-values.yaml,核心关注 storageClass 指向 Ceph RBD、Sentinel 启用与 quorum 设置、资源限制与密码:
# redis-sentinel-values.yaml
# Ceph+K8s 中间件实战 | 第 6 天
# Redis Sentinel 哨兵模式 – Ceph RBD 持久化配置
global:
storageClass: "ceph-rbd-sc" # ← 指向 Ceph RBD StorageClass
# — 认证配置 —
auth:
enabled: true
password: "Redis@Ceph2026!" # 生产环境建议使用 Secret 引用
sentinel: true # Sentinel 也需要密码认证
# — Redis 副本配置 —
replica:
replicaCount: 3 # 3 节点:1 Master + 2 Replica
resources:
requests:
cpu: 200m
memory: 256Mi
limits:
cpu: 1000m
memory: 1Gi
persistence:
enabled: true
storageClass: "ceph-rbd-sc" # ← 显式指定 Ceph RBD
accessModes:
– ReadWriteOnce
size: 8Gi # 每节点 8Gi 持久化卷
# — Sentinel 哨兵配置 —
sentinel:
enabled: true # ← 启用 Sentinel 模式
quorum: 2 # 3 Sentinel 中需 2 个同意才判定故障
downAfterMilliseconds: 5000 # 5 秒无响应判定主观下线
failoverTimeout: 180000 # 故障转移超时 3 分钟
parallelSyncs: 1 # 故障转移后同时同步的 Replica 数
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi
# — 架构调度 —
# 使用 anti-affinity 让 3 个 Redis Pod 分散到不同节点
architecture: replication
master:
count: 1
persistence:
enabled: true
storageClass: "ceph-rbd-sc"
size: 8Gi
# — 服务配置 —
service:
type: ClusterIP
ports:
redis: 6379
sentinel: 26379
# — 指标采集 —
metrics:
enabled: true # 启用 Prometheus Exporter
serviceMonitor:
enabled: false # 后续第 15 天统一接入
执行 Helm 部署
# 创建命名空间
kubectl create namespace middleware
# 部署 Redis Sentinel 集群
helm install redis-sentinel bitnami/redis
–namespace middleware
–values redis-sentinel-values.yaml
–version 20.13.4
–timeout 10m
# 等待所有 Pod 就绪
kubectl wait –namespace middleware
–for=condition=ready pod
–selector=app.kubernetes.io/instance=redis-sentinel
–timeout=300s
验证 Pod / Service / PVC 状态
# 查看 Pod 状态 – 应有 3 个 Running Pod,每个含 redis + sentinel 两个容器
kubectl get pods -n middleware -l app.kubernetes.io/instance=redis-sentinel -o wide
# 查看 Service
kubectl get svc -n middleware -l app.kubernetes.io/instance=redis-sentinel
# 查看 PVC – 应有 3 个 Bound 状态的 Ceph RBD 卷
kubectl get pvc -n middleware -l app.kubernetes.io/instance=redis-sentinel
预期输出:
NAME READY STATUS RESTARTS AGE
redis-sentinel-node-0 2/2 Running 0 2m
redis-sentinel-node-1 2/2 Running 0 2m
redis-sentinel-node-2 2/2 Running 0 2m
NAME TYPE CLUSTER-IP PORT(S)
redis-sentinel-master ClusterIP 10.96.15.200 6379/TCP,26379/TCP
redis-sentinel-headless ClusterIP None 6379/TCP,26379/TCP
NAME STATUS VOLUME CAPACITY
data-redis-sentinel-node-0 Bound pvc-xxxx-ceph-rbd 8Gi
data-redis-sentinel-node-1 Bound pvc-yyyy-ceph-rbd 8Gi
data-redis-sentinel-node-2 Bound pvc-zzzz-ceph-rbd 8Gi
每个 Pod READY 2/2 表明 Redis 和 Sentinel 两个容器均已正常启动。3 个 PVC 全部 Bound 说明 Ceph RBD 已成功供给持久化卷。

登录验证
获取连接密码与连接 Master
# 获取 Redis 密码
REDIS_PASSWORD=$(kubectl get secret –namespace middleware redis-sentinel
-o jsonpath="{.data.redis-password}" | base64 -d)
echo "Redis Password: $REDIS_PASSWORD"
# 获取 Sentinel 密码
SENTINEL_PASSWORD=$(kubectl get secret –namespace middleware redis-sentinel
-o jsonpath="{.data.sentinel-password}" | base64 -d)
# 通过 Service 连接 Redis Master(Sentinel 自动维护指向当前 Master)
kubectl exec -it -n middleware redis-sentinel-node-0 —
redis-cli -a "$REDIS_PASSWORD" -h redis-sentinel-master INFO replication
预期输出:
# Replication
role:master
connected_slaves:2
slave0:ip=10.244.1.15,port=6379,state=online,offset=14256,lag=0
slave1:ip=10.244.2.22,port=6379,state=online,offset=14256,lag=0
master_failover_state:no-failover
role:master 且 connected_slaves:2 确认当前节点为 Master,2 个 Replica 已连接并同步数据。
通过 Sentinel 查询集群拓扑
# 连接 Sentinel 并查询 Master 地址
kubectl exec -it -n middleware redis-sentinel-node-0 —
redis-cli -a "$SENTINEL_PASSWORD" -p 26379 SENTINEL get-master-addr-by-name mymaster
# 查看所有 Sentinel 节点
kubectl exec -it -n middleware redis-sentinel-node-0 —
redis-cli -a "$SENTINEL_PASSWORD" -p 26379 SENTINEL sentinels mymaster
# 查看 Master 的监控副本
kubectl exec -it -n middleware redis-sentinel-node-0 —
redis-cli -a "$SENTINEL_PASSWORD" -p 26379 SENTINEL replicas mymaster
SENTINEL get-master-addr-by-name 会返回当前 Master 的 IP 和端口,这是客户端发现 Master 的标准方式——客户端不应硬编码 Master 地址,而应通过 Sentinel 查询。
验证读写功能
# 写入测试数据
kubectl exec -it -n middleware redis-sentinel-node-0 —
redis-cli -a "$REDIS_PASSWORD" -h redis-sentinel-master SET testkey "hello-ceph-k8s"
# 读取验证
kubectl exec -it -n middleware redis-sentinel-node-0 —
redis-cli -a "$REDIS_PASSWORD" -h redis-sentinel-master GET testkey
# 检查 key 的 TTL 与类型
kubectl exec -it -n middleware redis-sentinel-node-0 —
redis-cli -a "$REDIS_PASSWORD" -h redis-sentinel-master TYPE testkey
模拟故障转移验证(可选)
# 找到当前 Master Pod
MASTER_POD=$(kubectl get pod -n middleware
-l app.kubernetes.io/instance=redis-sentinel,app.kubernetes.io/role=master
-o jsonpath='{.items[0].metadata.name}')
echo "Current Master: $MASTER_POD"
# 强制关闭 Master Redis 进程触发故障转移
kubectl exec -n middleware "$MASTER_POD" — redis-cli -a "$REDIS_PASSWORD" SHUTDOWN NOSAVE
# 等待故障转移完成(约 10-30 秒)
sleep 15
# 再次查询 Sentinel 确认新 Master
kubectl exec -it -n middleware redis-sentinel-node-0 —
redis-cli -a "$SENTINEL_PASSWORD" -p 26379 SENTINEL get-master-addr-by-name mymaster
# 确认数据仍然存在
kubectl exec -it -n middleware redis-sentinel-node-0 —
redis-cli -a "$REDIS_PASSWORD" -h redis-sentinel-master GET testkey
故障转移后
testkey的值应仍为hello-ceph-k8s,证明数据持久化在 Ceph RBD 上且故障转移不会丢失已写入的数据。
日常巡检
健康检查
# 1. 检查所有 Pod 状态(2/2 容器均需 Running)
kubectl get pods -n middleware -l app.kubernetes.io/instance=redis-sentinel
# 2. 检查 Sentinel 仲裁状态
for i in 0 1 2; do
echo "=== Sentinel Node $i ==="
kubectl exec -n middleware redis-sentinel-node-$i —
redis-cli -a "$SENTINEL_PASSWORD" -p 26379 SENTINEL master mymaster
done
# 3. 检查 Redis 复制延迟
kubectl exec -n middleware redis-sentinel-node-0 —
redis-cli -a "$REDIS_PASSWORD" -h redis-sentinel-master INFO replication | grep -E "lag|offset"
日志查看
# 查看 Redis 主日志
kubectl logs -n middleware redis-sentinel-node-0 -c redis
# 查看 Sentinel 日志(关注故障检测与转移记录)
kubectl logs -n middleware redis-sentinel-node-0 -c sentinel
# 查看最近 1 小时的 Sentinel 日志中的关键事件
kubectl logs -n middleware redis-sentinel-node-0 -c sentinel –since=1h |
grep -E "failover|odown|sdown|promote"
性能监控
# 检查 Redis 内存使用
kubectl exec -n middleware redis-sentinel-node-0 —
redis-cli -a "$REDIS_PASSWORD" -h redis-sentinel-master INFO memory |
grep -E "used_memory_human|maxmemory_human|mem_fragmentation_ratio"
# 检查客户端连接数
kubectl exec -n middleware redis-sentinel-node-0 —
redis-cli -a "$REDIS_PASSWORD" -h redis-sentinel-master INFO clients |
grep -E "connected_clients|blocked_clients"
# 检查慢查询日志
kubectl exec -n middleware redis-sentinel-node-0 —
redis-cli -a "$REDIS_PASSWORD" -h redis-sentinel-master SLOWLOG GET 10
# 检查每秒处理命令数(QPS)
kubectl exec -n middleware redis-sentinel-node-0 —
redis-cli -a "$REDIS_PASSWORD" -h redis-sentinel-master INFO stats |
grep instantaneous_ops_per_sec
容量与存储巡检
# 检查 Ceph RBD PVC 使用情况
kubectl get pvc -n middleware -l app.kubernetes.io/instance=redis-sentinel
# 检查 PVC 容量使用率
for i in 0 1 2; do
echo "=== Node $i PVC ==="
kubectl exec -n middleware redis-sentinel-node-$i —
df -h /data | tail -1
done
# 检查 Ceph 后端存储池容量
kubectl exec -n ceph-csi-rbd csi-rbdplugin-xxxxx —
rbd du -p k8s-rbd-pool –format json |
python3 -m json.tool | head -20
常见问题
Q1: 故障转移后客户端连接报错 “MOVED” 或 “NOROUTE”?
A: Redis Sentinel 与 Redis Cluster 是不同方案,不会返回 MOVED 重定向。如果客户端报 NOROUTE,通常是客户端未使用 Sentinel 模式连接。正确做法是客户端连接 Sentinel 端口(26379),通过 SENTINEL get-master-addr-by-name 获取 Master 地址后再连接。主流客户端(如 Jedis、Lettuce、go-redis)均原生支持 Sentinel 模式,只需配置 Sentinel 地址列表而非直连 Master。
Q2: 3 个 Pod 都显示 role:master,数据不一致怎么办?
A: 这通常发生在网络分区(脑裂)场景下。Bitnami Chart 使用 # 哨兵统一仲裁,quorum=2 保证只有多数派 Sentinel 同意的故障转移才会执行。如果出现脑裂,应立即检查 Pod 间网络连通性:
# 检查 Sentinel 间通信
kubectl exec -n middleware redis-sentinel-node-0 —
redis-cli -a "$SENTINEL_PASSWORD" -p 26379 SENTINEL sentinels mymaster
# 如果脑裂已发生,需要手动恢复:找出数据最新的节点,强制其他节点从它同步
# 使用 SENTINEL RESET * 重置所有 Sentinel 状态
kubectl exec -n middleware redis-sentinel-node-0 —
redis-cli -a "$SENTINEL_PASSWORD" -p 26379 SENTINEL RESET mymaster
Q3: Ceph RBD PVC 一直 Pending,Pod 无法启动?
A: 首先确认 StorageClass 名称与 Ceph CSI Driver 状态:
# 确认 StorageClass provisioner 指向 rbd.csi.ceph.com
kubectl get sc ceph-rbd-sc -o jsonpath='{.provisioner}'
# 检查 PVC 事件
kubectl describe pvc -n middleware data-redis-sentinel-node-0
# 检查 CSI Driver Pod 日志
kubectl logs -n ceph-csi-rbd -l app=csi-rbdplugin-provisioner –tail=50
常见原因包括:Ceph monitor 地址不可达、CSI Secret 中的 user/keyring 过期、或 Ceph 存储池未创建。参考第 2 天的 CSI Driver 配置步骤逐一排查。
总结
本篇在 K8s 上通过 Bitnami bitnami/redis Chart 部署了 Redis Sentinel 哨兵模式高可用集群,核心要点回顾:
- 架构选型:Sentinel 模式适合不需要分片但需要自动故障转移的 Redis 场景,3 Sentinel + 1 Master + 2 Replica 是经典高可用组合
- Ceph 持久化:每个 Redis Pod 绑定独立 Ceph RBD PVC,数据写入 Ceph 分布式存储池,确保节点故障后数据不丢失
- 故障转移:Sentinel 通过 quorum 机制保证故障判定的可靠性,Master 故障后自动提升最优 Replica 为新 Master
- 客户端最佳实践:连接 Sentinel 而非直连 Master,让 Sentinel 屏蔽故障转移的复杂性
与第 5 天的 Redis Cluster 相比,Sentinel 模式不支持数据分片,但部署更简单、运维更直观。在实际项目中:数据量大需要分片用 Cluster,需要高可用但单分片够用选 Sentinel。
下期预告
第 7 天:K8s 部署 MinIO 对象存储集群(分布式架构 + 运维巡检)
从 Redis 缓存转向对象存储领域,MinIO 是云原生时代最流行的 S3 兼容对象存储。下一篇我们将部署分布式 MinIO 集群,探索其在 K8s 上的 Erasure Code 纠删码架构与 Ceph 存储的配合。
系列目录
- ✅ 第 1 天:Ceph 分布式存储回顾与 K8s 存储体系概述
- ✅ 第 2 天:K8s 接入 Ceph RBD 块存储(CSI Driver + StorageClass 配置实战)
- ✅ 第 3 天:K8s 接入 CephFS 共享文件存储(多读场景与性能调优)
- ✅ 第 4 天:K8s 部署 MySQL 高可用集群(Ceph RBD 持久化 + 架构设计 + 登录巡检)
- ✅ 第 5 天:K8s 部署 Redis Cluster 集群(Ceph RBD + 架构设计 + 巡检命令)
- 🔥 第 6 天:K8s 部署 Redis Sentinel 哨兵模式(高可用架构 + 登录验证)(本文)
- ⏳ 第 7 天:K8s 部署 MinIO 对象存储集群(分布式架构 + 运维巡检)
- ⏳ 第 8 天:K8s 部署 MongoDB 副本集集群(Ceph RBD + 架构设计 + 登录)
- ⏳ 第 9 天:K8s 部署 Nacos 注册配置中心(集群架构 + 登录巡检)
- ⏳ 第 10 天:K8s 部署 Zookeeper 集群(分布式协调架构 + 运维命令)
- ⏳ 第 11 天:K8s 部署 Elasticsearch 集群(Ceph RBD + 架构设计 + 巡检)
- ⏳ 第 12 天:K8s 部署 Kafka 集群(Ceph RBD + 消息队列架构 + 运维)
- ⏳ 第 13 天:K8s 部署 GitLab 代码托管平台(Ceph RBD 持久化 + 架构 + 巡检)
- ⏳ 第 14 天:K8s 部署 ClickHouse 列式数据库集群(Ceph RBD + 架构设计)
- ⏳ 第 15 天:K8s 中间件统一监控与运维巡检总结(Prometheus + Grafana 全景)

















暂无评论内容