Linux虚拟化基础

1 阅读12分钟

配资network namespace

Linux的namespace(名字空间)的作用就是隔离内核资源。在Linux的世界里,文件系统挂载点、主机名、POSIX进程间通信消息队列、进程PID数字空间、IP地址、user ID数字空间等全局系统资源被namespace分割,装到一个个抽象的独立空间里。而隔离上述系统资源的namespace分别是Mount namespace、UTS namespace、IPC namespace、PID namespace、network namespace和user namespace。对进程来说,要想使用namespace里面的资源,首先要进入(具体操作方法,下文会介绍)到这个namespace,而且还无法跨namespace访问资源。Linux的namespace给里面的进程造成了两个错觉:

(1)它是系统里唯一的进程。

(2)它独享系统的所有资源。

默认情况下,Linux进程处在和宿主机相同的namespace,即初始的根namespace里,默认享有全局系统资源。

通过Linux的network namespace技术可以自定义一个独立的网络栈,简单到只有loopback设备,复杂到具备系统完整的网络能力,这就使得network namespace成为Linux网络虚拟化技术的基石——不论是虚拟机还是容器时代。network namespace的另一个隔离功能在于,系统管理员一旦禁用namespace中的网络设备,即使里面的进程拿到了一些系统特权,也无法和外界通信。最后,网络对安全较为敏感,即使network namespace能够提供网络资源隔离的机制,用户还是会结合其他类型的namespace一起使用,以提供更好的安全隔离能力。

容器与host veth pair

部署过Docker或Kubernetes的读者肯定有这样的经历:在主机上输入ifconfig或ip addr命令查询网卡信息的时候,总会出来一大堆vethxxxx之类的网卡名,这些是Docker/Kubernetes为容器而创建的虚拟网卡。

veth是虚拟以太网卡(Virtual Ethernet)的缩写。veth设备总是成对的,因此我们称之为veth pair。veth pair一端发送的数据会在另外一端接收,非常像Linux的双向管道。根据这一特性,veth pair常被用于跨network namespace之间的通信,即分别将veth pair的两端放在不同的namespace里

容器中的eth0实际上和外面host上的某个veth是成对的(pair)关系,那么,有没有办法知道host上的vethxxx和哪个container eth0是成对的关系呢?

方法1

首先,在目标容器里查看:

然后,在主机上遍历/sys/claas/net下面的全部目录,查看子目录ifindex的值和容器里查出来的iflink值相当的veth名字,这样就找到了容器和主机的veth pair关系。例如,下面的例子中主机上veth63a89a3的ifindex刚好是5,意味着是目标容器veth pair的另一端。

方法2

在目标容器里执行以下命令:

从上面的命令输出可以看到116:eth0@if117,其中116是eth0接口的index,117是和它成对的veth的index。

当host执行下面的命令时,可以看到对应117的veth网卡是哪一个,这样就得到了容器和veth pair的关系。

方法3

可以通过ethtool-S命令列出veth pair对端的网卡index,例如:

Linux bridge连接

两个network namespace可以通过veth pair连接,但要做到两个以上network namespace相互连接,veth pair就显得捉襟见肘了。

Linux bridge有牵线搭桥之意,用于连接两个不同的局域网,是网线的延伸。网桥是二层网络设备,两个端口分别有一条独立的交换信道,不共享一条背板总线,可隔离冲突域。网桥比集线器(hub)性能更好,集线器上各端口都是共享同一条背板总线的。后来,网桥被具有更多端口、可隔离冲突域的交换机(switch)所取代。

顾名思义,Linux bridge就是Linux系统中的网桥,但是Linux bridge的行为更像是一台虚拟的网络交换机,任意的真实物理设备(例如eth0)和虚拟设备(例如,前面讲到的veth pair和后面即将介绍的tap设备)都可以连接到Linux bridge上。需要注意的是,Linux bridge不能跨机连接网络设备。

Linux bridge与Linux上其他网络设备的区别在于,普通的网络设备只有两端,从一端进来的数据会从另一端出去。例如,物理网卡从外面网络中收到的数据会转发给内核协议栈,而从协议栈过来的数据会转发到外面的物理网络中。Linux bridge则有多个端口,数据可以从任何端口进来,进来之后从哪个口出去取决于目的MAC地址,原理和物理交换机差不多。

