技术干货|一杯咖啡的时间教你玩转flannel(二)

2018-03-05技术干货

上次我们讲到不同backend的配置方式完全不同,下面我们就对各种backend的基本原理进行解析,并说明它们如何处理EventAdded和EventRemoved这两类事件。

 
3. backend原理解析

在本节中,我们将对hostgw,udp和vxlan三种backend进行解析。

 
3.1 hostgw

hostgw是最简单的backend,它的原理非常简单,直接添加路由,将目的主机当做网关,直接路由原始封包。

例如,我们从etcd中监听到一个EventAdded事件subnet为10.1.15.0/24被分配给主机Public IP 192.168.0.100,hostgw要做的工作就是在本主机上添加一条目的地址为10.1.15.0/24,网关地址为192.168.0.100,输出设备为上文中选择的集群间交互的网卡即可。对于EventRemoved事件,只需删除对应的路由。

 
3.2 udp

我们知道当backend为hostgw时,主机之间传输的就是原始的容器网络封包,封包中的源IP地址和目的IP地址都为容器所有。这种方法有一定的限制,就是要求所有的主机都在一个子网内,即二层可达,否则就无法将目的主机当做网关,直接路由。

而udp类型backend的基本思想是:既然主机之间是可以相互通信的(并不要求主机在一个子网中),那么我们为什么不能将容器的网络封包作为负载数据在集群的主机之间进行传输呢?这就是所谓的overlay。具体过程如下所示:

当容器10.1.15.2/24要和容器10.1.20.2/24通信时,因为该封包的目的地不在本主机subnet内,因此封包会首先通过网桥转发到主机中。最终在主机上经过路由匹配,进入网卡flannel0。需要注意的是flannel0是一个tun设备,它是一种工作在三层的虚拟网络设备,而flanneld是一个proxy,它会监听flannel0并转发流量。当封包进入flannel0时,flanneld就可以从flannel0中将封包读出,由于flannel0是三层设备,所以读出的封包仅仅包含IP层的报头及其负载。最后flanneld会将获取的封包作为负载数据,通过udp socket发往目的主机。同时,在目的主机的flanneld会监听Public IP所在的设备,从中读取udp封包的负载,并将其放入flannel0设备内。由此,容器网络封包到达目的主机,之后就可以通过网桥转发到目的容器了。

最后和hostgw不同的是,udp backend并不会将从etcd中监听到的事件里所包含的lease信息作为路由写入主机中。每当收到一个EventAdded事件,flanneld都会将其中的subnet和Public IP保存在一个数组中,用于转发封包时进行查询,找到目的主机的Public IP作为udp封包的目的地址。

 
3.3 vxlan

首先,我们对vxlan的基本原理进行简单的叙述。从下图所示的封包结构来看,vxlan和上文提到的udp backend的封包结构是非常类似的,不同之处是多了一个vxlan header,以及原始报文中多了个二层的报头。

下面让我们来看看,当有一个EventAdded到来时,flanneld如何进行配置,以及封包是如何在flannel网络中流动的。

如上图所示,当主机B加入flannel网络时,和其他所有backend一样,它会将自己的subnet 10.1.16.0/24和Public IP 192.168.0.101写入etcd中,和其他backend不一样的是,它还会将vtep设备flannel.1的mac地址也写入etcd中。

之后,主机A会得到EventAdded事件,并从中获取上文中B添加至etcd的各种信息。这个时候,它会在本机上添加三条信息:

1) 路由信息:所有通往目的地址10.1.16.0/24的封包都通过vtep设备flannel.1设备发出,发往的网关地址为10.1.16.0,即主机B中的flannel.1设备。

2) fdb信息:MAC地址为MAC B的封包,都将通过vxlan首先发往目的地址192.168.0.101,即主机B

3)arp信息:网关地址10.1.16.0的地址为MAC B

现在有一个容器网络封包要从A发往容器B,和其他backend中的场景一样,封包首先通过网桥转发到主机A中。此时通过,查找路由表,该封包应当通过设备flannel.1发往网关10.1.16.0。通过进一步查找arp表,我们知道目的地址10.1.16.0的mac地址为MAC B。到现在为止,vxlan负载部分的数据已经封装完成。由于flannel.1是vtep设备,会对通过它发出的数据进行vxlan封装(这一步是由内核完成的,相当于udp backend中的proxy),那么该vxlan封包外层的目的地址IP地址该如何获取呢?事实上,对于目的mac地址为MAC B的封包,通过查询fdb,我们就能知道目的主机的IP地址为192.168.0.101。

最后,封包到达主机B的eth0,通过内核的vxlan模块解包,容器数据封包将到达vxlan设备flannel.1,封包的目的以太网地址和flannel.1的以太网地址相等,三层封包最终将进入主机B并通过路由转发达到目的容器。

事实上,flannel只使用了vxlan的部分功能,由于VNI被固定为1,本质上工作方式和udp backend是类似的,区别无非是将udp的proxy换成了内核中的vxlan处理模块。而原始负载由三层扩展到了二层,但是这对三层网络方案flannel是没有意义的,这么做也仅仅只是为了适配vxlan的模型。vxlan详细的原理参见文后的参考文献,其中的分析更为具体,也更易理解。

 
4. 总结

总的来说,flannel更像是经典的桥接模式的扩展。我们知道,在桥接模式中,每台主机的容器都将使用一个默认的网段,容器与容器之间,主机与容器之间都能互相通信。要是,我们能手动配置每台主机的网段,使它们互不冲突。接着再想点办法,将目的地址为非本机容器的流量送到相应主机:如果集群的主机都在一个子网内,就搞一条路由转发过去;若是不在一个子网内,就搞一条隧道转发过去。这样以来,容器的跨网络通信问题就解决了。而flannel做的,其实就是将这些工作自动化了而已。

 

End

 

参考文献:

1. flannel源码:https://github.com/coreos/flannel

2.《vxlan协议原理解析》:http://cizixs.com/2017/09/25/vxlan-protocol-introduction

3.《linux上实现vxlan网络》:http://cizixs.com/2017/09/28/linux-vxlan

4.《VxLAN和VTEP》:http://maoxiaomeng.com/2017/07/31/vxlan%E5%92%8Cvtep/

电子邮件地址不会被公开。 必填项已用*标注