EvenChan's Ops.

flannel跨主网络通信方案(UDP、VXLAN、HOST-GW)详解

字数统计: 2.5k阅读时长: 9 min
2020/06/21

  本文中,笔者主要结合自己使用flannel心得,以及flannel的技术演进,介绍下flannel网络实现方案。在没有介绍flannel overlay网络实现方案之前,先回顾下docker网络实现方案。

docker网络模式有哪些?

bridge、host、none 新版本docker出现了macvlan、overlay跨主机网络通信方案。

★ 桥接模式是如何实现的呢?

首先docker在默认安装情况下,启动之后会默认建立docker0 linux网桥设备、该网桥设备拥有一个私有网络地址以及子网,通常使用子网中第一个没有被占用的地址。比如:172.16.0.1;

然后docker容器在启动的时候会连接到网桥设备上,并分配一个子网地址。容器连接到网桥的网络接口会把docker0设备作为网关。创建容器时,docker会创建一对网络设备接口,并把他们放到独立的命名空间中:一个网络设备放到容器的网络命名空间中eth0,另一个网络设备会放到宿主机网络空间中,例如:veth80025c52,并连接到docker0网桥设备上。所以如果仔细观察容器内部网卡设备信息和宿主机的网卡信息,你会发现这一对网络设备是一一对应的。当然宿主机上其它容器也会连接到docker0网桥设备上,这样就实现了宿主机内容器的通信;

最后容器绑定到网桥设备之后,如果需要访问外网,那么借助于linuxIP转发规则,以及docker引擎管理的防火墙规则以及nat功能,实现了外部网络的访问。


flannel三层网络实现方式

★ 需求描述:node1(11.101.1.2)上的container1(10.244.0.13)需要跨主机访问node2(11.101.1.3)上的container2(10.244.1.14)。对于flannel是如何实现的呢?img


UDP跨主通信模式

img

如上图所示:首先flannel会在各个节点上创建路由规则,这些路由规则存储在etcd中,跟宿主机节点IP一一对应。

然后在node1上,container1跨主访问node2上的container2,因为container2IP地址为10.244.1.14,根据路由规则,从而进入到flannel0设备中。

最后flannel0看到container1要访问的IP地址为10.244.1.14的容器,因为flanneletcd中存储着子网和宿主机ip的对应关系,所以能够找到10.244.1.14对应的宿主机IP11.101.1.3,进而开始组装UDP数据包发送数据到目的主机。当然这个请求得以完成的原因每个节点上都启动着一个flanneld udp进程,都监听着8285端口,所以node1通过flanneld进程把数据包发送给node2flanneld进程的相应端口即可。

可以看出flannel UDP模式提供了一个三层OverLay网络,这就好比在不同宿主机的容器上打通了一条隧道,容器不用关心IP地址即可直接通信。它首先对发出端的数据包进行UDP封装,然后在接收端进行解包,进而把包发送到目的容器地址。但是这里面有一个非常严重的问题,就是flannel UDP进程运行在用户态,而数据的交互和传递则在内核态完成,这就造成了为了传递数据,需要内核态和用户态的频繁切换,这个切换过程有一定性能损耗代价,所以UDP模式已经废弃。


VXLAN跨主通信模式

VXLAN(Vitrue Extension lan虚拟可扩展局域网)Linux本身支持的一种虚拟可扩展局域网。VXLAN完全在内核态完成上述封包和解包的过程。从而通过前面的隧道机制完成overlay 覆盖网络。rfc7348详细地介绍了VXLAN的实现机制。本质上VXLAN是一种隧道技术。通过将虚拟网络中的数据帧封装在实际物理网络中的报文中进行传输。具体实现方式为:将虚拟网络的数据帧添加VXLAN首部后,封装在物理网络中的UDP报文中,然后以传统网络的通信方式传送该UDP报文,到达目的主机后,去掉物理网络报文的头部信息以及VXLAN首部,将报文交付给目的终端。整个通信过程目的终端不会感知到物理网络的存在。


  • VXLAN技术组网过程!
    img
    图中两台终端T1和T2位于不同的网络中,二者通过路由器来实现互通,通过VXLAN可以使得这两台终端在“逻辑上”位于“同一个”链路层网络中而与两台终端直接相连的路由器也在逻辑上构建了一条在虚拟链路中的通道vxlan tunnel,这样的路由器我们称之为vxlan隧道终端(VXLAN Tunnel End Point, VTEP)。在包含VXLAN的网络中,VXLAN的实现机制仅仅对VTEP节点可见。

  • VXLAN通信原理
    img
    VXLAN通过将逻辑网络中通信的数据帧封装在物理网络中进行传输,封装和解封装的过程由VTEP节点完成。VXLAN将逻辑网络中的数据帧添加VXLAN首部后,封装在物理网络中的UDP报文中传送,VXLAN首部的格式如下:
    img
    VXLAN首部由8个字节组成,第1个字节为标志位,其中标志位I设为1表示是一个合法的VXLAN首部,其余标志则保留,在传输过程中必须置为0;第2-4字节为保留部分,第5-7字节为VXLAN标识符,用来表示唯一的一个逻辑网络;第8个字节同样为保留字段,暂未使用。VXLAN传输过程中,将逻辑链路网络的数据帧添加VXLAN首部后,依次添加UDP首部,IP首部,以太网帧首部后,在物理网络中传输,数据帧的封装格式可以用下图来描述:
    img
    需要注意的是,外部UDP首部的目的端口号为4789,该数值为默认VXLAN解析程序的端口,外层IP首部中的源IP和目的IP地址均填写通信双方的VTEP地址,协议的其余部分和传统网络相同。

  • 通信过程

