一、前言
Flannel 是一个简单、高效的容器网络解决方案,适用于需要在多个主机上运行容器的场景。它通过虚拟网络技术和 IP 地址管理来实现容器之间的通信和跨主机连接,为容器平台提供了可靠的网络基础设施,flannel有三种模式,分别是udp、vxlan、host-gw,每种模式的性能都不一样,下面就来介绍一下三种模式的性能以及原理
二、模式解析
讲解前先来了解一下veth pair,veth pair 是 Linux 内核中的一种网络设备,它由两个相互连接的虚拟网络接口组成。这两个接口成对出现,数据从一个接口进来,会从另一个接口出去。通常,一个接口连接到一个网络命名空间(如容器或 Pod),另一个接口连接到主机的网络命名空间或一个桥接设备(bridge),veth pair 只是简单地转发数据包,不进行任何网络层的处理,在k8s集群的节点中,每个节点都有一个cni0的虚拟网卡,这个就是veth pair网桥设备
udp
udp是flannel最早使用的一种模式,但是性能却是最差的,现已被弃用
1.在k8s集群中使用udp模式部署flannel时,会在所有节点生成一个flannel0的虚拟网卡,并且每个虚拟网卡会生成一个网段就是一个子网,而这个 flannel0 它是一个 TUN 设备,TUN 设备是一种工作在三层的虚拟网络设备,它的功能就是在操作系统内核和用户应用程序之间传递 IP 包,flannel会将所有节点的flannel0的网段信息与其对应的宿主机ip地址形成key-value对,并将key-value对存储到etcd集群中
这里使用node01的pod访问node02的pod的工作过程来说一下udp的原理,流程如下图所示
2.10.244.4.5容器访问10.244.3.5容器时会根据容器中的默认路由将数据包发送到cni0网桥中
3.网桥通过内核态中的路由表查询转发到flannel0中
4.flannel0会将这个数据包转给flannel进程,flannel进程通过该数据包目的地址的子网到etcd中查询,前面有说到集群创建新的节点时flannel会将所有节点的flannel0的网段信息与其对应的宿主机ip地址形成key-value对存储到etcd中,在etcd中通过子网地址查询到所属的node节点的地址
5.flannel就会用查询到的宿主机地址作为目的地址,本地地址作为源地址,并且用flannel端口作为目的端口将原ip包封装为一个udp包,并将udp包传递到内核态中,通过宿主机的网卡发送到目的宿主机的8285端口,即flannel进程的端口
6.node2宿主机的flannel进程接收到数据包后,就会拆解数据包,解析到ip包后将该包转发到flannel0,flannel0转发给内核态
7.内核态根据路由表转发到cni0网桥中
8.cni0网桥会查找数据包的目标ip地址,并确定该ip地址的端口记录,如果有,就从该端口发送数据包,如果没有记录就通过arp协议广播帧,得到应答后就能知道端口与ip的映射关系,从而将数据包发往该端口
通过以上工作流程会发现期间存在多次的用户态和内核态之间的数据拷贝
1.容器进程发送ip包到cni0网桥进入内核态
2.flannel0将ip包发送到用户态的flannel进程
3.flannel进程将ip包封装为udp包后发送到宿主机网卡进入内核态
4.目的宿主机的网卡接收到udp包后发送到用户态的flannel进程
5.flannel进程接收udp包后拆包,将拆出的ip包发送到flannel0进入内核态
6.cni0将ip包发送到容器进程
其实用户空间和内核空间之间的上下文切换会增加处理数据包的延迟和系统开销,这也是udp性能差的主要原因,而且用户态封装包通常需要通过系统调用(如 sendto、recvfrom)将数据包传递给操作系统内核进行发送和接收
vxlan
VXLAN(Virtual Extensible LAN)是一种用于在现有网络基础设施上创建虚拟网络的隧道协议,用于在第2层网络上创建虚拟化的第2层网络(即虚拟局域网)。它通过将第2层以太网帧封装在第4层 UDP 数据包中,从而在第3层网络上进行传输
vxlan模式就是减少用户态的使用,将封装包和拆解包都在内核态上,从而优化性能,原理是通过一个大的二层网络将地址段覆盖,使其处于同一个子网内,然后再从这个大的子网下面分出小的子网
通过配置文件我们可以看到,flannel的子网是10.244.0.0/16
而每个节点的容器地址范围就处于10.244.1.0/24、10.244.2.0/24等这些网段中
在 Flannel 的 VXLAN 模式下,每个节点(主机)都会创建一个 VXLAN 隧道接口,用于在不同节点之间传输容器流量,即flannel.1也叫VTEP,VTEP的作用是将ip包封装成二层数据帧,然后再将二层数据帧加上vxlan的头,再加上目的地址封装为一个udp包,且还作为一个网桥,转发udp包到宿主机的网卡上
1.在k8s集群中使用vxlan模式部署flannel时,会在所有节点生成一个flannel.1的虚拟网卡,并且每个虚拟网卡会生成一个子网的IP地址,flannel会将每个节点的flannel.1的地址和mac地址信息发送到其它节点上存储,即ARP记录,同时每个节点将其余节点的宿主机地址与之对应的flannel.1的mac地址绑定存储在一个叫做FDB的转发数据库中
这里使用node01的pod访问node02的pod的工作过程来说一下vxlan的原理,流程如下图所示,实际上和udp的工作流程没太大区别,主要就是在flannel.1的区别上
2.10.244.4.5容器访问10.244.3.5容器时会根据容器中的默认路由将数据包发送到cni0网桥中
3.cni0网桥通过路由信息将ip包转发到flannel.1上,同时获知下一跳网关是10.244.3.0,这个网关就是对端vtep的地址
4.我们知道flannel.1就是vtep,他的作用就是封装包,先通过下一跳的网关地址查询arp表获取对端vtep的mac地址,将ip包用获取到的对端vtep ip地址和mac地址封装成二层数据帧
5.二层数据帧不能直接转发到对端的vtep中,还需要在封装一层作为udp包,才可以用于转发,在封装udp包前,需要先加一个vxlan的头部信息,这样对端的node节点接收到数据包后,才知道这是一个vxlan的数据帧,在vxlan的头部信息中有一个重要的数据是vni,在flannel中vni的默认值是1,只有vni相同的网络才能解包,实际vni的值就是flannel.1中的1,封装为udp包还需要知道目的地址,这时就需要通过对端的vtep的mac地址到FDB转发数据库中查询,查询到目的地址后就可以封装为udp包
6.flannel.1作为网桥将udp数据包转发到宿主机网卡中,发送到对端宿主机中
7.对端宿主机的内核态接收到数据包后,发现有vxlan header以及vni标记是1,就将vxlan包发送到本机的vni也为1的flannel.1上
8.flannel.1进行解包,取出目的地址,然后根据路由表将数据包发送到cni0网桥中
9.cni0网桥会查找数据包的目标ip地址,并确定该ip地址的端口记录,如果有,就从该端口发送数据包,如果没有记录就通过arp协议广播帧,得到应答后就能知道端口与ip的映射关系,从而将数据包发往该端口
通过以上工作流程可以发现,vxlan减少了在用户态上处理ip包的过程,封装包和拆解包都是在内核态中,减少了用户空间和内核空间之间的上下文切换从而大大提升了性能
host-gw
host-gw
模式是一种使用主机间的直接路由来实现容器网络通信的模式。它不依赖于封装技术(如 VXLAN),而是通过在每个主机上配置静态路由,使得每个节点可以直接将数据包发送到目标节点上的容器网络,即每个主机都作为网关,减少了包的封装和拆解,很大程度的优化了性能
host-gw
模式下,Flannel 使用路由表条目来确保不同主机上的容器能够互相通信,每个节点会被分配一个唯一的子网,容器的 IP 地址从这个子网中分配,Flannel 在每个节点上都配置到其余节点的静态路由,使得节点之间可以直接路由数据包,在大规模的集群中,路由表会很庞大
host-gw模式也有限制,就是集群中的所有节点都必须处于一个二层连通的环境中
1.在k8s集群中使用host-gw模式部署flannel时,flannel会将每个node节点的ip地址,以及分配的对应的容器子网,写入到etcd中存储,flannel取出其它节点的ip地址以及对应的容器子网以静态路由的方式写入到每个node节点的路由表中,将node节点的ip地址作为下一跳网关
这里使用node01的pod访问node02的pod的工作过程来说一下host-gw模式的原理,流程如下图所示,host-gw模式以node节点的ip地址作为网关直接使用了路由的方式
2.10.244.4.5容器访问10.244.3.5容器时会根据容器中的默认路由将数据包发送到cni0网桥中
3. cni网桥根据路由信息将数据包由宿主机网卡转发到对端主机中
4.数据包来到node2主机的网卡上后,根据路由表转发到cni0上
5.cni0网桥会查找数据包的目标ip地址,并确定该ip地址的端口记录,如果有,就从该端口发送数据包,如果没有记录就通过arp协议广播帧,得到应答后就能知道端口与ip的映射关系,从而将数据包发往该端口