当前位置: 首页 > news >正文

使用 Kubernetes(k8s) 搭建 Redis 3 主 3 从集群教程

一、技术选型

一、为什么用 StatefulSet 部署 Redis 而非 Deployment?

Redis 集群是典型的有状态应用,对 “节点身份” 和 “存储稳定性” 有强依赖,而 StatefulSet 相比 Deployment 的核心优势恰好匹配这些需求:

  1. 稳定的网络标识StatefulSet 为每个 Pod 分配固定名称(如redis-cluster-0redis-cluster-1)和 DNS 记录(如redis-cluster-0.redis-cluster-service.redis-cluster.svc.cluster.local),确保 Redis 节点之间的通信地址固定(集群初始化时配置的节点地址不会因 Pod 重建失效)。

  2. 有序部署与扩展StatefulSet 会按顺序(0→1→2→...)创建 Pod,且只有前一个 Pod 就绪后才会创建下一个,避免了集群初始化时节点未就绪导致的配置失败。

  3. 绑定专属持久存储通过volumeClaimTemplates为每个 Pod 自动创建独立的 PersistentVolumeClaim(PVC),确保每个 Redis 节点的数据存储在专属的持久卷(PV)中,即使 Pod 被删除重建,数据也不会丢失(Deployment 的 PVC 会被多个 Pod 共享,不适合有状态场景)。

二、为什么使用 Headless Service(无 ClusterIP)?

在方案中,Redis 服务定义为clusterIP: None的 Headless Service,而非普通 Service,原因是:

  1. 支持 Redis 节点间的点对点通信Redis 集群需要节点间通过 Gossip 协议交换状态(端口 16379),并在客户端请求时重定向到目标节点(槽位所在主节点)。Headless Service 会为每个 Pod 生成唯一的 DNS A 记录(如redis-cluster-0.redis-cluster-service),节点可通过域名直接访问其他节点,无需经过 Service 的负载均衡(普通 Service 的 ClusterIP 会导致请求被随机转发,破坏 Redis 集群的路由逻辑)。

  2. 简化集群初始化配置集群初始化时,可直接通过固定的 DNS 域名(如redis-cluster-0.redis-cluster-service.redis-cluster.svc.cluster.local:6379)指定节点地址,无需担心 IP 变化(K8s 中 Pod 的 IP 是动态的,而 DNS 域名是固定的)。

三、为什么用 ConfigMap 管理 Redis 配置?

  1. 配置与镜像解耦Redis 的核心配置(如cluster-enabled yescluster-node-timeout 5000)通过 ConfigMap 挂载到容器,而非硬编码到镜像中。当需要调整配置时,只需更新 ConfigMap 并重启 Pod,无需重新构建镜像,符合 “配置即代码” 的最佳实践。

  2. 集中管理与复用所有 Redis 节点共享同一套基础配置,避免了 “每个节点单独配置” 的冗余,且便于后期统一修改(如调整超时时间、开启 AOF 持久化等)。

二、部署实战

本次部署使用存储方面使用的是StorageClass动态供给,本次不演示创建过程

前提条件:

  1. 已搭建好的 Kubernetes 集群
  2. kubectl命令行工具已配置并能连接到 K8s 集群
  3. 集群中至少有 3 个节点(推荐)

1、部署configmap

Redis 的核心配置(如cluster-enabled yescluster-node-timeout 5000)通过 ConfigMap 挂载到容器,而非硬编码到镜像中。

apiVersion: v1
kind: ConfigMap
metadata:name: redis-cluster-confignamespace: test  #名称空间
data:redis.conf: |port 6380cluster-enabled yescluster-config-file /data/nodes.confcluster-node-timeout 15000cluster-require-full-coverage noappendonly yesappendfsync everysecprotected-mode nodir /data

2、创建Headless Service

# redis-service.yaml
apiVersion: v1
kind: Service
metadata:name: redis-clusternamespace: test
spec:clusterIP: Noneports:- port: 6380 #端口,可以修改targetPort: 6380 #端口,可以修改name: client - port: 16380   #端口,可以修改targetPort: 16380 #端口,可以修改name: clusterselector:app: redis-cluster

3、RBAC权限创建

 创建权限原因:为Redis集群创建一个专用的ServiceAccount并授予必要的权限用于获取pod的ip

 为什么需要获取ip??

