redis pub/sub连接失败需先确认容器是否在同一docker网络:默认bridge网络不支持服务名解析,localhost在容器内指向自身而非redis实例;必须使用docker-compose.yml中定义的服务名(如redis)作为host,且确保bind配置为0.0.0.0、protected-mode关闭或配密码。

Redis Pub/Sub 连接失败时,先确认是否在同一个 Docker 网络里
Pub/Sub 依赖 TCP 长连接和双向通信,容器间若不在同一自定义网络,DNS 解析失败或路由不通会导致 subscribe 命令卡住、无响应、超时。默认的 bridge 网络不支持跨容器服务名解析,localhost 在容器内永远指向自己,不是 Redis 实例。
检查方式:
- 运行
docker inspect redis-container | jq '.[0].NetworkSettings.Networks',确认输出中包含你期望的网络名(如app_net) - 对发布端容器执行
docker exec -it publisher-container ping redis-service(redis-service是你在docker-compose.yml中定义的服务名) - 若 ping 不通,说明网络隔离已生效——这不是 bug,是 Docker 的默认行为
用 conntrack 直接抓取 Redis Pub/Sub 的 ESTABLISHED 连接
ss 和 lsof 在容器外查不到 Pub/Sub 连接,因为它们只看主机命名空间;而 Pub/Sub 流量经过 NAT 后,在内核 conntrack 表里是可见的。这是唯一能确认“客户端是否真连上了 Redis”的方法。
操作步骤:
- 获取 Redis 容器 IP:
docker inspect redis-container | grep IPAddress→ 得到类似"IPAddress": "172.18.0.3" - 确认 Redis 端口映射或监听配置:默认是
6379,但若用了--port 6380或自定义配置,需同步调整 - 运行:
sudo conntrack -L --dst 172.18.0.3 --dport 6379 | grep ESTABLISHED - 若有输出,说明至少有一个客户端建立了长连接;若为空,说明订阅端根本没连上来,问题出在网络层或客户端代码
docker-compose.yml 中 Redis 服务名必须与应用代码里的 host 一致
Docker 内置 DNS 只响应服务名(如 redis),不响应 localhost、127.0.0.1 或宿主机 IP。很多 SDK 默认连 localhost:6379,这在容器里必然失败。
典型错误写法(Python 示例):
redis.Redis(host="localhost", port=6379)
正确写法:
redis.Redis(host="redis", port=6379)
关键点:
-
host必须等于docker-compose.yml中该服务的service name(即redis:这一行的 key) - 不要在 compose 文件里加
hostname:字段覆盖默认 DNS 名,容易引发歧义 - 如果使用了自定义网络(推荐),确保所有相关服务都显式声明
networks: [app_net]
Pub/Sub 消息收不到?检查 Redis 配置中的 bind 和 protected-mode
即使网络通、连接建起来了,Redis 默认配置也会拒绝非本地 Pub/Sub 请求:
-
bind 127.0.0.1:仅监听回环地址,容器间无法访问 → 改为bind 0.0.0.0或删掉该行(Redis 7+ 默认已放开) -
protected-mode yes:启用保护模式时,若未设置密码且未绑定公网地址,会拒绝外部连接 → 设为no或配requirepass - 检查方式:进入 Redis 容器执行
redis-cli config get bind和config get protected-mode
这些配置项必须通过挂载自定义 redis.conf 或 command 覆盖,镜像默认配置通常不够用。