1.虚拟机

虚拟机通过tun/tap或者其他类似的虚拟网络设备,将虚拟机内的网卡同br0连接起来,这样就达到和真实交换机一样的效果,虚拟机发出去的数据包先到达br0,然后由br0交给eth0发送出去,数据包都不需要经过host机器的协议栈,效率高

2.容器

容器运行在自己单独的network namespace里,因此都有自己单独的协议栈。Linux bridge在容器场景的组网和上面的虚拟机场景差不多,但也存在一些区别。例如,容器使用的是veth pair设备,而虚拟机使用的是tun/tap设备。在虚拟机场景下,我们给主机物理网卡eth0分配了IP地址;而在容器场景下,我们一般不会对宿主机eth0进行配置。在虚拟机场景下,虚拟器一般会和主机在同一个网段;而在容器场景下,容器和物理网络不在同一个网段内。

混杂模式(Promiscuous mode),简称Promisc mode,俗称监听模式。混杂模式通常被网络管理员用来诊断网络问题,但也会被无认证的、想偷听网络通信的人利用。根据维基百科的定义,混杂模式是指一个网卡会把它接收的所有网络流量都交给CPU,而不是只把它想转交的部分交给CPU

Linux IPtables

iptables在Docker和Kubernetes网络中应用甚广。例如,Docker容器和宿主机的端口映射、Kubernetes Service的默认模式、CNI的portmap插件、Kubernetes网络策略等都是通过iptables实现的

iptables的底层实现是netfilter。netfilter是Linux内核2.4版引入的一个子系统,最初由Linux内核防火墙和网络的维护者Rusty Russell提出。它作为一个通用的、抽象的框架,提供一整套hook函数的管理机制,使得数据包过滤、包处理(设置标志位、修改TTL等)、地址伪装、网络地址转换、透明代理、访问控制、基于协议类型的连接跟踪,甚至带宽限速等功能成为可能。netfilter的架构就是在整个网络流程的若干位置放置一些钩子,并在每个钩子上挂载一些处理函数进行处理。

IP层的5个钩子点的位置,对应iptables就是5条内置链,分别是PREROUTING、POSTROUTING、INPUT、OUTPUT和FORWARD。

我们常说的iptables 5X5,即5张表(table)和5条链(chain)。5条链即iptables的5条内置链,对应上文介绍的netfilter的5个钩子。这5条链分别是:

·INPUT链:一般用于处理输入本地进程的数据包;

·OUTPUT链:一般用于处理本地进程的输出数据包;

·FORWARD链:一般用于处理转发到其他机器/network namespace的数据包;

·PREROUTING链:可以在此处进行DNAT;

·POSTROUTING链:可以在此处进行SNAT。

5张表如下所示。

·filter表:用于控制到达某条链上的数据包是继续放行、直接丢弃(drop)或拒绝(reject);

·nat表:用于修改数据包的源和目的地址;

·mangle表:用于修改数据包的IP头信息;

·raw表:iptables是有状态的,即iptables对数据包有连接追踪(connection tracking)机制,而raw是用来去除这种追踪机制的;

·security表:最不常用的表(通常,我们说iptables只有4张表,security表是新加入的特性),用于在数据包上应用SELinux。

linux隧道ipip

tun设备也叫作点对点设备,之所以叫这个名字,是因为tun经常被用来做隧道通信(tunnel)。

我们可以通过命令ip tunnel help查看IP隧道的相关操作。Linux原生支持下列5种L3隧道:

·ipip:即IPv4 in IPv4,在IPv4报文的基础上封装一个IPv4报文;

·GRE:即通用路由封装(Generic Routing Encapsulation),定义了在任意一种网络层协议上封装其他任意一种网络层协议的机制,适用于IPv4和IPv6;

·sit:和ipip类似,不同的是sit用IPv4报文封装IPv6报文,即IPv6 over IPv4;

·ISATAP:即站内自动隧道寻址协议(Intra-Site Automatic Tunnel Addressing Protocol),与sit类似,也用于IPv6的隧道封装;

