K8S搭建三主三从高可用redis集群

  • 一、创建存储卷
  • 二、创建PV
  • 三、创建configmap
  • 四、创建headless service
  • 五、创建redis集群节点
  • 六、初始化redis集群
  • 七、创建用于访问的service
  • 八、redis主从切换测试

本方案采用StatefulSet进行redis的部署。它为了解决有状态服务的问题,它所管理的Pod拥有固定的Pod名称,启停顺序。在Deployment中,与之对应的服务是service,而在StatefulSet中与之对应的headless service,headless service,即无头服务,与service的区别就是它没有Cluster IP,解析它的名称时将返回该Headless Service对应的全部Pod的Endpoint列表。
在k8s上搭建Redis sentinel完全没有意义,经过测试,当master节点宕机后,sentinel选择新的节点当主节点,当原master恢复后,此时无法再次成为集群节点。因为在物理机上部署时,sentinel探测以及更改配置文件都是以IP的形式,集群复制也是以IP的形式,但是在容器中,虽然采用的StatefulSet的Headless Service来建立的主从,但是主从建立后,master、slave、sentinel记录还是解析后的IP,但是pod的IP每次重启都会改变,所有sentinel无法识别宕机后又重新启动的master节点,所以一直无法加入集群,虽然可以通过固定pod IP或者使用NodePort的方式来固定,或者通过sentinel获取当前master的IP来修改配置文件。 sentinel实现的是高可用Redis主从,检测Redis Master的状态,进行主从切换等操作,但是在k8s中,无论是dc或者ss,都会保证pod以期望的值进行运行,再加上k8s自带的活性检测,当端口不可用或者服务不可用时会自动重启pod或者pod的中的服务,所以当在k8s中建立了Redis主从同步后,相当于已经成为了高可用状态,并且sentinel进行主从切换的时间不一定有k8s重建pod的时间快,所以个人认为在k8s上搭建sentinel没有意义。

K8s集群环境

节点

IP
master
192.168.1.100
node1
192.168.1.101
node2
192.168.1.102
node3
192.168.1.103

下载镜像经导入集群中redis:3.2.8、inem0o/redis-trib:latest
docker pull redis:3.2.8; docker save –o redis.tar redis:3.2.8
docker pull inem0o/redis-trib:latest; docker save –o redis-trib.tar inem0o/redis-trib:latest
redis.tar上传至k8s的各个node节点;redis-trib.tar上传至k8s的master节点

一、创建存储卷

创建NFS存储主要是为了给Redis提供稳定的后端存储,当Redis的Pod重启或迁移后,依然能获得原先的数据。

  1. 安装nfs软件包
1. ]# yum –y install nfs-utils rpcbind #任选一台节点(这里选k8s-master)
  1. 创建共享存储
]# mkdir -p /usr/local/k8s/redis/pv{1…6} #创建共享目录
 ]# cat /etc/exports #配置共享路径
 /redis/pv1 192.168.1.0/24(rw,sync,no_root_squash)
 /redis/pv2 192.168.1.0/24(rw,sync,no_root_squash)
 /redis/pv3 192.168.1.0/24(rw,sync,no_root_squash)
 /redis/pv4 192.168.1.0/24(rw,sync,no_root_squash)
 /redis/pv5 192.168.1.0/24(rw,sync,no_root_squash)
 /redis/pv6 192.168.1.0/24(rw,sync,no_root_squash)
 ]# systemctl restart rpcbind;systemctl restart nfs;systemctl enable nfs
  1. 查看共享路径
2.  exportfs –v #k8s-master上操作
 其他节点安装nfs客户端,并验证
 ]# yum -y install nfs-utils
 ]# showmount -e 192.168.1.100
 Export list for 192.168.1.10:
 /redis/pv1 192.168.1.0/24
 /redis/pv2 192.168.1.0/24
 /redis/pv3 192.168.1.0/24
 /redis/pv4 192.168.1.0/24
 /redis/pv5 192.168.1.0/24
 /redis/pv6 192.168.1.0/24

