我在 NAS 上部署了一个 NginxProxyManager 方便管理其他 Self Host 服务的 SSL 证书,为了避免占用宿主机的 80/443 端口,我用了 macvlan 为 NPM 容器分配了一个独立的局域网 IP。
networks:
macvlan_network:
driver: macvlan
driver_opts:
parent: <your-network-interface>
ipam:
config:
- subnet: 192.168.100.0/24
gateway: 192.168.100.1
services:
npm:
image: 'jc21/nginx-proxy-manager:latest'
restart: unless-stopped
networks:
macvlan_network:
ipv4_address: 192.168.100.22
environment:
DISABLE_IPV6: 'true'
volumes:
- ./data:/data
- ./letsencrypt:/etc/letsencrypt
这时,局域网其他的设备就可以通过 192.168.100.22 访问 NPM,但是对于宿主机以及宿主机上其他的容器来说,这个地址是无法访问的。
在咨询了 GPT 之后,它建议了下面的方案:
[Unit]
Description=Set up specific macvlan route for a Docker container
After=network.target
[Service]
Type=oneshot
RemainAfterExit=yes
# Replace <your-network-interface> with the actual interface name
ExecStart=/usr/bin/ip link add mvlan0 link <your-network-interface> type macvlan mode bridge
ExecStart=/usr/bin/ip addr add <unused-ip>/24 dev mvlan0
ExecStart=/usr/bin/ip link set mvlan0 up
ExecStart=/usr/bin/ip route del 192.168.100.0/24 dev mvlan0
ExecStart=/usr/bin/ip route add 192.168.100.22 dev mvlan0
ExecStop=/usr/bin/ip link delete mvlan0
[Install]
WantedBy=multi-user.target
默认情况下的问题:
- 当使用 macvlan/ipvlan 时,Docker 容器会直接连接到物理网络接口
- 但是宿主机无法通过物理接口直接与这些容器通信,因为物理接口不会处理宿主机到 macvlan 接口的流量
创建 mvlan0 的作用:
sudo ip link add mvlan0 link <your-network-interface> type macvlan mode bridge
sudo ip addr add <unused-ip>/24 dev mvlan0
sudo ip link set mvlan0 up
- 这实际上是在宿主机创建了一个新的网络接口 mvlan0
- 这个接口也是一个 macvlan 接口,与 Docker 容器使用相同的技术
- mvlan0 接口可以看作是宿主机在 192.168.100.0/24 网段的一个”入口”
通信流程:
宿主机 -> mvlan0 (unused-ip) -> 物理网卡 -> Docker 容器 (192.168.100.22)
- 当宿主机要访问 192.168.100.22 时
- 数据包会通过 mvlan0 接口发出
- 由于 mvlan0 和容器的网络接口都是 macvlan 类型,它们可以在同一层次通信
类比解释:
- 可以把这个设置想象成宿主机也”加入”到了容器所在的网络
- mvlan0 就像是宿主机的一个”虚拟网卡”,使它能够与容器在同一个网络层面通信
为什么需要这样:
- 这种设置避免了常规的网络栈限制
- 提供了一个直接的通信路径
- 保持了网络隔离性的同时又允许必要的通信
这就是为什么添加这个 macvlan 接口可以让宿主机访问容器的原理。这种方法既保持了容器网络的独立性,又提供了必要的访问路径。
发表回复