背景说明

MacVLAN是Linux kernel 支持的新特性,支持的版本有 v3.9-3.19 和 4.0+,比较稳定的版本推荐4.0+。它一般是以内核模块的形式存在。

MacVLAN这种技术能将一块物理网卡虚拟成多块虚拟网卡。 MacVLAN使得容器网络和主机网络在同一个广播域内,是一种跨主机互联的网络模式 不能识别容器的主机名称进行PING

解决方案

环境检查

系统检查

我们可以通过以下方法判断当前系统是否支持

  1. [root@vm2 ~]# modprobe macvlan
  2. [root@vm2 ~]# lsmod | grep macvlan
  3. macvlan 19239 0
  4. [root@vm2 ~]#

网卡检查

  1. [root@vm2 docker]# ip addr show ens33
  2. 2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
  3. link/ether 00:0c:29:43:2c:2d brd ff:ff:ff:ff:ff:ff
  4. inet 192.168.184.142/24 brd 192.168.184.255 scope global noprefixroute dynamic ens33
  5. valid_lft 1140sec preferred_lft 1140sec
  6. inet6 fe80::1d72:8c06:652b:cc91/64 scope link tentative noprefixroute dadfailed
  7. valid_lft forever preferred_lft forever
  8. inet6 fe80::2452:200d:395f:968a/64 scope link noprefixroute
  9. valid_lft forever preferred_lft forever
  10. [root@vm2 docker]#

由于并没有包含PROMISC,通过如下命令进行开启

  1. [root@vm2 docker]# ip link set ens33 promisc on
  2. [root@vm2 docker]# ip addr show ens33
  3. 2: ens33: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
  4. link/ether 00:0c:29:43:2c:2d brd ff:ff:ff:ff:ff:ff
  5. inet 192.168.184.142/24 brd 192.168.184.255 scope global noprefixroute dynamic ens33
  6. valid_lft 1051sec preferred_lft 1051sec
  7. inet6 fe80::1d72:8c06:652b:cc91/64 scope link tentative noprefixroute dadfailed
  8. valid_lft forever preferred_lft forever
  9. inet6 fe80::2452:200d:395f:968a/64 scope link noprefixroute
  10. valid_lft forever preferred_lft forever
  11. [root@vm2 docker]#

主机网络

查看主机网络的网络范围和网关地址,这里网络范围:192.168.184.0/24 网关:192.168.184.2

  1. [root@vm1 ~]# ip route
  2. default via 192.168.184.2 dev ens33 proto dhcp metric 100
  3. 172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1
  4. 192.168.184.0/24 dev ens33 proto kernel scope link src 192.168.184.137 metric 100
  5. [root@vm1 ~]# ip addr show ens33
  6. 2: ens33: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
  7. link/ether 00:0c:29:ac:19:5a brd ff:ff:ff:ff:ff:ff
  8. inet 192.168.184.137/24 brd 192.168.184.255 scope global noprefixroute dynamic ens33
  9. valid_lft 1568sec preferred_lft 1568sec
  10. inet6 fe80::1d72:8c06:652b:cc91/64 scope link noprefixroute
  11. valid_lft forever preferred_lft forever
  12. [root@vm1 ~]#

工作原理

image.png

网络创建

创建MacVLAN网络,两台主机均需要执行,注意网络范围和网关需要和主机网络保持一致。
主机192.168.184.137 vm1

  1. [root@vm1 ~]# docker network create --driver macvlan --subnet 192.168.184.0/24 --gateway 192.168.184.2 -o parent=ens33 macvlantest
  2. 013ccaa2997eb2f9cbdef05d10b609e4c85fdf13242f553a2d828576edbd68a8
  3. [root@vm1 ~]#
  4. [root@vm1 ~]# docker network ls
  5. NETWORK ID NAME DRIVER SCOPE
  6. 892af10cd339 bridge bridge local
  7. 4a5006c650f6 host host local
  8. 94030ad50044 macvlantest macvlan local
  9. a027c870d158 none null local
  10. [root@vm1 ~]#

