Docker 网络不通的排查:bridge、端口映射与 DNS

一、现象与影响面:三种”不通”先对号入座

Docker 网络问题的症状可以归成三类:容器 A 访问不了容器 B;宿主机或外部用户访问不了映射出来的端口;容器里解析不了域名,装依赖、拉镜像全失败。三类症状背后是不同的层,混在一起乱查是浪费时间的第一原因。

反模式一:上来就 restart 容器、重建网络。重启会冲掉现场——容器 IP 重新分配、临时网络配置丢失、日志滚动,原本两分钟能看出的线索全部蒸发。Docker 网络问题几乎都有稳定的复现路径,先取证再动手。

先建立分层模型:容器内服务 → bridge 网桥 → 端口映射(DNAT)→ 宿主防火墙;容器出网和 DNS 各走其中几段。下面按 容器内 → bridge → 端口映射 → 宿主防火墙 → DNS 的顺序推进,每条命令都标注了在哪跑。一层正常就往下走,不必回头。

二、第一层:容器内,先分清”网络不通”还是”服务没起”

大量”网络问题”最后定位出来是目标服务没监听。所以第一站是让两个容器都开口说话:

# 宿主机上进容器;debian-slim 这类精简镜像没有 bash 就换 sh
docker exec -it web sh

1. ——以下命令都在 web 容器内——
ip addr            # 确认 eth0 拿到 IP 且网段符合预期;没有 ip 命令就看 cat /proc/net/fib_trie
ping -c2 8.8.8.8   # 先测裸 IP,把"网络不通"和"DNS 不通"分开
curl -v --max-time 3 http://172.18.0.5:8080/   # 直接测目标容器 IP,--max-time 防止卡死终端

1. 切到目标容器里看服务;精简镜像没有 ss 时装一个,或看 cat /proc/net/tcp
docker exec -it api ss -tlnp
1. LISTEN 0 511 0.0.0.0:8080 ...  ← 盯住监听地址与端口
现象组合 结论 下一站
ping IP 通、curl 域名不通 DNS 层问题 第六节
curl 目标 IP 直接 connection refused 目标服务没起或没监听 留在本层查目标容器,别去动网络
ping 目标 IP 也不通 链路问题 第三节 bridge
容器里连 ping/curl 都没有 镜像太精简 alpine 用 busybox 自带的 ping/wget/nslookup 顶上;或起一个 netshoot 之类调试容器加入同一网络排查

反模式二:拿”宿主机 curl 映射端口”当第一测试。它一次穿过多层,失败时说不清是哪层的问题。先在离问题最近的点测起,逐层往外推。

这层确认了服务活着、IP 拿对了,继续往下走。

三、第二层:bridge,容器到容器通不通

容器到容器的流量发生在网桥上。在宿主机上核对两件事:两个容器是否真在同一个网络、网桥与伪装规则是否完好:

# 以下命令都在宿主机上
docker network ls

1. 两个容器必须同时出现在同一个网络的 Containers 列表里
docker network inspect app-net --format '{{range .Containers}}{{.Name}}  {{.IPv4Address}}{{"n"}}{{end}}'
1. api   172.18.0.5/16
1. web   172.18.0.3/16

ip addr show docker0                          # 默认网桥存在、网段正常
iptables -t nat -L POSTROUTING -n | grep -i masq   # 容器出网用的伪装规则在不在

这里藏着 Docker 网络问题的头号根因:默认 bridge 与自定义 bridge 不是一回事。docker run 不指定网络时容器落在默认 bridge,compose 项目则自建自定义网络——于是”手动 run 的容器”和”compose 起的容器”根本不在一个网络里,连对方的 IP 都见不到。

维度 默认 bridge 自定义网络
容器名互相解析 不支持,只能用 IP(遗留的 –link 方案已不推荐) 支持,内嵌 DNS 直接按容器名/compose 服务名解析
加入方式 docker run 不指定网络时的默认落点 compose 自动创建,或 docker network create 后 –network 加入
定位方式 .HostConfig.NetworkMode 显示 bridge 显示具体网络名(如 app-net)
适用场景 一次性试验 任何正式部署

同一网络里、IP 互 ping 还不通,多半是宿主防火墙动过转发规则——典型场景是 firewalld 一旦 reload,Docker 写入 iptables 的规则会被清掉,容器互访立刻全断,重启 docker 服务即可恢复(此行为随版本演进,以官方文档为准)。这类问题归下一层管。

这层两个容器同网同列表、互 ping 通,就往下走。

四、第三层:端口映射,宿主机与外部访问不通

# 以下命令都在宿主机上
docker ps --format '{{.Names}}  {{.Ports}}'
1. web   0.0.0.0:8080->80/tcp       ← 绑定地址、宿主端口、容器端口三段都在这
1. db    127.0.0.1:3306->3306/tcp   ← 绑在回环上,外部永远访问不了(这往往是故意的)

curl -v --max-time 3 http://127.0.0.1:8080/    # 宿主机本机先测一发
docker inspect web --format '{{json .NetworkSettings.Ports}}'

分诊很简单:宿主机本机 curl 通、外部不通,映射本身没问题,问题在防火墙层,进第五节;宿主机本机也不通,才是映射或监听的问题。本机不通的高频误会只有一个:

反模式三:容器内服务监听 127.0.0.1,还指望 -p 能救。端口映射把流量送到容器的 eth0 IP 上,不是容器里的回环。应用绑死容器内的 127.0.0.1 时,宿主机访问映射端口就是 connection refused。修法是应用监听 0.0.0.0;安全的收紧靠发布时的绑定地址(如 127.0.0.1:8080:80)或 DOCKER-USER 规则,而不是让应用绑回环。

