Kubernetes 构建高可用、高性能 Redis 集群

一、实验准备

明确集群角色与网络规划

实验环境的节点分工是后续所有操作的基础,需先明确每个节点的核心作用,避免资源混乱或网络不通导致部署失败:

  • k8s-master(192.168.67.100)

    • Kubernetes 控制平面,负责集群资源调度、API 管理(如创建 StatefulSet、Service 等),是整个集群的 "大脑"。
  • k8s-node1(192.168.67.10)

  • k8s-node2(192.168.67.20)

    • Kubernetes 工作节点,实际运行 Redis Pod、Proxy Pod 等业务容器,承担数据存储和计算任务。
  • harbor-nfs(192.168.67.123)

    • 双重角色 ------① 提供 NFS 共享存储,用于 Redis 数据持久化(避免 Pod 删除后数据丢失);② 作为私有镜像仓库(Harbor),存储 Redis、Redis Proxy、RedisInsight 等镜像,避免依赖外部仓库(如 Docker Hub)的网络波动。

为什么这样规划?

  • 分离控制平面与工作节点:避免 master 节点因运行业务容器导致资源不足,保证集群调度稳定。

  • 独立 NFS 存储节点:Redis 集群需要持久化存储(如 AOF 文件、集群配置文件 nodes.conf),NFS 是跨节点共享存储的低成本方案,适合中小规模集群;同时集成 Harbor 可统一管理私有镜像,提高拉取效率和安全性。


二、搭建 nfs 共享目录

为 Redis 提供持久化存储基础

Redis 集群是有状态应用,数据(如键值对、集群槽位配置)必须持久化到外部存储,否则 Pod 重启 / 重建后数据会丢失。NFS 的核心作用是提供跨 K8s 节点的共享存储,让所有 Redis Pod 能访问统一的数据目录。

2.1.部署 NFS 服务端

NFS 主机(192.168.67.123)操作:

bash 复制代码
dnf install nfs-utils -y
​
systemctl enable --now nfs-server.service
​
vim /etc/exports
###########
/nfsdata        *(rw,sync,no_root_squash)       # 配置 NFS 共享目录:定义哪些目录可被哪些客户端访问及权限
###########
​
​
exportfs -rv        # 重新加载 NFS 配置:让 /etc/exports 的修改生效
​
showmount -e        # 验证共享是否成功:查看当前 NFS 服务暴露的共享目录

关键配置解析:

  • **/nfsdata:**要共享的本地目录,后续 Redis 数据会存储到这里。

  • ***:**允许所有客户端访问(实验环境简化配置,生产环境建议指定 K8s 节点 IP 段,如 192.168.67.0/24,提高安全性)。

  • **rw:**客户端对共享目录有读写权限(Redis 需要写入数据,只读权限会导致启动失败)。

  • **sync:**数据同步写入磁盘(而非缓存到内存),避免服务器断电导致数据丢失(牺牲少量性能换数据安全性)。

  • **no_root_squash:**客户端的 root 用户在共享目录下仍拥有 root 权限(Redis 容器默认用 root 启动,若开启 root_squash 会导致权限不足,无法写入数据)。

2.2.部署 NFS 客户端

所有 K8s 集群主机(master、node1、node2)操作:

bash 复制代码
dnf install nfs-utils -y
​
showmount -e 192.168.67.123     # 验证能否访问 NFS 服务端的共享目录:确保网络通畅、权限正常

为什么要在 K8s 节点安装客户端?

K8s 的 Pod 挂载 NFS 存储时,实际是通过节点的 NFS 客户端将共享目录挂载到 Pod 内部,若节点未安装客户端,会导致挂载失败,Redis Pod 无法启动。


三、基于 k8s 配置 redis 集群

从动态存储到集群初始化

这部分是核心流程,需按 "动态存储供应 → 配置管理 → 有状态部署 → 集群初始化" 的顺序操作,核心目标是实现:① 数据持久化(动态 PV/PVC);② 节点高可用(3 主 3 从);③ 网络可发现(Headless Service)。

3.1.创建 SA 并授权

为 NFS Provisioner 赋予权限

K8s 中,Pod 默认使用 default ServiceAccount(SA),但该 SA 权限极低,无法创建 PV、管理 StorageClass 等资源。而 NFS Provisioner(动态存储供应器) 需要动态创建 PV,必须赋予它足够的权限。

bash 复制代码
vim provisionerPrivilege.yml
##########
# 1. 创建独立命名空间:将 NFS Provisioner 资源与其他应用隔离,方便管理
apiVersion: v1
kind: Namespace
metadata:
  name: nfs-provisioner
---
# 2. 创建专用 SA:用于运行 NFS Provisioner Pod,避免使用 default SA 权限混乱
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-provisioner-svc
  namespace: nfs-provisioner
---
# 3. 创建 ClusterRole:定义 Provisioner 需要的集群级权限(跨命名空间生效)
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: nfs-clusterrole
rules:
- apiGroups:
  - ""
  resources:
  - nodes
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - ""
  resources:
  - persistentvolumes
  verbs:
  - get
  - list
  - watch
  - create
  - delete
- apiGroups:
  - ""
  resources:
  - persistentvolumeclaims
  verbs:
  - get
  - list
  - watch
  - update
- apiGroups:
  - "storage.k8s.io"
  resources:
  - storageclasses
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - ""
  resources:
  - events
  verbs:
  - create
  - update
  - patch
---
# 4. 绑定 ClusterRole 到 SA:让 SA 拥有 ClusterRole 定义的权限
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: nfs-clusterrolebinding
subjects:
  - kind: ServiceAccount
    name: nfs-provisioner-svc
    namespace: nfs-provisioner
roleRef:
  kind: ClusterRole
  name: nfs-clusterrole
  apiGroup: rbac.authorization.k8s.io
---
# 5. 创建 Role:定义 Provisioner 在自身命名空间内的权限(leader 选举)
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-elector
  namespace: nfs-provisioner
rules:
  - apiGroups: [""]
    resources: ["endpoints"]
    verbs: ["get", "list", "watch", "create", "update", "patch"] # 用于多实例 Provisioner 的 leader 选举
---
# 6. 绑定 Role 到 SA:让 SA 拥有 leader 选举权限
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-electorbinding
  namespace: nfs-provisioner
subjects:
  - kind: ServiceAccount
    name: nfs-provisioner-svc
    namespace: nfs-provisioner
roleRef:
  kind: Role
  name: leader-elector
  apiGroup: rbac.authorization.k8s.io
##########
bash 复制代码
kubectl apply -f provisionerPrivilege.yml       # 应用配置并验证 SA 是否创建成功
kubectl -n nfs-provisioner get serviceaccounts

3.2.部署 NFS Provisioner

实现动态存储供应