二、创建PV

以下操作在k8s-master上执行即可
1.每一个Redis Pod都需要一个独立的PV来存储自己的数据,因此可以创建一个pv.yaml文件,包含6个PV:

]# vim pv.yaml 
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv1
spec:
  capacity:
    storage: 2Gi
  accessModes:
- ReadWriteMany
  volumeMode: Filesystem
  persistentVolumeReclaimPolicy: Recycle
  storageClassName: "redis"
  nfs:
    server: 192.168.1.10
    path: "/usr/local/k8s/redis/pv1"
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-vp2
spec:
  capacity:
    storage: 2Gi
  accessModes:
- ReadWriteMany
  volumeMode: Filesystem
  persistentVolumeReclaimPolicy: Recycle
  storageClassName: "redis"
  nfs:
    server: 192.168.1.10
    path: "/usr/local/k8s/redis/pv2"
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv3
spec:
  capacity:
    storage: 2Gi
  accessModes:
- ReadWriteMany
  volumeMode: Filesystem
  persistentVolumeReclaimPolicy: Recycle
  storageClassName: "redis"
  nfs:
    server: 192.168.1.10
    path: "/usr/local/k8s/redis/pv3"
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-vp4
spec:
  capacity:
    storage: 2Gi
  accessModes:
- ReadWriteMany
  volumeMode: Filesystem
  persistentVolumeReclaimPolicy: Recycle
  storageClassName: "redis"
  nfs:
    server: 192.168.1.10
    path: "/usr/local/k8s/redis/pv4"
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv5
spec:
  capacity:
    storage: 2Gi
  accessModes:
- ReadWriteMany
  volumeMode: Filesystem
  persistentVolumeReclaimPolicy: Recycle
  storageClassName: "redis"
  nfs:
    server: 192.168.1.10
    path: "/usr/local/k8s/redis/pv5"
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-vp6
spec:
  capacity:
    storage: 2Gi
  accessModes:
- ReadWriteMany
  volumeMode: Filesystem
  persistentVolumeReclaimPolicy: Recycle
  storageClassName: "redis"
  nfs:
    server: 192.168.1.10
    path: "/usr/local/k8s/redis/pv6"

    
]# kubectl create -f pv.yaml #创建pv存储卷
persistentvolume "nfs-pv1" created
persistentvolume "nfs-pv2" created
persistentvolume "nfs-pv3" created
persistentvolume "nfs-pv4" created
persistentvolume "nfs-pv5" created
persistentvolume "nfs-pv6" created

三、创建configmap

将Redis的配置文件转化为Configmap,这是一种更方便的配置读取方式。配置文件redis.conf如下

]# vim redis.conf
appendonly yes
cluster-enabled yes
cluster-config-file /var/lib/redis/nodes.conf
cluster-node-timeout 5000
dir /var/lib/redis
port 6379

]# kubectl create configmap redis-conf --from-file=redis.conf
]# kubectl describe cm redis-conf #查看创建的configmap:
Name:         redis-conf
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
redis.conf:
----
appendonly yes
cluster-enabled yes
cluster-config-file /var/lib/redis/nodes.conf
cluster-node-timeout 5000
dir /var/lib/redis
port 6379

Events:  <none>

四、创建headless service

Headless service是StatefulSet实现稳定网络标识的基础,我们需要提前创建。准备文件headless-service.yml如下:

]# vim headless-service.yaml 
apiVersion: v1
kind: Service
metadata:
  name: redis-service
  labels:
    app: redis
spec:
  ports:
  - name: redis-port
    port: 6379
  clusterIP: None
  selector:
app: redis

]# kubectl create -f headless-service.yml
]# kubectl get svc redis-service

