macvlan 本身是 linux kernel 模块,其功能是允许在同一个物理网卡上配置多个 MAC 地址,即多个 interface,每个 interface 可以配置自己的 IP,macvlan 本质上是一种网卡虚拟化技术。
一、实验环境
IP | 主机名 | 内核版本 |
---|---|---|
10.1.1.17 | master | kernel-5.2.11 |
10.1.1.13 | host1 | kernel-5.2.11 |
10.1.1.14 | host2 | kernel-5.2.11 |
二、创建macvlan网络
在master、node1和node2上同时执行以下命令:
[root@master ~]# docker network create -d macvlan --subnet=172.16.10.0/24 --gateway=172.16.10.1 -o parent=ens33 mac1
476cfc5eb16c51647c02f87ff682452d4a76568b47d770a612996d0e09420e21
[root@master ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
7fd1d76008e3 bridge bridge local
af93f80d0ba6 host host local
476cfc5eb16c mac1 macvlan local
23d2bfb36bf0 none null local
node1:
[root@node1 ~]# docker network create -d macvlan --subnet=172.16.10.0/24 --gateway=172.16.10.1 -o parent=ens33 mac1
33e73b4f6637ce7064b4f6198a43125f07557e7bf824ad1ea39a276e910e11eb
[root@node1 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
9986d9dda86f bridge bridge local
8611ebf969a6 host host local
33e73b4f6637 mac1 macvlan local
556e2a599b82 none null local
node2:
[root@node2 ~]# docker network create -d macvlan --subnet=172.16.10.0/24 --gateway=172.16.10.1 -o parent=ens33 mac1
14b860ca6be2458d3f210286be2f6a867177403f41d96985a5fcac60ec93fa78
[root@node2 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
3891241149c3 bridge bridge local
a63bf958be9e host host local
14b860ca6be2 mac1 macvlan local
fb8797af5710 none null local
三、用macvlan网络创建容器:
master:
[root@master ~]# docker run -itd --name c1 --ip=172.16.10.2 --network mac1 busybox
50f2d1b18bcf4301a13afa08c5eb780f1d37351e3e30617076c5a557e4eda512
node1:
[root@node1 ~]# docker run -itd --name c2 --ip=172.16.10.3 --network mac1 busybox
91ce7ad4a9f628417067a93df8c547199af438a8d0b1b20d616cbdc3742b655a
node2:
[root@node2 ~]# docker run -itd --name c3 --ip=172.16.10.4 --network mac1 busybox
02fa6f6be82c6c680f0e798662e3555bae204dddfa5b722d00b5f71ca80a7163
(4)三个容器的IP分别为172.16.10.2\3\4,进入容器互相ping对方:
master:
[root@master ~]# docker attach c1
/ # ping -c 1 172.16.10.3
PING 172.16.10.3 (172.16.10.3): 56 data bytes
64 bytes from 172.16.10.3: seq=0 ttl=64 time=2.546 ms
--- 172.16.10.3 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 2.546/2.546/2.546 ms
/ # ping -c 1 172.16.10.4
PING 172.16.10.4 (172.16.10.4): 56 data bytes
64 bytes from 172.16.10.4: seq=0 ttl=64 time=1.240 ms
--- 172.16.10.4 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 1.240/1.240/1.240 ms
node1:
[root@node1 ~]# docker attach c2
/ # ping -c 1 172.16.10.2
PING 172.16.10.2 (172.16.10.2): 56 data bytes
64 bytes from 172.16.10.2: seq=0 ttl=64 time=0.510 ms
--- 172.16.10.2 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.510/0.510/0.510 ms
/ # ping -c 1 172.16.10.4
PING 172.16.10.4 (172.16.10.4): 56 data bytes
64 bytes from 172.16.10.4: seq=0 ttl=64 time=1.460 ms
--- 172.16.10.4 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 1.460/1.460/1.460 ms
node2:
[root@node2 ~]# docker attach c3
/ # ping -c 1 172.16.10.2
PING 172.16.10.2 (172.16.10.2): 56 data bytes
64 bytes from 172.16.10.2: seq=0 ttl=64 time=1.994 ms
--- 172.16.10.2 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 1.994/1.994/1.994 ms
/ # ping -c 1 172.16.10.3
PING 172.16.10.3 (172.16.10.3): 56 data bytes
64 bytes from 172.16.10.3: seq=0 ttl=64 time=1.213 ms
--- 172.16.10.3 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 1.213/1.213/1.213 ms
互相之间都是能够ping通的。
四、网络结构分析:
macvlan是不依赖Linux bridge的,创建好macvlan网络之后,通过brctl show可以确认没有创建新的网桥:
[root@master ~]# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.024276b03dbc no
查看c1容器的网络:
[root@master ~]# docker exec c1 ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
4: eth0@if2: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:10:0a:02 brd ff:ff:ff:ff:ff:ff
除了lo,容器只有一个eth0,eth0后面有个if2,这说明该接口有个对应的interface,全局编号为2,而在主机上执行 ip link可以看到,ens33的编号也是2:
[root@master ~]# ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
link/ether 00:0c:29:c9:32:dd brd ff:ff:ff:ff:ff:ff
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default
link/ether 02:42:76:b0:3d:bc brd ff:ff:ff:ff:ff:ff
所以,可以确定的是,容器抄底eth0就是ens33通过macvlan虚拟出来的interface。容器的interface直接与主机的网卡进行连接,这种方案使得容器无需通过NAT和端口映射就能与外网相通,在网络上与其他独立主机没有区别。
五、不同 macvlan 网络之间的通信
macvlan会独占主机的网卡,也就是说每个网卡只能创建一个macvlan网络,否则会报错。但主机的网卡是有限的,如何支持更多的macvlan网络呢?好在macvlan不仅可以连接到interface,如ens33,还可以连接到sub-interface,如ens33.100,ens33.200。
Linux网卡支持VLAN技术,VLAN是现代常用的网络虚拟化技术,同一个网卡(interface)可以支持多个VLAN的数据包,不过前提是要创建sub-interface。
比如希望ens33网卡支持VLAN10和VLAN20,则需要创建sub-interface ens33.10和ens33.20。在交换机上,如果某个口智能手法单个VLAN的数据,则port为access模式;若要接受多个VLAN的数据,则为trunk模式。所以ens33网卡对端要接在交换机的trunk口上。因为我们是虚拟机,就不需要这样操作了。下面开始创建基于VLAN的macvlan网络。
首先两台主机上安装vconfig工具:
[root@master ~]# wget https://mirrors.aliyun.com/centos/6.10/os/x86_64/Packages/vconfig-1.9-8.1.el6.x86_64.rpm
rpm -ivh vconfig-1.9-8.1.el6.x86_64.rpm
加载8021q模块:
[root@master ~]# modprobe 8021q
开启ens33网卡的混杂模式:
[root@master ~]# ifconfig ens33 promisc
确认混杂模式已经开启:
ens33: flags=4419<UP,BROADCAST,RUNNING,PROMISC,MULTICAST> mtu 1500
inet 10.1.1.13 netmask 255.255.255.0 broadcast 10.1.1.255
inet6 fe80::55d8:65e5:d67d:8eaf prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:5c:02:a3 txqueuelen 1000 (Ethernet)
RX packets 138 bytes 14859 (14.5 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 210 bytes 21630 (21.1 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
启用IPV4. forwarding:
[root@master ~]# vim /etc/sysctl.conf
net.ipv4.ip_forward=1
然后重启network。
[root@master ~]# systemctl restart network
现在三台主机上分别基于ens33网卡创建两个VLAN:
[root@master ~]# vconfig add ens33 100
[root@master ~]# vconfig add ens33 200
启用VLAN:
[root@master ~]# ifconfig ens33.100 up
[root@master ~]# ifconfig ens33.200 up
基于两个子接口分别创建mac10和mac20的macvlan网络:
[root@master ~]# docker network create -d macvlan --subnet=172.16.10.0/24 --gateway=172.16.10.1 -o parent=ens33.100 mac10
[root@master ~]# docker network create -d macvlan --subnet=172.16.20.0/24 --gateway=172.16.20.1 -o parent=ens33.200 mac20
在node1上创建d1和d2两个容器,分别基于mac10和mac20:
[root@master ~]# docker run -itd --name d1 --ip=172.16.10.10 --network mac10 busybox
[root@master ~]# docker run -itd --name d2 --ip=172.16.20.10 --network mac20 busybox
在node2上创建d3和d4两个容器,分别基于mac10和mac20:
[root@master ~]# docker run -itd --name d3 --ip=172.16.10.11 --network mac10 busybox
[root@master ~]# docker run -itd --name d4 --ip=172.16.20.11 --network mac20 busybox
正常来讲d1和d3属于同一个网段,d2和d4属于同一个网段,应该是能ping通的,目前我的实验没通,不知道是不是虚拟机本身不支持这个网络。正在研究中。