手动创建 PV 效率低(尤其集群规模大时),NFS Provisioner 的核心作用是:用户只需创建 PVC(存储请求),Provisioner 自动创建 PV 并关联 NFS 共享目录,大幅降低运维成本。

bash 复制代码
vim nfs-provioner.yml 
###########
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nfs-provisioner
  name: nfs-provisioner
  namespace: nfs-provisioner
spec:
  replicas: 2 # 部署 2 个实例,实现 Provisioner 自身高可用
  selector:
    matchLabels:
      app: nfs-provisioner
  template:
    metadata:
      labels:
        app: nfs-provisioner
    spec:
      serviceAccountName: nfs-provisioner-svc # 使用前面创建的专用 SA
      containers:
      - image: sig-storage/nfs-subdir-external-provisioner:v4.0.2 # K8s 官方维护的 NFS 动态供应器镜像
        name: nfs-subdir-external-provisioner
        volumeMounts:
          - name: nfs-root
            mountPath: /persistentvolumes # 将 NFS 共享目录挂载到容器内,用于创建 PV 数据目录
        env:
          - name: PROVISIONER_NAME # 标识当前 Provisioner,后续 StorageClass 需指定此名称
            value: k8s-sigs.io/nfs-subdir-external-provisioner
          - name: NFS_SERVER # NFS 服务端 IP(即 harbor-nfs 节点)
            value: 192.168.67.123
          - name: NFS_PATH # NFS 服务端共享目录(与 /etc/exports 配置一致)
            value: /nfsdata
      volumes:
        - name: nfs-root # 定义 NFS 卷,关联服务端共享目录
          nfs:
            server: 192.168.67.123
            path: /nfsdata
###########
bash 复制代码
kubectl apply -f nfs-provioner.yml      # 应用配置并验证 Provisioner Pod 是否正常运行(需处于 Running 状态)
kubectl -n nfs-provisioner get pods

关键配置解析

  • replicas:2:Provisioner 是动态存储的核心组件,单实例故障会导致无法创建新 PV,因此部署 2 个实例实现高可用(通过 leader 选举确保只有一个实例工作)。

  • volumeMounts:将 NFS 共享目录 /nfsdata 挂载到容器的 /persistentvolumes,后续 Provisioner 为 PVC 创建 PV 时,会在 /nfsdata 下生成独立子目录(如 redis-cluster-redis-cluster-data-redis-cluster-0),每个 PV 对应一个子目录,实现数据隔离。

  • PROVISIONER_NAME:必须与后续 StorageClass 的 provisioner 字段一致,否则 StorageClass 无法找到对应的 Provisioner,动态供应失败。

3.3.创建 StorageClass

定义动态 PV 的 "模板"

StorageClass 是动态存储的 "规则模板",用于指定 PV 的创建策略(如存储类型、清理策略),用户创建 PVC 时只需关联该 StorageClass,即可自动生成符合规则的 PV。

bash 复制代码
vim storageclass.yml 
#########
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs-storageclass # StorageClass 名称,后续 PVC 需指定此名称
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner # 关联前面的 Provisioner
parameters:
  archiveOnDelete: "false" # 删除 PVC 时,是否归档 NFS 目录(false=直接删除,避免残留数据;true=改名归档,用于数据恢复)
#########
bash 复制代码
kubectl apply -f storageclass.yml           # 应用配置并清理旧 StorageClass(避免同名冲突)
kubectl delete storageclasses.storage.k8s.io nfs-client

为什么需要 StorageClass?

  • 统一 PV 配置:避免用户创建 PVC 时手动指定 PV 的存储类型、权限等,减少配置错误。

  • 支持多存储类型:若集群有多种存储(如 NFS、Ceph),可创建多个 StorageClass,用户按需选择(如 Redis 用 NFS,数据库用 Ceph)。

  • archiveOnDelete: "false":实验环境中,删除 PVC 后通常不需要保留数据,设为 false 可自动清理 NFS 目录,避免磁盘空间浪费;生产环境若需数据备份,可设为 true。

3.4.创建 Redis 命名空间

隔离 Redis 相关资源

bash 复制代码
vim namespace.yml 
########
apiVersion: v1
kind: Namespace
metadata:
  name: redis-cluster # Redis 集群专属命名空间
########
bash 复制代码
kubectl apply -f namespace.yml      # 应用配置并验证
kubectl get namespaces | grep redis

命名空间的核心作用

  • 资源隔离:将 Redis 的 Pod、Service、ConfigMap 等资源集中在 redis-cluster 命名空间,避免与 NFS Provisioner、其他应用(如 MySQL)的资源混淆,方便后续管理(如批量删除、权限控制)。

  • 权限控制:可针对命名空间设置 RBAC 权限,例如只允许特定 SA 操作 redis-cluster 命名空间的资源,提高安全性。

3.5.创建 Redis 配置 ConfigMap

统一管理集群配置

Redis 集群需要统一的配置(如开启集群模式、持久化策略、密码),将配置文件放入 ConfigMap,可实现 "配置与容器分离"------ 修改配置时无需重建镜像,只需更新 ConfigMap 并重启 Pod。

bash 复制代码
vim redis.conf 
###########
protected-mode no
appendonly yes
dir /data
port 6379
cluster-enabled yes
cluster-config-file /data/nodes.conf
clueter-node-timeout 5000
masterauth openlab
requirepass openlab
############
bash 复制代码
kubectl create configmap redis-config --from-file=redis.conf -n redis-cluster --dry-run=client -o yaml > configmap-redis.yml
​
vim configmap-redis.yml
#############
apiVersion: v1
kind: ConfigMap
metadata:
  name: redis-config # ConfigMap 名称,后续 StatefulSet 需引用
  namespace: redis-cluster
data:
  redis.conf: | # 将上面编写的 redis.conf 内容填入
    protected-mode no
    appendonly yes
    dir /data
    port 6379
    cluster-enabled yes
    cluster-config-file /data/nodes.conf
    cluster-node-timeout 5000
    masterauth openlab
    requirepass openlab
#############
bash 复制代码
kubectl apply -f configmap-redis.yml        # 应用配置并验证 ConfigMap 是否创建成功
kubectl -n redis-cluster get configmaps

关键配置解析

  • appendonly yes:Redis 持久化有两种方式 ------RDB(定时快照)和 AOF(实时日志)。开启 AOF 可确保 "每一次写操作都被记录",即使服务器断电,数据丢失风险极低,适合 Redis 集群的生产环境。

  • cluster-config-file /data/nodes.conf:nodes.conf 是 Redis 集群的核心配置文件,记录了所有节点的 IP、端口、槽位分配等信息,必须存储在持久化目录 /data(挂载 PVC),否则 Pod 重建后会丢失集群信息,导致集群崩溃。

  • masterauth 与 requirepass:两者都设为 openlab,确保:① 从节点连接主节点时需验证密码(防止未授权从节点加入);② 客户端访问 Redis 时需验证密码(防止未授权读写)。

