前言
容器跑起来了,但是网络不通——ping不通外网、容器间互相访问不了、端口映射不生效…
这类问题排查比较麻烦,涉及容器网络、宿主机网络、iptables规则等多个层面。这篇整理一套系统的排查流程,覆盖常见的网络问题场景。
一、容器访问不了外网
症状:
dockerexec-it myappping8.8.8.8# 卡住或者 Network is unreachable第一反应:检查宿主机的IP转发有没有开。
cat/proc/sys/net/ipv4/ip_forward如果是0,容器的包出不去。开一下:
echo1>/proc/sys/net/ipv4/ip_forward# 永久生效要写到sysctl.conf还是不通?看下iptables的NAT规则:
iptables -t nat -L -n|grepMASQUERADE应该有条类似这样的规则:
MASQUERADE all -- 172.17.0.0/16 0.0.0.0/0没有的话Docker的NAT可能被清掉了,重启Docker一般能恢复:
systemctl restartdocker还有一个大坑:firewalld。CentOS默认开着,它和Docker的iptables规则会打架。
# 先关了试试systemctl stop firewalld如果关了就好了,说明是防火墙的问题。正式解决要配置firewalld的docker zone,或者干脆用iptables。
二、容器间网络不通
在同一台机器上,两个容器互相访问不了。
先确认它们在不在同一个网络:
dockerinspect 容器A --format'{{.NetworkSettings.Networks}}'dockerinspect 容器B --format'{{.NetworkSettings.Networks}}'如果都在默认的bridge网络,有个坑:默认bridge不支持通过容器名访问。
dockerexec容器Aping容器B# ping: 容器B: Name or service not known只能用IP:
# 先拿到IPdockerinspect 容器B --format'{{.NetworkSettings.IPAddress}}'# 172.17.0.3dockerexec容器Aping172.17.0.3# 这样就通了嫌麻烦的话,用自定义网络:
dockernetwork create mynetdockernetwork connect mynet 容器Adockernetwork connect mynet 容器B# 现在可以用名字了dockerexec容器Aping容器B自定义网络有内置DNS,会自动解析容器名。
三、端口映射不生效
dockerrun -p8080:80 nginxcurlhttp://localhost:8080# 不通先确认服务在容器里跑起来没:
dockerexec容器curllocalhost:80如果容器里能访问说明服务没问题,那问题在外面。
检查点:
1、服务监听的地址对不对:
dockerexec容器netstat-tlnp如果显示127.0.0.1:80,那外面肯定访问不了,要改成0.0.0.0:80。
2、宿主机端口有没有被占:
netstat-tlnp|grep80803、防火墙/安全组:
# 本地防火墙firewall-cmd --list-ports# 云服务器别忘了安全组云服务器安全组没开端口是个常见的坑。
四、DNS解析失败
能ping通IP,但ping域名不行:
dockerexec容器ping8.8.8.8# 通dockerexec容器pingbaidu.com# 不通看下容器的DNS配置:
dockerexec容器cat/etc/resolv.conf如果DNS服务器不可达,最简单的办法是启动时指定:
dockerrun --dns8.8.8.8 nginx或者全局配置,改/etc/docker/daemon.json:
{"dns":["8.8.8.8","114.114.114.114"]}五、跨主机容器通信
这个稍微复杂点。两台机器上的容器默认是不通的,因为各自的bridge网络是隔离的。
最简单的方案:用端口映射,通过宿主机IP访问。
# 机器B上dockerrun -p8080:80 nginx# 机器A上访问curlhttp://机器B的IP:8080想让容器直接互通的话,要用overlay网络或者第三方方案(Flannel、Calico这些)。
还有个偏门办法:如果两台主机已经通过WireGuard或者其他组网工具连在一起了,可以配静态路由让容器网段互通。不过这个配置比较麻烦,一般不推荐。
六、一键诊断脚本
懒得一个个查,写了个脚本:
#!/bin/bash# 用法: ./check.sh 容器名C=$1echo"=== 检查$C==="echo-e"\n[网络模式]"dockerinspect$C--format'{{.HostConfig.NetworkMode}}'echo-e"\n[IP地址]"dockerinspect$C--format'{{.NetworkSettings.IPAddress}}'echo-e"\n[路由]"dockerexec$Ciproute2>/dev/null||echo"无ip命令"echo-e"\n[DNS]"dockerexec$Ccat/etc/resolv.conf2>/dev/nullecho-e"\n[外网连通性]"dockerexec$Cping-c1-W28.8.8.82>/dev/null&&echo"OK"||echo"不通"echo-e"\n[宿主机IP转发]"cat/proc/sys/net/ipv4/ip_forward跑一下基本能看出问题在哪。
总结
Docker网络问题90%出在这几个地方:
| 问题 | 原因 | 解决 |
|---|---|---|
| 容器出不了外网 | ip_forward没开 | echo 1 > /proc/sys/net/ipv4/ip_forward |
| 容器出不了外网 | 防火墙拦截 | 检查firewalld/iptables |
| 容器间不通 | 不在同一网络 | 使用自定义网络 |
| 端口映射失败 | 服务监听127.0.0.1 | 改成监听0.0.0.0 |
| DNS解析失败 | DNS服务器不可达 | 指定DNS服务器 |
排查顺序:网络配置→IP转发→防火墙规则→服务监听地址→DNS配置
有问题评论区交流。