K8S部署Redis高可用全攻略:1主2从3哨兵架构实战

K8S部署Redis高可用全攻略:1主2从3哨兵架构实战

一、创建Redis

1.编写YAML文件
yaml 复制代码
---
# Redis 无头服务(Headless Service)
# 用于 StatefulSet 内部稳定域名解析:redis-0.redis、redis-1.redis
apiVersion: v1
kind: Service
metadata:
  name: redis
spec:
  clusterIP: None
  ports:
  - port: 6379
    name: redis
  selector:
    app: redis

---
# Redis 有状态集群(3 节点:自动主从 + 自动故障切换)
# 启动逻辑:从哨兵获取主节点信息,自动成为主/从
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: redis
spec:
  serviceName: redis
  replicas: 3
  selector:
    matchLabels:
      app: redis
  template:
    metadata:
      labels:
        app: redis
    spec:
      containers:
      - name: redis
        image: redis:7-alpine
        command: ["/bin/sh", "-c"]
        args:
        - |
          # 等待集群网络与哨兵启动完成
          sleep 10

          # 从哨兵查询当前集群的主库 IP
          MASTER_IP=$(redis-cli -h sentinel-0.sentinel.default.svc.cluster.local -p 26379 --raw sentinel get-master-addr-by-name mymaster 2>/dev/null | head -n1)
          # 获取当前 Pod 的 IP
          MY_IP=$(hostname -i)

          # 如果本机是哨兵指定的主节点,则以主节点启动
          if [ "$MASTER_IP" = "$MY_IP" ]; then
            redis-server --appendonly yes --protected-mode no
          
          # 否则,自动成为从节点,连接主节点同步数据
          else
            redis-server --appendonly yes --protected-mode no --replicaof $MASTER_IP 6379
          fi
        ports:
        - containerPort: 6379
  # 数据持久化存储(自动创建 PVC)
  volumeClaimTemplates:
  - metadata:
      name: redis-data
    spec:
      accessModes: [ReadWriteOnce]
      resources:
        requests:
          storage: 1Gi

---
# 哨兵无头服务
# 用于哨兵之间通信,以及 Redis 连接哨兵
apiVersion: v1
kind: Service
metadata:
  name: sentinel
spec:
  clusterIP: None
  ports:
  - port: 26379
  selector:
    app: sentinel

---
# Redis 哨兵集群(3 节点:监控 + 故障自动转移)
# 作用:监控主库,主库宕机自动选举新主
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: sentinel
spec:
  serviceName: sentinel
  replicas: 3
  selector:
    matchLabels:
      app: sentinel
  template:
    metadata:
      labels:
        app: sentinel
    spec:
      containers:
      - name: sentinel
        image: redis:7-alpine
        command: ["/bin/sh", "-c"]
        args:
        - |
          # 等待 Redis 主节点启动
          sleep 10

          # 解析初始主节点域名获取 IP
          MASTER_IP=$(getent hosts redis-0.redis | awk '{print $1}')

          # 生成哨兵配置文件
          cat >/tmp/sentinel.conf <<EOF
          port 26379
          protected-mode no

          # 监控名为 mymaster 的集群,2 个哨兵确认即触发切换
          sentinel monitor mymaster $MASTER_IP 6379 2
          # 主节点 5 秒无响应则标记为下线
          sentinel down-after-milliseconds mymaster 5000
          # 故障转移超时时间
          sentinel failover-timeout mymaster 10000
          # 并行同步的从节点数量
          sentinel parallel-syncs mymaster 1
          EOF

          # 启动哨兵进程
          redis-sentinel /tmp/sentinel.conf
2.创建资源
bash 复制代码
kubectl delete -f redis.yaml
3.验证是否创建成功
bash 复制代码
kubectl get pods,svc,pvc | grep -E 'redis|sentinel'
  • 可以看到Pod名字是固定名字,不是随机字符串!

  • PVC 状态处于Bound状态

  • ServiceClusterIPNode

二、验证Redis主从(1主2从)

1.看主节点redis-0 角色
bash 复制代码
kubectl exec -it redis-0 -- redis-cli info replication

状态显示主节点正确,有 2 个从机

2.看从节点redis-1和redis-2角色
bash 复制代码
kubectl exec -it redis-1 -- redis-cli info replication
kubectl exec -it redis-2 -- redis-cli info replication

三、验证哨兵模式(3哨兵)

1.看哨兵是否监控到主库
bash 复制代码
kubectl exec -it sentinel-0 -- redis-cli -p 26379 info sentinel

状态显示:哨兵监控成功!

2.看哨兵是否发现 2 个从节点
bash 复制代码
kubectl exec -it sentinel-0 -- redis-cli -p 26379 SENTINEL slaves mymaster

