本文翻译自https://blog.oddbit.com/post/2018-03-12-using-docker-macvlan-networks/
在docker上经常出现的一个问题是:”我怎样才能直接将容器连接到我的本地网络?” 一个方法是使用macvlan网络类型,这让你可以在主机上创建物理接口的”克隆”,并使用它直接将容器连接到本地网络。大部分情况下它运行得很好,但会有一些小的注意事项和限制。我想在这里探讨一下这些。
以这个例子为例,假设我们有一个看起来像这样的主机接口eno1
:
eno1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 64:00:6a:7d:06:1a brd ff:ff:ff:ff:ff:ff
inet 192.168.1.24/24 brd 192.168.1.255 scope global dynamic eno1
valid_lft 73303sec preferred_lft 73303sec
inet6 fe80::b2c9:3793:303:2a55/64 scope link
valid_lft forever preferred_lft forever
要创建一个连接到该接口的名为mynet的macvlan网络,你可能会运行如下命令:
docker network create -d macvlan -o parent=eno1 \
--subnet 192.168.1.0/24 \
--gateway 192.168.1.1 \
mynet
…但不要这样做。
地址分配
当你创建一个连接到macvlan网络的容器时,Docker会从子网范围中选择一个地址并将其分配给你的容器。这可能导致冲突:如果Docker选择的地址已经被你网络上的另一个主机分配了,那你就有问题了!
你可以通过为Docker保留子网范围的一部分来避免这个问题。这个解决方案有两个部分:
- 你必须配置你网络上的任何DHCP服务,使其不会在给定范围内分配地址。(路由器里面有相关的设置的)
- 你必须告诉Docker关于那个保留的地址范围。
如何完成前者完全取决于你的本地网络基础设施,超出了本文的范围。后者可以通过docker network create
的--ip-range
选项来完成。
在我的本地网络上,我的DHCP服务器不会分配任何高于192.168.1.190
的地址。我决定将192.168.1.192/27
的子集分配给Docker,这是一个从192.168.1.192
开始到192.168.1.223
结束的32个地址的范围。相应的docker network create
命令将是:
docker network create -d macvlan -o parent=eno1 \
--subnet 192.168.1.0/24 \
--gateway 192.168.1.1 \
--ip-range 192.168.1.192/27 \
mynet
现在可以创建连接到本地网络的容器而不用担心IP地址冲突的可能性。
主机访问
当容器连接到macvlan网络时,你会发现它可以毫无问题地与本地网络上的其他系统联系,但容器将无法连接到你的主机(你的主机也无法连接到你的容器)。这是macvlan接口的一个限制:没有来自网络交换机的特殊支持,你的主机无法向它自己的macvlan接口发送数据包。
幸运的是,有一个解决这个问题的方法:你可以在你的主机上创建另一个macvlan接口,并使用它与macvlan网络上的容器通信。
首先,我要使用docker network create
的--aux-address
选项从我们的网络范围中为主机接口预留一个地址。这使我们的最终命令行看起来像这样:
docker network create -d macvlan -o parent=eno1 \
--subnet 192.168.1.0/24 \
--gateway 192.168.1.1 \
--ip-range 192.168.1.192/27 \
--aux-address 'host=192.168.1.223' \
mynet
这将阻止Docker将该地址分配给容器。
接下来,我们在主机上创建一个新的macvlan
接口。你可以随意命名,但我称这个为mynet-shim
:
ip link add mynet-shim link eno1 type macvlan mode bridge
现在我们需要配置该接口的地址并启动它:
ip addr add 192.168.1.223/32 dev mynet-shim
ip link set mynet-shim up
我们需要做的最后一件事是告诉我们的主机在与容器通信时使用该接口。这相对容易,因为我们已将容器限制在本地网络的特定CIDR子集中;我们只需像这样添加一个到该范围的路由:
ip route add 192.168.1.192/27 dev mynet-shim
有了这个路由,你的主机在与mynet网络上的容器通信时将自动使用mynet-shim接口。
请注意,这里介绍的接口和路由配置不是持久的 - 如果你重启你的主机,你将失去这些配置。如何使其持久化取决于分发。
本文翻译自https://blog.oddbit.com/post/2018-03-12-using-docker-macvlan-networks/
下面是个人的一些补充
开机启动执行脚本
我们可以添加一个system service来开机启动执行脚本,这样就可以在开机的时候自动执行上面的命令了。
- 创建一个脚本,并添加执行权限
$ touch /usr/local/bin/mynet-shim.sh
$ chmod +x /usr/local/bin/mynet-shim.sh
- 将下面的内容添加到脚本里面
#!/bin/bash
ip link add mynet-shim link eno1 type macvlan mode bridge
ip addr add 192.168.1.223/32 dev mynet-shim
ip link set mynet-shim up
ip route add 192.168.1.192/27 dev mynet-shim
- 创建system service,并添加到开机启动
$ touch /etc/systemd/system/mynet-shim.service
- 将下面的内存添加到service文件里面
[Unit]
Description=My Mac Service
After=network.target
[Service]
ExecStart=/usr/local/bin/mynet-shim.sh
Type=simple
[Install]
WantedBy=multi-user.target
- 开机启动service
$ systemctl enable mynet-shim.service
$ systemctl start mynet-shim.service
- 查看是否生效, 使用下面命令看下有没有对应的route
$ ip route
- 重启主机,查看是否生效
使用macvlan网络
在docker-compose.yaml里面加上mynet网络,并且指定ip地址
version: '3'
services:
clash:
build: .
image: clash
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
privileged: true
volumes:
- ./config/:/root/.config/clash/
restart: always
ulimits:
memlock: -1
nproc: 65535
nofile:
soft: 20000
hard: 40000
networks:
mynet:
ipv4_address: "192.168.50.222"
networks:
default:
name: mynet
external: true
mynet:
external: true