主题
Redis 高可用集群部署文档
环境:RKE2 v1.35.6(6 节点)|内部 Harbor
192.168.122.156:30000|NFS192.168.122.1:/mnt/xfs/rancher/redis组件:Redis 8.0.2 主从(1主2从)+ Sentinel 自动故障转移 + 读写分离 Service + CronJob 每日备份 更新:2026-08-01
1. 架构
应用 ──写──► redis-master.redis:6379 selector isMaster=true(始终指向当前主库)
──读──► redis-read.redis:6379 selector isMaster=false(负载到全部从库)
└─Sentinel 感知客户端─► redis.redis:26379(masterSet: mymaster)
redis-node-0/1/2(每 Pod 3 容器:redis + sentinel + labeler),跨 3 个节点
主从异步复制 + Sentinel 自动故障转移(quorum=2)
存储:NFS 192.168.122.1:/mnt/xfs/rancher/redis(StorageClass: nfs-redis)
备份: CronJob 每天 02:00(北京) redis-cli --rdb → NFS,保留 7 天
补偿: redis-label-sync 每 5 分钟补打丢失的 isMaster 标签与 MySQL 方案的关键差异:Redis 用 Sentinel 实现自动故障转移(主库宕机 ~30s 自动选主), 读写分离通过 isMaster 标签驱动的两个 Service 实现,无需 ProxySQL 类代理。
2. 镜像与 Chart(全部来自内部 Harbor)
| 内容 | 内部地址 | 来源 |
|---|---|---|
| Redis 镜像 | redis/redis:8.0.2-debian-12-r4 | daocloud bitnamilegacy/redis |
| Sentinel 镜像 | redis/redis-sentinel:8.0.2-debian-12-r2 | daocloud bitnamilegacy/redis-sentinel |
| labeler 镜像 | redis/kubectl:1.33.2-debian-12-r0 | daocloud bitnamilegacy/kubectl |
| Redis chart | oci://…/charts/redis:21.2.6 | daocloud OCI bitnamicharts/redis |
| NFS provisioner | charts/nfs-subdir-external-provisioner:4.0.18 + sig-storage/…:v4.0.2 | Harbor 已有 |
3. 前置准备
3.1 NFS 导出(192.168.122.1,已就绪)
bash
mkdir -p /mnt/xfs/rancher/redis
echo '/mnt/xfs/rancher/redis *(rw,sync,no_subtree_check,no_root_squash)' >> /etc/exports
exportfs -ra3.2 Harbor 项目与物料同步
bash
curl -u 'admin:xxx' -X POST 'http://192.168.122.156:30000/api/v2.0/projects' \
-H 'Content-Type: application/json' -d '{"project_name":"redis","public":true}'
export HARBOR_USER=admin HARBOR_PASS='xxx'
./deploy.sh sync # 3 个镜像 + redis chart 一键同步4. 一键部署
交付目录 redis/:
redis/
├── deploy.sh # 一键部署(all|sync|check)
├── redis-values.yaml # bitnami redis chart 参数(Sentinel、存储、RBAC)
├── nfs-provisioner-values.yaml # 专用 StorageClass nfs-redis
├── rw-services.yaml # redis-read 读服务 + isMaster 标签补偿 CronJob(含 RBAC)
├── backup.yaml # 备份 PVC + CronJob(RDB,保留 7 天)
├── .secrets.env # REDIS_PASSWORD(勿提交公共仓库)
└── README.md / 部署文档.md / 操作文档.mdbash
export KUBECONFIG=~/.kube/config-122.31
cd redis/
./deploy.sh手动分步(等价命令)
bash
kubectl create ns redis
helm install redis-nfs-provisioner \
oci://192.168.122.156:30000/charts/nfs-subdir-external-provisioner \
--version 4.0.18 --plain-http -n redis -f nfs-provisioner-values.yaml
helm install redis oci://192.168.122.156:30000/charts/redis \
--version 21.2.6 --plain-http -n redis -f redis-values.yaml
kubectl apply -f rw-services.yaml -f backup.yaml
# 初次部署后给两个从库补打标签(之后由 labeler + label-sync 自动维护)
kubectl -n redis label pod redis-node-<从库序号> isMaster=false5. 部署后验证
bash
# 3 个节点 3/3 Running(redis+sentinel+labeler),跨节点分布,主库带 isMaster=true
kubectl -n redis get pods -l app.kubernetes.io/instance=redis -L isMaster -o wide
# Sentinel 视角主库
kubectl -n redis exec <主库Pod> -c sentinel -- \
redis-cli -p 26379 -a "$PW" --no-auth-warning SENTINEL get-master-addr-by-name mymaster
# 读写分离
kubectl -n redis get endpoints redis-master redis-read # master→主库IP, read→两个从库IP
redis-cli -h redis-master -a "$PW" SET k v # 写主库
redis-cli -h redis-read -a "$PW" GET k # 读从库
# 备份
kubectl -n redis create job --from=cronjob/redis-backup redis-backup-manual-$(date +%s)
# 故障转移演练:删除主库 Pod,~30s 后 Sentinel 完成选主,
# redis-master/redis-read 后端自动切换,数据不丢(异步复制无写入冲突时)
kubectl -n redis delete pod <主库Pod>6. 关键设计决策与踩坑记录
- Sentinel 而非单纯主从:bitnami
architecture=replication + sentinel.enabled=true, 每个节点 Pod 内 3 容器(redis / sentinel / kubectl labeler),主库宕机自动选主。 replica.replicaCount在 Sentinel 模式是节点总数:1主2从要填 3(默认 3), 填 2 只有 1主1从。这是与直觉不符的坑。- 读写分离靠标签 Service:
sentinel.masterService.enabled=true生成redis-master(selectorisMaster=true),chart labeler 在选主事件时维护标签; 读服务redis-read(selectorisMaster=false)为自建,见rw-services.yaml。 必须同时开启rbac.create + serviceAccount.create + replica.automountServiceAccountToken, 否则 chart 校验拒绝部署。 - 从库 Pod 重建丢标签:labeler 只在选主事件时打标,重建的从库 Pod 没有
isMaster=false, 会掉出redis-read后端。由redis-label-syncCronJob(每 5 分钟)自动补偿, 其 RBAC 独立配置(chart 自带 SA 无 pods get 权限)。 - 备份用
redis-cli --rdb:通过 SYNC 从主库拉全量 RDB(主库 fork BGSAVE 子进程,不阻塞), 避免直接挂载主库数据卷。 - bitnami 镜像下线:同 MySQL,用
bitnamilegacy仓库 +global.security.allowInsecureImages。
7. 应用接入
写: redis-master.redis.svc.cluster.local:6379
读: redis-read.redis.svc.cluster.local:6379
Sentinel 客户端: redis.redis.svc.cluster.local:26379, masterSet=mymaster
密码: xxx .secrets.env