K8s部署 Redis 主从集群
原文链接
一、 Redis集群说明
一般来说,Redis部署有三种模式。
1)单实例模式 一般用于测试环境。
2)哨兵模式 在redis3.0以前,要实现集群一般是借助哨兵sentinel工具来监控master节点的状态。如果master节点异常,则会做主从切换,将某一台slave作为master。引入了哨兵节点,部署更复杂,维护成本也比较高,并且性能和高可用性等各方面表现一般。
3)集群模式 3.0 后推出的 Redis 分布式集群解决方案;主节点提供读写操作,从节点作为备用节点,不提供请求,只作为故障转移使用;如果master节点异常,会自动做主从切换,将slave切换为master。
后两者用于生产部署,但总的来说,集群模式明显优于哨兵模式。k8s环境下,如何部署redis集群(三主三从)。
二、安装NFS
1、在 master 节点(也可以在其它节点)创建 NFS 存储
yum -y install nfs-utils rpcbind
2、创建NFS共享文件夹
mkdir -p /var/nfs/redis/pv{1..6}
3、配置共享文件夹
vim /etc/exports/var/nfs/redis/pv1 *(rw,sync,no_root_squash) /var/nfs/redis/pv2 *(rw,sync,no_root_squash) /var/nfs/redis/pv3 *(rw,sync,no_root_squash) /var/nfs/redis/pv4 *(rw,sync,no_root_squash) /var/nfs/redis/pv5 *(rw,sync,no_root_squash) /var/nfs/redis/pv6 *(rw,sync,no_root_squash)
4、使配置生效
exportfs -r
5、查看所有共享目录
exportfs -v
6、启动nfs
systemctl start nfs-server systemctl enabled nfs-server systemctl start rpcbind systemctl enabled rpcbind
7、其他节点安装nfs-utils
yum -y install nfs-utils
三、创建PV卷
1、创建namespace
kubectl create ns redis-cluster
2、创建nfs 客户端sa授权
cat > redis-nfs-client-sa.yamlapiVersion: v1 kind: ServiceAccount metadata:name: redis-nfs-clientnamespace: redis-cluster --- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata:name: nfs-client-runnernamespace: redis-cluster rules:- apiGroups: [""]resources: ["persistentvolumes"]verbs: ["get","list","watch","create","delete"]- apiGroups: [""]resources: ["persistentvolumeclaims"]verbs: ["get","list","watch","create","delete"]- apiGroups: ["storage.k8s.io"]resources: ["storageclasses"]verbs: ["get","list","watch"]- apiGroups: [""]resources: ["events"]verbs: ["get","list","watch","create","update","patch"]- apiGroups: [""]resources: ["endpoints"]verbs: ["create","delete","get","list","watch","patch","update"]--- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata:name: run-nfs-provisionernamespace: redis-cluster subjects:- kind: ServiceAccountname: redis-nfs-clientnamespace: redis-cluster roleRef:kind: ClusterRolename: nfs-client-runnerapiGroup: rbac.authorization.k8s.io
3、创建nfs 客户端
cat > redis-nfs-client.yamlapiVersion: apps/v1 kind: Deployment metadata:name: redis-nfs-clientlabels:app: redis-nfs-client# replace with namespace where provisioner is deployednamespace: redis-cluster spec:replicas: 1strategy:type: Recreateselector:matchLabels:app: redis-nfs-clienttemplate:metadata:labels:app: redis-nfs-clientspec:serviceAccountName: redis-nfs-clientcontainers:- name: redis-nfs-client## image: quay.io/external_storage/nfs-client-provisioner:latestimage: crpi-pl50bq1hplpmj5tc.cn-hangzhou.personal.cr.aliyuncs.com/aliyun-lee/nfs-subdir-external-provisioner:v4.0.2volumeMounts:- name: redis-nfs-client-rootmountPath: /persistentvolumesenv:- name: PROVISIONER_NAME ## 这个名字必须与storegeclass里面的名字一致value: my-redis-nfs- name: ENABLE_LEADER_ELECTION ## 设置高可用允许选举,如果replicas参数等于1,可不用value: "True"- name: NFS_SERVERvalue: 192.168.1.81 #修改为自己的ip(部署nfs的机器ip)- name: NFS_PATHvalue: /var/nfs/redis #修改为自己的nfs安装目录volumes:- name: redis-nfs-client-rootnfs:server: 192.168.1.81 #修改为自己的ip(部署nfs的机器ip)path: /var/nfs/redis #修改为自己的nfs安装目录
4、创建StoreClass
cat > redis-storeclass.yamlapiVersion: storage.k8s.io/v1 kind: StorageClass metadata:name: redis-nfs-storagenamespace: redis-cluster provisioner: my-redis-nfs
5、执行命令创建NFS sa授权、NFS客户端以及StoreClass
kubectl apply -f redis-nfs-client-sa.yamlkubectl apply -f redis-nfs-client.yamlkubectl apply -f redis-storeclass.yaml
6、创建PV
创建6个PV卷,分别对应Redis的三主三从。
vim redis-pv.yamlapiVersion: v1 kind: PersistentVolume metadata:name: redis-nfs-pv1 spec:capacity:storage: 50MaccessModes:- ReadWriteManystorageClassName: "" # 必须设置为空字符串persistentVolumeReclaimPolicy: Retainnfs:server: 192.168.1.81path: /var/nfs/redis/pv1claimRef: # 关键:预绑定到 PVCnamespace: redis-clustername: redis-data-redis-0 # StatefulSet 生成的 PVC 名称 --- apiVersion: v1 kind: PersistentVolume metadata:name: redis-nfs-pv2 spec:capacity:storage: 50MaccessModes:- ReadWriteManystorageClassName: "" # 必须设置为空字符串persistentVolumeReclaimPolicy: Retainnfs:server: 192.168.1.81path: /var/nfs/redis/pv2claimRef: # 关键:预绑定到 PVCnamespace: redis-clustername: redis-data-redis-1 # StatefulSet 生成的 PVC 名称 --- apiVersion: v1 kind: PersistentVolume metadata:name: redis-nfs-pv3 spec:capacity:storage: 50MaccessModes:- ReadWriteManystorageClassName: "" # 必须设置为空字符串persistentVolumeReclaimPolicy: Retainnfs:server: 192.168.1.81path: /var/nfs/redis/pv3claimRef: # 关键:预绑定到 PVCnamespace: redis-clustername: redis-data-redis-2 # StatefulSet 生成的 PVC 名称 --- apiVersion: v1 kind: PersistentVolume metadata:name: redis-nfs-pv4 spec:capacity:storage: 50MaccessModes:- ReadWriteManystorageClassName: "" # 必须设置为空字符串persistentVolumeReclaimPolicy: Retainnfs:server: 192.168.1.81path: /var/nfs/redis/pv4claimRef: # 关键:预绑定到 PVCnamespace: redis-clustername: redis-data-redis-3 # StatefulSet 生成的 PVC 名称 --- apiVersion: v1 kind: PersistentVolume metadata:name: redis-nfs-pv5 spec:capacity:storage: 50MaccessModes:- ReadWriteManystorageClassName: "" # 必须设置为空字符串persistentVolumeReclaimPolicy: Retainnfs:server: 192.168.1.81path: /var/nfs/redis/pv5claimRef: # 关键:预绑定到 PVCnamespace: redis-clustername: redis-data-redis-4 # StatefulSet 生成的 PVC 名称 --- apiVersion: v1 kind: PersistentVolume metadata:name: redis-nfs-pv6 spec:capacity:storage: 50MaccessModes:- ReadWriteManystorageClassName: "" # 必须设置为空字符串persistentVolumeReclaimPolicy: Retainnfs:server: 192.168.1.81path: /var/nfs/redis/pv6claimRef: # 关键:预绑定到 PVCnamespace: redis-clustername: redis-data-redis-5 # StatefulSet 生成的 PVC 名称 kubectl apply -f redis-pv.yaml
四、搭建Redis集群
1、创建headless服务
cat > redis-hs.yamlapiVersion: v1 kind: Service metadata:labels:k8s.kuboard.cn/layer: dbk8s.kuboard.cn/name: redisname: redis-hsnamespace: redis-cluster spec:ports:- name: nnbaryport: 6379protocol: TCPtargetPort: 6379selector:k8s.kuboard.cn/layer: dbk8s.kuboard.cn/name: redisclusterIP: None
2、创建redis.conf配置
bind 0.0.0.0 port 6379 daemonize no# requirepass redis-cluster # 集群配置 cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000
3、创建名称为redis-conf的Configmap
kubectl create configmap redis-conf --from-file=redis.conf -n redis-cluster
4、创建redis 对应pod集群
cat > redis.yamlapiVersion: apps/v1 kind: StatefulSet metadata:name: redisnamespace: redis-clusterlabels:k8s.kuboard.cn/layer: dbk8s.kuboard.cn/name: redis spec:replicas: 6selector:matchLabels:k8s.kuboard.cn/layer: dbk8s.kuboard.cn/name: redisserviceName: redis-hstemplate:metadata:labels:k8s.kuboard.cn/layer: dbk8s.kuboard.cn/name: redisspec:terminationGracePeriodSeconds: 20containers:- name: redisimage: rediscommand:- "redis-server"args:- "/etc/redis/redis.conf"- "--protected-mode"- "no" # 增加:为了解决节点重启后IP地址变化导致集群不可用问题(有待检验)- "--cluster-announce-ip"- "$(POD_IP)"env:- name: POD_IPvalueFrom:fieldRef:fieldPath: status.podIP #1、启动参数增加了 --cluster-announce-ip, 其值来自环境变量 POD_IP. 注意 $(POD_ID) 这里是小括号而非大括号。 #2、这个环境变量的值又来自 status.podIP, 即当前 pod 的 ip. 每次 pod 启动时会分配一个不同的 ip, 通过 status.podIP 可以拿这个 ip,进而通知集群。 #参考: https://github.com/redis/redis/issues/4289 # 增加:为了解决节点重启后IP地址变化导致集群不可用问题 ports:- name: rediscontainerPort: 6379protocol: "TCP"- name: clustercontainerPort: 16379protocol: "TCP"volumeMounts:- name: "redis-conf"mountPath: "/etc/redis"- name: "redis-data"mountPath: "/data"volumes:- name: "redis-conf"configMap:name: "redis-conf"items:- key: "redis.conf"path: "redis.conf"volumeClaimTemplates:- metadata:name: redis-dataspec:accessModes: [ "ReadWriteMany" ]resources:requests:storage: 50MstorageClassName: redis-nfs-storage
5、执行命令创建Service和Redis 集群Pod
kubectl apply -f redis-hs.yamlkubectl apply -f redis.yaml
6、查看集群状态
1、 进入容器(可以通过k8s页面,选中节点,通过base或sh进来),然后 cd /usr/local/bin/ kubectl exec -it redis-0 -n redis-cluster -- bash 2、连接上Redis节点: redis-cli -c 3、查看集群状态:cluster info
五、集群初始化
1、创建三主三从redis集群
kubectl exec -it redis-0 -n redis-cluster -- bash redis-cli --cluster create \redis-0.redis-hs.redis-cluster:6379 \redis-1.redis-hs.redis-cluster:6379 \redis-2.redis-hs.redis-cluster:6379 \redis-3.redis-hs.redis-cluster:6379 \redis-4.redis-hs.redis-cluster:6379 \redis-5.redis-hs.redis-cluster:6379 \--cluster-replicas 1
2、查看集群状态
1、进入容器(可以通过k8s页面,选中节点,通过base或sh进来),然后 cd /usr/local/bin/ kubectl exec -it redis-0 -n redis-cluster -- bash 2、连接上Redis节点: redis-cli -c 3、查看集群状态:cluster info 4、查看集群节点情况:cluster nodes
3、重建集群
(1) 进入每个 Redis Pod 执行数据清理 # 遍历所有 Redis Pod for pod in redis-0 redis-1 redis-2 redis-3 redis-4 redis-5; dokubectl exec -it $pod -n redis-cluster -- redis-cli FLUSHALL # 清空所有数据库kubectl exec -it $pod -n redis-cluster -- redis-cli CLUSTER RESET # 重置集群配置 done (2)重建集群命令调整 redis-cli --cluster create \redis-0.redis-hs.redis-cluster.svc.cluster.local:6379 \redis-1.redis-hs.redis-cluster.svc.cluster.local:6379 \redis-2.redis-hs.redis-cluster.svc.cluster.local:6379 \redis-3.redis-hs.redis-cluster.svc.cluster.local:6379 \redis-4.redis-hs.redis-cluster.svc.cluster.local:6379 \redis-5.redis-hs.redis-cluster.svc.cluster.local:6379 \--cluster-replicas 1 \--cluster-yes # 自动确认槽位分配(可选)
六、测试主从切换
1、进入容器:kubectl exec -it redis-0 -n redis-cluster -- bash 2、连接上Redis节点: redis-cli -c 3、查看节点角色:role 127.0.0.1:6379> role 1) "master" 2) (integer) 27342 3) 1) 1) "10.244.2.42"2) "6379"3) "27342" 可以看出,我们的redis-0节点,是Master节点,他的Slave 节点IP是10.244.2.42,即我们的redis-3节点。 可以查看redis-3节点角色进行验证。
1、删掉redis-0 Mster节点,观察情况
首先查看redis-0节点
kubectl get pod redis-0 -n redis-cluster -o wide
接着删除该Pod
kubectl delete pod redis-0 -n redis-cluster
再次进入redis-0和redis-3节点查看角色信息
七、开放外网端口
vim redis-access-service.yaml --- apiVersion: v1 kind: Service metadata:name: redis-access-servicelabels:app: redis-outip spec:type: NodePort # 添加此行ports:- name: redis-portprotocol: "TCP"port: 6379targetPort: 6379nodePort: 30379selector:k8s.kuboard.cn/layer: dbk8s.kuboard.cn/name: redis kubectl apply -f redis-access-service.yaml -n redis-cluster
八、IDEA中配置使用Redis集群
确保在 application.yml
或 application.properties
中正确配置集群节点信息,而非单节点地址。
spring:redis:cluster:# 节点配置下面三种方式都可以 # nodes: 10.244.1.46:6379,10.244.1.47:6379,10.244.2.41:6379,10.244.1.48:6379,10.244.2.43:6379,10.244.2.42:6379 # 所有主从节点地址 # nodes: redis-0.redis-hs.redis-cluster:6379,redis-1.redis-hs.redis-cluster:6379,redis-2.redis-hs.redis-cluster:6379,redis-3.redis-hs.redis-cluster:6379,redis-4.redis-hs.redis-cluster:6379,redis-5.redis-hs.redis-cluster:6379 # 所有主从节点地址nodes: redis-hs.redis-cluster:6379 # 所有主从节点地址 max-redirects: 3 # 最大重定向次数timeout: 5000 # 超时时间(毫秒)lettuce:pool:enabled: true # 启用连接池max-active: 8max-idle: 8