- 如果 Redis 是关键业务组件,并且性能要求极高(低延迟、百万 QPS),使用官方 Redis Cluster 直接部署在裸机或 VM 上更合适。
- 如果 Redis 主要是缓存层,且你的基础设施是 Kubernetes,使用 StatefulSet + Redis Operator 更方便管理和扩展。
裸机主机搭建参考文章:主机模式搭建redis cluster集群
目录
1,安装nfs 服务
推荐在生产中使用 NFS 或其他持久化存储服务。这里使用NFS存储服务。
生产环境中通常会部署独立的 NFS 服务(比如用 NAS、GlusterFS、CephFS),而不是依赖容器内运行的 NFS Server。所以单独部署在主机上,直接跑在宿主机上意味着 更少的网络转发和 NAT,对于 Redis 这种 IO 敏感的服务,延迟更低、吞吐更高。
安装 nfs ,示例IP:172.16.81.129
sudo apt update
sudo apt install -y nfs-kernel-server
# 创建共享目录
sudo mkdir -p /srv/nfs/redis-data
sudo chown nobody:nogroup /srv/nfs/redis-data
# 编辑导出目录
echo "/srv/nfs/redis-data *(rw,sync,no_subtree_check,no_root_squash)" | sudo tee -a /etc/exports
# 重启服务
sudo exportfs -rav
sudo systemctl restart nfs-kernel-server
2,安装NFS CSI 驱动实现自动创建 PV(动态供给)
NFS CSI Driver 是用来动态自动创建 PV(动态供给)的。Redis-0 的 PVC(data-redis-0
)没有绑定成功的 PV,整个 Pod就会无法调度。会报错pod has unbound immediate PersistentVolumeClaims
。
— 手动创建PV —
不想安装插件就手动创建6个PV。
#0-5依次对应pv位置
redis-0 >> /srv/nfs/redis-data/redis-0
....
redis-5 >> /srv/nfs/redis-data/redis-5
在nfs主机创建6个目录
sudo mkdir -p /srv/nfs/redis-data/redis-{0..5}
sudo chown -R nobody:nogroup /srv/nfs/redis-data
sudo exportfs -rav
主节点创建 pv-redis.yaml 文件。
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-redis-0
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: nfs-host
nfs:
server: 172.16.81.129
path: /srv/nfs/redis-data/redis-0
以上文件复制 6 次改掉 pv-redis-X
和 path
路径即可。
最后执行部署6个文件即可,pv就创建完成了。
kubectl apply -f pv-redis-0.yaml
....
kubectl apply -f pv-redis-5.yaml
— 安装NFS CSI自动创建PV —
嫌手动麻烦,可安装官方 NFS CSI Driver,然后 Redis 的 PVC 只要写 storageClassName: nfs-csi
,就能自动在 NFS 主机上动态创建目录并绑定。
官方地址:https://github.com/kubernetes-csi/csi-driver-nfs/tree/master
#在线安装(目前最新版本v4.11.0):
curl -skSL https://raw.githubusercontent.com/kubernetes-csi/csi-driver-nfs/v4.11.0/deploy/install-driver.sh | bash -s v4.11.0 --
#下载本地安装
git clone https://github.com/kubernetes-csi/csi-driver-nfs.git
cd csi-driver-nfs
./deploy/install-driver.sh v4.11.0 local
安装完成后可查看服务。
root@master:/opt/redis-k8s# kubectl -n kube-system get pod -o wide -l app=csi-nfs-controller
root@master:/opt/redis-k8s# kubectl -n kube-system get pod -o wide -l app=csi-nfs-node
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
csi-nfs-controller... 5/5 Running 2 (2m ago) 3m 172.16.81.129 node01 <none> <none>
csi-nfs-node-hcm4b 3/3 Running 1 (2m ago) 3m 172.16.81.129 node01 <none> <none>
csi-nfs-node-v4r5b 3/3 Running 1 (2m ago) 3m 172.16.81.128 master <none> <none>
最后部署redis完成后不需要也可以卸载掉。
#在线卸载
curl -skSL https://raw.githubusercontent.com/kubernetes-csi/csi-driver-nfs/v4.11.0/deploy/uninstall-driver.sh | bash -s v4.11.0 --
#本地卸载
git clone https://github.com/kubernetes-csi/csi-driver-nfs.git
cd csi-driver-nfs
git checkout v4.11.0
./deploy/uninstall-driver.sh v4.11.0 local
3,redis集群yaml文件
文件目录结构如下:
root@master:/opt/redis-k8s#
.
├── 1-namespace.yaml
├── 2-redis-cluster.yaml
├── 3-init-cluster-job.yaml
└── storageclass-nfs.yaml
文件名 | 说明 |
---|---|
1-namespace.yaml | 创建 redis-cluster 命名空间(可以复用) |
2-redis-cluster.yaml | ConfigMap + Service(2个)+ StatefulSet(6节点,挂载 NFS) |
3-init-cluster-job.yaml | 创建 Redis 集群初始化 Job(自动主从+分槽) |
storageclass-nfs.yaml | 定义使用 NFS 的 StorageClass(绑定到NFS) |
第二个文件2-redis-cluster.yaml
,如果想更清晰,分开管理,可以分离单独的3个文件部署。
配置文件ConfigMap一个,Service一个,主体StatefulSet1个即可,这里统一管理,就不分了。
— storageclass-nfs.yaml —
StorageClass 指向 NFS 主机。
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-csi
provisioner: nfs.csi.k8s.io
parameters:
server: 172.16.81.129 # 你的 NFS 服务地址
share: /srv/nfs/redis-data # 你导出的 NFS 路径
reclaimPolicy: Retain
volumeBindingMode: Immediate
这里用的是主路径 /srv/nfs/redis-data
,CSI Driver 会自动为每个 PVC 创建子目录,比如创建完成后nfs目录:
ubuntu@node01:~$ ls /srv/nfs/redis-data/
pvc-1a9349a7-afca-49f6-b073-e45dabcc5365 pvc-57d7a764-2101-4f8b-8e7c-91512e028ad9 pvc-88d9b066-7ed7-4a77-ba55-cabf8d7a47d1
pvc-5777dc53-4815-4047-b3bd-dd49dbe6d3bf pvc-5992e08d-88c4-4b9e-a4c5-51e373c88766 pvc-b55fe3d4-0b44-42b3-a0f8-bcef0528f25d
— 1-namespace.yaml —
apiVersion: v1
kind: Namespace
metadata:
name: redis-cluster
须独立,作用范围全局
— 2-redis-cluster.yaml —
---
apiVersion: v1
kind: ConfigMap
metadata:
name: redis-config
namespace: redis-cluster
data:
redis.conf: |
port 6379
requirepass passwd123
masterauth passwd123
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
dir /data
---
apiVersion: v1
kind: Service
metadata:
name: redis
namespace: redis-cluster
spec:
clusterIP: None
selector:
app: redis
ports:
- port: 6379
---
apiVersion: v1
kind: Service
metadata:
name: redis-access
namespace: redis-cluster
spec:
type: ClusterIP
selector:
app: redis
ports:
- port: 6379
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: redis
namespace: redis-cluster
spec:
serviceName: redis
replicas: 6
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis:7.2
command: [ "redis-server", "/usr/local/etc/redis/redis.conf" ]
ports:
- containerPort: 6379
volumeMounts:
- name: data
mountPath: /data
- name: config
mountPath: /usr/local/etc/redis/redis.conf
subPath: redis.conf
volumes:
- name: config
configMap:
name: redis-config
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: nfs-csi
resources:
requests:
storage: 1Gi
配置文件里面两个服务:
- 第一个是无头服务,允许 StatefulSet 使用 DNS 发现(如
redis-0.redis.redis-cluster.svc.cluster.local
),仅集群内部服务访问使用。 - 第二个是普通服务,用于在初始化集群时作为一个公共连接入口。可按需更改Ingress 或 NodePort暴露端口给外部访问。
可以保留两个,职责不同, 可选优化:如果你通过 kubectl exec
初始化,不需要 redis-access service。
— 3-init-cluster-job.yaml —
初始化集群
apiVersion: batch/v1
kind: Job
metadata:
name: redis-init-cluster
namespace: redis-cluster
spec:
template:
spec:
containers:
- name: redis-init
image: redis:7.2
command:
- sh
- -c
- |
echo "Waiting for Redis pods to be ready...";
sleep 10;
redis-cli --cluster create \
redis-0.redis:6379 \
redis-1.redis:6379 \
redis-2.redis:6379 \
redis-3.redis:6379 \
redis-4.redis:6379 \
redis-5.redis:6379 \
--cluster-replicas 1 -a passwd123 --cluster-yes
restartPolicy: OnFailure
4,部署
— 部署顺序 —
kubectl apply -f storageclass-nfs.yaml
kubectl apply -f 1-namespace.yaml
kubectl apply -f 2-redis-cluster.yaml
#等待所有在 redis-cluster 命名空间中,带有 app=redis 标签的 Pod,进入 Ready 状态,最多等 300 秒。
kubectl wait --for=condition=Ready pod -l app=redis -n redis-cluster --timeout=300s
#node都ready后执行初始化集群
kubectl apply -f 3-init-cluster-job.yaml
— 集群查看验证 —
查看集群
root@master:/opt/redis-k8s# kubectl get pods -n redis-cluster -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
redis-0 1/1 Running 0 15m 10.244.196.135 node01 <none> <none>
redis-1 1/1 Running 0 4m5s 10.244.219.76 master <none> <none>
redis-2 1/1 Running 0 4m2s 10.244.196.136 node01 <none> <none>
redis-3 1/1 Running 0 3m59s 10.244.219.77 master <none> <none>
redis-4 1/1 Running 0 3m57s 10.244.196.137 node01 <none> <none>
redis-5 1/1 Running 0 3m55s 10.244.196.138 node01 <none> <none>
redis-init-cluster-fgdsn 0/1 Completed 0 27s 10.244.196.139 node01 <none> <none>
查看初始化日志
root@master:/opt/redis-k8s# kubectl logs -n redis-cluster pod/redis-init-cluster-fgdsn
Waiting for Redis pods to be ready...
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica redis-4.redis:6379 to redis-0.redis:6379
Adding replica redis-5.redis:6379 to redis-1.redis:6379
Adding replica redis-3.redis:6379 to redis-2.redis:6379
M: 9aecccf8d6857a6d67a0f5b52ce85dbf9c667b78 redis-0.redis:6379
slots:[0-5460] (5461 slots) master
M: 281228e13747ebc41577979243d5166846ea2c81 redis-1.redis:6379
slots:[5461-10922] (5462 slots) master
M: 970d60926019635d605c8d999eccaf69343099cd redis-2.redis:6379
slots:[10923-16383] (5461 slots) master
S: c0fbc76dd0002db204842b8cb6f434f97dcb832e redis-3.redis:6379
replicates 970d60926019635d605c8d999eccaf69343099cd
S: 202e3cf341c722817cac1248a2a413cd1a2d72fb redis-4.redis:6379
replicates 9aecccf8d6857a6d67a0f5b52ce85dbf9c667b78
S: 8e0e18c60ae05eefb1fb0b722d0dc05e1774bbb9 redis-5.redis:6379
replicates 281228e13747ebc41577979243d5166846ea2c81
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
>>> Performing Cluster Check (using node redis-0.redis:6379)
M: 9aecccf8d6857a6d67a0f5b52ce85dbf9c667b78 redis-0.redis:6379
slots:[0-5460] (5461 slots) master
1 additional replica(s)
S: 202e3cf341c722817cac1248a2a413cd1a2d72fb 10.244.196.137:6379
slots: (0 slots) slave
replicates 9aecccf8d6857a6d67a0f5b52ce85dbf9c667b78
S: 8e0e18c60ae05eefb1fb0b722d0dc05e1774bbb9 10.244.196.138:6379
slots: (0 slots) slave
replicates 281228e13747ebc41577979243d5166846ea2c81
M: 970d60926019635d605c8d999eccaf69343099cd 10.244.196.136:6379
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
M: 281228e13747ebc41577979243d5166846ea2c81 10.244.219.76:6379
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
S: c0fbc76dd0002db204842b8cb6f434f97dcb832e 10.244.219.77:6379
slots: (0 slots) slave
replicates 970d60926019635d605c8d999eccaf69343099cd
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
初始化也没问题,集群就部署完了。
查看无头服务dns解析也没问题。
root@master:/opt/redis-k8s# kubectl get svc -n kube-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 13d
root@master:/opt/redis-k8s# nslookup redis.redis-cluster.svc.cluster.local 10.96.0.10
Server: 10.96.0.10
Address: 10.96.0.10#53
Name: redis.redis-cluster.svc.cluster.local
Address: 10.244.196.135
Name: redis.redis-cluster.svc.cluster.local
Address: 10.244.196.138
Name: redis.redis-cluster.svc.cluster.local
Address: 10.244.219.77
Name: redis.redis-cluster.svc.cluster.local
Address: 10.244.196.137
Name: redis.redis-cluster.svc.cluster.local
Address: 10.244.219.76
Name: redis.redis-cluster.svc.cluster.local
Address: 10.244.196.136
命令测试
root@master: kubectl exec -it redis-0 -n redis-cluster -- redis-cli -a passwd123 -c cluster nodes
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
281228e13747ebc41577979243d5166846ea2c81 10.244.219.76:6379@16379 myself,master - 0 1745036774000 2 connected 5461-10922
202e3cf341c722817cac1248a2a413cd1a2d72fb 10.244.196.137:6379@16379 slave 9aecccf8d6857a6d67a0f5b52ce85dbf9c667b78 0 1745036774000 1 connected
9aecccf8d6857a6d67a0f5b52ce85dbf9c667b78 10.244.196.135:6379@16379 master - 0 1745036775128 1 connected 0-5460
c0fbc76dd0002db204842b8cb6f434f97dcb832e 10.244.219.77:6379@16379 slave 970d60926019635d605c8d999eccaf69343099cd 0 1745036774120 3 connected
8e0e18c60ae05eefb1fb0b722d0dc05e1774bbb9 10.244.196.138:6379@16379 slave 281228e13747ebc41577979243d5166846ea2c81 0 1745036775128 2 connected
970d60926019635d605c8d999eccaf69343099cd 10.244.196.136:6379@16379 master - 0 1745036775027 3 connected 10923-16383
root@master: kubectl exec -it redis-0 -n redis-cluster -- redis-cli -a passwd123 -c cluster info
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:2
cluster_stats_messages_ping_sent:107940
cluster_stats_messages_pong_sent:110904
cluster_stats_messages_meet_sent:1
cluster_stats_messages_sent:218845
cluster_stats_messages_ping_received:110904
cluster_stats_messages_pong_received:107941
cluster_stats_messages_received:218845
total_cluster_links_buffer_limit_exceeded:0
root@master: kubectl exec -it redis-1 -n redis-cluster -- redis-cli -a passwd123 -c
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> set redis hello
-> Redirected to slot [1151] located at 10.244.196.135:6379
OK
10.244.196.135:6379> exit
root@master: kubectl exec -it redis-2 -n redis-cluster -- redis-cli -a passwd123 -c
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> get redis
-> Redirected to slot [1151] located at 10.244.196.135:6379
"hello"
10.244.196.135:6379>
Pingback引用通告: 主机模式搭建redis cluster集群 - 运维笔记(ywbj.cc)