Docker macvlan 容器与宿主机互通

Docker 容器使用 macvlan 后,可以像局域网里的独立设备一样拥有 IP。但宿主机默认无法通过自己的物理网卡直接访问这些容器。这是 Linux macvlan 的限制。解决方法是在宿主机上再创建一张 macvlan 虚拟网卡,让宿主机通过它访问容器。

本文的网络配置

用途 地址或名称
宿主机物理网卡 eno1
宿主机虚拟网卡 macvlan-host
虚拟网卡 IP 192.168.5.223
Docker 网络的 Subnet 192.168.5.0/24
分配给容器的 IPRange 192.168.5.192/28
qBittorrent 容器 IP 192.168.5.199

先检查自己的 Docker 网络,不能只看容器 IP。

1
docker network inspect <macvlan网络名>

本文的做法要求 Options.parent 是 eno1,Docker 网络的 Subnet 是 192.168.5.0/24,而 192.168.5.192/28 是专门分配给容器的地址段。Docker 网络的网关也应与实际局域网配置一致。

192.168.5.223 在 /24 内,但不在 192.168.5.192/28 内。它必须是未被 NAS、其他设备或 DHCP 占用的独立 IP。如果 Docker 网络的 Subnet 本身就是 192.168.5.192/28,不要照搬 .223;应从 .193~.206 中选择一个空闲地址作为宿主机虚拟网卡的 IP,并在 Docker 网络中用 --aux-address 保留,避免分配给容器。

还要确认 .192/28 整段只用于这些 macvlan 容器。添加路由后,宿主机发往这个范围内的流量都会走 macvlan-host;如果里面有普通局域网设备,宿主机访问它们可能受到影响。

临时配置

以具有管理员权限的 shell 执行:

1
2
3
4
ip link add macvlan-host link eno1 type macvlan mode bridge
ip addr add 192.168.5.223/32 dev macvlan-host
ip link set macvlan-host up
ip route add 192.168.5.192/28 dev macvlan-host src 192.168.5.223

/32 只给虚拟网卡指定一个本机地址;单独添加的路由负责将容器地址段导向这张网卡。src 则明确指定宿主机访问容器时使用 .223 作为源地址。

检查路由选取:

1
ip route get 192.168.5.199

输出中应包含 dev macvlan-host src 192.168.5.223。然后测试连通性:

1
ping 192.168.5.199

如果路由正确但 ping 不通,还需要检查容器是否运行、防火墙规则,以及容器是否响应 ICMP。也可以直接测试容器实际提供的服务端口。

用 systemd 持久化

临时配置在宿主机重启后会消失。创建以下服务,使系统启动时自动恢复接口和路由:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
cat >/etc/systemd/system/macvlan-host.service <<'EOF'
[Unit]
Description=Host macvlan interface for Docker containers
Wants=network-online.target
After=network-online.target

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/sh -c 'ip link show dev macvlan-host >/dev/null 2>&1 || ip link add macvlan-host link eno1 type macvlan mode bridge'
ExecStart=/bin/sh -c 'ip -4 addr show dev macvlan-host | grep -Fq "inet 192.168.5.223/32 " || ip addr add 192.168.5.223/32 dev macvlan-host'
ExecStart=/bin/sh -c 'ip link set macvlan-host up'
ExecStart=/bin/sh -c 'ip route replace 192.168.5.192/28 dev macvlan-host src 192.168.5.223'
ExecStop=/bin/sh -c 'ip link del macvlan-host'

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable --now macvlan-host.service

如果已经执行过临时配置,服务会复用现有的虚拟网卡。检查服务和路由:

1
2
3
systemctl status macvlan-host.service
ip addr show dev macvlan-host
ip route get 192.168.5.199

以后容器只要使用 192.168.5.192/28 内的 IP,宿主机就不需要再为每个容器添加单独的路由。这里的 /28 覆盖 .192~.207,通常可分配的主机地址为 .193~.206;请结合 Docker 网络的实际配置保留宿主机所用地址。

参考:Docker macvlan 网络文档 · Docker 网络创建参数