Docker 网络进阶:overlay/macvlan 网络模式与自定义网络实战
深入讲解 Docker 网络的进阶模式:overlay 网络实现跨主机容器通信(Swarm 场景)、macvlan 让容器拥有真实 MAC 地址和物理网段 IP、ipvlan 模式对比、自定义 bridge 网络的子网/网关/IP 固定分配,以及容器网络诊断工具(ip/netstat/tcpdump/ss)在排障中的实战使用。
掌握了 bridge/host/none 三种基础网络模式后,本文进入进阶网络:overlay 用于跨主机容器通信,macvlan 让容器直接接入物理网络,自定义 bridge 提供精细化的网段管理。这些是企业生产环境中不可避免的场景。
网络模式全景
Docker 网络驱动(Driver):
bridge → 同一宿主机内的容器通信(默认,最常用)
host → 容器直接使用宿主机网络
none → 无网络
overlay → 跨主机容器通信(Swarm/多主机场景)
macvlan → 容器直接分配物理网段 IP,有真实 MAC 地址
ipvlan → 类似 macvlan,但共享宿主机 MAC(适合交换机有 MAC 限制时)
一、自定义 Bridge 网络进阶配置
固定 IP 分配
# 创建指定子网的自定义网络
docker network create \
--driver bridge \
--subnet 172.20.0.0/24 \
--gateway 172.20.0.1 \
--ip-range 172.20.0.128/25 \ # 可分配 IP 范围(128-254)
--opt "com.docker.network.bridge.name=br-myapp" \ # 宿主机网桥名
myapp-net
# 给容器指定固定 IP
docker run -d \
--network myapp-net \
--ip 172.20.0.10 \
--name mysql \
mysql:8.0
docker run -d \
--network myapp-net \
--ip 172.20.0.11 \
--name redis \
redis:7.2
docker run -d \
--network myapp-net \
--ip 172.20.0.20 \
--name api \
myapp:v1
自定义 bridge 的额外选项
# 选项列表
docker network create \
--driver bridge \
--subnet 10.0.1.0/24 \
--opt "com.docker.network.bridge.enable_ip_masquerade=true" \ # NAT(默认 true)
--opt "com.docker.network.bridge.enable_icc=true" \ # 容器间通信(默认 true)
--opt "com.docker.network.bridge.host_binding_ipv4=0.0.0.0" \ # 宿主机绑定 IP
--opt "com.docker.network.mtu=1450" \ # MTU(overlay 需要调小)
internal-net # 不联网的隔离网络
# 创建完全隔离(无互联网访问)的内部网络
docker network create \
--driver bridge \
--internal \ # 禁止访问外部网络
--subnet 10.99.0.0/24 \
air-gapped-net
docker run -d --network air-gapped-net myapp
# 容器内 curl google.com → 失败(无法访问外网)
# 容器间仍然可以通信
一个容器连接多个网络
# 场景:API 服务需要同时访问 frontend 和 backend 网络
docker network create frontend-net --subnet 172.21.0.0/24
docker network create backend-net --subnet 172.22.0.0/24
# 启动时只连接一个网络
docker run -d --name api --network frontend-net myapp:v1
# 事后连接第二个网络
docker network connect backend-net api
# 现在 api 有两个网卡,可以同时访问两个网段
docker inspect api --format '{{json .NetworkSettings.Networks}}' | jq 'keys'
# ["backend-net", "frontend-net"]
# 断开某个网络
docker network disconnect backend-net api
二、Overlay 网络 — 跨主机容器通信
Overlay 网络基于 VXLAN,将多台物理主机的容器网络“叠加”成一个逻辑网络。
前置条件
# Overlay 需要 Docker Swarm 模式(overlay 是 Swarm 的基础网络)
# 或者使用 --attachable 参数允许非 Swarm 容器加入
# Swarm 所需端口(需要开放):
# 2377/tcp → Swarm 管理通信
# 7946/tcp → 节点间通信
# 7946/udp → 节点间通信
# 4789/udp → VXLAN overlay 流量
# 初始化 Swarm(在管理节点)
docker swarm init --advertise-addr <管理节点IP>
# 输出 join token
# 其他节点加入 Swarm
docker swarm join --token <token> <管理节点IP>:2377
创建和使用 Overlay 网络
# 创建 overlay 网络
docker network create \
--driver overlay \
--subnet 10.10.0.0/24 \
--attachable \ # 允许普通容器(非 Service)加入
overlay-net
# 在不同主机上运行容器,同在 overlay 网络中
# 主机1
docker run -d --name service-a --network overlay-net myapp-a:v1
# 主机2(不同物理机!)
docker run -d --name service-b --network overlay-net myapp-b:v1
# service-b 可以直接访问 service-a:
docker exec service-b curl http://service-a:8080
# VXLAN 封装流量,穿越物理网络,就像在同一个局域网
Overlay 的工作原理
VXLAN 封装过程:
主机1(192.168.1.10) 主机2(192.168.1.20)
┌────────────────┐ ┌────────────────┐
│ service-a │ │ service-b │
│ 10.10.0.2 │ │ 10.10.0.3 │
└───────┬────────┘ └────────┬───────┘
│ 容器层流量 │
┌─────┴──────┐ ┌──────┴─────┐
│ overlay net│ │ overlay net│
│ (VTEP) │ │ (VTEP) │
└─────┬──────┘ └──────┬─────┘
│ UDP 4789 封装 │
┌─────┴──────┐ 物理网络传输 ┌──────┴─────┐
│ eth0 │ ──────────────────────→ │ eth0 │
│192.168.1.10│ │192.168.1.20│
└────────────┘ └────────────┘
service-a 发包到 service-b(10.10.0.3):
→ VTEP 查 FDB 表,知道 10.10.0.3 在 192.168.1.20
→ 用 UDP 封装(VXLAN ID + 原始帧)
→ 发送到 192.168.1.20:4789
→ 对方 VTEP 解封装,交给 service-b
三、Macvlan 网络 — 容器直连物理网络
Macvlan 让每个容器有独立的 MAC 地址,直接获取物理网段的 IP,就像一台真实的机器。
适用场景
✅ 容器需要被当作普通主机对待(有物理网段 IP,可被外部直接访问)
✅ 需要处理非 TCP/UDP 流量(VRRP、PIM 等协议)
✅ 现有基础设施按 IP 分配访问控制(防火墙按 IP 规则)
✅ 监控系统需要容器直接响应特定 IP
❌ 不适合大量容器(每个容器占用一个物理 IP)
❌ 宿主机与容器不能直接通信(需要 macvlan bridge 变通)
创建 Macvlan 网络
# 先确认宿主机的物理网卡名称
ip addr show
# eth0: inet 192.168.1.100/24
# 在交换机/路由器上开启混杂模式(如果需要)
ip link set eth0 promisc on
# 创建 macvlan 网络
docker network create \
--driver macvlan \
--subnet 192.168.1.0/24 \ # 与物理网络相同子网!
--gateway 192.168.1.1 \ # 物理网关
--ip-range 192.168.1.200/29 \ # 容器 IP 范围(200-207,避免与其他设备冲突)
--opt parent=eth0 \ # 绑定的物理网卡
macvlan-net
# 启动容器,直接拥有物理 IP
docker run -d \
--network macvlan-net \
--ip 192.168.1.200 \ # 物理网段的真实 IP
--name container-a \
nginx
# 从物理网络的其他机器访问
curl http://192.168.1.200 # 直接访问!不需要端口映射
Macvlan VLAN 模式(802.1q)
# 创建 VLAN 子接口
ip link add link eth0 name eth0.100 type vlan id 100
# 在 VLAN 100 上创建 macvlan 网络
docker network create \
--driver macvlan \
--subnet 10.100.0.0/24 \
--gateway 10.100.0.1 \
--opt parent=eth0.100 \ # 绑定 VLAN 子接口
macvlan-vlan100
# 不同 VLAN 的容器完全隔离
宿主机与 Macvlan 容器通信(变通方案)
# Macvlan 的限制:宿主机和容器之间不能直接通信
# 变通:创建一个 macvlan 接口在宿主机上
# 创建 macvlan bridge(特殊模式)
docker network create \
--driver macvlan \
--subnet 192.168.1.0/24 \
--gateway 192.168.1.1 \
--ip-range 192.168.1.200/29 \
--opt parent=eth0 \
--opt macvlan_mode=bridge \ # bridge 模式(默认就是 bridge)
macvlan-net
# 在宿主机上添加 macvlan 接口
ip link add macvlan-shim link eth0 type macvlan mode bridge
ip addr add 192.168.1.250/32 dev macvlan-shim # 宿主机侧 IP
ip link set macvlan-shim up
ip route add 192.168.1.200/29 dev macvlan-shim # 路由到容器 IP 段
# 现在宿主机可以 ping 容器了
ping 192.168.1.200
四、IPvlan 网络
# IPvlan 与 macvlan 区别:所有容器共享宿主机 MAC,只有 IP 不同
# 适合:交换机对每个端口的 MAC 数量有限制时
docker network create \
--driver ipvlan \
--subnet 192.168.1.0/24 \
--gateway 192.168.1.1 \
--ip-range 192.168.1.210/29 \
--opt parent=eth0 \
--opt ipvlan_mode=l2 \ # l2(二层,默认)或 l3(三层路由)
ipvlan-net
docker run -d \
--network ipvlan-net \
--ip 192.168.1.210 \
nginx
五、网络排障工具
容器内诊断
# 进入容器后的网络诊断
docker exec -it myapp bash
# 查看容器网络接口
ip addr show
ip route show
# 测试连通性
ping -c 3 mysql # ping 其他服务(通过容器名)
ping -c 3 8.8.8.8 # 测试外网访问
traceroute mysql # 路由追踪
# 测试端口连通性
nc -zv mysql 3306 # netcat 测试 TCP 端口
curl -v http://api:8080/health
# DNS 解析
nslookup mysql # 解析容器名
cat /etc/resolv.conf # 查看 DNS 配置
# 查看监听端口
ss -tlnp # 容器内监听的端口
netstat -tlnp
宿主机诊断
# 查看 Docker 网络
docker network ls
docker network inspect bridge | jq '.[0].Containers'
# 查看容器 IP
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' myapp
# 从宿主机抓包(分析容器网络流量)
# 找到容器对应的 veth 接口
CONTAINER_ID=$(docker inspect -f '{{.Id}}' myapp)
# 找 veth pair
ip link | grep -A1 "${CONTAINER_ID:0:12}"
# 抓包
tcpdump -i veth3a4b5c6 -n -w /tmp/container.pcap
# 用 Wireshark 分析 pcap 文件
# 抓 docker0 网桥的所有流量
tcpdump -i docker0 -n host 172.17.0.2
# 检查 iptables(NAT 和过滤规则)
sudo iptables -t nat -L DOCKER -n -v # Docker NAT 规则
sudo iptables -L DOCKER-USER -n -v # 用户自定义规则
# 检查容器间通信是否被 iptables 阻断
sudo iptables -L DOCKER-ISOLATION-STAGE-1 -n -v
网络性能测试
# 测试容器间网络带宽(iperf3)
# 服务端(另一个容器内)
docker run -d --name iperf-server --network mynet networkstatic/iperf3 -s
# 客户端
docker run --rm --network mynet networkstatic/iperf3 \
-c iperf-server -t 10
# 典型结果:
# bridge 网络内:约 10-40 Gbps(取决于宿主机)
# overlay 网络:约 1-5 Gbps(VXLAN 封装开销)
# macvlan:约等于物理网卡速度
# host 网络:物理网卡速度(无软件开销)
网络模式选型指南
场景 推荐网络模式 理由
──────────────────────────────────────────────────────────────
单机多服务(开发/小规模生产) 自定义 bridge DNS解析+隔离,最简单
多机容器互通(Swarm集群) overlay VXLAN跨主机
容器需要物理IP(NAT穿透/监控) macvlan 直接使用物理网段
交换机MAC数量受限 ipvlan 共享宿主机MAC
高性能网络(监控组件) host 零开销
CI任务(无需网络) none 隔离安全
小结
Docker 网络的核心理解:网络模式决定容器如何与外界通信。
自定义 bridge 够用 90% 的场景(DNS + 隔离);overlay 是 Swarm 集群的网络基础,本质是 VXLAN 跨主机封装;macvlan 让容器真正“融入”物理网络,适合需要物理 IP 的特殊场景。
排障时先 docker network inspect 看网络配置,再进容器用 ip/ping/nc 测试,宿主机用 tcpdump 抓包确认流量路径。
