Docker跨主机通信秘籍:macvlan实战全解析
前面我们学习了 Docker 五种基础网络模式:bridge、host、none、container、自定义网络。基础 bridge 网络只能实现单机容器互通,在实际生产中,我们还需要掌握:容器访问外网、外网访问容器、多台主机上的容器跨主机通信。
说明:RHEL7 使用 iptables 做 NAT;RHEL8/9 使用 nftables,Docker 会自动维护对应的地址伪装、DNAT 转发规则。
1.1 Docker 容器内外网的访问
1.1.1 容器访问外网

默认 bridge 模式下,容器想要访问互联网,依靠 SNAT 地址伪装(MASQUERADE) 实现。 通信流程:
- 容器发出外网请求,数据包发送到
docker0网桥 - 主机内核做 SNAT 转换:把容器内网 IP(172.17.0.x)替换成宿主机网卡公网 IP,前提:宿主机开启内核 IP 转发
- 转换后的数据包从宿主机物理网卡 eth0 发往外网
- 外网回包,主机根据 NAT 记录转发回容器
查看 nat 表 POSTROUTING 链的伪装规则:
[root@docker ~]# iptables -t nat -nL
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
MASQUERADE 6 -- 172.17.0.2 172.17.0.2 tcp dpt:80 #内网访问外网策略
Chain DOCKER (0 references)
target prot opt source destination
DNAT 6 -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 to:172.17.0.2:80
实验验证
1.启动 busybox 容器测试外网连通性:
[root@docker-node1 ~]# docker run -it --name busybox rickiechina/busyboxplus:latest
[ root@e99ce1949814:/ ]$ ping www.baidu.com
PING www.baidu.com (103.235.46.115): 56 data bytes
64 bytes from 103.235.46.115: seq=0 ttl=127 time=1.758 ms
64 bytes from 103.235.46.115: seq=1 ttl=127 time=1.625 ms
^C
--- www.baidu.com ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 1.625/1.691/1.758 ms
2.删除 MASQUERADE 伪装规则后,容器无法访问外网:
[root@docker-node1 ~]# iptables -t nat -D POSTROUTING 1
# 回到容器再次ping外网,不通
[root@docker-node1 ~]# docker attach busybox
[ root@e99ce1949814:/ ]$ ping www.baidu.com
小结:容器访问外网核心就是 SNAT/MASQUERADE 地址伪装,由 Docker 启动时自动添加。
1.1.2 外网访问容器
外网不能直接路由到容器内网 IP,需要使用 端口映射 -p 宿主机端口:容器端口,依靠 DNAT 目标地址转换。
通信流程:
- 外网用户访问宿主机公网 IP + 端口,数据包到达宿主机 eth0
- 内核 DNAT 转换:数据包目标 IP 由宿主机 IP 修改为容器内网 IP
- 数据包转发到 docker0 网桥,最终交付容器
- 容器回包再经过 SNAT 返回外网
端口映射同时会启动 docker-proxy 进程和 iptables DNAT 规则,二者共存,系统自动选择转发通路。
# 启动nginx,映射宿主机80端口到容器80端口
[root@docker ~]# docker run -d --name webserver -p 80:80 nginx
# 查看docker-proxy进程
[root@docker ~]# ps ax
133986 ? Sl 0:00 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 80 -container-ip 172.17.0.2 -container-port 80
133995 ? Sl 0:00 /usr/bin/docker-proxy -proto tcp -host-ip :: -host-port 80 -container-ip 172.17.0.2 -container-port 80
134031 ? Sl 0:00 /usr/bin/containerd-shim-runc-v2 -namespace moby -id cae79497a01c0b8c488c7597b43de4a43f361f21a398ff423b4504c0905db143 -address /run/containerd/containerd.sock
134059 ? Ss 0:00 nginx: master process nginx -g daemon off;
134099 ? S 0:00 nginx: worker process
134100 ? S 0:00 nginx: worker process
查看自动生成的 DNAT 转发规则:
[root@docker ~]# iptables -t nat -nL
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
MASQUERADE 6 -- 172.17.0.2 172.17.0.2 tcp dpt:80
Chain DOCKER (0 references)
target prot opt source destination
DNAT 6 -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 to:172.17.0.2:80
注意:docker-proxy 和 DNAT 同时生效,优先走性能更好的转发路径。
2.1 Docker 容器间跨主机访问
默认 bridge 网络只局限单台宿主机。生产环境容器分布在多台服务器,需要跨主机容器通信。
跨主机网络主流方案
- Docker 原生方案:
overlay、macvlan - 第三方 CNI 方案:flannel、weave、calico
Docker 网络底层依赖 libnetwork 库,抽象标准模型 CNM(Container Network Model)。
2.1.1 CNM(Container Network Model)
CNM 定义了 Docker 容器网络的抽象模型,包含三大组件:
- Sandbox:容器独立网络栈,对应 Linux network namespace,保存容器网卡、路由表、DNS 配置
- Endpoint:端点,把 Sandbox 接入网络,底层一般是 veth pair
- Network:一组 Endpoint 的集合,同一个 Network 内的端点二层互通
2.1.2 macvlan 网络实现跨主机通信
macvlan 是 Linux 内核原生网卡虚拟化技术,不需要网桥、不需要 NAT、不需要端口映射,性能高,适合业务容器直接接入现有二层局域网。
原理:
- 在宿主机物理网卡上虚拟多个 mac 地址,每个 macvlan 容器拥有独立 MAC、独立 IP,和物理网络内其他设备同二层
- macvlan 独占父网卡;可以创建 vlan 子接口划分多个隔离 macvlan 网络(VLAN ID 1~4094)
- 不同 macvlan 网络二层隔离,如需互通,依靠三层网关转发
实操步骤(两台 Docker 主机 node1、node2)
1.两台主机都准备一张专用网卡(示例 eth1),开启网卡混杂模式
[root@docker-node1 ~]# ip link set eth1 promisc on
[root@docker-node1 ~]# ip link set up eth1
[root@docker-node1 ~]# ip a s eth1
11: eth1: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:0c:29:dd:45:a8 brd ff:ff:ff:ff:ff:ff
altname enp11s0
altname ens192
node2 主机执行完全一样的网卡配置
2.两台主机创建相同 macvlan 网络(网段、网关、父网卡保持一致)
[root@docker ~]# docker network create \
-d macvlan \
--subnet 1.1.1.0/24 \
--gateway 1.1.1.1 \
-o parent=eth1 macvlan1
查看网络列表:
[root@docker-node1 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
6040deaf7317 bridge bridge local
7fc981c8c297 host host local
83903417114a macvlan1 macvlan local
8cff8a861f8b my_net1 bridge local
1d42d28522d9 my_net2 bridge local
76f674c83d42 none null local
(1)分别在两台主机启动容器,指定 macvlan 网络与静态 IP
# node2启动容器
[root@docker-node2 ~]# docker run -it --name busybox --network macvlan1 --ip 1.1.1.100 --rm rickiechina/busyboxplus:latest
# node1启动容器
[root@docker-node1 ~]# docker run -it --name busybox --network macvlan1 --ip 1.1.1.101 --rm rickiechina/busyboxplus:latest
(2)跨主机连通测试
[ root@8157d7f54341:/ ]$ ping 1.1.1.101
PING 1.1.1.101 (1.1.1.101): 56 data bytes
64 bytes from 1.1.1.101: seq=0 ttl=64 time=0.104 ms
64 bytes from 1.1.1.101: seq=1 ttl=64 time=0.101 ms
^C
--- 1.1.1.101 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.101/0.102/1.104 ms
✅ 跨主机容器直接二层互通,无 NAT 损耗。
macvlan 适合对网络性能要求高、需要容器直接暴露在局域网的场景;缺点是依赖物理网卡、配置 VLAN 规划,集群大规模编排一般优先 Overlay(Swarm/Calico)。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)