原因如下:

  • Redis集群初始化时可以使用域名,但集群运行后依赖IP地址。

  • 在Kubernetes中,由于Pod IP可能会变化,所以使用域名初始化集群在Pod重启后可能会失败。

  • 使用IP初始化集群,并结合cluster-announce-ip配置,可以避免Pod重启后集群通信失败的问题。

apiVersion: v1
kind: ServiceAccount
metadata:name: redis-clusternamespace: test
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:name: redis-cluster-pod-reader
rules:
- apiGroups: [""]resources: ["pods"]verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:name: redis-cluster-pod-reader
subjects:
- kind: ServiceAccountname: redis-clusternamespace: middleware
roleRef:kind: ClusterRolename: redis-cluster-pod-readerapiGroup: rbac.authorization.k8s.io

4、StatefulSet构建pod

通过StatefulSet创建6个redis的pod ,实现3主3从的redis集群

apiVersion: apps/v1
kind: StatefulSet
metadata:name: redis-clusternamespace: test
spec:serviceName: redis-clusterreplicas: 6selector:matchLabels:app: redis-clustertemplate:metadata:labels:app: redis-clusterspec:serviceAccountName: redis-cluster # 使用具有get pod权限的ServiceAccountcontainers:- name: redisimage: 192.168.1.11:8000/library/redis:6.2.14ports:- containerPort: 6380name: client- containerPort: 16380name: clusterenv:- name: POD_IPvalueFrom:fieldRef:fieldPath: status.podIPcommand: - sh- -c- |# 从ConfigMap读取基础配置,并添加IP相关配置cat /etc/redis/redis.conf > /tmp/redis.confecho "cluster-announce-ip ${POD_IP}" >> /tmp/redis.confecho "cluster-announce-port 6380" >> /tmp/redis.confecho "cluster-announce-bus-port 16380" >> /tmp/redis.confecho "replica-announce-ip ${POD_IP}" >> /tmp/redis.confecho "replica-announce-port 6380" >> /tmp/redis.confecho "使用配置文件:"cat /tmp/redis.confredis-server /tmp/redis.confvolumeMounts:- name: redis-configmountPath: /etc/redis- name: redis-datamountPath: /datalivenessProbe:tcpSocket:port: 6380initialDelaySeconds: 30periodSeconds: 10timeoutSeconds: 5failureThreshold: 3readinessProbe:tcpSocket:port: 6380initialDelaySeconds: 10periodSeconds: 5timeoutSeconds: 3failureThreshold: 3volumes:- name: redis-configconfigMap:name: redis-cluster-configitems:- key: redis.confpath: redis.confvolumeClaimTemplates:- metadata:name: redis-datanamespace: middlewarespec:accessModes: [ "ReadWriteOnce" ]storageClassName: zk-scresources:requests:storage: 10Gi

5、创建job任务,实现集群初始化

镜像问题:redis-tools:6.2.14这个镜像是我使用dockerfile分层构建的,基础镜像也是redis,这个可以自行选择。

dockerfile:

FROM redis:6.2.14# 安装curl工具并清理缓存
RUN apt-get add --no-cache curl bash# 保留原始Redis启动命令
CMD ["redis-server"]

构建的目的:因为我需要通过curl等命令自动获取ip,使用脚本自动加入集群,不需要像其他人一样手动获取pod的ip,然后使用命令初始化集群