3.6.创建 Headless Service

实现 Redis 节点间网络发现

Redis 集群的节点需要互相通信(如主从同步、槽位迁移),但 Pod 的 IP 是动态变化的(重启后 IP 会变),因此需要 Headless Service(无头服务) 提供固定的 DNS 域名,让节点通过域名访问,而非依赖动态 IP。

bash 复制代码
vim headless.yml 
##########
apiVersion: v1
kind: Service
metadata:
  labels:
    app: headless-redis
  name: headless-redis # Service 名称,后续 StatefulSet 需引用
  namespace: redis-cluster
spec:
  clusterIP: None # Headless Service 的核心标识:无 ClusterIP,仅提供 DNS 解析
  selector:
    app.kubernetes.io/name: redis-cluster # 匹配 Redis Pod 的标签,确保 DNS 解析到正确的 Pod
  type: ClusterIP
  ports:
    - port: 6379 # Service 暴露的端口
      targetPort: 6379 # 转发到 Pod 的端口(与 Redis 监听端口一致)
##########
bash 复制代码
kubectl apply -f headless.yml       # 应用配置并验证 Service 是否创建成功
kubectl -n redis-cluster get service

Headless Service 与普通 Service 的区别

特性 普通 Service(ClusterIP 类型) Headless Service(clusterIP: None)
ClusterIP 有(集群内唯一虚拟 IP)
访问方式 通过 ClusterIP:Port 访问 通过 Pod DNS 域名访问
负载均衡 自动负载均衡到后端 Pod 不提供负载均衡,仅解析 Pod 域名
适用场景 客户端访问无状态应用 有状态应用节点间通信(如 Redis 集群)

为什么 Redis 集群需要 Headless Service? Redis 集群的节点需要知道其他节点的 "固定标识"(如主节点地址),若用普通 Service,客户端只能通过 ClusterIP 访问,无法直接定位到具体节点;而 Headless Service 会为每个 Pod 生成固定的 DNS 域名(格式:<pod-name>.<service-name>.<namespace>.svc.cluster.local,如 redis-cluster-0.headless-redis.redis-cluster.svc.cluster.local),节点可通过域名永久访问其他节点,即使 Pod IP 变化。

3.7.创建 StatefulSet

部署高可用 Redis 集群

Redis 集群是有状态应用 (需要固定的名称、存储、网络标识),而 Deployment 适合无状态应用(Pod 名称随机、存储共享),因此必须用 StatefulSet 部署,确保:① 每个 Pod 有固定名称(如 redis-cluster-0 到 redis-cluster-5);② 每个 Pod 有独立的 PVC(数据隔离);③ 每个 Pod 有固定 DNS 域名(通过 Headless Service)。

bash 复制代码
vim statefulset.yml 
##########
apiVersion: apps/v1
kind: StatefulSet
metadata:
  labels:
    app: redis-cluster
  name: redis-cluster # StatefulSet 名称
  namespace: redis-cluster
spec:
  serviceName: headless-redis # 关联 Headless Service,用于生成 Pod DNS 域名
  replicas: 6 # 3 主 3 从(Redis 集群最小高可用配置:主节点数≥3,每个主节点至少 1 个从节点)
  selector:
    matchLabels:
      app.kubernetes.io/name: redis-cluster # 匹配 Pod 标签
  updateStrategy:
    type: RollingUpdate # 滚动更新:避免更新时集群整体不可用
    rollingUpdate:
      partition: 1 # 先更新从节点(索引 1、3、5),再更新主节点(索引 0、2、4),降低风险
  template:
    metadata:
      labels:
        app.kubernetes.io/name: redis-cluster # Pod 标签,与 Headless Service 的 selector 匹配
    spec:
      # 反亲和性配置:避免多个 Redis Pod 调度到同一 K8s 节点,提高高可用
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
            - weight: 100 # 权重越高,调度器越优先满足
              podAffinityTerm:
                labelSelector:
                  matchLabels:
                    app.kubernetes.io/name: redis-cluster
                topologyKey: kubernetes.io/hostname # 按主机名隔离(同一主机不调度多个 Redis Pod)
      containers:
      - image: redis/redis:7.2.6 # Redis 稳定版本(避免使用 latest,版本不固定)
        name: redis
        command: ["redis-server"] # 启动命令
        args:
          - "/etc/redis/redis.conf" # 加载 ConfigMap 中的配置文件
          - "--protected-mode"
          - "no" # 再次确认关闭保护模式(防止配置文件未生效)
          - "--cluster-announce-ip"
          - "$(POD_IP)" # 声明当前 Pod 的 IP(Redis 集群需要节点向其他节点报告自己的 IP)
        env:
          - name: POD_IP # 通过 K8s  downward API 获取当前 Pod 的 IP
            valueFrom:
              fieldRef:
                fieldPath: status.podIP
        ports:
          - name: redis
            containerPort: 6379 # Redis 监听端口
            protocol: TCP
        volumeMounts:
          - name: config # 挂载 ConfigMap 中的 redis.conf 到 /etc/redis
            mountPath: /etc/redis
          - name: redis-cluster-data # 挂载 PVC 到 /data,用于持久化数据
            mountPath: /data
        resources:
          limits: # 资源上限:避免 Redis 占用过多资源,影响其他应用
            cpu: '2'
            memory: 4Gi
          requests: # 资源请求:确保调度器为 Redis 分配足够资源
            cpu: 50m
            memory: 200Mi
      volumes:
        - name: config # 引用前面创建的 ConfigMap
          configMap:
            name: redis-config
            items:
              - key: redis.conf # ConfigMap 中的配置项名称
                path: redis.conf # 挂载到容器内的路径(与 args 中的配置文件路径一致)
  # PVC 模板:StatefulSet 会为每个 Pod 自动创建一个 PVC(名称格式:redis-cluster-data-<pod-name>)
  volumeClaimTemplates:
    - metadata:
        name: redis-cluster-data # PVC 名称,与 volumeMounts 中的 name 一致
      spec:
        accessModes: ["ReadWriteOnce"] # 访问模式:只能被一个 Pod 挂载读写(Redis 数据目录不允许共享)
        storageClassName: "nfs-storageclass" # 关联前面创建的 StorageClass,实现动态 PV
        resources:
          requests:
            storage: 5Gi # 每个 Pod 请求 5Gi 存储(满足 Redis 数据存储需求)
##########
bash 复制代码
kubectl apply -f statefulset.yml        # 应用配置并验证 Redis Pod 是否正常运行(需 6 个 Pod 均处于 Running 状态)
kubectl -n redis-cluster get pods