·VTI:即虚拟隧道接口(Virtual Tunnel Interface),是思科提出的一种IPSec隧道技术。下面我们以ipip为例,介绍Linux隧道[…]

Linux隧道网络的代表:VXLAN

VLAN技术的缺陷是VLAN Header预留的长度只有12 bit,故最多只能支持2的12次方(4096)子网的划分,无法满足云计算场景下主机数量日益增长的需求。VXLAN能突破VLAN的最多4096个子网的数量限制,以满足大规模云计算数据中心的需求。具体来说,VXLAN技术解决以下几个问题:

·当前VXLAN的报文Header内有24 bit,可以支持2的24次方个子网,并通过VNI(Virtual Network Identifier)区分不同的子网,相当于VLAN中的LAN ID;

注:多播地址让源设备能够将分组发送给一组设备。属于多播组的设备将被分配一个多播组IP地址,多播地址范围为224.0.0.0~239.255.255.255。

为什么要引入多播。从多播的流程可以看出,其实隧道网络发送报文最关键的就是要知道对方虚拟机/容器的MAC地址及所在主机的VTEP IP地址。对overlay网络来说,它的网段范围是分布在多个主机上的,因此传统ARP报文的广播无法直接使用。要想做到overlay网络的广播,必须把报文发送到所有VTEP在的节点,这才使用了多播。如果能够事先知道MAC地址和VTEP IP信息,直接告诉发送方VTEP,就不需要多播了。

在虚拟机和容器的场景中,当虚拟机或者容器还没有进行网络通信时,我们就可以知道它的IP和MAC(可能是用某种方式获取,也可能是事先控制这两个地址),分布式控制中心保存了这些信息。除此之外,控制中心还保存了每个VXLAN网络的VTEP,以及这些VTEP的地址。有了这些信息,VTEP就能在发送报文时直接查询并添加头部,不需要多播去满网络地问。

VXLAN协议给虚拟网络带来了灵活性和扩展性,让云计算网络能够像计算、存储资源那样按需扩展,并灵活分布。与此同时,VXLAN也带来了额外的复杂度和性能开销。性能开销主要包含两个方面:

·每个VXLAN报文都有额外的50字节开销,加上VXLAN字段,开销要到54字节。这对于小报文的传输是非常昂贵的操作。试想,如果某个报文应用数据才几个字节,那么原来的网络头部加上VXLAN报文头部就有100字节的控制信息;

·每个VXLAN报文的封包和解包操作都是必需的,如果用软件来实现这些步骤,则额外的计算量是不可忽略的影响因素。

多播实现很简单,不需要中心化的控制。不是所有的网络都支持多播,需要事先规划多播组和VNI的对应关系,在overlay网络数量比较多时也会很麻烦,多播会导致大量的无用报文出现在网络中。很多云计算的网络通过自动化的[…]

物理网卡的分身术:

Macvlan

最早版本的Docker是不支持容器网络与宿主机网络直接互通的。从Docker 1.12版本开始,为了解决容器的跨机通信问题引入了overlay和Macvlan网络,其中Macvlan支持容器之间使用宿主机所在网段资源。

在自定义Docker与外部网络通信的网络时会用到NAT,还有Linux bridge、Open vSwitch、Macvlan几种选择,相比之下,Macvlan拥有更好的性能。

IPvlan

与Macvlan类似,IPvlan也是从一个主机接口虚拟出多个虚拟网络接口。区别在于IPvlan所有的虚拟接口都有相同的MAC地址,而IP地址却各不相同。因为所有的IPvlan虚拟接口共享MAC地址,所以特别需要注意DHCP使用的场景。DHCP分配IP地址的时候一般会用MAC地址作为机器的标识。因此,在使用Macvlan的情况下,客户端动态获取IP的时候需要配置唯一的Client ID,并且DHCP服务器也要使用该字段作为机器标识,而不是使用MAC地址。

我们将IPvlan称为Macvlan的救护员是因为IPvlan除了能够完美解决以上问题,还允许用户基于IPvlan搭建比较复杂的网络拓扑,不再基于Macvlan的简单的二层网络,而是能够与BGP(Boader Gateway Protocol,边界网关协议)等协议扩展我们的网络边界。