Mac端使用Docker部署Redis 主从复制踩坑实录:别再被 localhost 坑了

19 阅读3分钟

最近我在本地用 Docker 搭了个 Redis 主从 + Sentinel 的测试环境。主节点配好了,两个从节点也按照文档配置上了 slaveof localhost 7001,看起来一切正常。

但奇怪的是,主节点始终显示:

connected_slaves:0

也就是说,两个从节点压根没连上来。

我查日志、试连接、重启服务……折腾了一两个小时,最后才发现问题出在一个看似无关紧要的细节上:localhost127.0.0.1 其实不一样!


🧩 到底发生了什么?

在 Linux 系统中,localhost127.0.0.1 通常是一样的,都指向本机。但在 Docker 容器里,尤其是在 macOS 上使用 Docker Desktop 的时候,这个规则就不灵了。

如果你用了 network_mode: host,你以为容器和宿主机共享网络,访问 localhost 就能访问别的容器的服务。但实际上,在 macOS 的 Docker 中,localhost 是指向宿主机本身的,而不是其他容器。

所以当你在从节点里配置:

--slaveof localhost 7001

它其实是去宿主机找 7001 端口有没有 Redis 在运行 —— 而不是去找另一个容器里的 Redis 主节点!

这就导致了从节点一直连不上主节点,主节点也就看不到任何从节点。


✅ 解决方法

把所有的 slaveof localhost 7001 改成:

--slaveof 127.0.0.1 7001

这样,Redis 容器之间就能正确通信了,从节点也能顺利连接上主节点。


🧪 我是怎么验证的?

改完配置后,我执行了下面几步来确认:

  1. 进入从节点容器内部测试连接主节点:
docker exec -it r2 redis-cli -p 7001 ping

返回:

PONG

说明网络是通的。

  1. 查看从节点复制状态:
docker exec -it r2 redis-cli -p 7002 info replication

返回片段如下:

master_link_status:up
slave_repl_offset:12345

说明已经成功建立复制链路。

  1. 回到主节点查看从节点数量:
docker exec -it r1 redis-cli -p 7001 info replication

输出:

connected_slaves:2
slave0:ip=127.0.0.1,port=7002,state=online
slave1:ip=127.0.0.1,port=7003,state=online

✅ 成功识别两个从节点!


📄 推荐的完整 docker-compose.yaml 配置

以下是优化后的 docker-compose.yaml 文件,包含主节点、两个从节点和三个 Sentinel 节点的完整配置,确保服务间通过 127.0.0.1 正确通信。

services:
  r1:
    image: redis:8.0.2
    container_name: r1
    network_mode: "host"
    entrypoint: [
      "redis-server", 
      "--port", "7001",
      "--bind", "0.0.0.0",
      "--protected-mode", "no"
    ]

  r2:
    image: redis:8.0.2
    container_name: r2
    network_mode: "host"
    entrypoint: [
      "redis-server", 
      "--port", "7002", 
      "--slaveof", "127.0.0.1", "7001",
      "--bind", "0.0.0.0"
    ]

  r3:
    image: redis:8.0.2
    container_name: r3
    network_mode: "host"
    entrypoint: [
      "redis-server", 
      "--port", "7003", 
      "--slaveof", "127.0.0.1", "7001",
      "--bind", "0.0.0.0"
    ]

  s1:
    image: redis:8.0.2
    container_name: s1
    network_mode: "host"
    volumes:
      - ./sentinel/s1:/etc/redis
    entrypoint: [
      "redis-sentinel", 
      "/etc/redis/sentinel.conf", 
      "--port", "27001"
    ]

  s2:
    image: redis:8.0.2
    container_name: s2
    network_mode: "host"
    volumes:
      - ./sentinel/s2:/etc/redis
    entrypoint: [
      "redis-sentinel", 
      "/etc/redis/sentinel.conf", 
      "--port", "27002"
    ]

  s3:
    image: redis:8.0.2
    container_name: s3
    network_mode: "host"
    volumes:
      - ./sentinel/s3:/etc/redis
    entrypoint: [
      "redis-sentinel", 
      "/etc/redis/sentinel.conf", 
      "--port", "27003"
    ]

💡 提示:你也可以将 slaveof 写入 redis.conf 并挂载进容器,以实现更稳定的主从配置。


📌 总结一下

  • localhost127.0.0.1 不总是等价的,特别是在 Docker 容器环境下。
  • 如果你用的是 macOS 的 Docker Desktop,或者不确定平台行为,请统一使用 127.0.0.1 来做服务间通信
  • 使用 docker-compose 配置 Redis 主从时,虽然可以用 --slaveof 参数设置从属关系,但这不会写入配置文件,容易重启后失效。建议挂载 redis.conf 文件并写入 slaveof 127.0.0.1 <port>,确保稳定生效。