最近我在本地用 Docker 搭了个 Redis 主从 + Sentinel 的测试环境。主节点配好了,两个从节点也按照文档配置上了 slaveof localhost 7001
,看起来一切正常。
但奇怪的是,主节点始终显示:
connected_slaves:0
也就是说,两个从节点压根没连上来。
我查日志、试连接、重启服务……折腾了一两个小时,最后才发现问题出在一个看似无关紧要的细节上:localhost
和 127.0.0.1
其实不一样!
🧩 到底发生了什么?
在 Linux 系统中,localhost
和 127.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 容器之间就能正确通信了,从节点也能顺利连接上主节点。
🧪 我是怎么验证的?
改完配置后,我执行了下面几步来确认:
- 进入从节点容器内部测试连接主节点:
docker exec -it r2 redis-cli -p 7001 ping
返回:
PONG
说明网络是通的。
- 查看从节点复制状态:
docker exec -it r2 redis-cli -p 7002 info replication
返回片段如下:
master_link_status:up
slave_repl_offset:12345
说明已经成功建立复制链路。
- 回到主节点查看从节点数量:
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
并挂载进容器,以实现更稳定的主从配置。
📌 总结一下
localhost
和127.0.0.1
不总是等价的,特别是在 Docker 容器环境下。- 如果你用的是 macOS 的 Docker Desktop,或者不确定平台行为,请统一使用
127.0.0.1
来做服务间通信。 - 使用
docker-compose
配置 Redis 主从时,虽然可以用--slaveof
参数设置从属关系,但这不会写入配置文件,容易重启后失效。建议挂载redis.conf
文件并写入slaveof 127.0.0.1 <port>
,确保稳定生效。