五、创建redis集群节点

  1. 通过StatefulSet创建6个redis的pod ,实现3主3从的redis集群
    ]# vim redis.yaml
    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
    name: redis-app
    spec:
    serviceName: “redis-service”
    replicas: 6
    selector:
    matchLabels:
    app: redis
    appCluster: redis-cluster
    template:
    metadata:
    labels:
    app: redis
    appCluster: redis-cluster
    spec:
    containers:
    - name: redis
    image: “redis:3.2.8”
    command:
    - “redis-server”
    args:
    - “/etc/redis/redis.conf”
    - “–protected-mode”
    - “no”
    resources:
    requests:
    cpu: “100m”
    memory: “100Mi”
    ports:
    - name: redis
    containerPort: 6379
    protocol: “TCP”
    - name: cluster
    containerPort: 16379
    protocol: “TCP”
    volumeMounts:
    - name: “redis-conf”
    mountPath: “/etc/redis”
    - name: “redis-data”
    mountPath: “/var/lib/redis”
    volumes:
    - name: “redis-conf”
    configMap:
    name: “redis-conf”
    items:
    - key: “redis.conf”
    path: “redis.conf”
    volumeClaimTemplates:
    - metadata:
    name: redis-data
    spec:
    accessModes: [ “ReadWriteMany” ]
    storageClassName: “redis”
    resources:
    requests:
    storage: 2Gi
    ]# kubectl create -f redis.yaml
    ]# kubectl get pods -o wide

k8s 搭建redis集群 k8s redis 集群_IP

六、初始化redis集群

初始化集群采用redis-trib这个工具,直接yum安装redis-trib这个软件,执行初始化

yum -y install redis-trib

]# redis-trib create --replicas 1 10.244.3.20:6379 10.244.2.42:6379 10.244.1.44:6379 10.244.2.43:6379 10.244.3.21:6379 10.244.1.45:6379

k8s 搭建redis集群 k8s redis 集群_redis_02


输入 yes 确定

k8s 搭建redis集群 k8s redis 集群_IP_03


k8s 搭建redis集群 k8s redis 集群_后端_04


或者采用部署redis-trib容器初始化:参考链接https://github.com/iNem0o/docker-redis-trib

]# docker run --rm -ti inem0o/redis-trib create --replicas 1 10.244.3.20:6379  10.244.2.42:6379  10.244.1.44:6379  10.244.2.43:6379  10.244.3.21:6379  10.244.1.45:6379    # IP为6个redis pod的IP以及端口
在提示中输入Yes继续初始化

验证集群状态,集群节点状态为OK,共有6个节点

#kubectl exec -ti redis-app-0 -- redis-cli -c
> cluster iinfo    # 查看集群状态
> role    #查看角色

k8s 搭建redis集群 k8s redis 集群_IP_05

七、创建用于访问的service

之前创建了用于实现StatefulSet的Headless Service,但该Service没有Cluster IP,因此不能用于外界访问。所以,我们还需要创建一个Service,专用于为Redis集群提供访问和负载均衡;也可以部署为Ingress供集群外部访问。这里只创建用于内部访问的service

]# vim redis-access-service.yaml 
apiVersion: v1
kind: Service
metadata:
  name: redis-access-service
  labels:
    app: redis
spec:
  ports:
  - name: redis-port
    protocol: "TCP"
    port: 6379
    targetPort: 6379
  selector:
    app: redis
    appCluster: redis-cluster

]# kubectl create -f redis-access-service.yaml
该Service名称为 redis-access-service,在K8S集群中暴露6379端口。如果需要提供集群外部访问,可以创建NodePort或者ingress类型

八、redis主从切换测试

删除一个pod为redis的master
]# kubectl delete pods redis-app-1
pod “redis-app-0” deleted

删除pod后,k8s会自动重建一个名称为“redis-app-1”并加入到集群中,但IP不一定是原来的IP;再次查看集群角色,redis-app-1由master变为salve,集群整体依然是6个