15.11.6 容器网络故障排查

本节聚焦 Docker 容器网络问题的快速定位与恢复,覆盖链路可达性、DNS、端口映射与跨主机通信。排查遵循“宿主机网络 → Docker 网络 → 容器内网络 → 应用端口”的分层验证思路,并提供可执行示例、安装与排错练习。

容器网络原理草图(NAT 与端口映射):

文章图片

常见现象与初步判断(示例与命令):
- 容器无法访问外网
- 先验证宿主机出网:
bash ping -c 3 8.8.8.8 curl -I https://www.baidu.com
- 宿主机无法访问容器
- 核对端口映射与监听地址:
bash docker ps --format "table {{.Names}}\t{{.Ports}}" docker exec -it web sh -c "ss -lntp | grep :80"
- 容器之间互通失败
- 确认同网络与网段:
bash docker network ls docker network inspect app_net
- DNS 解析异常
- 检查容器 resolv.conf:
bash docker exec -it web cat /etc/resolv.conf
- 跨主机通信异常(overlay)
- 检查 UDP 4789 端口与节点互通:
bash nc -uzv 10.0.0.12 4789

安装与工具准备(推荐最小集):

# 宿主机抓包工具
sudo yum install -y tcpdump
# 容器内网络工具(netshoot 镜像)
docker pull nicolaka/netshoot:latest

分层排查流程(含示例与命令解释):

1) 宿主机网络验证

# 查看路由与DNS
ip route
cat /etc/resolv.conf
# 解释:确保默认路由指向网关,DNS 可解析

2) Docker 网络与网桥检查

# Docker 网络列表与网桥状态
docker network ls
ip addr show docker0
# 解释:docker0 应有网关地址,如 172.17.0.1/16

3) 容器内网络核对

# 进入容器确认IP、路由与连通性
docker exec -it web sh -c "ip a; ip r; ping -c 2 8.8.8.8"
# 解释:默认路由应指向网桥网关

4) 端口映射与服务监听

# 映射关系
docker port web
# 服务监听是否为 0.0.0.0
docker exec -it web sh -c "ss -lntp | grep :80"

5) iptables 与 NAT 规则

# NAT 与 DOCKER 相关链
sudo iptables -t nat -L -n --line-numbers | sed -n '1,120p'
sudo iptables -L DOCKER -n --line-numbers
# 解释:POSTROUTING 中应有 MASQUERADE,DOCKER 链含DNAT规则

6) Overlay 跨主机通信

# Swarm/overlay 网络检查
docker network inspect my_overlay
# 防火墙端口(UDP 4789 VXLAN, TCP/UDP 7946 节点发现)
sudo firewall-cmd --list-ports

典型故障与修复示例:

示例1:容器无法出网(NAT 规则丢失)

# 现象:容器 ping 外网失败,宿主机正常
docker exec -it web ping -c 2 8.8.8.8

# 修复:重启 Docker 或重建 NAT 规则
sudo systemctl restart docker

# 验证
docker exec -it web ping -c 2 8.8.8.8

示例2:端口映射失效(服务绑定 127.0.0.1)

# 宿主机访问失败
curl -I http://127.0.0.1:8080

# 容器内检查监听
docker exec -it web sh -c "ss -lntp | grep :80"
# 发现监听 127.0.0.1:80

# 修复:调整应用监听为 0.0.0.0(示例:nginx)
docker exec -it web sh -c "sed -i 's/127.0.0.1/0.0.0.0/' /etc/nginx/conf.d/default.conf && nginx -s reload"

示例3:网段冲突导致访问异常

# 查看物理网段与 Docker 网段
ip route | head -n 5
docker network inspect bridge | grep Subnet

# 解决:创建新网段并迁移容器
docker network create --subnet 172.30.0.0/16 app_net
docker run -d --name web --network app_net -p 8080:80 nginx:alpine

示例4:DNS 解析异常(宿主机 DNS 变更未同步)

# 查看容器 DNS
docker exec -it web cat /etc/resolv.conf

# 修复:重建容器或指定 DNS
docker run -d --name web --dns 114.114.114.114 -p 8080:80 nginx:alpine

示例5:跨主机 Overlay 不通(端口被阻断)

# 互通验证
nc -uzv 10.0.0.12 4789

# 放通端口(firewalld)
sudo firewall-cmd --add-port=4789/udp --permanent
sudo firewall-cmd --add-port=7946/tcp --permanent
sudo firewall-cmd --add-port=7946/udp --permanent
sudo firewall-cmd --reload

抓包定位示例(宿主机与容器同时验证):

# 宿主机抓包:观察到容器到外网的转发
sudo tcpdump -i docker0 -nn icmp

# 容器内发起 ping
docker exec -it web ping -c 2 8.8.8.8

命令说明速查表(常用):
- docker network inspect <net>:查看网段、网关、容器加入情况。
- ip route:检查默认路由是否正确。
- iptables -t nat -L:确认 NAT 规则是否存在。
- ss -lntp:查看端口监听与绑定地址。
- tcpdump -i docker0:确认容器流量是否到达网桥。

实战练习(建议按顺序完成):
1. 使用 nginx:alpine 启动容器并映射端口,验证访问成功。
2. 将容器服务改为仅绑定 127.0.0.1,观察宿主机访问失败并修复。
3. 手动创建自定义网段,迁移容器,验证容器间互通。
4. 删除 NAT 规则(在测试环境)并重启 Docker 修复。
5. 使用 netshoot 容器检查 DNS 解析与路由。

练习脚本(可直接执行):

# 1) 启动示例容器
docker run -d --name web -p 8080:80 nginx:alpine
curl -I http://127.0.0.1:8080

# 2) 使用 netshoot 进行网络排查
docker run --rm -it --network container:web nicolaka/netshoot:latest bash -c "ip a; ip r; nslookup www.baidu.com"

规避与最佳实践:
- 网段规划避免与物理网络冲突;生产环境优先自定义网络。
- 防火墙规则中保留 Docker 链与 MASQUERADE。
- 应用监听统一绑定 0.0.0.0,减少误判。
- DNS、路由变更后重启 Docker 或重建容器,确保配置生效。
- 使用 netshoottcpdump 进行流量确认,避免盲目重启。