目录

  • 服务器资源
  • 配置文件
  • 创建redis服务
  • redis集群资源清单
  • 初始化集群
  • 集群验证
  • 验证方式一
  • 验证方式二
  • 集群使用
  • 集群暴露
  • 连接redis集群


服务器资源

k8s中有三台worker节点

192.168.1.100

192.168.1.101

192.168.1.102

配置文件

创建配置字典,挂载redis的配置文件

key为redis.conf

value为:

appendonly yes
cluster-enabled yes
cluster-config-file /data/nodes.conf
cluster-require-full-coverage no
cluster-migration-barrier 1
cluster-node-timeout 60000
protected-mode no
daemonize no     #让redis前台运行
port 6379
#下面的认证需要在集群搭建成功后添加,然后重启redis集群
requirepass XXX@2022   #开启密码认证
masterauth XXX@2022	#开启认证

创建redis服务

通过statefulset创建redis集群,有状态应用可以是副本之间有主从关系,数据需要做持久化。

在项目空间的 工作负载-有状态副本集-创建 进行 Redis 的创建。

Redis k8s 集群 k8s 部署redis集群_redis

基本信息定义

Redis k8s 集群 k8s 部署redis集群_redis集群_02

容器组设置,从自己的镜像仓库选择redis的版本,设置副本数为6,设置启动命令如下

Redis k8s 集群 k8s 部署redis集群_redis集群_03

存储设置,先是声明持久卷声明,再是挂载配置文件字典

Redis k8s 集群 k8s 部署redis集群_redis_04

PVC声明,挂载到容器的/data路径

Redis k8s 集群 k8s 部署redis集群_redis_05

配置文件的挂载,挂载到conf目录(依据自己使用的redis容器读取配置文件位置挂载)

Redis k8s 集群 k8s 部署redis集群_kubernetes_06

创建

Redis k8s 集群 k8s 部署redis集群_redis集群_07

redis集群资源清单

kind: StatefulSet
apiVersion: apps/v1
metadata:
  name: ipaas-redis-cluster-v1
  namespace: xiaoyu
  labels:
    app: ipaas-redis-cluster
    version: v1
  annotations:
    kubesphere.io/creator: admin
spec:
  replicas: 6
  selector:
    matchLabels:
      app: ipaas-redis-cluster
      version: v1
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: ipaas-redis-cluster
        version: v1
      annotations:
        kubesphere.io/restartedAt: '2022-11-03T02:20:00.393Z'
        logging.kubesphere.io/logsidecar-config: '{}'
    spec:
      volumes:
        - name: host-time
          hostPath:
            path: /etc/localtime
            type: ''
        - name: volume-tdz1y1
          configMap:
            name: redis-conf
            items:
              - key: redis.conf
                path: redis.conf
            defaultMode: 420
      containers:
        - name: redis-cluster
          image: 'harbor.leadchina.cn/ipaas/ipaas-redis:5.0.14'
          command:
            - redis-server
          args:
            - /conf/redis.conf
            - '--cluster-announce-ip'
            - $(POD_IP)  
          ports:
            - name: tcp-6379
              containerPort: 6379
              protocol: TCP
          env: #环境变量需要在yml中创建
            - name: POD_IP
              valueFrom:
                fieldRef:
                  apiVersion: v1
                  fieldPath: status.podIP
          resources:
            limits:
              cpu: 200m
              memory: 512Mi
            requests:
              cpu: 100m
              memory: 128Mi
          volumeMounts:
            - name: host-time
              mountPath: /etc/localtime
            - name: redis-pvc
              mountPath: /data
            - name: volume-tdz1y1
              mountPath: /conf
          terminationMessagePath: /dev/termination-log
          terminationMessagePolicy: File
          imagePullPolicy: IfNotPresent
      restartPolicy: Always
      terminationGracePeriodSeconds: 30
      dnsPolicy: ClusterFirst
      serviceAccountName: default
      serviceAccount: default
      securityContext: {}
      imagePullSecrets:
        - name: ipaas-repo
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
            - weight: 100
              podAffinityTerm:
                labelSelector:
                  matchLabels:
                    app: ipaas-redis-cluster
                    version: v1
                topologyKey: kubernetes.io/hostname
      schedulerName: default-scheduler
  volumeClaimTemplates:
    - kind: PersistentVolumeClaim
      apiVersion: v1
      metadata:
        name: redis-pvc
        namespace: ipaas
        creationTimestamp: null
      spec:
        accessModes:
          - ReadWriteOnce
        resources:
          requests:
            storage: 10Gi
        storageClassName: csi-rbd-sc
        volumeMode: Filesystem
      status:
        phase: Pending
  serviceName: ipaas-redis-cluster
  podManagementPolicy: OrderedReady
  updateStrategy:
    type: RollingUpdate
    rollingUpdate:
      partition: 0
  revisionHistoryLimit: 10

初始化集群

上面创建的redis副本之间并没什么关联,只是单个的redis服务,而通过容器化部署的redis不能通过副本的虚拟ip进行初始化,使用 ip 地址的方式在每次 K8s 调度 redisip 都会发生变化,所以在 K8s 集群中使用 ip 方式初始化集群并不太合适,但是如果使用内部 DNS 直接跟上面一样初始化集群会出现错误,因为 redis 对域名的支持并不太好,所以这时候可以用 Redis-tribe

