Docker 容器网络通信原理:我用 3 个实战案例彻底搞懂了它
结论先行:Docker 容器网络的核心是 Linux 网络命名空间 + veth pair + 网桥,搞懂这三样,99% 的容器网络问题你都能自己解决。
1. 写在前面:为什么我要研究这个?
刚接触 Docker 那会儿,我遇到一个经典场景:docker run -p 8080:80 nginx 后,浏览器访问 localhost:8080 就能看到页面。当时觉得“好神奇”,但后来生产环境里容器间通信失败、跨主机网络不通,我才意识到——不懂原理,就是盲人摸象。
这篇文章是我从“能用”到“懂原理”的实战记录,每个命令我都亲手敲过,每个坑我都踩过。

2. 三个核心概念,一次讲透
2.1 网络命名空间(Network Namespace)
Docker 为每个容器创建独立的网络命名空间,相当于给容器一个“虚拟网络环境”。
验证一下:
# 查看本机所有网络命名空间
sudo lsns -t net
# 启动一个容器,查看它的网络命名空间
docker run -d --name test nginx
sudo lsns -t net | grep nginx

你会发现容器有自己的网络栈:自己的 lo、eth0,自己的路由表,自己的 iptables 规则。
注意:默认情况下,容器内的进程看不到宿主机的网络设备,反之亦然。
2.2 veth pair(虚拟以太网对)
veth pair 是一对虚拟网卡,像一根虚拟网线——一端在容器里,一端在宿主机上。
实战创建一对 veth:
# 创建一对 veth
sudo ip link add veth0 type veth peer name veth1
# 查看这对网卡
ip link | grep veth
你会看到两个网卡,它们像连在一起的管道:数据从 veth0 进,从 veth1 出。
Docker 就是靠这个把容器“插”到宿主机网络里的。
2.3 网桥(Bridge)
Docker 默认创建一个叫 docker0 的网桥,所有容器通过 veth pair 连到这个网桥上,实现相互通信。
查看 docker0 网桥:
ip addr show docker0
# 输出类似:inet 172.17.0.1/16
查看容器如何连接:
docker network inspect bridge
你会看到每个容器都分配了 172.17.0.x 的 IP,并且通过 veth 对连到 docker0。
3. 实战案例一:容器间通信
场景
启动两个容器,让它们互相 ping 通。
操作步骤
# 启动两个容器
docker run -d --name c1 nginx
docker run -d --name c2 nginx
# 查看它们的 IP
docker inspect c1 | grep IPAddress
docker inspect c2 | grep IPAddress
# 假设 c1=172.17.0.2, c2=172.17.0.3
# 从 c1 ping c2
docker exec c1 ping 172.17.0.3
能通! 原理就是:c1 的 veth 端在 docker0 上,c2 的也在,docker0 像交换机一样转发数据包。
踩坑记录
我一开始以为 docker exec c1 ping c2(用容器名)也能通,结果报错 ping: c2: Name or service not known。默认 bridge 网络不支持 DNS 解析容器名,需要自定义网络才行。
4. 实战案例二:宿主机与容器通信
场景
从宿主机访问容器的服务。
操作步骤
# 启动一个暴露端口的容器
docker run -d --name web -p 8080:80 nginx
# 宿主机访问
curl localhost:8080
能通! 原理是 iptables 的 DNAT 规则把宿主机 8080 端口的流量转发到容器 80 端口。
查看规则:
sudo iptables -t nat -L -n | grep 8080
# 输出:DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:8080 to:172.17.0.2:80
踩坑记录
有次我改了宿主机防火墙规则,iptables -F 清空了所有规则,结果容器端口映射失效了。Docker 的端口映射依赖 iptables,别乱清!
5. 实战案例三:跨主机容器通信(Overlay 网络)
场景
两台宿主机上的容器需要通信,但物理网络不通。
操作步骤
# 在每台宿主机上初始化 Swarm
docker swarm init
# 创建 overlay 网络
docker network create -d overlay my-overlay
# 在任意节点启动服务
docker service create --name app --network my-overlay nginx
原理:Overlay 网络使用 VXLAN 技术,在宿主机之间建立隧道,把容器数据包封装在 UDP 里传输。
查看隧道:
# 在宿主机上查看 VXLAN 接口
ip link | grep vxlan
踩坑记录
跨主机通信需要 所有宿主机之间 4789 端口(VXLAN 默认端口)互通。我第一次配置时忘了开防火墙端口,折腾了两小时才发现。
6. 网络排查三板斧
当容器网络出问题时,我按这个顺序查:
1. 检查网络命名空间
# 进入容器的网络命名空间
docker run -it --rm --net=container:<容器ID> nicolaka/netshoot
# 然后执行 ip addr, route, iptables-save 等命令
2. 检查网桥和 veth
# 查看网桥上的设备
sudo brctl show docker0
# 查看所有 veth 对
ip link | grep veth
3. 抓包分析
# 在宿主机上抓容器 eth0 的包
tcpdump -i docker0 host 172.17.0.2
注意:
netshoot镜像是我最常用的网络调试工具包,内置了 curl、ping、tcpdump、nslookup 等。
7. 核心总结
- 容器网络本质:网络命名空间隔离 + veth pair 连接 + 网桥/bridge 转发
- 端口映射:依赖 iptables DNAT,别乱清规则
- 跨主机通信:需要 Overlay 网络,确保 VXLAN 端口(4789)互通
- 排查工具:netshoot 镜像 + brctl + tcpdump 三板斧
最后一句经验:别怕看底层网络命令,ip link、ip netns、iptables 这些命令你用得越熟,Docker 网络对你来说就越透明。
8. 延伸思考
- 如果你需要更精细的网络隔离,可以试试 Macvlan 网络模式,让容器直接使用宿主机物理网卡的 IP
- 生产环境建议使用 Calico 或 Cilium 这类 CNI 插件,它们支持更高级的网络策略和加密
- 下次遇到“容器无法访问外网”的问题,先检查宿主机的
ip_forward是否开启:sysctl net.ipv4.ip_forward

评论已关闭!