apiVersion: batch/v1
kind: Job
metadata:name: redis-cluster-initnamespace: test
spec:template:spec:serviceAccountName: redis-clustercontainers:- name: initimage: 192.168.1.11:8000/library/redis-tools:6.2.14  # 使用带有工具的Redis镜像command:- /bin/sh- -c- |echo "等待Redis Pod完全启动..."sleep 20# 获取Service Account token和CA证书TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)CA_CERT=/var/run/secrets/kubernetes.io/serviceaccount/ca.crtAPI_SERVER="https://kubernetes.default.svc"NAMESPACE=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace)# 使用Kubernetes API获取所有Pod IPPOD_IPS=""for i in 0 1 2 3 4 5; doecho "获取 redis-cluster-$i 的IP..."IP=$(curl -s --cacert $CA_CERT -H "Authorization: Bearer $TOKEN" \"$API_SERVER/api/v1/namespaces/$NAMESPACE/pods/redis-cluster-$i" | \jq -r '.status.podIP // empty')if [ -n "$IP" ]; thenPOD_IPS="$POD_IPS $IP:6380"echo "获取到 redis-cluster-$i IP: $IP"# 测试Redis连接if redis-cli -h $IP -p 6380 ping; thenecho "Redis服务正常"elseecho "Redis服务异常"fielseecho "无法获取 redis-cluster-$i 的IP"fidoneecho "所有Pod IP: $POD_IPS"# 检查是否获取到所有6个IPIP_COUNT=$(echo $POD_IPS | wc -w)if [ "$IP_COUNT" -ne 6 ]; thenecho "错误:只获取到 $IP_COUNT 个IP,需要6个IP才能初始化集群"exit 1fi# 初始化集群echo "开始初始化Redis集群..."redis-cli -h $(echo $POD_IPS | cut -d' ' -f1 | cut -d: -f1) -p 6380 \--cluster create $POD_IPS --cluster-replicas 1 --cluster-yes# 验证集群状态echo "集群初始化完成,验证状态..."redis-cli -h $(echo $POD_IPS | cut -d' ' -f1 | cut -d: -f1) -p 6380 cluster infoecho "节点列表:"redis-cli -h $(echo $POD_IPS | cut -d' ' -f1 | cut -d: -f1) -p 6380 cluster nodesecho "Redis集群初始化成功!"restartPolicy: OnFailurebackoffLimit: 3

6、shell脚本验证集群状态

#!/bin/bash
echo "=== Redis集群状态验证 ==="# 1. 获取集群节点信息
echo "1. 集群节点列表:"
kubectl exec -it -n test redis-cluster-0 -c redis -- redis-cli -p 6380 cluster nodesecho -e "\n2. 主从节点统计:"
kubectl exec -it -n test redis-cluster-0 -c redis -- redis-cli -p 6380 cluster nodes | \awk '{print $3}' | sort | uniq -c
echo -e "\n3. 哈希槽分配情况:"
kubectl exec -it -n test redis-cluster-0 -c redis -- redis-cli -p 6380 cluster nodes | \grep master | awk '{print $8 " -> " $9}'echo -e "\n4. 集群基本信息:"
kubectl exec -it -n test redis-cluster-0 -c redis -- redis-cli -p 6380 cluster infoecho -e "\n5. 数据读写测试:"
#kubectl exec -it -n test redis-cluster-0 -c redis -- redis-cli -p 6380 -c set test-cluster "hello-redis"
#kubectl exec -it -n test redis-cluster-0 -c redis -- redis-cli -p 6380 -c get test-cluster

到这里就搭建完成了,有什么问题欢迎评论区讨论

http://www.dtcms.com/a/422659.html

相关文章:

  • icejs状态管理store使用
  • Web开发 20
  • GPU计算效率提升:混合精度训练、并行优化、量化与VLLM实践
  • 做新闻类网站建站公司排名 软通
  • wordpress js 统计网站的seo是什么意思
  • 实用Excel学习资料包(含操作+函数+图表教程)
  • 开源AI智能名片链动2+1模式S2B2C商城小程序在公益课裂变法中的应用与影响研究
  • # vim中给变量添加双引号
  • wps word添加水印
  • 软考-系统架构设计师 应用程序与数据库的交互详细讲解
  • 改bug的一些体会
  • 安全对齐到底是什么
  • 专业VBA代码优化服务邀约‌,OFFICE excel计算优化,wrod报表生成
  • 织梦门户网站源码下载平面设计师的培训机构
  • 2025 AI 消费端变革:从生活助手到体验重构的全民浪潮
  • 【VUECLI】node.js打造自己的前端cli脚手架工具
  • 磁共振成像原理(理论)15:空间信息编码 (Spatial Information Encoding) -频率编码相位编码
  • 磐石网站seo手机nfc网站开发
  • 命名视图学习笔记
  • CentOS7安装OpenStack云计算平台框架
  • PyCharm中搭建PyTorch和YOLOv10开发环境
  • 无人机开源项目
  • 查看网站建设时间如何免费做网站优化
  • UNIX下C语言编程与实践8-UNIX 静态库原理与创建:ar 命令的使用与静态库调用全流程
  • MATLAB用到的符号计算数学引擎
  • 精读C++20设计模式——结构型设计模式:组合模式
  • 做网站费用怎么入账新洲城乡建设局网站
  • Windows系统安装arm麒麟系统
  • ARMv8的异常处理
  • IA-静态路由