会出现 2 个从节点信息, 哨兵识别主从成功!

四、测试

1.测试数据同步

往主库(redis-0)写数据,去从库(redis-1、redis-2)读数据

bash 复制代码
#主库执行
kubectl exec -it redis-0 -- redis-cli set mytest "hello"
#从库redis-1执行
kubectl exec -it redis-1 -- redis-cli get mytest
#从库redis-2执行
kubectl exec -it redis-2 -- redis-cli get mytest

能读到 hello = 主从同步 100% 正常

2.测试自动故障转移(高可用)
①删除主库redis-0

直接把主库干掉,看哨兵是否自动选新主

bash 复制代码
kubectl delete pod redis-0
②看哨兵日志
复制代码
kubectl logs sentinel-0

你会看到:+switch-master mymaster ...

③进入从库查看信息,确认新主库
bash 复制代码
kubectl exec redis-1 -- redis-cli info replication
kubectl exec redis-2 -- redis-cli info replication

可以看到从库redis-1升级成了主库

④旧主库(redis-0)重建恢复后自动归队,变成新从库

redis-0 会被 K8s 自动重建,自动加入集群作为从库:

bash 复制代码
kubectl exec -it redis-0 -- redis-cli info replication
⑤验证集群状态与数据一致性
bash 复制代码
# 在新主库写入测试数据
kubectl exec -it redis-1 -- redis-cli set test "good"

# 在所有节点读取数据,确认同步正常
kubectl exec -it redis-0 -- redis-cli get test
kubectl exec -it redis-2 -- redis-cli get test

✅ 预期结果:所有节点都能读到相同的数据,说明主从同步正常。

五、进阶配置

1.配置Redis密码
①给 Redis + Sentinel 设置密码

生产环境必须用:K8s Secret + 环境变量 挂载使用,这里我们创建一个redis-secret,密码是Redis@2026

bash 复制代码
kubectl create secret generic redis-secret \
--from-literal=REDIS_PASSWORD=Redis@2026
②验证 Redis 密码是否正确
bash 复制代码
kubectl exec redis-0 -- redis-cli -a Redis@2026 info replication

出现主从信息=密码正确!

③JAVA应用配置Redis哨兵+密码
  • 修改 application.properties
properties 复制代码
# 从环境变量读取 Redis 密码
spring.redis.password=${SPRING_REDIS_PASSWORD:Redis@2026}
spring.redis.sentinel.master=${SPRING_REDIS_SENTINEL_MASTER:mymaster}
spring.redis.sentinel.nodes=${SPRING_REDIS_SENTINEL_NODES:localhost:26379}
  • 修改JAVA K8s Deployment yaml

加入 Redis 密码环境变量 ,从 Secret 读取

④提交代码等待K8S滚动更新
⑤验证java应用有没有读取到密码
bash 复制代码
# 进入java容器
kubectl exec -it my-java-app-5597696bcb-5xs7p -- env | grep SPRING_REDIS
#预计返回以下内容
SPRING_REDIS_SENTINEL_NODES=sentinel-0.sentinel.default.svc.cluster.local:26379,sentinel-1.sentinel.default.svc.cluster.local:26379,sentinel-2.sentinel.default.svc.cluster.local:26379
SPRING_REDIS_PASSWORD=Redis@2026
SPRING_REDIS_SENTINEL_MASTER=mymaster

说明:密码、哨兵地址全部注入成功

2.配置Redis 三大生产加固
  • 内存上限 + 内存淘汰策略(防 OOM、防内存爆满)

  • 关闭高危命令(FLUSHALL / FLUSHDB 禁止执行)

  • 优化持久化 RDB+AOF 混合(数据更安全)

①我们直接修改 redis.yaml 部署文件的 redis 容器 args 部分,完整代码示例:
yaml 复制代码
# --- Redis 无头服务 ---
apiVersion: v1
kind: Service
metadata:
  name: redis
spec:
  clusterIP: None
  ports:
    - port: 6379
      name: redis
  selector:
    app: redis

