平时做技术实践时,很多问题不是概念不会,而是细节没串起来。拿“Redis Cluster 高可用集群部署方案”来说,它看着像小点,放到项目里常会牵出环境、配置、兼容性和维护成本。下面按实际采用顺序,把思路、关键写法和容易踩坑的地方讲清楚,便于大家直接对照操作。
Redis Cluster 高可用集群的 标准部署方案是“3主3从”共6个节点理解这一步时,,最少需3个主节点才能形成法定多数投票机制,每个主节点至少配1个从节点用来故障自动切换,这样能容忍1个主节点及其对应从节点同时故障。
一、方案概述
1.1 目标
结合项目来看,在已有的 K8s 高可用集群上,部署一套 Redis Cluster(集群模式),具备:
- 高可用:3 主 3 从,容忍 1 个主节点故障
- 数据分片:16384 个 hash 平均分配到 3 个主节点
- 自动故障转移:主节点故障时,从节点自动提升为主
- 持久化:每个节点独立 PVC,数据落盘
1.2 技术选型
| 组件 | 用途 |
|---|---|
| Bitnami Redis Cluster Helm Chart | 部署 Redis Cluster |
| StatefulSet | 管理 6 个 Redis Pod |
| PersistentVolumeClaim | 每个节点的持久化存储 |
| Redis Cluster | 数据分片和自动故障转移 |
1.3 架构
应用
↓
Service: production-redis-redis-cluster:6379
↓
Redis Cluster (3 主 3 从)
├── master-0 ( 0-5460) ← slave-0
├── master-1 ( 5461-10922) ← slave-1
└── master-2 ( 10923-16383) ← slave-2
↓
PersistentVolume (local-path)
二、前置条件
2.1 K8s 集群状态
- 至少 3 个可调度节点
- 集群
kubectl get nodes全部Ready - CNI 已部署(Flannel 或 Calico)
2.2 存储要求
Redis 的 StatefulSet 需动态存储。必须提前配好 StorageClass。
检查:
kubectl get storageclass
预期:至少有一个 StorageClass,且设为 default。
若没有,先装 Local Path Provisioner:
kubectl apply -f https://raw.githubusercontent.com/rancher/local-path-provisioner/v0.0.28/deploy/local-path-storage.
kubectl patch storageclass local-path -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
解析:
kubectl apply -f:部署 Provisioner。kubectl patch:设为默认 StorageClass。
2.3 镜像网络要求
这是最容易踩坑的地方。 Redis Cluster 需以下镜像:
| 镜像 | 仓库 |
|---|---|
| bitnami/redis-cluster | Docker Hub |
| bitnami/redis-exporter | Docker Hub(可选,坚控用) |
落到代码里,Bitnami 从 2025 年 8 月 28 日起,把免费镜像从 Docker Hub 公共目录移除了。 直接拉 bitnami/redis-cluster 会得到 403 Forbidden。
解决方案:从 bitnamilegacy 仓库拉旧版镜像,随后打标签。
# 从 DaoCloud 代理拉 bitnamilegacy 镜像
crictl pull docker.m.daocloud.io/bitnamilegacy/redis-cluster:8.2.1-debian-12-r0
# 打标签,让 containerd 认为本地有 bitnami/redis-cluster
ctr -n k8s.io images tag docker.m.daocloud.io/bitnamilegacy/redis-cluster:8.2.1-debian-12-r0 docker.io/bitnami/redis-cluster:8.2.1-debian-12-r0
解析:
crictl pull:用 containerd 拉镜像。docker.m.daocloud.io/bitnamilegacy/:DaoCloud 代理的 Bitnami Legacy 仓库,免认证。ctr -n k8s.io images tag:在 K8s 命名空间里给镜像打新标签。docker.io/bitnami/redis-cluster:Helm chart 里 Pod 引用的镜像名。
2.4 设置 containerd 镜像加速
在每台节点上设置,解决所有 Docker Hub 镜像拉取问题。
编辑 /etc/containerd/config.,找到:
[plugins."io.containerd.grpc.v1.cri".registry.mirrors]
在它下面加:
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
endpoint = [
"https://docker.m.daocloud.io",
"https://docker.mirrors.ustc.edu.cn"
]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."ghcr.io"]
endpoint = [
"https://ghcr.nju.edu.cn"
]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."quay.io"]
endpoint = [
"https://quay.mirrors.ustc.edu.cn"
]
解析:
endpoint是数组,containerd 会按顺序尝试,第一个失败试第二个。- 多个源提高容错性。
重启:
systemctl restart containerd
systemctl status containerd --no-pager | head -5
用 Ansible 批量推:
---
- name: 配置 containerd 多镜像源
hosts: k8s_cluster
gather_facts: no
become: no
tasks:
- name: 备份
copy:
src: /etc/containerd/config.
dest: /etc/containerd/config..bak
remote_src: yes
force: no
- name: 插入 docker.io 镜像加速
blockinfile:
path: /etc/containerd/config.
marker: "# {mark} ANSIBLE MANAGED MIRRORS"
insertbefore: '\[plugins\."io\.containerd\.grpc\.v1\.cri"\.x509_key_pair_streaming\]'
block: |
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
endpoint = [
"https://docker.m.daocloud.io",
"https://docker.mirrors.ustc.edu.cn"
]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."ghcr.io"]
endpoint = [
"https://ghcr.nju.edu.cn"
]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."quay.io"]
endpoint = [
"https://quay.mirrors.ustc.edu.cn"
]
- name: 重启 containerd
systemd:
name: containerd
state: restarted
enabled: yes
- name: 验证状态
command: systemctl is-active containerd
register: status
changed_when: false
- name: 输出
debug:
msg: "{{ inventory_hostname }}: containerd {{ status.stdout }}"
执行:
ansible-playbook -i inventory.ini containerd-mirror-multi.yml
三、安装 Helm
3.1 确认 Helm 可用
helm version
如果没有:
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 |
hash -r
helm version
解析
curl ... |:下载官方安装脚本同时执行。hash -r:让 shell 重新扫描 PATH。
四、下载 Redis Cluster Chart
4.1 从 DaoCloud 代理拉取
不能用 helm repo add bitnami,因为 Bitnami 的 chart 走 Docker Hub OCI,国内不通。
直接用 DaoCloud 代理:
helm pull oci://docker.m.daocloud.io/bitnamicharts/redis-cluster --version 13.0.4
解析:
helm pull:只下载 chart,不安装。oci://docker.m.daocloud.io/bitnamicharts/redis-cluster:DaoCloud 代理的 OCI 地址。--version 13.0.4:指定版本,避免查最新版超时。
预期输出:
Pulled: docker.m.daocloud.io/bitnamicharts/redis-cluster:13.0.4
Digest: sha256:45229772bdde004303e5eaf12c1fff839811ba7f17d63e9fc6cbd8923d0531c2
下载后本地会有:redis-cluster-13.0.4.tgz
4.2 常用问题
问题:华为云源得到 401
Error: INSTALLATION FAILED: GET "...swr.cn-north-4.myhuaweicloud.com...": response status code 401: denied: You may not login yet
原因:华为云的 Docker Hub 代理需登录认证。
解决方案:用 DaoCloud,它免认证。
五、部署 Redis Cluster
5.1 新建命名空间
kubectl create namespace redis
解析:
kubectl create namespace:新建redis命名空间。- Helm 的
--namespace参数不会自动新建命名空间,需提前建好。
5.2 安装 Chart
helm install production-redis ./redis-cluster-13.0.4.tgz \
--namespace redis \
--set password=l48pW3luQOpBkJyAyFfJ \
--set cluster.nodes=6 \
--set cluster.replicas=1
逐项解析:
| 参数 | 含义 |
|---|---|
production-redis | release 名 |
./redis-cluster-13.0.4.tgz | 本地 chart 包 |
--namespace redis | 装到 redis 命名空间 |
--set password=... | 设置 Redis 密码 |
--set cluster.nodes=6 | 总共 6 个节点(3 主 3 从) |
--set cluster.replicas=1 | 每个主节点 1 个从节点 |
预期输出:
NAME: production-redis
LAST DEPLOYED: ...
NAMESPACE: redis
STATUS: deployed
REVISION: 1
5.3 观察 Pod 启动
kubectl get pods -n redis -w
按 Ctrl+C 退出。
预期:6 个 Pod 逐渐启动。
NAME READY STATUS RESTARTS AGE
production-redis-redis-cluster-0 1/1 Running 0 ...
production-redis-redis-cluster-1 1/1 Running 0 ...
production-redis-redis-cluster-2 1/1 Running 0 ...
production-redis-redis-cluster-3 1/1 Running 0 ...
production-redis-redis-cluster-4 1/1 Running 0 ...
production-redis-redis-cluster-5 1/1 Running 0 ...
5.4 常用问题
问题一:Pod 卡在 ImagePullBackOff,拉 bitnami/redis-cluster 失败
原因:Bitnami 从 2025 年 8 月 28 日起移除了 Docker Hub 公共目录的免费镜像,得到 403 Forbidden。
排查:
kubectl describe pod -n redis production-redis-redis-cluster-0 | grep -A10 "Events:"
解决方案:从 bitnamilegacy 拉镜像,打标签。
# 每台节点执行
crictl pull docker.m.daocloud.io/bitnamilegacy/redis-cluster:8.2.1-debian-12-r0
ctr -n k8s.io images tag docker.m.daocloud.io/bitnamilegacy/redis-cluster:8.2.1-debian-12-r0 docker.io/bitnami/redis-cluster:8.2.1-debian-12-r0
用 Ansible 批量:
ansible k8s_cluster -i inventory.ini -m shell -a "
crictl pull docker.m.daocloud.io/bitnamilegacy/redis-cluster:8.2.1-debian-12-r0
ctr -n k8s.io images tag docker.m.daocloud.io/bitnamilegacy/redis-cluster:8.2.1-debian-12-r0 docker.io/bitnami/redis-cluster:8.2.1-debian-12-r0
" -b
然后删除卡住的 Pod:
kubectl delete pod -n redis --all
问题二:Pod 卡在 Pending,报 FailedScheduling
原因:PVC 绑不上,或节点不够。
排查:
kubectl get pvc -n redis
kubectl describe pod -n redis production-redis-redis-cluster-0 | tail -30
如果 PVC 是 Pending,检查 Provisioner:
kubectl get pods -n local-path-storage
kubectl logs -n local-path-storage -l app=local-path-provisioner --tail=50
问题三:Pod 卡在 ContainerCreating,报挂载失败
原因:PV 绑定失败。
排查:
kubectl describe pod -n redis production-redis-redis-cluster-0 | grep -A5 "Volumes"
kubectl get pv | grep redis
六、验证集群
6.1 查看 Pod 状态
kubectl get pods -n redis -o wide
预期:6 个 Pod 全部 Running 1/1。
6.2 取密码
export REDIS_PASSWORD=$(kubectl get secret --namespace redis production-redis-redis-cluster -o jsonpath="{.data.redis-password}" | base64 -d)
echo $REDIS_PASSWORD解析:
kubectl get secret:取 Bitnami 自动新建的 Secret。-o jsonpath="{.data.redis-password}":提取密码字段。| base64 -d:解码。export:存到环境变量。
保存这个密码。
6.3 查看集群节点
kubectl exec -it -n redis production-redis-redis-cluster-0 -- redis-cli -a $REDIS_PASSWORD cluster nodes
解析:
kubectl exec -it:进入 Pod 执行命令。-n redis:命名空间。production-redis-redis-cluster-0:Pod 名。redis-cli cluster nodes:查看集群拓扑。-a:密码。
预期输出:
10.244.5.21:6379@16379 myself,master - 0 0 1 connected 0-5460 10.244.0.7:6379@16379 master - 0 ... 2 connected 5461-10922 10.244.6.17:6379@16379 master - 0 ... 3 connected 10923-16383 10.244.5.20:6379@16379 slave ... 10.244.1.7:6379@16379 slave ... 10.244.4.7:6379@16379 slave ...
关注:
- 3 个
master,各自负责一段 。 - 3 个
slave,分别跟随对应的 master。 - 所有节点
connected。 - 覆盖 0-16383 全部 16384 个,没有遗漏。
6.4 查看集群信息
kubectl exec -it -n redis production-redis-redis-cluster-0 -- redis-cli -a $REDIS_PASSWORD cluster info
预期关键字段:
| 字段 | 值 | 含义 |
|---|---|---|
cluster_state | ok | 集群正常 |
cluster_s_assigned | 16384 | 所有 都分配了 |
cluster_known_nodes | 6 | 6 个节点都认识 |
cluster_size | 3 | 3 个分片 |
6.5 验证读写
kubectl exec -it -n redis production-redis-redis-cluster-0 -- redis-cli -c -a $REDIS_PASSWORD set test-key "hello"
kubectl exec -it -n redis production-redis-redis-cluster-0 -- redis-cli -c -a $REDIS_PASSWORD get test-key
解析:
-c:集群模式,自动跟随重定向。set/get:写入和读取。
预期:
set得到OK。get得到"hello"。
6.6 高可用验证
测试:删掉一个 master,看自动故障转移
第一步:找到 master 对应的 Pod
kubectl exec -it -n redis production-redis-redis-cluster-0 -- redis-cli -a $REDIS_PASSWORD cluster nodes | grep myself
出里 myself,master 那一行就是当前 Pod 的角色。记下它的 IP。
第二步:找到 IP 对应的 Pod 名
kubectl get pods -n redis -o wide
第三步:删掉那个 Pod
kubectl delete pod -n redis
第四步:观察
kubectl get pods -n redis -w
预期:
- 被删的 master 短暂下线。
- 它的 slave 被提升为新 master。
- 原 master 重建后,以 slave 身份重新加入。
- 集群自动恢复, 不丢。
第五步:验证恢复
kubectl exec -it -n redis production-redis-redis-cluster-1 -- redis-cli -a $REDIS_PASSWORD cluster nodes
预期:6 个节点重新在线,角色可能互换,但 分配仍然完整。
七、应用接入
7.1 连接信息
在集群内部:
| 用途 | 地址 |
|---|---|
| Redis Cluster | production-redis-redis-cluster.redis.svc.cluster.local:6379 |
简写(同命名空间):
production-redis-redis-cluster:6379
跨命名空间:
production-redis-redis-cluster.redis.svc.cluster.local:6379
密码:从 Secret 取。
7.2 应用设置示例
Python (redis-py):
from redis.cluster import RedisCluster
client = RedisCluster(
host='production-redis-redis-cluster.redis',
port=6379,
password='<密码>',
decode_responses=True
)
Node.js (ioredis):
const Redis = require('ioredis');
const cluster = new Redis.Cluster([
{ host: 'production-redis-redis-cluster.redis', port: 6379 }
], {
redisOptions: {
password: '<密码>'
}
});Java (Lettuce):
RedisClusterClient client = RedisClusterClient.create(
"redis://:<密码>@production-redis-redis-cluster.redis:6379"
);
Go (go-redis):
import "github.com/redis/go-redis/v9"
rdb := redis.NewClusterClient(&redis.ClusterOptions{
Addrs: []string{"production-redis-redis-cluster.redis:6379"},
Password: "<密码>",
})
7.3 部署后端服务到 K8s
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-backend
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: my-backend
template:
metadata:
labels:
app: my-backend
spec:
containers:
- name: my-backend
image: my-backend:latest
ports:
- containerPort: 8080
env:
- name: REDIS_HOST
value: "production-redis-redis-cluster.redis"
- name: REDIS_PORT
value: "6379"
- name: REDIS_PASSWORD
valueFrom:
secretKeyRef:
name: production-redis-redis-cluster
key: redis-password
解析:
env:把连接信息借助环境变量传给应用。valueFrom.secretKeyRef:从 Secret 取密码,不写在 里。
7.4 验证连通性
进后端 Pod:
kubectl exec -it-- sh
测试端口:
nc -zv production-redis-redis-cluster.redis 6379
解析:
nc -zv:测试端口连通性。- 得到
succeeded说明网络通。
八、常用操作
8.1 查看集群状态
kubectl get pods -n redis
kubectl get pvc -n redis
kubectl get svc -n redis
8.2 查看日志
kubectl logs -n redis production-redis-redis-cluster-0 --tail=100
8.3 连接 Redis
kubectl exec -it -n redis production-redis-redis-cluster-0 -- redis-cli -c -a $REDIS_PASSWORD
8.4 扩容集群
增加节点:
helm upgrade production-redis ./redis-cluster-13.0.4.tgz \
--namespace redis \
--set password=l48pW3luQOpBkJyAyFfJ \
--set cluster.nodes=8 \
--set cluster.replicas=1
解析:
cluster.nodes=8:从 6 个增加到 8 个(4 主 4 从)。- Helm 会滚动更新 StatefulSet。
8.5 删除集群
helm uninstall production-redis -n redis
kubectl delete pvc -n redis -l app.kubernetes.io/instance=production-redis
kubectl delete namespace redis
警告:删除 PVC 会删除所有数据,操作前先备份。
九、架构总结
9.1 组件清单
| 组件 | 数量 | 作用 |
|---|---|---|
| Redis Pod | 6 | 3 主 3 从 |
| StatefulSet | 1 | 管理 Redis Pod |
| PVC | 6 | 每个 Pod 一块存储 |
| Service | 2 | 集群内部通信和客户端入口 |
| Secret | 1 | Redis 密码 |
9.2 端口速查
| 端口 | 用途 |
|---|---|
| 6379 | Redis 客户端连接 |
| 16379 | Redis Cluster 总线(集群内部通信) |
9.3 高可用机制
| 故障场景 | 影响 | 恢复方式 |
|---|---|---|
| 从节点故障 | 无影响 | 主节点继续服务,从节点重建后重新同步 |
| 主节点故障 | 该分片短暂不可用 | 从节点自动提升为主, 自动接管 |
| 多个主节点故障 | 部分 不可用 | 若超过半数主节点故障,集群停止服务 |
9.4 已知隐患
| 隐患 | 影响 | 解决方案 |
|---|---|---|
| 节点集中在 q5、q6 | 节点故障影响多个 Pod | 加工作节点,或允许调度到控制平面 |
| Local Path 存储 | Pod 漂移数据丢失 | 换 NFS / Ceph / Longhorn |
| Bitnami 免费镜像移除 | 无法拉取最新镜像 | 用 bitnamilegacy 旧版镜像 |
| 未配备份 | 数据无法恢复 | 用 redis-cli --rdb 或 Redis 持久化 |
十、总结
落到代码里,这套 Redis Cluster 基于 Bitnami Helm Chart,提供了:
- 高可用:3 主 3 从,容忍 1 个主节点故障
- 数据分片:16384 个 平均分配到 3 个主节点
- 自动故障转移:主节点故障时,从节点自动提升
- 持久化:每个节点独立 PVC
- 声明式管理:Helm chart 一条命令部署
部署中最容易踩的坑:
- Bitnami 免费镜像移除:必须用
bitnamilegacy旧版镜像,同时打标签。 - Docker Hub 访问超时:必须配 containerd 镜像加速。
- Helm chart 拉取超时:用 DaoCloud 的 OCI 代理。
结合项目来看,总的来说,Redis Cluster 集群部署适合结合实际项目边做边理解。先抓住核心思路,再逐步补上细节和边界处理,最后效果会更稳定,也更容易复用。

