最近在部署 Java 服务时遇到一个非常“坑爹”的问题——容器启动后,应用死活连不上 Redis,一顿排查才发现是 Docker 网络和 Redis 内网网段冲突导致的。
本文详细记录了整个排查与解决的过程,希望能帮到你。
🧩 一、问题背景
环境信息:
- 系统: CentOS(宿主机)
- 运行环境: Docker 容器
- 应用: Java(使用 Netty 连接 Redis)
- Redis: 阿里云 Redis 内网地址
172.18.3.177:6379
问题现象:
容器内报错如下 👇
Caused by: io.netty.channel.AbstractChannel$AnnotatedNoRouteToHostException: Host is unreachable: r-uf6i6m3hi5qtxpw1ed.redis.rds.aliyuncs.com/172.18.3.177:6379
Caused by: java.net.NoRouteToHostException: Host is unreachable
翻译过来就是 —— “主机不可达”。
一开始还以为是安全组或者端口问题,结果完全不是那回事。
🔍 二、深入排查:原来是 Docker 的锅!
进入容器后执行网络相关命令:
ip route
结果发现:
172.18.0.0/16 dev eth0 proto kernel scope link src 172.18.0.2
再执行:
docker network inspect bridge
输出片段:
"Subnet": "172.18.0.0/16",
"Gateway": "172.18.0.1"
到这里一切真相大白 👇
Docker 默认创建的
bridge网络使用的网段是172.18.0.0/16,
而阿里云 Redis 的内网地址刚好也是172.18.x.x!
这就导致容器以为 Redis 在“本地局域网”,不会走宿主机的网关去访问外部。
于是访问 172.18.3.177 时,数据包被路由到了 Docker 内部虚拟网桥,直接丢失。
🧭 三、验证过程
容器内执行:
ping r-uf6i6m3hi5qtxpw1ed.redis.rds.aliyuncs.com
nc -vz r-uf6i6m3hi5qtxpw1ed.redis.rds.aliyuncs.com 6379
输出:
connect to 172.18.3.177 port 6379 (tcp) failed: No route to host
完美复现!可以确定是 路由冲突 导致无法访问。
✅ 四、解决方案汇总
下面提供三种解决方案,根据实际场景选择。
🚀 方案一:修改 Docker 默认网段(推荐)
最彻底、最优雅的方式。
1️⃣ 编辑 Docker 配置
sudo vim /etc/docker/daemon.json
添加或修改如下内容:
{
"bip": "172.31.0.1/16"
}
bip表示 Docker 默认 bridge 网络的网关。
你可以改成任意不冲突的私有网段,例如:
- 172.31.0.1/16
- 192.168.250.1/24
- 10.200.0.1/16
2️⃣ 重启 Docker 服务
sudo systemctl restart docker
⚠️ 注意:这会删除并重建默认的 bridge 网络,运行中的容器会断网,请提前停止。
3️⃣ 验证是否修改成功
docker network inspect bridge
确认 "Subnet" 已变为新的网段。
重新启动你的容器后,Java 服务即可成功连接 Redis 🎉
🧱 方案二:创建自定义网络(不影响其他容器)
如果不想改全局配置,可以只为项目新建网络:
docker network create --subnet=172.31.0.0/16 mynet
运行容器时指定:
docker run --network=mynet ...
或在 docker-compose.yml 中指定:
networks:
default:
ipam:
config:
- subnet: 172.31.0.0/16
这样,容器的内部网段就不会与阿里云冲突。
🧩 方案三:使用宿主机网络(临时方案)
如果只是临时测试,也可以直接使用宿主机网络:
docker run --network=host ...
容器直接复用宿主机网络栈,不再受 Docker 虚拟网段影响。
不过这种方式会暴露端口,不太适合生产环境。
🧠 五、排查与解决总结
| 现象 | 根因 | 解决方式 |
|---|---|---|
| ping 不通 | Docker 与目标网段冲突 | 修改 Docker 网段 |
| nc 超时 | 路由错误或安全组问题 | 检查路由或安全组 |
| 其他容器正常 | 当前容器网络错误 | 使用自定义网络 |
| 所有容器都不通 | Docker 默认 bridge 冲突 | 改 /etc/docker/daemon.json |
💬 六、结语
这次问题的关键在于:
Docker 默认的
172.18.0.0/16网段,与阿里云 Redis 内网网段冲突,导致容器内流量无法正确路由。
改一下 Docker 的默认网段,就能立刻恢复正常。
🧾 总结一句话:
遇到 “No route to host” 错误时,别急着查防火墙,先看 Docker 的网段冲不冲突!
