使用 macvlan 配置网络让docker连接宿主机

ubuntu 上配置 macvlan

Ticket:要将docker容器 nginx-ui 添加到一个名为:network_172_16 的 network 上,并指定ip地址为: 172.16.2.241,网关: 172.16.15.253, 其中宿主机ip: 172.16.2.240/20, gw:172.16.15.253, 实现让容器 nginx-ui 可以以内网的方式访问宿主机未对外开放的端口。

  • 创建基于 macvlan 的 docker network
# 创建基于 macvlan 的虚拟网桥 network_100
docker network create -d macvlan \
    --subnet=192.168.100.0/24 \
    --gateway=192.168.100.1 \
    -o parent=ens18 \
    network_100

# aliyun wodedata
docker network create -d macvlan \
    --subnet=172.16.0.1/20 \
    --gateway=172.16.15.253 \
    -o parent=eth0 \
    network_172_16

# 为已存在的容器添加到网络: network_100, 并指定ip: 192.168.100.145
docker network connect --ip 192.168.100.145 network_100 nginx-ui

# 运行容器并指定 macvlan 网络
docker run -dit \
    --name networktool \
    --network=network_100 \
    --ip=192.168.100.149 \
    docker.wodedata.com/network-multitool:alpine-extra

# 进入容器shell
docker exec -it networktool sh
# ping 测试
# ping 192.168.100.100

通过上述操作已经可以很舒服的给容器分配独立的IP地址,如果发现添加了 macvlan network 的容器虽然可以和局域网内其他的设备或者在他们之间通信,但是却无法与宿主机通信,其实这是Macvlan的一个安全机制,按照下面方法在宿主机上再添加一个 macvlan bridge + route rule 即可绕过该限制。

# 再创建一个 macvlan_100 的网桥
ip link add macvlan_100 link eth0 type macvlan mode bridge
# 添加一个与宿主机(192.168.100.100/24)同网段的ip: 192.168.100.140/24
ip addr add 192.168.100.140/24 dev macvlan_100
# 启动网桥
ip link set macvlan_100 up     
# 添加一条到宿主机(192.168.100.100/32)的路由
ip route add 192.168.100.100 dev macvlan_100

# aliyun wodedata 案例
ip link add mll link eth0 type macvlan mode bridge
ip addr add 172.16.2.100/12 dev mll
ip link set mll up                                
ip route add 172.16.2.241 dev mll

注: 要开启ip转发后并重启 docker 以后才能实现 macvlan bridge 与宿主机通信,编辑 sudo vim /etc/sysctl.conf 设置 net.ipv4.ip_forward=1, 然后再 sudo sysctl -psudo systemctl restart docker.

设置自启动

在ubuntu上,若要将以上命令添加成开机后自动启动,可有以下两种方式:

方法 1:使用 Systemd 服务

  1. sudo vim /usr/local/bin/setup_macvlan.sh, 添加内容:
#!/bin/bash
ip link add mll link eth0 type macvlan mode bridge
ip addr add 172.16.2.100/12 dev mll
ip link set mll up                                
ip route add 172.16.2.241 dev mll
  1. 运行以下命令,使脚本可执行:sudo chmod +x /usr/local/bin/setup_macvlan.sh
  2. 创建一个新的 Systemd 服务文件:sudo vim /etc/systemd/system/setup_macvlan.service, 并添加以下内容:
[Unit]
Description=Setup Macvlan Interface
After=network.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/setup_macvlan.sh
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
  1. 运行以下命令以启用服务,使其在启动时自动执行:sudo systemctl enable setup_macvlan.service
  2. 立即启动服务进行测试: sudo systemctl start setup_macvlan.service

方法 2:使用 Netplan 配置(适用于 Ubuntu 17.10 及以上版本)
通常,Netplan 配置文件位于 /etc/netplan/ 目录下,可以先查看当前系统现在的 netplan 配置。

  1. 新增配置文件:sudo vim /etc/netplan/02-macvlan.yaml,也可修改(如:sudo vim /etc/netplan/01-netcfg.yaml), 添加以下内容:
network:
    version: 2
    macvlans:
        mll:
            link: eth0
            mode: bridge
            addresses:
                - 172.16.2.100/24
            routes:
                - to: 172.16.2.241
                  via: 172.16.2.100

确保文件名按字母顺序排列,以便 Netplan 正确应用配置。在这种情况下,02-macvlan.yaml 的前缀 02 确保它在 01-netcfg.yaml 之后被处理。 2. 保存并关闭文件后,使用命令:sudo netplan apply 应用新的 Netplan 配置.

最后,如果是阿里云(aliyun)服务器,防火墙配置加上内网(172.16.0.0/20 或整个B类子网172.16.0.0/12)即可.

Synology 上配置 macvlan

参考:macvlan systemd script

Three files are required. Each file states where it must be copied to. You will require sudo access for this as these areas are protected.

  1. macvlan.service
# Service file for creating macvlan shim, after docker has started
# copy this file to /usr/local/lib/systemd/system
# For use with systemd on DSM7.2
# Synology renamed pkgctl-Docker to pkg-ContainerManager-dockerd


[Unit]
Description=Macvlan shim to allow docker to route to host

# Ensure macvlan is stopped if pkg-ContainerManager-dockerd.service stops/fails
BindsTo=pkg-ContainerManager-dockerd.service

# Define dependency
Requires=pkg-ContainerManager-dockerd.service

# Ensure order of startup
After=pkg-ContainerManager-dockerd.service


[Service]
Type=oneshot
ExecStart=/bin/bash /usr/local/bin/macvlan_start.sh
ExecStop=/bin/bash /usr/local/bin/macvlan_stop.sh
RemainAfterExit=yes
Restart=no


[Install]
# Informs systemd to start macvlan after this service at startup
WantedBy=pkg-ContainerManager-dockerd.service
  1. macvlan_start.sh
#!/bin/bash

# macvlan address range is 192.168.100.33 to 192.168.100.46
# IP address used for R100 is 192.168.100.1
# mac address is a0:b1:c2:d3:e4:f5
# copy this file to /usr/local/bin/macvlan_start.sh

ip link add macvlan_100 link ovs_eth0 type macvlan mode bridge 
ip link set macvlan_100 address a0:b1:c2:d3:e4:f5
ip addr add 192.168.100.33/32 dev macvlan_100
ip link set macvlan_100 up
# ip route add 192.168.100.0/24 dev macvlan_100  # because exsists
ip route add 192.168.100.8/32 dev macvlan_100
  1. macvlan_stop.sh
#!/bin/bash

# macvlan address range is 192.168.100.33 to 192.168.100.46
# IP address used for R100 is 192.168.100.1
# mac address is a0:b1:c2:d3:e4:f5
# copy this file to /usr/local/bin/macvlan_stop.sh

ip route del 192.168.100.8/32 dev macvlan_100 || true
# ip route del 192.168.100.0/24 dev macvlan_100 || true
ip link set macvlan_100 down || true
ip addr del 192.168.100.33/32 dev macvlan_100 || true
ip link del macvlan_100 || true

Having saved the 3 files to the locations as documented in the files you will need to enable the macvlan service to ensure it runs at startup.

sudo systemctl enable macvlan.service

Created symlink from /etc/systemd/system/pkg-ContainerManager-dockerd.service.wants/macvlan.service to /usr/local/lib/systemd/system/macvlan.service.

常见的特殊保留网段( 内网地址 / 保留网络 )

参考:
Docker网络之Macvlan
从 VLAN 到 IPVLAN: 聊聊虚拟网络设备及其在云原生中的应用
Configuring Macvlan and Ipvlan Linux Networking
Docker 使用 macvlan 网络容器与宿主机的通信过程