主机192.168.184.142 vm2

  1. [root@vm2 ~]# docker network create --driver macvlan --subnet 192.168.184.0/24 --gateway 192.168.184.2 -o parent=ens33 macvlantestfba0554e018d9bc0812d422ed1c88d9fa280873d429d533239cddf15ac540d2d
  2. [root@vm2 ~]# docker network ls
  3. NETWORK ID NAME DRIVER SCOPE
  4. 801380e310dd bridge bridge local
  5. 4a5006c650f6 host host local
  6. fba0554e018d macvlantest macvlan local
  7. a027c870d158 none null local
  8. [root@vm2 ~]#

由于MacVLAN 网络会独占物理网卡,也就是说一张物理网卡只能创建一个 macvlan网络,重复创建出现如下错误

  1. [root@vm1 ~]# docker network create --driver macvlan --subnet 192.168.184.0/24 --gateway 192.168.184.2 -o parent=ens33 -o macvlan_mode=bridge macvlan1
  2. Error response from daemon: Pool overlaps with other one on this address space

如果想创建多个macvlan网络就需要多块网卡,也可以通过VLAN子接口的方案。

容器创建

网络创建完成后,创建容器
主机192.168.184.137 vm1

  1. [root@vm1 ~]# docker run -it --name c11 --network=macvlantest centos /bin/bash
  2. [root@6dd18751f4d7 /]# ip addr
  3. 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
  4. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  5. inet 127.0.0.1/8 scope host lo
  6. valid_lft forever preferred_lft forever
  7. 12: eth0@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default
  8. link/ether 02:42:c0:a8:b8:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
  9. inet 192.168.184.3/24 brd 192.168.184.255 scope global eth0
  10. valid_lft forever preferred_lft forever
  11. [root@6dd18751f4d7 /]#
  12. [root@6dd18751f4d7 /]# ping 192.168.184.142
  13. PING 192.168.184.142 (192.168.184.142) 56(84) bytes of data.
  14. 64 bytes from 192.168.184.142: icmp_seq=1 ttl=64 time=0.281 ms
  15. 64 bytes from 192.168.184.142: icmp_seq=2 ttl=64 time=0.328 ms
  16. 64 bytes from 192.168.184.142: icmp_seq=3 ttl=64 time=0.229 ms
  17. [root@6dd18751f4d7 /]# ping 192.168.184.137
  18. PING 192.168.184.137 (192.168.184.137) 56(84) bytes of data.
  19. From 192.168.184.3 icmp_seq=1 Destination Host Unreachable

由于容器创建时的网络地址是macvlantest分配的,它并不知道哪些IP进行了使用,可能有些IP已经被使用了会出现冲突的情况,建议容器创建时指定—p进行指定。

主机192.168.184.142 vm2

  1. docker run -it --name c22 --network=macvlantest centos /bin/bash
  2. [root@218d4f9d0464 /]#
  3. [root@218d4f9d0464 /]# ip addr
  4. 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
  5. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  6. inet 127.0.0.1/8 scope host lo
  7. valid_lft forever preferred_lft forever
  8. 11: eth0@if2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default
  9. link/ether 02:42:c0:a8:b8:01 brd ff:ff:ff:ff:ff:ff link-netnsid 0
  10. inet 192.168.184.4/24 brd 192.168.184.255 scope global eth0
  11. valid_lft forever preferred_lft forever
  12. [root@218d4f9d0464 /]#
  13. [root@0d5042b162e8 /]# ping 192.168.184.137
  14. PING 192.168.184.137 (192.168.184.137) 56(84) bytes of data.
  15. 64 bytes from 192.168.184.137: icmp_seq=1 ttl=64 time=0.612 ms
  16. 64 bytes from 192.168.184.137: icmp_seq=2 ttl=64 time=0.269 ms
  17. [root@0d5042b162e8 /]# ping 192.168.184.142
  18. PING 192.168.184.142 (192.168.184.142) 56(84) bytes of data.
  19. From 192.168.184.4 icmp_seq=1 Destination Host Unreachable

由于容器创建时的网络地址是macvlantest分配的,它并不知道哪些IP进行了使用,可能有些IP已经被使用了会出现冲突的情况,建议容器创建时指定—p进行指定。

网络测试