另一类是网络模式错配:给 host 网络模式的容器配 -p 不会报错但完全无效——host 模式下容器直接用宿主机网络栈,端口由进程自己监听,docker ps 的 Ports 列是空的,一眼可辨。

这层本机通了、外部不通,往下查防火墙。

五、第四层:宿主防火墙,FORWARD 链与 conntrack

发布端口的流量走转发路径:nat 表 PREROUTING 里 Docker 写的 DNAT 规则把目标地址改成容器 IP,随后包过 FORWARD 链——Docker 在这里插了自己的 DOCKER 链做放行。你手工加的 FORWARD 规则、ufw 的默认拒绝、firewalld 的 zone,都可能和它纠缠:

# 以下命令都在宿主机上
iptables -L FORWARD -n | head -5      # 看默认策略,以及 DOCKER 链有没有被前置规则截胡
iptables -L DOCKER-USER -n            # Docker 官方留给用户加规则的位置

dmesg -T | grep -i nf_conntrack | tail
1. nf_conntrack: table full, dropping packet    ← 高并发下偶发不通的元凶
cat /proc/sys/net/netfilter/nf_conntrack_count /proc/sys/net/netfilter/nf_conntrack_max

坑一:ufw 规则对已发布端口不生效——两个方向都不生效。Docker 直接改写 iptables,发布端口绕过 ufw:你以为 ufw deny 挡住了,实际端口是通的;反过来在 ufw 里 allow,对容器流量也不起作用。想限制容器端口,把规则加进 DOCKER-USER 链,例如只放行办公网段: iptables -I DOCKER-USER -i eth0 ! -s 203.0.113.0/24 -j DROP,具体写法以 Docker 官方文档为准。

坑二:firewalld reload 清空 Docker 规则。现象是”动过防火墙之后批量不通”,重启 docker 服务恢复;治理办法是防火墙变更后把关键端口 curl 一遍。

坑三:conntrack 表满。内核给每条连接记一笔跟踪,小内存机器的表上限不高;表满后新连接直接被丢,症状是偶发的、毫无规律的不通。dmesg 出现 table full 字样时,先确认哪些流量不该被跟踪,再谈调大 nf_conntrack_max。

这层 FORWARD 放行正常、conntrack 没打满,症状又是”解析不了域名”,进最后一层。

六、第五层:DNS,容器名与外部域名是两套解析

# ——容器内——
cat /etc/resolv.conf
1. nameserver 127.0.0.11        ← Docker 内嵌 DNS 的标志,自定义网络标配
1. nameserver 192.168.x.x       ← 照抄宿主机,默认 bridge 的行为
nslookup api                    # 容器名能解析吗(自定义网络应该能)
nslookup www.example.com        # 外部域名能解析吗

1. ——宿主机——
docker inspect web --format '{{.HostConfig.NetworkMode}}  Dns={{.HostConfig.Dns}}'

解析分两套:自定义网络里,Docker 内嵌 DNS(127.0.0.11)负责容器名与 compose 服务名;外部域名则转发给 resolv.conf 里的上级 DNS,而这份 resolv.conf 默认继承自宿主机。所以”容器名解析失败”查网络模式(默认 bridge 没有名字解析,回第三节改网络),”外部域名解析失败”查宿主机 DNS 是否正常、daemon.json 里的 dns 是否指对了地方。

七、根因清单:按出现频率排序

根因 典型症状 一行验证
容器内应用只监听 127.0.0.1 映射端口 connection refused 目标容器内 ss -tlnp 看绑定地址
容器不在同一自定义网络 互 ping 不通、互相见不到 IP docker network inspect 对照 Containers 列表
在默认 bridge 里用容器名互访 IP 通、名字解析失败 看 .HostConfig.NetworkMode
-p 绑定了 127.0.0.1 宿主机本机通、外部不通 docker ps 的 Ports 列
防火墙动过 FORWARD/DOCKER 链 动防火墙后批量不通 iptables -L FORWARD -n,重启 docker 对照
conntrack 表满 高并发下偶发丢连接 dmesg 找 table full,对照 count 与 max
host 模式配 -p 映射列表为空、端口不通 docker ps 的 Ports 列
DNS 上游配错 域名不通、IP 通 容器内 nslookup,对比 resolv.conf

八、预防

措施 做什么 边界
全员进自定义网络 一律用 compose 管理(默认自建网络);手动 run 的容器显式 --network 加入 默认 bridge 只留给一次性试验
监听与发布分离 应用监听 0.0.0.0,收紧靠绑定地址或 DOCKER-USER 绑定 127.0.0.1 的端口除本机反代外谁都够不着,想清楚再绑
防火墙变更后自检 动过 firewalld/ufw 后 curl 一遍关键映射端口;不通先重启 docker 重启 docker 有秒级中断,挑低峰做
预置排障工具 常备一个网络调试工具箱镜像,加入同网络或 --network container:xxx 借网络栈 第三方镜像以官方仓库说明为准

这套走法收拢成一句:先在最近的点测试(容器内),再逐层往外推(网桥 → 映射 → 防火墙),症状像 DNS 的最后看解析——跳层测试是 Docker 网络排障最大的时间黑洞。

延展阅读:把容器网络放回更大的部署图景里看,见《多节点集群架构规划》;本文用到的命令的日常版本,见《Linux 常用命令》;搭环境阶段就撞上的网络坑,见《开发环境》。

版本核实(以官方文档为准):内嵌 DNS(127.0.0.11)与自定义网络的容器名解析自 Docker 1.10 起提供;DOCKER-USER 链自 Docker 17.06 起官方提供;默认 bridge 不做容器名解析、host 模式忽略 -p、Docker 直接管理 iptables 并绕过 ufw,均为长期稳定行为。firewalld reload 清除 Docker 规则的表现随版本演进,以 Docker 与 firewalld 官方文档为准。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