容器一上生产,网络问题最多:容器互 ping 不通、容器出不了网、外部就是访问不到映射端口。很多人上来就
docker restart,碰运气。这篇给你一套五步排查法,从现象归类到根因,一步步收敛。
一、先分清是哪一类不通
"网络不通"其实是三种完全不同的问题,先归类再动手:
- 容器之间不通:A 容器 ping/访问不到 B 容器;
- 容器出网不通:容器访问不了外网或内网其他服务(apt/yum、连数据库超时);
- 外部访问不通 :宿主机或其他机器访问
-p映射的端口不通。
分类测试命令:
bash
# 容器之间:进 A 容器测 B 容器 IP
docker exec -it a1 sh
ping -c 2 172.18.0.3
curl -m 3 http://172.18.0.3:8080
# 容器出网:进容器测外网与内网目标
docker exec -it a1 sh
ping -c 2 223.5.5.5 # 通 = 路由和转发正常
ping -c 2 www.baidu.com # 不通而 IP 通 = DNS 问题
# 外部访问:宿主机上测映射端口
curl -m 3 http://127.0.0.1:8080
注意:很多业务镜像没有 ping/curl,先
apt-get install -y iputils-ping curl或换用wget -T 3 -O-。Alpine 镜像自带wget。
二、第二步:看网段,两个容器是不是一伙的
容器间不通,第一反应是它们根本不在同一个网络 。docker run 不指定网络时进默认 bridge(docker0),docker compose 会自动建独立网络,很容易出现"一个在 bridge、一个在 app_default"的情况。
bash
# 看所有网络与各自挂在哪个网段
docker network ls
docker network inspect bridge | grep -A 20 Containers
docker network inspect app_default | grep -A 20 Containers
# 看某容器的 IP 与所属网络
docker inspect -f '{{range $k,$v := .NetworkSettings.Networks}}{{$k}}: {{$v.IPAddress}} {{end}}' a1
如果确认需要互通但不同网:docker network connect app_default a1 把容器加进目标网络即可,不用重建。
另外查网段冲突:公司内网常用 172.16~172.31 或 192.168 网段,与 Docker 默认网段撞车后,容器访问"内网服务"的包被路由进 docker0,表现就是"出了容器就通,进了容器反而连不上内网"。
bash
ip addr show docker0
# 解决:/etc/docker/daemon.json 固定网段,改完重启 docker
# { "bip": "172.29.0.1/16", "default-address-pools": [{"base": "172.30.0.0/16", "size": 24}] }
三、第三步:验 DNS,服务名解析对不对
容器之间按服务名/容器名互访失败、按 IP 却通,是 DNS 问题。这里有个高频坑:
- 自定义网络 (
docker network create或 compose)才有内嵌 DNS(127.0.0.11),支持按容器名/服务名解析; - 默认 bridge 没有服务名解析,只能用容器 IP(老的
--link已废弃,别用); - 容器里的
/etc/resolv.conf被启动参数--dns、--network host、compose 的dns:覆盖后,可能指向了不通的 DNS。
bash
# 进容器看生效的 DNS 配置
cat /etc/resolv.conf
# 验证内嵌 DNS 是否解析服务名
getent hosts b1
# 或
nslookup b1 127.0.0.11
出网域名不通但 IP 通,多半是容器 DNS 指向的上游不通(比如继承宿主的 127.0.0.53 却没通到 systemd-resolved 的路径)。临时可用 --dns 223.5.5.5 启动验证。
四、第四步:查转发与 NAT,出网和端口映射的命门
容器出网依赖宿主的 IP 转发 + MASQUERADE 伪装;外部访问 -p 端口依赖 DNAT。这三处被破坏,表现就是"容器活着但就是不通"。
bash
# 1. 内核转发开关(手动 sysctl -w 或某些安全基线会关掉)
sysctl net.ipv4.ip_forward # 必须为 1
# 2. NAT 规则还在不在
iptables -t nat -nL POSTROUTING # 应看到 MASQUERADE
iptables -t nat -nL DOCKER # 应看到 -p 映射的 DNAT
# 3. DOCKER-USER 链(安全加固常在这里加 DROP)
iptables -nL DOCKER-USER
典型翻车现场:
- firewalld/ufw reload 或重启 后把 Docker 的规则冲掉(Docker 直接操作 iptables,和 firewalld 不太兼容)→
systemctl restart docker让它重建规则,立刻恢复; - 某些安全基线脚本批量清了 FORWARD 链策略 →
iptables -P FORWARD ACCEPT; - FORWARD 链默认 DROP 且没有放行 docker0 相关规则。
五、第五步:通外口,端口映射与安全组收尾
前三步都通了、外部还是访问不到,就查映射这一层:
bash
# 映射到底生效没有
docker port a1
docker ps --format '{{.Names}}\t{{.Ports}}'
# 容器内服务有没有真的监听
docker exec a1 ss -ntlp # 监听 0.0.0.0:8080 才行,127.0.0.1:8080 外面永远连不进
# 分层 curl:先容器内 → 再宿主 → 再远程机器
docker exec a1 curl -m 3 http://127.0.0.1:8080
curl -m 3 http://127.0.0.1:8080
curl -m 3 http://<宿主内网IP>:8080
三个经典坑:
- 应用监听
127.0.0.1:映射了也进不来,改成0.0.0.0; -p 127.0.0.1:8080:80:只绑了宿主回环,别的机器访问不到,这是刻意写法还是手误要确认;- 云机器:宿主层全通,还差安全组/防火墙 放行端口------
iptables -nL INPUT与云控制台各查一遍。
避坑清单
- 跨容器互访用自定义网络 ,别用默认 bridge(无服务名解析),也别再用
--link; - 网段冲突早规划 :daemon.json 固定
bip和default-address-pools,别和公司内网撞车; - 防火墙服务重启后重启 docker :firewalld reload 会冲掉 Docker 的 NAT 规则,
systemctl restart docker是标准动作; - 别关 ip_forward:安全基线加固时误关,容器全部断网,这是隐形炸弹;
- 应用必须监听 0.0.0.0,容器里监听 127.0.0.1 等于自我封闭;
- healthcheck 别依赖外部地址 :容器内探活用
127.0.0.1:端口,外网抖动会误杀健康容器; - 排查顺序自内向外:容器内 → 容器间 → 宿主 → 外部,每层一次 curl,别跳层。
一图总结
css
容器网络不通?
├─ 第一步 分性质:容器间不通 / 出网不通 / 外部访问不通
├─ 第二步 看网段:network inspect 同网络?网段冲突?
├─ 第三步 验 DNS:自定义网络才有服务名解析,127.0.0.11
├─ 第四步 查转发:ip_forward / MASQUERADE / DOCKER-USER
└─ 第五步 通外口:-p 映射、监听 0.0.0.0、安全组
小结:Docker 网络问题九成出在"不同网络、DNS 指错、转发/NAT 被清、监听回环"这四件事上。记住五步:分性质 → 看网段 → 验 DNS → 查转发 → 通外口,每步一条命令就能把范围砍掉一半。