StatefulSet 关键配置解析:

  • **replicas:6:**Redis 集群需要至少 3 个主节点(才能分配 16384 个槽位,确保数据分片),每个主节点 1 个从节点(主节点故障时,从节点可升级为主节点),因此共 6 个 Pod。

  • **updateStrategy.rollingUpdate.partition:1:**滚动更新时,先更新索引 ≥1 的 Pod(从节点:redis-cluster-1、3、5),再更新索引 = 0 的主节点,避免主节点同时更新导致集群不可用。

  • **podAntiAffinity:**反亲和性配置,确保 Redis Pod 分散在不同 K8s 节点(如 redis-cluster-0 在 node1,redis-cluster-1 在 node2),若某个 K8s 节点宕机,仅影响该节点上的 1-2 个 Pod,其他节点的 Pod 仍可正常工作,提高集群容错性。

  • **--cluster-announce-ip $(POD_IP):**Redis 集群节点需要向其他节点报告自己的 IP,若不配置此参数,节点可能会用容器内部的虚拟 IP(如 127.0.0.1),导致其他节点无法连接。通过 downward API 获取 Pod 的真实 IP(如 10.244.104.40),确保节点间通信正常。

  • **volumeClaimTemplates:**StatefulSet 的核心特性,为每个 Pod 自动创建独立的 PVC,且 PVC 名称与 Pod 名称绑定(如 redis-cluster-data-redis-cluster-0 对应 redis-cluster-0),即使 Pod 重建,PVC 仍存在,数据不会丢失。

3.8.初始化 Redis 集群

分配槽位与主从关系

此时 6 个 Redis Pod 已启动,但尚未组成集群(每个 Pod 都是独立的实例),需执行 redis-cli --cluster create 命令初始化集群,自动分配槽位和主从关系。

bash 复制代码
[root@master redis]# kubectl exec -it pod/redis-cluster-0 -n redis-cluster -- redis-cli -a openlab --cluster create --cluster-replicas 1 $(kubectl get pod -n redis-cluster -o jsonpath='{range.items[*]}{.status.podIP}:6379 {end}')       # 进入任意一个 Redis Pod(如 redis-cluster-0),执行集群初始化命令
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 10.244.104.42:6379 to 10.244.104.40:6379
Adding replica 10.244.166.178:6379 to 10.244.166.176:6379
Adding replica 10.244.166.177:6379 to 10.244.104.41:6379
M: 909686a57ae0c96cd13cfd22975510618f62cfb3 10.244.104.40:6379
   slots:[0-5460] (5461 slots) master
M: 41aff067129235c7929415c2d17f199d19d4f3b1 10.244.166.176:6379
   slots:[5461-10922] (5462 slots) master
M: 960f133a20493412f84fb6906de1b0655d3ed8ff 10.244.104.41:6379
   slots:[10923-16383] (5461 slots) master
S: 6d7df83c82bcc2b5780e2d90378620a35194127a 10.244.166.177:6379
   replicates 960f133a20493412f84fb6906de1b0655d3ed8ff
S: e1fe297ae9249758477ce339eb0dabd83a8bf314 10.244.104.42:6379
   replicates 909686a57ae0c96cd13cfd22975510618f62cfb3
S: a56a452a028d941fa2eb0c5e120fc77bbdf50f76 10.244.166.178:6379
   replicates 41aff067129235c7929415c2d17f199d19d4f3b1
Can I set the above configuration? (type 'yes' to accept): yes
>>> 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 10.244.104.40:6379)
M: 909686a57ae0c96cd13cfd22975510618f62cfb3 10.244.104.40:6379
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
S: e1fe297ae9249758477ce339eb0dabd83a8bf314 10.244.104.42:6379
   slots: (0 slots) slave
   replicates 909686a57ae0c96cd13cfd22975510618f62cfb3
S: a56a452a028d941fa2eb0c5e120fc77bbdf50f76 10.244.166.178:6379
   slots: (0 slots) slave
   replicates 41aff067129235c7929415c2d17f199d19d4f3b1
M: 41aff067129235c7929415c2d17f199d19d4f3b1 10.244.166.176:6379
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
M: 960f133a20493412f84fb6906de1b0655d3ed8ff 10.244.104.41:6379
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
S: 6d7df83c82bcc2b5780e2d90378620a35194127a 10.244.166.177:6379
   slots: (0 slots) slave
   replicates 960f133a20493412f84fb6906de1b0655d3ed8ff
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

命令解析:

  • **kubectl exec -it:**进入 Pod 的交互式终端。

  • **redis-cli -a openlab:**用密码 openlab 连接 Redis(对应 requirepass openlab)。

  • **--cluster create:**创建 Redis 集群。

  • **--cluster-replicas 1:**指定每个主节点有 1 个从节点(6 个 Pod 会分成 3 主 3 从)。

  • **$(kubectl get pod ...):**通过 jsonpath 自动获取所有 Redis Pod 的 IP:6379,避免手动输入(减少错误)。

初始化过程关键输出解析:

  • **槽位分配:**3 个主节点分别负责 16384 个槽位的 1/3:

    • 主节点 1:Slots 0 - 5460

    • 主节点 2:Slots 5461 - 10922

    • 主节点 3:Slots 10923 - 16383

    • (Redis 集群通过槽位分片存储数据,Key 会通过哈希算法映射到某个槽位,再由对应主节点存储)。

  • **主从关联:**自动将 3 个从节点分别关联到 3 个主节点(如从节点 10.244.104.42 关联主节点 10.244.104.40)。

  • **最终验证:**输出 [OK] All 16384 slots covered 表示所有槽位已分配,集群初始化成功。

查看集群状态 ok


四、构建 Redis Cluster Proxy

解决客户端兼容性与外部访问问题

Redis 集群要求客户端支持 MOVED/ASK 重定向协议(如 redis-cli -c),但很多旧客户端(如早期 Java 客户端)或简单应用不支持;同时 K8s 外部客户端无法直接访问 Pod 的动态 IP。Redis Cluster Proxy 作为中间层,可解决这些问题。

4.1.Proxy 核心价值

让集群 "像单机一样易用"