创建部署

Redis k8s 集群 k8s 部署redis集群_数据库_08

通过yaml创建

apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: xiaoyu
  labels:
    app: redis-cluster-tools
  name: redis-cluster-tools
spec:
  replicas: 1
  selector:
    matchLabels:
      app: redis-cluster-tools
  template:
    metadata:
      labels:
        app: redis-cluster-tools
      name: pos-redis
    spec:
     containers:
     - name: pos-redis
       image: sunnywang/redis-tools-ubuntu:v0.5.1
       imagePullPolicy: IfNotPresent
       args:
       - /bin/bash
       - -c
       - sleep 3600

Redis k8s 集群 k8s 部署redis集群_数据库_09

进入到redis-cluster-tools的终端,分别进行master节点的初始化和slave节点的关联

首先进入到redis集群副本的终端查看容器的DNS

Redis k8s 集群 k8s 部署redis集群_redis集群_10

进入redis-cluster-tools的终端,先利用上面查看到的redis集群副本的DNS进行master节点的初始化

#执行以下命令初始化 master 节点,这时候之前的内部 DNS 的域名可以用了
redis-trib.py create `dig +short redis-cluster-0.redis-cluster-49ag.yek.svc.cluster.local`:6379 `dig +short redis-cluster-1.redis-cluster-49ag.yek.svc.cluster.local`:6379 `dig +short redis-cluster-2.redis-cluster-49ag.yek.svc.cluster.local`:6379

Redis k8s 集群 k8s 部署redis集群_kubernetes_11

给每个master节点绑定对应的副本节点

#给master节点0绑定5
redis-trib.py replicate --master-addr `dig +short redis-cluster-0.redis-cluster-49ag.yek.svc.cluster.local`:6379 --slave-addr `dig +short redis-cluster-5.redis-cluster-49ag.yek.svc.cluster.local`:6379
#给master节点1绑定3
redis-trib.py replicate --master-addr `dig +short redis-cluster-1.redis-cluster-49ag.yek.svc.cluster.local`:6379 --slave-addr `dig +short redis-cluster-3.redis-cluster-49ag.yek.svc.cluster.local`:6379
#给master节点2绑定4
redis-trib.py replicate --master-addr `dig +short redis-cluster-2.redis-cluster-49ag.yek.svc.cluster.local`:6379 --slave-addr `dig +short redis-cluster-4.redis-cluster-49ag.yek.svc.cluster.local`:6379

#注意点,这里在进行主从绑定时,要注意交叉绑定,最终的结果就是不要把一对主从绑定完被调度到同一台节点上,这样的话,当发生机器节点宕机时,副本没有及时调度会造成redis集群缺少哈希槽而不可用。

不合适的结构

Redis k8s 集群 k8s 部署redis集群_Redis k8s 集群_12

合适的结构

Redis k8s 集群 k8s 部署redis集群_redis集群_13

绑定成功输出信息

Redis k8s 集群 k8s 部署redis集群_kubernetes_14

集群验证

进入redis集群的任意一个副本中,查看集群状态

redis-cli
127.0.0.1:6379>cluster info

Redis k8s 集群 k8s 部署redis集群_数据库_15


此时的集群是没有设置密码的,需要在配置字典中redis.conf添加参数然后重新创建redis集群让其生效

验证方式一

使用基础命令进行验证,验证集群模式的 redis-cli 需要加-c
如果已经设置密码的话,需要使用 redis-cli -a 密码 -c 来进入redis集群

Redis k8s 集群 k8s 部署redis集群_redis集群_16

验证方式二

验证集群是否可以正常主从切换,在带密码认证的情况下

#进入容器0,通过以下命令查看是否为主节点
cat nodes.conf
#然后删除该容器让其重新创建,正常情况下副本5应该会变为master节点,而新的副本0会变为slave

集群使用

集群暴露

上面方式创建的redis集群是产生的服务是headless类型的,就是对应的服务是没有ClusterIP的,不过一样可以通过该服务的DNS在集群内进行该服务的访问。只需在连接redis集群的微服务那里配置 DNS:6379就可以,这个DNS会被解析为一串对应的6个redis副本的虚拟IP。

还可以将其通过具有ClusterIP的服务暴露,k8s集群内需要连接redis集群的微服务只需配置ClusterIP:6379也是可以的

上面俩种方式都是只能在k8s集群内进行访问redis集群,如果要想让k8s集群外部也可以使用,可以把服务的访问类型改为NodePord类型,那么就可以通过集群内任一节点的ip:主机端口进行访问了。除了修改服务的访问类型还可以通过配置ingress来暴露redis集群到外部访问。

连接redis集群

当应用连接redis集群时,应用会通过redis集群的主节点进行写操作,而从节点进行读操作;需要注意的是当集群内发生任意一对主从的切换,要保证代码中可以做到自动刷新redis集群的拓扑结构,防止发生主从切换时代码内还会连接旧master的IP。

如果是java代码,在确保springboot的版本为2.3.0以上的情况下,配置文件中添加如下配置

spring.redis.timeout=60s
spring.redis.lettuce.cluster.refresh.period=60s
spring.redis.lettuce.cluster.refresh.adaptive=true