- Kubernetes网络权威指南:基础、原理与实践
- 杜军
- 2841字
- 2020-08-27 19:36:57
1.8 物理网卡的分身术:Macvlan
最早版本的Docker是不支持容器网络与宿主机网络直接互通的。从Docker 1.12版本开始,为了解决容器的跨机通信问题引入了overlay和Macvlan网络,其中Macvlan支持容器之间使用宿主机所在网段资源。在介绍Kubernetes网络插件的章节会详细讨论overlay网络,本节将重点介绍Macvlan。除了在容器中有着广泛应用,Macvlan/Macvtap设备也大量应用在虚拟机场景。
1.8.1 Macvlan五大工作模式解析
通常,我们在自定义Docker与外部网络通信的网络时会用到NAT,还有Linux bridge、Open vSwitch、Macvlan几种选择,相比之下,Macvlan拥有更好的性能。
在Macvlan出现之前,我们可以通过网卡别名(例如eth0:1)的方式为一块以太网卡添加多个IP地址,却不能为其添加多个MAC地址。原因是以太网卡是以MAC地址为唯一识别的,而网卡别名并没有改变这些网卡的MAC地址。
Macvlan接口可以看作是物理以太网接口的虚拟子接口。Macvlan允许用户在主机的一个网络接口上配置多个虚拟的网络接口,每个Macvlan接口都有自己的区别于父接口的MAC地址,并且可以像普通网络接口一样分配IP地址。因此,使用Macvlan技术带来的效果是一块物理网卡上可以绑定多个IP地址,每个IP地址都有自己的MAC地址。
用Macvlan虚拟出来的虚拟网卡,在逻辑上和物理网卡是对等的,应用程序可以像使用物理网卡的IP地址那样使用Macvlan设备的IP地址。Macvlan所连接的物理接口通常称为“下部设备”或“上部设备”,方便起见,且与下文要介绍的IPvlan保持一致,称物理接口为父接口,Macvlan设备为子接口。有时,我们也形象地称Macvlan“寄生”在宿主机的物理网卡上。
Macvlan的主要用途是网络虚拟化(包括容器和虚拟机)。另外,有一些比较特殊的场景,例如,keepalived使用虚拟MAC地址。需要注意的是,使用Macvlan的虚拟机或者容器网络与主机在同一个网段,即同一个广播域中。
Macvlan支持5种模式,分别是bridge、VEPA、Private、Passthru和Source模式。
1. bridge模式
该模式类似Linux bridge,是Macvlan最常用的模式,比较适合共享同一个父接口的Macvlan网卡进行直接通信的场景。在bridge模式下,拥有相同父接口的两块Macvlan虚拟网卡可以直接通信,不需要把流量通过父接口发送到外部网络,广播帧将会被洪泛到连接在“网桥”上的所有其他子接口和物理接口。网桥带双引号是因为实际上并没有网桥实体的产生,而是指在这些网卡之间数据流可以实现直接转发,这有点类似于Linux网桥。但Macvlan的bridge模式和Linux网桥不是一回事,它不需要学习MAC地址,也不需要生成树协议(STP),因此性能要优于Linux网桥。Macvlan bridge模式如图1-26所示。
图1-26 Macvlan bridge模式
bridge模式的缺点是如果父接口故障,所有Macvlan子接口会跟着故障,子接口之间也将无法进行通信。
2. VEPA模式
VEPA(Virtual Ethernet Port Aggregator,虚拟以太网端口聚合)是默认模式。所有从Macvlan接口发出的流量,不管目的地址是什么,全部“一股脑”地发送给父接口——即使流量的目的地是共享同一个父接口的其他Macvlan接口。在二层网络下,由于生成树协议的原因,两个Macvlan接口之间的通信会被阻塞,这时就需要接入的外部交换机支持hairpin,把源和目的地址都是本地Macvlan接口地址的流量,发给相应的接口。在VEPA模式下,从父接口收到的广播包会洪泛给所有的子接口。Macvlan VEPA模式如图1-27所示。
图1-27 Macvlan VEPA模式
目前,大多数交换机都不支持hairpin模式,但Linux可以通过一种hairpin模式的网桥,让VEPA模式下的Macvlan接口能够直接通信(前文已经提到,我们可以把Linux网桥看作二层交换机)。接下来,配置Linux网桥某个端口的hairpin模式:
以上命令的作用是配置Linux网桥br0,使得从eth0收到包后再从eth0发送出去。
以上brctl haripin子命令原型是:
或者使用iproute2直接设置网卡的hairpin模式:
也可以通过写sysfs目录下的设备文件设置网桥某个端口的hairpin模式。下面的例子设置了网桥br0的eth1端口的hairpin:
配置了hairpin后,源地址和目的地址都是本地Macvlan接口地址的流量,会被Linux网桥发回给相应的接口。
如果想在物理交换机层面对虚拟机或容器之间的访问流量进行优化设定,VEPA模式是一种比较好的选择。
3. Private模式
Private模式类似于VEPA模式,但又增强了VEPA模式的隔离能力,其完全阻止共享同一父接口的Macvlan虚拟网卡之间的通信。即使配置了hairpin,让从父接口发出的流量返回宿主机,相应的通信流量依然被丢弃。Macvlan Priviate模式如图1-28所示。
图1-28 Macvlan Private模式
Private的具体实现方式是丢弃广播/多播数据,这就意味着以太网地址解析ARP将无法工作。除非手工探测MAC地址,否则通信将无法在同一宿主机下的多个Macvlan网卡间进行。
如果需要Macvlan的隔离功能,那么Private模式会非常有用。
4. Passthru模式
Passthru模式翻译过来就是直通模式。在这种模式下,每个父接口只能和一个Macvlan网卡捆绑,并且Macvlan网卡继承父接口的MAC地址。Macvlan Passthru模式如图1-29所示。
图1-29 Macvlan Passthru模式
在VEPA和Passthru模式下,两个Macvlan网卡之间的通信会经过父接口两次——第一次是发出的时候,第二次是返回的时候。除了限制了Macvlan接口之间的通信性能,还影响物理接口的宽带。
5. Source模式
在这种模式下,寄生在物理设备上,Macvlan设备只接收指定的源Mac地址的数据包,其他数据包一概丢弃。
1.8.2 测试使用Macvlan设备
在宿主机上创建Macvlan设备:
查看该Macvlan网卡的详细信息:
这时,Macvlan网卡eth0.1的设备状态为DOWN,启用它:
一般情况下,Macvlan设备的MAC地址是Linux系统自动分配的,用户也可以自定义。使用以下命令就可在新建Macvlan网卡的同时指定其MAC地址:
如果要删除Macvlan网卡,则只需简单调用以下命令:
1.8.3 Macvlan的跨机通信
我们的实验环境包含两个节点,分别是A节点,IP地址为192.168.1.2;B节点,IP地址为192.168.1.3。直接使用Docker容器进行下面的实验。如果读者对Docker还不熟悉,则可以阅读第2章的内容提前获取必要的背景知识。
先在A节点上创建一个不带网络初始化的Docker容器:
同时,获取新创建容器对应的PID:
然后创建Macvlan设备:
再将Macvlan设备eth0.1放入容器的网络namespace中:
进入网络namespace中配置Macvlan网卡:
如上所示,Macvlan设备启用后会自动分配MAC地址而没有IP(v4)地址。我们为其分配IP地址并设置网关。
现在,我们可以从主机B上访问容器test1,如下所示:
从主机A上ping容器test1,发现不通:
这是什么原因呢?在Macvlan虚拟网络世界中,物理网卡(父接口)相当于一个交换机,对于进出其子Macvlan网卡的数据包,物理网卡只转发数据包而不处理数据包,于是也就造成了使用本机Macvlan网卡的IP无法和物理网卡的IP通信。
总结,Macvlan只为虚拟机或容器提供访问外部物理网络的连接。
1.8.4 Macvlan与overlay对比
Macvlan和overlay都是Docker原生提供的网络方案,但是Macvlan和overlay网络的工作方式有所不同。
首先,Macvlan和overlay的网络作用范围不一样。overlay是全局作用范围类型的网络,而Macvlan的作用范围只是本地。举例来说,全局类型的网络可以作用于一个Docker集群,而本地类型的网络只作用于一个Docker节点。
其次,每个宿主机创建的Macvlan网络都是独立的,一台机器上创建的Macvlan网络并不影响另一台机器上的网络。但这并不意味着两台Macvlan的主机不能通信,当同时满足以下两个条件时,可以实现Macvlan网络的跨主机通信:
(1)通信两端的主机在网卡配置混杂模式。
(2)两台主机上的Macvlan子网IP段没有重叠。
1.8.5 小结
Macvlan是将虚拟机或容器通过二层连接到物理网络的一个不错的方案,但它也有一些局限性,例如:
·因为每个虚拟网卡都要有自己的MAC地址,所以Macvlan需要大量的MAC地址,而Linux主机连接的交换机可能会限制一个物理端口的MAC地址数量上限,而且许多物理网卡的MAC地址数量也有限制,超过这个限制就会影响到系统的性能;
·IEEE 802.11标准(即无线网络)不喜欢同一个客户端上有多个MAC地址,这意味着你的Macvlan子接口没法在无线网卡上通信。
我们可以通过复杂的办法突破以上这些限制,但还有一种更简单的办法。那就是使用IPvlan。