Ceph+K8s 中间件实战 | 第 6 天:K8s 部署 Redis Sentinel 哨兵模式(高可用架构 + 登录验证)

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

K8s Logo

引言

在前一天的实战中,我们使用 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 实例部署在同一节点,减少网络延迟对故障检测的干扰。

数据流向

  1. 写入路径:客户端通过 redis Service 连接当前 Master → Master 处理写请求 → 异步复制到 2 个 Replica
  2. 读取路径:客户端可通过 redis Service 读 Master,也可直连 Replica 读取(读写分离)
  3. 故障检测:3 个 Sentinel 每秒向 Master/Replica/其他 Sentinel 发送 PING → 超过 down-after-milliseconds 无响应则标记为主观下线(SDOWN)→ 达到 quorum 个 Sentinel 同意则升级为客观下线(ODOWN)
  4. 故障转移: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 已成功供给持久化卷。

K8s Logo

登录验证

获取连接密码与连接 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 存储的配合。

系列目录

微信二维码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发
头像 - 恒星
欢迎您留下宝贵的见解!
提交
头像 - 恒星

昵称

取消
昵称表情代码图片快捷回复

    暂无评论内容