在主机192.168.184.142 vm2上ping容器c11

  1. [root@vm2 ~]# ping 192.168.184.3
  2. PING 192.168.184.3 (192.168.184.3) 56(84) bytes of data.
  3. 64 bytes from 192.168.184.3: icmp_seq=1 ttl=64 time=0.505 ms
  4. 64 bytes from 192.168.184.3: icmp_seq=2 ttl=64 time=0.481 ms

在主机192.168.184.137 vm1上ping容器c22

  1. [root@vm1 ~]# ping 192.168.184.4
  2. PING 192.168.184.4 (192.168.184.4) 56(84) bytes of data.
  3. 64 bytes from 192.168.184.4: icmp_seq=1 ttl=64 time=0.461 ms
  4. 64 bytes from 192.168.184.4: icmp_seq=2 ttl=64 time=0.991 ms

网络问题

在上文中可以发现,宿主机和宿主机上面容器之间无法互相PING通,一般在macvlan模式下同网段的其他机器可以和容器互通,但宿主不能和容器互通,这是在macvlan模式设计的时候为了安全而禁止了宿主机和容器直接通信。

参考网址

https://rehtt.com/index.php/archives/236/

解决方案

如果想要实现互通,有个曲线救国的方法,就是macvlan与macvlan之间可以互通,只需要在宿主机再创建一个macvlan网络,然后修改路由,让数据经过这个macvlan达到互通的目的。

环境梳理

现有网段: 192.168.184.0/24 网关: 192.168.184.2

名字 网络地址 接口
宿主机vm1 192.168.184.137 ens33
容器c11 192.168.184.3 macvlantest
宿主机vm2 192.168.184.142 ens33
容器c22 192.168.184.4 macvlantest

网络创建

这里以宿主机vm1进行举例,在宿主机上执行,建立一个名为macvlan-fixed的macvlan接口,并分配一个ip:

名字 网络地址 接口
macvlan-fixed 192.168.184.200 ens33

这里的网络地址在网段192.168.184.0/24范围内均可

[root@vm1 ~]# ip link add macvlan-fixed link ens33 type macvlan mode bridge
[root@vm1 ~]# ip addr add 192.168.184.200 dev macvlan-fixed
[root@vm1 ~]# ip link set macvlan-fixed up

语法: ip link add macvlan2(一个网络名称) link ovs_eth0(你的物理网卡) type macvlan mode bridge

路由添加

修改路由,让宿主机到容器(192.168.184.3)的数据经过macvlan2:

[root@vm1 ~]# ip route add 192.168.184.3 dev macvlan-fixed

这里的192.168.184.3是容器网络地址 语法格式: ip route add 目的ip(需要建立通讯的macvlan容器 ip) dev macvlan(刚宿主机建立的macvlan)

访问验证

宿主机访问容器:192.168.184.3 => 192.168.184.200

[root@0a10f82ad3ea /]# ping 192.168.184.200
PING 192.168.184.200 (192.168.184.200) 56(84) bytes of data.
64 bytes from 192.168.184.200: icmp_seq=1 ttl=64 time=0.696 ms
64 bytes from 192.168.184.200: icmp_seq=2 ttl=64 time=1.01 ms
64 bytes from 192.168.184.200: icmp_seq=3 ttl=64 time=0.274 ms
^C
--- 192.168.184.200 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2015ms
rtt min/avg/max/mdev = 0.274/0.661/1.013/0.302 ms
[root@0a10f82ad3ea /]#

容器访问宿主机: 192.168.184.137 vm1

[root@0a10f82ad3ea /]# ping 192.168.184.137
PING 192.168.184.137 (192.168.184.137) 56(84) bytes of data.
64 bytes from 192.168.184.137: icmp_seq=1 ttl=64 time=0.131 ms
64 bytes from 192.168.184.137: icmp_seq=2 ttl=64 time=0.066 ms
64 bytes from 192.168.184.137: icmp_seq=3 ttl=64 time=0.043 ms
^C
--- 192.168.184.137 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2067ms
rtt min/avg/max/mdev = 0.043/0.080/0.131/0.037 ms
[root@0a10f82ad3ea /]#