k8s(十六): VXLAN和Flannel

前言

目前k8s中比较常用的cni有calico、flannel、kube-router等,个人比较熟悉的是kube-router的bgp纯直通方案,flannel则是另一款使用较多的比较简单易用的方案,这里着重了解一下flannel的vxlan这一常用模式

VXLAN

在了解flannel之前,有必要掌握vxlan的基础知识。首先来看看vxlan协议的报文封装格式:
k8s(十六): VXLAN和Flannel_第1张图片

说明:

vxlan,给数据中心大二层网络使用,何为大二层,又为何需要vxlan?

1.vlan数量有限

vlan的tag位一个4个字节,其中12bit是给vlan id使用,也即是一共有4096个vlan id支持,在大型数据中心中不够用,但这个问题其实QinQ(IEEE 802.1 ad)标准可以解决,重点原因是因为第二点

2.mac地址表限制

虚拟化/容器化场景下,一台物理机内部有众多虚拟网卡,而外部的二层设备(交换机)是将mac地址都缓存入内存中的,且交换机内存空间一般较小,在虚拟化的数据中心中,如果mac表满了,会出现大量的广播泛洪,造成
极大的网络资源和计算资源的浪费

3.灵活部署限制

如果虚机和物理机之间使用桥接网络,那么虚拟机则同样受物理机网络的限制,只能使用那一个vlan的地址,不同vlan下的虚机受制于vlan无法顺畅的进行互相迁移,容易主机的资源利用率的不均衡。虽然可以通过物理机与交换设备全部通过trunk的方式连接来解决vlan切换这个问题,但是这样无疑会形成一个巨大的传统二层网络空间,相应的BUM(Broadcast,Unknown Unicast,Multicast)风暴和交换机MAC地址表的问题也会随之产生,这是无法接受的。

那么vxlan是怎么解决上面几个问题的呢?

从上面的报文封装图可以看出,vxlan外层(二层头部、三层头部)继续沿用现有标准,只是在传输层,使用了udp封装,udp封装之内,就是vxlan的协议封装。VXLAN Tunnel EndPoint(简称VTE, 是指支持vxlan封装、拆包的交换设备,一般可理解为承载着虚拟机的物理机),通过vxlan header内部封装的信息,拆包后直接将original layer 2 frame数据,转发给相应的虚拟网卡。

如此,在外部的网络设备层面,vxlan保持着传统的通信方式,即各个VTE之间以UDP的方式互相通信;而在VTE层面,则通过报文封装,实现了内部众多的虚拟网卡mac地址之间的数据交换:
其一,24bit的VNID标识,实现了1600多万个不同二层子网的区分;
其二,通过报文封装的格式,
其三,通过VXLAN的封装,实现了虚拟网卡之间越过传统三层网络,以特殊的二层数据帧交换的方式通信,走的是一套独立于物理网络(underlay network)的overlay network,在物理网络上可以保持不变,但是同时,虚拟机的部署和迁移,又不用受物理网络的限制,有利于物理资源利用率维持均衡

以上也就是为什么vxlan又称为虚拟大二层网络,有了以上基础铺垫,下面来简述一下flannel 的vxlan实现的工作具体流程。

Flannel

按照惯例,先上流程图:

k8s(十六): VXLAN和Flannel_第2张图片

步骤详解:

源端:

1)源容器veth0向目标容器发送数据,根据容器内的默认路由,数据首先发送给宿主机的docker0网桥
2)宿主机docker0网桥接受到数据后,宿主机查询路由表,pod相关的路由都是交由flannel.1网卡,因此,将其转发给flannel.1虚拟网卡处理
3)flannel.1接受到数据后,查询etcd数据库,获取目标pod网段对应的目标宿主机地址、目标宿主机的flannel网卡的mac地址、vxlan vnid等信息。然后对数据进行udp封装如下:
udp头封装:
source port 8285,target port 8285
udp内部封装:
1.vxlan封装:vxlan vnid等信息
2. original layer 2 frame封装:source {源 flannel.1网卡mac地址} target{目标flannel.1网卡的mac地址}
完成以上udp封装后,将数据转发给物理机的eth0网卡

4)宿主机eth0接收到来自flannel.1的udp包,还需要将其封装成正常的通信用的数据包,为它加上通用的ip头、二层头,这项工作在由linux内核来完成。
Ethernet Header的信息:
source:{源宿主机机网卡的MAC地址}
target:{目标宿主机网卡的MAC地址}
IP Header的信息:
source:{源宿主机网卡的IP地址}
target:{目标宿主机网卡的IP地址}
通过此次封装,一个真正可用的数据包就封装完成,可以通过物理网络传输了。

目标端:

5)目标宿主机的eth0接收到数据后,对数据包进行拆封,拆到udp层后,将其转发给8285端口的flannel进程
6)目标宿主机端flannel拆除udp头、vxlan头,获取到内部的原始数据帧,在原始数据帧内部,解析出源容器ip、目标容器ip,重新封装成通用的数据包,查询路由表,转发给docker0网桥;
7)最后,docker0网桥将数据送达目标容器内的veth0网卡,完成容器之间的数据通信。

总结:

通过对vxlan设计思想和flannel的落地方案的互相印证,对这两者会有更为深刻的理解,同时,不难发现,flannel性能表现不佳的原因很可能是因为反复拆封包过程、etcd查询这几个步骤带来的额外开销。

参考:

https://blog.csdn.net/u010039418/article/details/90451081
https://www.cnblogs.com/cwind/p/10085146.html
https://events.static.linuxfound.org/sites/events/files/slides/2013-linuxcon.pdf

你可能感兴趣的:(kubernetes,网络,kubernetes那些事儿,kubernetes,VXLAN)