问题场景 传统方案痛点 Proxy 解决方案
客户端不支持集群协议 连接后报错 MOVED,无法读写数据 Proxy 自动处理重定向,客户端像访问单机 Redis 一样操作(无需改代码)
K8s 外部客户端访问 无法直接访问 Pod 动态 IP,NodePort 暴露后仍需处理重定向 Proxy 通过 LoadBalancer 暴露,外部客户端只需连接 Proxy IP:Port
跨槽操作(如 MGET key1 key2 报错 CROSSSLOT,需客户端拆分命令 Proxy 自动拆分命令到不同节点,合并结果返回(需开启 --enable-cross-slot
客户端连接数过多 每个客户端需连接所有主节点,资源消耗大 Proxy 维护共享连接池,连接数降低 90%+

4.2.编译 Proxy 镜像

适配实验环境

Redis Cluster Proxy 官方镜像可能存在版本兼容问题,因此手动编译并推到私有 Harbor 仓库:

bash 复制代码
mkdir foo
cd foo/
​
git config --global user.name 'jjdjr01' # 配置 Git 身份(克隆需身份验证)
git config --global user.email '13303836+jjdjr01@user.noreply.gitee.com'
git clone https://gitee.com/mirrors_RedisLabs/redis-cluster-proxy.git # 国内镜像仓库,拉取更快
bash 复制代码
# 修复编译错误(部分版本存在 sds.h/sds.c 语法问题,需修改代码适配 GCC 编译)
vim redis-cluster-proxy/src/sds.h # 按实际报错修改(如补充头文件、调整变量定义)
复制代码
vim redis-cluster-proxy/src/sds.c   # 同上

多阶构建:基于基础镜像:centos:stream9

bash 复制代码
# 打包源码(方便 Docker 构建时复制)
tar czf redis-cluster-proxy.tar.gz redis-cluster-proxy
bash 复制代码
# 编写多阶段 Dockerfile(减小镜像体积:编译阶段用带工具的镜像,运行阶段用干净镜像)
vim dockerfile 
##########
# 第一阶段:编译 Proxy(builder 阶段)
FROM reg.zyz.org/library/centos:stream9 AS builder
ADD redis-cluster-proxy.tar.gz /mnt # 将源码复制到容器内
WORKDIR /mnt/redis-cluster-proxy
# 安装编译依赖(gcc 编译器、make 构建工具、git 版本控制)
RUN  yum clean all && yum makecache && \
    yum install -y gcc make git && \
    make PREFIX=/opt/proxy install # 编译并安装到 /opt/proxy
​
# 第二阶段:运行 Proxy(干净镜像,仅包含编译结果)
FROM reg.zyz.org/library/centos:stream9
COPY --from=builder /opt/proxy/bin/redis-cluster-proxy /usr/local/bin/ # 复制编译好的二进制文件
EXPOSE 7777 # Proxy 默认端口
# 启动命令:加载 /etc/proxy/proxy.conf 配置文件
ENTRYPOINT ["/usr/local/bin/redis-cluster-proxy", "-c", "/etc/proxy/proxy.conf"]
##########
bash 复制代码
docker build -t redis-cluster-proxy:v1 .        # 构建镜像并推到私有 Harbor 仓库(方便 K8s 拉取)
​
docker tag redis-cluster-proxy:v1 reg.zyz.org/library/redis-cluster-proxy:v1
docker push reg.zyz.org/library/redis-cluster-proxy:v1

多阶段构建优势

  • 编译阶段(builder)包含 GCC、Make 等工具,镜像体积大(约几百 MB),但仅用于编译;

  • 运行阶段仅包含 Proxy 二进制文件和基础系统,镜像体积小(约几十 MB),启动更快,占用资源更少。

4.3.部署 Proxy 到 K8s

高可用 + 外部访问

创建 Proxy 配置 ConfigMap

Proxy 需要知道 Redis 集群节点的地址,将配置放入 ConfigMap,方便修改:

bash 复制代码
vim configmap-redis-cluster-proxy.yml 
###########
apiVersion: v1
kind: ConfigMap
metadata:
  name: cluster-proxy # ConfigMap 名称
  namespace: redis-cluster
data:
  proxy.conf: | # Proxy 核心配置
    # Redis 集群节点地址(用 Headless Service 域名,避免 Pod IP 变化)
    cluster redis-cluster-0.headless-redis.redis-cluster.svc.cluster.local:6379
    cluster redis-cluster-1.headless-redis.redis-cluster.svc.cluster.local:6379
    cluster redis-cluster-2.headless-redis.redis-cluster.svc.cluster.local:6379
    cluster redis-cluster-3.headless-redis.redis-cluster.svc.cluster.local:6379
    cluster redis-cluster-4.headless-redis.redis-cluster.svc.cluster.local:6379
    cluster redis-cluster-5.headless-redis.redis-cluster.svc.cluster.local:6379
    bind 0.0.0.0 # 允许所有地址访问 Proxy
    port 7777 # Proxy 监听端口
    threads 3 # 处理请求的线程数(根据 CPU 核心数调整,提高并发)
    daemonize no # 不后台运行(K8s 需前台运行,方便管理进程)
    enable-cross-slot yes # 允许跨槽操作(如 MGET 多个不同槽的 Key)
    auth openlab # Redis 集群密码(对应 requirepass openlab)
    log-level error # 日志级别:仅输出错误日志,减少日志量
###########
bash 复制代码
kubectl apply -f configmap-redis-cluster-proxy.yml      # 应用配置并验证
kubectl -n redis-cluster get configmaps

创建 Proxy Deployment:高可用部署

bash 复制代码
vim dep-redis-cluster-proxy.yml 
##########
apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis-proxy # Deployment 名称
  namespace: redis-cluster
spec:
  replicas: 2 # 2 个实例,实现 Proxy 高可用(避免单实例故障导致外部无法访问)
  selector:
    matchLabels:
      app: redis-proxy # 匹配 Pod 标签
  template:
    metadata:
      labels:
        app: redis-proxy
    spec:
      containers:
        - name: redis-proxy
          image: library/redis-cluster-proxy:v1 # 私有仓库镜像(若 Harbor 有前缀,需补全如 reg.zyz.org/library/...)
          imagePullPolicy: IfNotPresent # 本地有镜像则不拉取,加快启动
          command: ["/usr/local/bin/redis-cluster-proxy"] # 启动命令(与 Dockerfile ENTRYPOINT 一致,可覆盖)
          args:
            - -c
            - /etc/proxy/proxy.conf # 加载 ConfigMap 中的配置文件
          ports:
            - name: redis-7777
              containerPort: 7777 # Proxy 监听端口
              protocol: TCP
          volumeMounts:
            - name: cluster-proxy-v # 挂载 ConfigMap 到 /etc/proxy
              mountPath: /etc/proxy
      volumes:
        - name: cluster-proxy-v
          configMap:
            name: cluster-proxy # 引用前面创建的 ConfigMap
            items:
              - key: proxy.conf
                path: proxy.conf # 挂载路径(与 args 中的配置文件路径一致)
##########
bash 复制代码
kubectl apply -f dep-redis-cluster-proxy.yml        # 应用配置并验证 Proxy Pod 是否正常运行
kubectl -n redis-cluster get pods

创建 LoadBalancer Service:暴露 Proxy 供外部访问

K8s 外部客户端(如本地电脑、其他服务器)无法直接访问 Pod IP,需通过 LoadBalancer 类型的 Service 暴露 Proxy(生产环境可用云厂商的 LoadBalancer,实验环境可用 MetalLB 模拟):

bash 复制代码
vim loadbalancer.yml 
###########
apiVersion: v1
kind: Service
metadata:
  labels:
    app: redis-cluster-proxy
  name: cluster-proxy # Service 名称
  namespace: redis-cluster
spec:
  ports:
  - port: 6379 # Service 暴露的端口(与 Redis 默认端口一致,方便客户端使用)
    protocol: TCP
    targetPort: 7777 # 转发到 Proxy Pod 的 777 端口
  selector:
    app: redis-proxy # 匹配 Proxy Pod 标签
  type: LoadBalancer # 类型为 LoadBalancer,自动分配外部 IP
###########
bash 复制代码
kubectl apply -f loadbalancer.yml       # 应用配置并查看 Service(重点看 EXTERNAL-IP,即外部客户端访问的 IP)
kubectl -n redis-cluster get service

五、测试

验证集群可用性、性能与故障切换

5.1.基础读写测试

验证 Proxy 与集群通信正常

bash 复制代码
# 方式 1:本地安装 Redis 客户端测试
dnf install redis -y
redis-cli -h 192.168.67.154 -p 6379 -a openlab  # 192.168.67.154 是 Proxy Service 的 EXTERNAL-IP
set age 20      # 写数据
get age         # 读数据(若返回 20,说明读写正常)

测试目的:验证 Proxy 能正确转发客户端请求到 Redis 集群,且集群能正常读写数据。

5.2.性能测试

用 redis-benchmark 评估吞吐量与延迟

redis-benchmark 是 Redis 自带的性能测试工具,可模拟多客户端并发请求,评估集群性能:

测试 PING 命令(基础连通性与延迟)

关键输出:throughput summary(吞吐量,如 5263.16 requests per second)、latency summary(延迟,如 avg 2.884ms)

bash 复制代码
root@2d8d4fc5b23a:/data# redis-benchmark -h 192.168.67.154 -p 6379 -n 100 -c 20
WARNING: Could not fetch server CONFIG
====== PING_INLINE ======                                         
  100 requests completed in 0.02 seconds
  20 parallel clients
  3 bytes payload
  keep alive: 1
  multi-thread: no
​
Latency by percentile distribution:
0.000% <= 0.735 milliseconds (cumulative count 2)
50.000% <= 1.575 milliseconds (cumulative count 50)
75.000% <= 3.071 milliseconds (cumulative count 75)
87.500% <= 8.039 milliseconds (cumulative count 88)
93.750% <= 9.055 milliseconds (cumulative count 94)
96.875% <= 9.839 milliseconds (cumulative count 97)
98.438% <= 10.055 milliseconds (cumulative count 99)
99.219% <= 10.255 milliseconds (cumulative count 100)
100.000% <= 10.255 milliseconds (cumulative count 100)
​
Cumulative distribution of latencies:
0.000% <= 0.103 milliseconds (cumulative count 0)
5.000% <= 0.807 milliseconds (cumulative count 5)
12.000% <= 0.903 milliseconds (cumulative count 12)
15.000% <= 1.007 milliseconds (cumulative count 15)
16.000% <= 1.103 milliseconds (cumulative count 16)
21.000% <= 1.207 milliseconds (cumulative count 21)
28.000% <= 1.303 milliseconds (cumulative count 28)
36.000% <= 1.407 milliseconds (cumulative count 36)
45.000% <= 1.503 milliseconds (cumulative count 45)
52.000% <= 1.607 milliseconds (cumulative count 52)
55.000% <= 1.703 milliseconds (cumulative count 55)
59.000% <= 1.807 milliseconds (cumulative count 59)
60.000% <= 1.903 milliseconds (cumulative count 60)
65.000% <= 2.007 milliseconds (cumulative count 65)
66.000% <= 2.103 milliseconds (cumulative count 66)
75.000% <= 3.103 milliseconds (cumulative count 75)
80.000% <= 4.103 milliseconds (cumulative count 80)
83.000% <= 5.103 milliseconds (cumulative count 83)
85.000% <= 6.103 milliseconds (cumulative count 85)
86.000% <= 7.103 milliseconds (cumulative count 86)
88.000% <= 8.103 milliseconds (cumulative count 88)
94.000% <= 9.103 milliseconds (cumulative count 94)
99.000% <= 10.103 milliseconds (cumulative count 99)
100.000% <= 11.103 milliseconds (cumulative count 100)
​
Summary:
  throughput summary: 5263.16 requests per second
  latency summary (msec):
          avg       min       p50       p95       p99       max
        2.884     0.728     1.575     9.527    10.055    10.255

测试 SET 命令(写操作性能)

关键输出:SET 命令吞吐量(如 3703.70 requests per second),延迟略高于 PING(因需写磁盘)

bash 复制代码
root@2d8d4fc5b23a:/data# redis-benchmark -h 192.168.67.154 -t set -n 1000 -r 100
WARNING: Could not fetch server CONFIG
====== SET ======                                                   
  1000 requests completed in 0.27 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1
  multi-thread: no
​
Latency by percentile distribution:
0.000% <= 0.735 milliseconds (cumulative count 1)
50.000% <= 5.615 milliseconds (cumulative count 500)
75.000% <= 9.391 milliseconds (cumulative count 750)
87.500% <= 17.519 milliseconds (cumulative count 875)
93.750% <= 43.903 milliseconds (cumulative count 938)
96.875% <= 68.159 milliseconds (cumulative count 969)
98.438% <= 161.791 milliseconds (cumulative count 985)
99.219% <= 194.303 milliseconds (cumulative count 993)
99.609% <= 228.223 milliseconds (cumulative count 997)
99.805% <= 230.911 milliseconds (cumulative count 999)
99.902% <= 231.039 milliseconds (cumulative count 1000)
100.000% <= 231.039 milliseconds (cumulative count 1000)
​
Cumulative distribution of latencies:
0.000% <= 0.103 milliseconds (cumulative count 0)
0.300% <= 0.807 milliseconds (cumulative count 3)
0.600% <= 0.903 milliseconds (cumulative count 6)
0.800% <= 1.007 milliseconds (cumulative count 8)
1.400% <= 1.103 milliseconds (cumulative count 14)
2.000% <= 1.207 milliseconds (cumulative count 20)
3.000% <= 1.303 milliseconds (cumulative count 30)
4.000% <= 1.407 milliseconds (cumulative count 40)
5.200% <= 1.503 milliseconds (cumulative count 52)
7.100% <= 1.607 milliseconds (cumulative count 71)
8.400% <= 1.703 milliseconds (cumulative count 84)
9.100% <= 1.807 milliseconds (cumulative count 91)
10.100% <= 1.903 milliseconds (cumulative count 101)
11.100% <= 2.007 milliseconds (cumulative count 111)
12.200% <= 2.103 milliseconds (cumulative count 122)
26.000% <= 3.103 milliseconds (cumulative count 260)
36.900% <= 4.103 milliseconds (cumulative count 369)
45.600% <= 5.103 milliseconds (cumulative count 456)
55.400% <= 6.103 milliseconds (cumulative count 554)
62.700% <= 7.103 milliseconds (cumulative count 627)
69.100% <= 8.103 milliseconds (cumulative count 691)
74.100% <= 9.103 milliseconds (cumulative count 741)
77.000% <= 10.103 milliseconds (cumulative count 770)
79.800% <= 11.103 milliseconds (cumulative count 798)
82.000% <= 12.103 milliseconds (cumulative count 820)
83.900% <= 13.103 milliseconds (cumulative count 839)
85.100% <= 14.103 milliseconds (cumulative count 851)
85.900% <= 15.103 milliseconds (cumulative count 859)
86.600% <= 16.103 milliseconds (cumulative count 866)
87.100% <= 17.103 milliseconds (cumulative count 871)
88.100% <= 18.111 milliseconds (cumulative count 881)
89.300% <= 19.103 milliseconds (cumulative count 893)
89.900% <= 20.111 milliseconds (cumulative count 899)
90.600% <= 21.103 milliseconds (cumulative count 906)
91.000% <= 22.111 milliseconds (cumulative count 910)
91.400% <= 23.103 milliseconds (cumulative count 914)
92.300% <= 24.111 milliseconds (cumulative count 923)
92.600% <= 25.103 milliseconds (cumulative count 926)
92.900% <= 26.111 milliseconds (cumulative count 929)
93.000% <= 27.103 milliseconds (cumulative count 930)
93.200% <= 28.111 milliseconds (cumulative count 932)
93.300% <= 29.103 milliseconds (cumulative count 933)
93.600% <= 30.111 milliseconds (cumulative count 936)
93.700% <= 42.111 milliseconds (cumulative count 937)
93.900% <= 44.127 milliseconds (cumulative count 939)
94.000% <= 45.119 milliseconds (cumulative count 940)
94.200% <= 48.127 milliseconds (cumulative count 942)
94.600% <= 49.119 milliseconds (cumulative count 946)
94.700% <= 50.111 milliseconds (cumulative count 947)
94.900% <= 51.103 milliseconds (cumulative count 949)
95.000% <= 54.111 milliseconds (cumulative count 950)
95.500% <= 55.103 milliseconds (cumulative count 955)
95.700% <= 57.119 milliseconds (cumulative count 957)
95.900% <= 58.111 milliseconds (cumulative count 959)
96.000% <= 60.127 milliseconds (cumulative count 960)
96.400% <= 61.119 milliseconds (cumulative count 964)
96.900% <= 68.159 milliseconds (cumulative count 969)
97.000% <= 75.135 milliseconds (cumulative count 970)
97.100% <= 82.111 milliseconds (cumulative count 971)
97.200% <= 88.127 milliseconds (cumulative count 972)
97.300% <= 89.151 milliseconds (cumulative count 973)
97.400% <= 90.111 milliseconds (cumulative count 974)
97.500% <= 102.143 milliseconds (cumulative count 975)
97.600% <= 103.103 milliseconds (cumulative count 976)
97.700% <= 104.127 milliseconds (cumulative count 977)
97.800% <= 105.151 milliseconds (cumulative count 978)
97.900% <= 127.103 milliseconds (cumulative count 979)
98.000% <= 139.135 milliseconds (cumulative count 980)
98.100% <= 142.207 milliseconds (cumulative count 981)
98.200% <= 144.127 milliseconds (cumulative count 982)
98.300% <= 152.191 milliseconds (cumulative count 983)
98.400% <= 153.215 milliseconds (cumulative count 984)
98.500% <= 162.175 milliseconds (cumulative count 985)
98.600% <= 166.143 milliseconds (cumulative count 986)
98.700% <= 178.175 milliseconds (cumulative count 987)
98.800% <= 179.199 milliseconds (cumulative count 988)
99.000% <= 193.151 milliseconds (cumulative count 990)
99.200% <= 194.175 milliseconds (cumulative count 992)
99.400% <= 195.199 milliseconds (cumulative count 994)
99.500% <= 226.175 milliseconds (cumulative count 995)
99.600% <= 227.199 milliseconds (cumulative count 996)
99.700% <= 228.223 milliseconds (cumulative count 997)
99.800% <= 229.119 milliseconds (cumulative count 998)
100.000% <= 231.167 milliseconds (cumulative count 1000)
​
Summary:
  throughput summary: 3703.70 requests per second
  latency summary (msec):
          avg       min       p50       p95       p99       max
       12.955     0.728     5.615    53.631   192.767   231.039

性能指标解读

  • 吞吐量:单位时间内处理的请求数(越高越好),实验环境中 3000-5000 req/s 属于正常范围(生产环境可通过增加 Redis 节点、优化资源配置进一步提升)。

  • 延迟:处理单个请求的时间(越低越好),实验环境中 avg < 20ms 属于正常范围,若延迟过高,需检查 NFS 存储性能、K8s 节点资源是否充足。

5.3.故障切换测试:验证集群高可用

Redis 集群的核心优势是 "主节点故障后,从节点自动升级为主节点,保证服务不中断",需验证此功能:

查看初始集群状态

bash 复制代码
kubectl exec -it pod/redis-cluster-0 -n redis-cluster -- redis-cli -a openlab --cluster check $(kubectl get pod -l app.kubernetes.io/name=redis-cluster -n redis-cluster -o jsonpath='{.items[0].status.podIP}:6379')       # 记录主节点 IP 与对应的从节点(如主节点 10.244.104.40,从节点 10.244.104.42)

删除从节点 Pod,验证自动重建

bash 复制代码
kubectl -n redis-cluster get pods -o wide
bash 复制代码
# 删除一个从节点(如 redis-cluster-4)
kubectl -n redis-cluster delete pods redis-cluster-4
​
# 查看 Pod 状态:StatefulSet 会自动重建 redis-cluster-4(约 10-20 秒)
kubectl -n redis-cluster get pods -o wide
bash 复制代码
# 再次检查集群状态:新重建的 redis-cluster-4 会自动加入集群,成为原主节点的从节点
kubectl exec -it pod/redis-cluster-0 -n redis-cluster -- redis-cli -a openlab --cluster check $(kubectl get pod -l app.kubernetes.io/name=redis-cluster -n redis-cluster -o jsonpath='{.items[0].status.podIP}:6379')

删除主节点 Pod,验证故障切换

bash 复制代码
kubectl -n redis-cluster get pods -o wide
bash 复制代码
# 删除一个主节点(如 redis-cluster-0,对应主节点 10.244.104.40)
kubectl -n redis-cluster delete pods redis-cluster-0
​
# 查看 Pod 状态:redis-cluster-0 会自动重建,同时原从节点(如 10.244.104.42)会升级为主节点
kubectl -n redis-cluster get pods -o wide
bash 复制代码
# 检查集群状态:
# 1. 原从节点已升级为主节点,接管原主节点的槽位(0-5460);
# 2. 重建后的 redis-cluster-0 成为新主节点的从节点;
# 3. 所有 16384 个槽位仍覆盖完整,集群正常提供服务。
kubectl exec -it pod/redis-cluster-1 -n redis-cluster -- redis-cli -a openlab --cluster check $(kubectl get pod -l app.kubernetes.io/name=redis-cluster -n redis-cluster -o jsonpath='{.items[1].status.podIP}:6379')

故障切换核心逻辑

  1. 主节点故障(如 Pod 被删除),集群内其他节点检测到该节点超时(cluster-node-timeout 5000);

  2. 该主节点的从节点发起选举,投票成为新主节点;

  3. 新主节点接管原主节点的所有槽位,继续提供服务;

  4. StatefulSet 重建原主节点 Pod,新 Pod 启动后自动成为新主节点的从节点,恢复 3 主 3 从架构。


六、Redis 集群图形化管理工具 RedisInsight

命令行管理 Redis 集群效率低,RedisInsight 是 Redis 官方推出的图形化工具,支持查看集群状态、数据、执行命令、分析性能,大幅降低运维成本。

6.1.部署 RedisInsight 到 K8s

bash 复制代码
# 拉取镜像并推到私有 Harbor(避免外部仓库依赖)
docker pull swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/redislabs/redisinsight:2.56
​
docker tag swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/redislabs/redisinsight:2.56 reg.zyz.org/redislabs/redisinsight:2.56
  
docker push reg.zyz.org/redislabs/redisinsight:2.56 

编写部署文件(Deployment + Service)

bash 复制代码
vim dep-RedisInsight.yml 
############
# Deployment:部署 RedisInsight
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app.kubernetes.io/name: redisinsight
  name: redisinsight
  namespace: redis-cluster
spec:
  replicas: 1 # 图形化工具无需多实例(数据存储在本地,多实例会导致配置不同步)
  selector:
    matchLabels:
      app.kubernetes.io/name: redisinsight
  template:
    metadata:
      labels:
        app.kubernetes.io/name: redisinsight
    spec:
      containers:
      - image: redislabs/redisinsight:2.56 # 私有仓库镜像(需补全前缀)
        name: redisinsight
        ports:
        - name: redisinsight
          containerPort: 5540 # RedisInsight 默认端口
          protocol: TCP
        resources:
          limits: # 资源上限
            cpu: "2"
            memory: 2Gi
          requests: # 资源请求
            cpu: 100m
            memory: 500Mi
---
# Service:暴露 RedisInsight 供外部访问(LoadBalancer 类型)
apiVersion: v1
kind: Service
metadata:
  name: redisinsight-svc
  namespace: redis-cluster
  labels:
    app.kubernetes.io/name: redisinsight
spec:
  type: LoadBalancer
  ports:
  - name: redisinsight
    protocol: TCP
    port: 8080 # 暴露 8080 端口(方便浏览器访问,无需记 5540)
    targetPort: 5540 # 转发到 Pod 的 5540 端口
  selector:
    app.kubernetes.io/name: redisinsight
############
bash 复制代码
# 应用配置并验证
kubectl apply -f dep-RedisInsight.yml
kubectl -n redis-cluster get pods
kubectl -n redis-cluster get service # 查看 EXTERNAL-IP(如 192.168.67.155)

6.2.访问与使用 RedisInsight

  • 访问界面 :打开浏览器,输入 http://<EXTERNAL-IP>:8080(如 http://192.168.67.155:8080),按提示完成初始化(设置密码)。
  • 添加 Redis 集群:

    • 点击 "Add Redis Database",选择 "Redis Cluster"。

    • 输入任意一个 Redis 节点的地址(如 redis-cluster-0.headless-redis.redis-cluster.svc.cluster.local:6379),密码 openlab。

    • 点击 "Add",RedisInsight 会自动发现所有集群节点。

然后直接点击我们的数据库名称,就可以查看里面所有的数据,右上角可以添加数据

核心功能使用:

  • Cluster View:查看集群拓扑(主从关系、槽位分布)。

  • Browser:可视化查看 / 编辑 Key-Value 数据。

  • Workbench:执行 Redis 命令(如 cluster info、set key value)。

  • Analysis Tools:分析集群性能(如内存使用、命令执行频率)。


七、总结

实验核心成果与生产环境优化建议

7.1.实验核心成果

  • 构建了 3 主 3 从 Redis 集群,实现数据分片与高可用(主节点故障后从节点自动切换)。

  • 实现 动态存储供应(NFS Provisioner + StorageClass),用户无需手动创建 PV,降低运维成本。

  • 部署 Redis Cluster Proxy,解决客户端兼容性问题,K8s 外部客户端可无感知访问集群。

  • 提供 图形化管理工具(RedisInsight),简化集群监控与运维。

7.2.生产环境优化建议

  • 存储优化:实验用 NFS,生产环境建议用性能更好的分布式存储(如 Ceph、GlusterFS),避免 NFS 成为性能瓶颈。

  • 安全优化:

    • 关闭 no_root_squash,改用 root_squash 并为 Redis 配置专用用户,降低权限风险。

    • 为 Redis 密码、Proxy 配置等敏感信息使用 Secret(而非 ConfigMap),避免明文存储。

  • 性能优化:

    • 调整 Redis 配置(如 maxmemory-policy、hash-max-ziplist-entries),优化内存使用。

    • 增加 Proxy 实例数(replicas:3),并配置 HPA(Horizontal Pod Autoscaler),根据请求量自动扩缩容。

  • 监控告警:集成 Prometheus + Grafana 监控 Redis 集群(如槽位覆盖率、主从同步延迟、内存使用率),设置告警(如主节点故障、内存使用率超 90%)。

相关推荐
2301_8035545212 小时前
Docker(自写)
运维·docker·容器
惜.己12 小时前
docker命令(二)
运维·docker·容器
KiraFenvy12 小时前
【Docker】Docker的容器Container、镜像Image和卷Volume对比
docker·容器
海梨花13 小时前
你的Redis是不是在家能用,到了学校就连不上?
数据库·redis·ubuntu·虚拟机
CHHC188013 小时前
C#简易KV存储
redis·c#
AKAMAI16 小时前
应用平台更新:可定制目录、基于Git的密钥管理与K8s项目自动化管理
人工智能·云原生·云计算
KiraFenvy16 小时前
【Docker】Docker容器和镜像管理常用命令
docker·容器
XMYX-017 小时前
Kubernetes 中根据 Pod IP 查找 Pod 及关联服务的方法
kubernetes
KellenKellenHao17 小时前
k8s三阶段项目
云原生·容器·kubernetes