弹性容器实例

ECI对接Redis服务

2025-06-16 02:02:59

背景信息

Redis支持以集群模式运行,在该模式下,Redis将所有存储空间分为16384个哈希槽,集群中的每个Master节点负责N个哈希槽(一个数据分片),当用户写入一条数据时,Redis计算其哈希槽,然后将数据写在负责该哈希槽的节点上。且每个Master节点可以添加一个或多个Slave节点,当某个Master节点不可用时,其Slave节点自动代替Master节点继续工作。

由此可见,在Redis集群模式下,可以获得更高的吞吐量和一定程度的可用性。需要注意的是,在集群模式下,Redis仍不能保证数据零丢失,更多信息,请参见Redis官方文档。

前提条件

已创建Kubernetes集群,且集群需满足以下条件:

  • 集群具备公网环境,可以通过公网拉取镜像。

  • 集群中已部署存储插件。

    • 集群版本高于1.16时,建议使用CSI插件,需确保已部署天翼云CSI-Provisioner组件。

  • 集群中已部署CoreDNS。

搭建Redis集群

本文以Redis官方镜像6.0.8版本作为示例,创建一个6个节点的Redis集群,其中3个Master节点,3个Slave节点。因为每个节点有自己的状态和标识,所以使用Statefulset来创建Pod,此外需要为每个节点挂载一个云盘,用于持久化存储节点数据。

1.创建一个ConfigMap,用来存储和管理Redis集群的配置。

kubectl create -f redis-config.yaml

redis-config.yaml的内容示例如下:

apiVersion: v1
kind: ConfigMap
metadata:
  name: redis-cluster
data:
  redis.conf: |
    bind 0.0.0.0
    port 6379
    cluster-announce-bus-port 16379
    cluster-enabled yes
    appendonly yes
    cluster-node-timeout 5000
    dir /data
    cluster-config-file /data/nodes.conf
    requirepass pass123
    masterauth pass123
  • 字段dir为Redis节点数据的持久化存储目录,所以Pod的/data目录应当是一个持久化存储目录。

  • 字段cluster-config-file是Redis集群的节点信息,由Redis节点自动生成和修改,该配置也应当是一个持久化存储目录,以便节点宕机恢复后能够找到集群中的其他节点,并继续工作。

2.创建一个headless类型的Service。

kubectl create -f redis-service.yaml

redis-service.yaml的内容示例如下:

apiVersion: v1
kind: Service
metadata:
  name: redis-cluster-svc
spec:
  clusterIP: None
  selector:
    app: redis-cluster

3.创建一个Statefulset,用于部署Redis。

创建Statefulset时引用之前创建的Service,将ConfigMap挂载到每一个Pod的/config,并且为每一个Pod创建一个PVC,挂载到/data。

kubectl create -f redis.yaml

redis.yaml的内容示例如下:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: redis-cluster
spec:
  selector:
    matchLabels:
      app: redis-cluster
  serviceName: redis-cluster-svc
  replicas: 6
  template:
    metadata:
      labels:
        app: redis-clus
        ctyun.cn/eci: "true"
    spec:
      terminationGracePeriodSeconds: 10
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - redis-cluster
              topologyKey: kubernetes.io/hostname
            weight: 100
      containers:
      - name: redis
        image: redis:6.0.8
        command: ["redis-server", "/config/redis.conf"]
        ports:
        - name: redis
          containerPort: 6379
          protocol: TCP
        - name: election
          containerPort: 16379
          protocol: TCP
        volumeMounts:
        - name: redis-conf
          mountPath: /config
        - name: pvc-essd-redis-data
          mountPath: /data
      volumes:
      - name: redis-conf
        configMap:
          name: redis-cluster
          items:
          - key: redis.conf
            path: redis.conf
  volumeClaimTemplates:
  - metadata:
      name: pvc-essd-redis-data
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: ctcloud-disk-essd
      resources:
        requests:
          storage: 20Gi

创建后,等待Statefulset中的所有Pod达到Ready状态。

kubectl get statefulset redis-cluster -o wide

预期返回:

NAME            READY   AGE     CONTAINERS   IMAGES
redis-cluster       6/6     8m52s   redis        redis:6.0.8

4.初始化集群地址。

    a.获取每个节点的IP地址。

目前Redis还不支持以hostname方式初始化集群,所以需要先获取每个节点的IP地址。

kubectl get pods -l app=redis-cluster -o wide

返回类似以下信息:

NAME         READY   STATUS    RESTARTS   AGE     IP             NODE                 NOMINATED NODE   READINESS GATES
redis-cluster-0   1/1     Running   0          9m31s   172.16.55.6    virtual-kubelet-cn-beijing-k   <none>           <none>
redis-cluster-1   1/1     Running   0          9m5s    172.16.55.7    virtual-kubelet-cn-beijing-k   <none>           <none>
redis-cluster-2   1/1     Running   0          8m20s   172.16.55.8    virtual-kubelet-cn-beijing-k   <none>           <none>
redis-cluster-3   1/1     Running   0          7m46s   172.16.55.9    virtual-kubelet-cn-beijing-k   <none>           <none>
redis-cluster-4   1/1     Running   0          7m7s    172.16.55.10   virtual-kubelet-cn-beijing-k   <none>           <none>
redis-cluster-5   1/1     Running   0          6m30s   172.16.55.11   virtual-kubelet-cn-beijing-k   <none>

    b.登录到其中一个Redis节点。

kubectl exec -ti redis-cluster-0 bash

为6个节点执行初始化命令,当选项--cluster-replicas指定为1时,表示为每个Master节点分配一个Slave节点,这样集群中刚好3个Master节点和3个Slave节点。

redis-cli -a pass123 --cluster create 172.16.55.6:6379 
172.16.55.7:6379 172.16.55.8:6379 172.16.55.9:6379 
172.16.55.10:6379 172.16.55.11:6379 --cluster-replicas 1

返回类似以下信息表示初始化成功。

OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

5.使用Redis。

由于之前创建了一个headless类型的Service,kubernetes集群会为该服务分配一个DNS A记录,格式为{service name}.{service namespace}.svc.{domain},可以映射到后端Pod IP列表,即每次访问该服务名时,将随机解析到其中一个Redis节点上。 

因此,进入集群中的任意一个Pod中均可以访问Redis服务。

redis-cli -a pass123 -c -h redis-cluster-svc.default.svc.cluster.local -p 6379

登录后的测试示例如下:

172.16.55.8> set k1 v1
OK
172.16.55.8> get k1
"v1"


40540UOtyaWo