对于处于同一个VXLAN的两台虚拟终端,其通信过程可以概括为如下的步骤:

  1. 发送方向接收方发送数据帧,帧中包含了发送方和接收方的虚拟MAC地址。

  2. 发送方连接的VTEP节点收到了数据帧,通过查找发送方所在的VXLAN以及接收方所连接的VTEP节点,将该报文添加VXLAN首部、外部UDP首部、外部IP首部后,发送给目的VTEP节点。

  3. 报文经过物理网络传输到达目的VTEP节点。

  4. 目的VTEP节点接收到报文后,拆除报文的外部IP首部和外部UDP首部,检查报文的VNI以及内部数据帧的目的MAC地址,确认接收方与本VTEP节点相连后,拆除VXLAN首部,将内部数据帧交付给接收方。

  5. 接收方收到数据帧,传输完成。

通过以上的步骤可以看出:VXLAN的实现细节以及通信过程对于处于VXLAN中的发送方和接收方是不可见的,基于发送方和接收方的视角,其通信过程和二者真实处于同一链路层网络中的情况完全相同。


对于Kubernetes flannel也是完全依赖linux vxlan实现了overlay的跨主网络通信,如下图所示:
img


从形式和流程上看,这个通信过程和上面基于UDP的通信方式是非常类似的,只不过flannel UDP进程换成了VTEP设备,通过VTEP设备完成封包和解包的过程,另外一点这个过程完全在内核中完成。flannel.1充当网桥的角色,进行UDP数据包的转发。其中vxlan的通信过程也是flannel网络插件中默认的通信方式,如下图所示:

img

巨人的肩膀:

1
https://blog.csdn.net/jsh13417/article/details/80303098

host-gw跨主通信方式

host-gw的工作原理就是将每个flannel子网转发地址设置成了该子网对应的宿主机的IP地址,通过这个过程,容器在通信过程中就减少了封包和解包的性能损耗。如下图所示:

img

  1. UDP、VXLAN模式一致,通过容器A的路由表IP包到达cni0,到达cni0IP包匹配到node1中的路由规则(10.244.1.1/24),且网关为11.101.1.3,即主机node2,所以内核将IP包发送给node2,IP包通过物理网络到达node2eth0;

  2. 到达node2eth0IP包匹配到node2上的路由表(10.244.0.1/24)IP包转发给cni0, cni0IP包转发给连接在cni0上的Container2

通过上述这个过程可以看出这台主机的host就充当了容器通信路径里的网关,IP封装成帧的时候,会使路由表中的下一跳来设置目的MAC地址,它会经过二层网络达到宿主机,但同时这个限制也是有问题的,首先要求我们必须保证集群内部所有主机二层网络必须是连通的,然后在大规模集群路由表的动态更新也存在一定压力。采用host-gw模式后,flanneld的唯一作用就是负责主机上路由表的动态更新。当然这个限制也是有解决方案的,这里不在过多介绍,详细可以了解Calico


总结

通过如上过程,我们可以看到flannelUDP、wxlan、host-gw网络通信方案的技术演进过程,通过一系列的演进使得架构更简单、同时性能得到了提高。如有问题请留言或者关注后拉你进群讨论。希望能够帮助到大家,谢谢阅读!

CATALOG
  1. 1. flannel三层网络实现方式
    1. 1.1. UDP跨主通信模式
    2. 1.2. VXLAN跨主通信模式
    3. 1.3. host-gw跨主通信方式
  2. 2. 总结