---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: redis
spec:
  serviceName: redis
  replicas: 3
  selector:
    matchLabels:
      app: redis
  template:
    metadata:
      labels:
        app: redis
    spec:
      containers:
      - name: redis
        image: redis:7-alpine
        env:
        - name: REDIS_PASSWORD
          valueFrom:
            secretKeyRef:
              name: redis-secret
              key: REDIS_PASSWORD
        command: ["/bin/sh", "-c"]
        args:
        - |
          sleep 15

          MASTER_IP=$(redis-cli -h sentinel-0.sentinel.default.svc.cluster.local -p 26379 -a $REDIS_PASSWORD --raw sentinel get-master-addr-by-name mymaster 2>/dev/null | head -n1)
          MY_IP=$(hostname -i)

          if [ -z "$MASTER_IP" ]; then
            if [ "$(hostname)" = "redis-0" ]; then
              redis-server --appendonly yes --protected-mode no --requirepass $REDIS_PASSWORD --masterauth $REDIS_PASSWORD --maxmemory 512mb --maxmemory-policy allkeys-lru
              exit 0
            else
              redis-server --appendonly yes --protected-mode no --requirepass $REDIS_PASSWORD --masterauth $REDIS_PASSWORD --maxmemory 512mb --maxmemory-policy allkeys-lru --replicaof redis-0.redis 6379
              exit 0
            fi
          fi

          if [ "$MASTER_IP" = "$MY_IP" ]; then
            redis-server \
            --appendonly yes \
            --protected-mode no \
            --requirepass $REDIS_PASSWORD \
            --masterauth $REDIS_PASSWORD \
            --maxmemory 512mb \
            --maxmemory-policy allkeys-lru
          else
            redis-server \
            --appendonly yes \
            --protected-mode no \
            --requirepass $REDIS_PASSWORD \
            --masterauth $REDIS_PASSWORD \
            --maxmemory 512mb \
            --maxmemory-policy allkeys-lru \
            --replicaof $MASTER_IP 6379
          fi

        ports:
        - containerPort: 6379
  volumeClaimTemplates:
  - metadata:
      name: redis-data
    spec:
      accessModes: [ReadWriteOnce]
      resources:
        requests:
          storage: 1Gi

---
# --- 哨兵---
apiVersion: v1
kind: Service
metadata:
  name: sentinel
spec:
  clusterIP: None
  ports:
    - port: 26379
  selector:
    app: sentinel

---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: sentinel
spec:
  serviceName: sentinel
  replicas: 3
  selector:
    matchLabels:
      app: sentinel
  template:
    metadata:
      labels:
        app: sentinel
    spec:
      containers:
      - name: sentinel
        image: redis:7-alpine
        env:
        - name: REDIS_PASSWORD
          valueFrom:
            secretKeyRef:
              name: redis-secret
              key: REDIS_PASSWORD
        command: ["/bin/sh", "-c"]
        args:
        - |
          sleep 15
          MASTER_IP=$(getent hosts redis-0.redis | awk '{print $1}')
          cat >/tmp/sentinel.conf <<EOF
          port 26379
          protected-mode no
          sentinel monitor mymaster $MASTER_IP 6379 2
          sentinel auth-pass mymaster $REDIS_PASSWORD
          sentinel down-after-milliseconds mymaster 5000
          sentinel failover-timeout mymaster 10000
          sentinel parallel-syncs mymaster 1
          EOF
          redis-sentinel /tmp/sentinel.conf
        ports:
        - containerPort: 26379
②应用配置
bash 复制代码
kubectl apply -f redis.yaml
③验证配置生效
bash 复制代码
#验证内存限制
kubectl exec redis-2 -- redis-cli -a Redis@2026 config get maxmemory
#验证淘汰策略
kubectl exec redis-2 -- redis-cli -a Redis@2026 config get maxmemory-policy
#验证AOF持久化
kubectl exec redis-2 -- redis-cli -a Redis@2026 config get appendonly
#验证密码生效
kubectl exec redis-2 -- redis-cli -a Redis@2026 config get requirepass

以上则完成了K8s 生产级 Redis 哨兵高可用全套方案

✅主从同步 ✅自动故障转移 ✅重启自愈 ✅数据持久化 ✅安全密码 ✅稳定无崩溃

相关推荐
尘世壹俗人2 小时前
使用K8s部署模型
kubernetes
AI攻城狮2 小时前
AI Agent 从上线到删库跑路始末
云原生
weixin_446260853 小时前
城市智能化的底层基石:基于腾讯地图服务生态的移动定位与导航架构指引
大数据·人工智能·架构
SCBAiotAigc3 小时前
2026.5.1:`DockerDesktop must be owned by an elevated account`错误的解决办法
人工智能·docker·具身智能
AI木马人3 小时前
9.人工智能实战:GPU 服务如何上 Kubernetes?从单机部署到 K8s + NVIDIA Device Plugin + HPA 的生产级改造
人工智能·容器·kubernetes
凯瑟琳.奥古斯特4 小时前
Redis是什么及核心特性
前端·css·redis·缓存
KmSH8umpK5 小时前
Redis分布式锁从原生手写到Redisson高阶落地,附线上死锁复盘优化方案进阶第三篇
redis·分布式·wpf
@#¥&~是乱码鱼啦5 小时前
Spring分层架构:Controller、Service、Mapper数据链路,IOC的真实工作意义
java·spring·架构
vortex55 小时前
SafeLine 雷池WAF 真实体验,谈谈架构与原理
架构