Z.S.K.'s Records

Flannel Vxlan封包原理剖析

flannel在kubernetes中算是比较常用的cni, 其中vxlan又是flannel中常用的模式,最近又详细地看了一遍vxlan的实现方式, 每看一次都会发现新大陆,听的太多人说flannel的vxlan需要封包解包,但并不是所有的人都知道到底是把什么封到包里,指的又是什么?

本文主要来解析vxlan的封包解包过程,flannel的一些基础概念,可参考Kubernetes学习(flannel深入学习)

先简单说一下flannel支持的三种模式:

  • Udp: 模式性能最差,现在几乎已不再使用,不再过多解释
  • host-gw: host-gw则是个纯三层的解决方案,直接把host当成是容器通信路径里的网关进行路由,为了达到这个目的,需要集群宿主机之间二层是互通的, 虽host-gw在三种模式中性能最好,但不是所有的集群都可以做到二层互通,还是有一定的局限
  • vxlan:

关于这三者之间的比较也不是本文的重点,感兴趣的同学可以参考Flannel的三种工作模式

接下来请出本次的主角: vxlan, 但在说这之前,还是需要先提一下vlan

vlan

由于篇幅有限,不打算过多地去解释vlan技术,很大程度上这属于网络领域范畴,这里作者用一张图来说明vlan技术要解决的问题

从这张图可以看到,vlan用于将一个物理的LAN在逻辑上划分成多个虚拟广播域的通信技术, 通过划分不同的vlan起到网络隔离,vlan内的主机间可以直接通信,而vlan间不能直接互通,从而将广播报文限制在一个vlan内

但是vlan有个很大的局限就是它能够划分的虚拟局域网个数非常有限,数量只有4000个左右,无法满足大二层网络的租户间隔离需求,因此诞生了vxlan

vxlan

Vxlan: (Virtual Extensible LAN 虚拟可扩展局域网),是在vlan的基础之上进行的扩展, 可以划分的vlan个数扩大到16M个

vxlan通过构建虚拟隧道达到大二层网络互通的目的

为了更好地理解flannel中使用vxlan实现跨主机通信的原理,跟vxlan相关的几个关键名词还是需要好好地介绍一下

VTEP

VTEP(VXLAN Tunnel Endpoints,VXLAN隧道端点),它可以是个物理设备,也可以是虚拟设备,flannel创建的flannel.1就是vtep设备,flannel中vxlan所说的封包解包就是由这个设备完成

vtep设置即有ip地址,也有mac地址.

VNI

VNI(VXLAN Network Identifier,VXLAN 网络标识符),VNI是一种类似于VLAN ID的用户标识,一个VNI代表了一个租户

在flannel中,vni默认都是1, 所以这就是为什么flannel创建的vtep设备的名称叫做flannel.1的原因

vxlan还有很多其它的技术细节,作者着实觉得不是网络专业出身的真的很难看懂,如果感兴趣的可以看看华为论坛的一篇文章,什么是VXLAN,看不懂也不影响接下来的理解,让我们回到flannel的vxlan模式

节点通信

重点说明的是,以下只讨论pod间通信,不涉及service的ClusterIP,如果是ClusterIP的话,那还涉及到怎么通过ClusterIP找到目的pod的IP,这属于coreDNS、Kube-proxy的范畴,不在此处讨论

同pod

同pod通信最为简单, 由于pod内部的多个container通过pause容器共享一个网络,自然通过localhost通信即可

同节点

对于在一个节点上的两个pod进行通信, 是不需要经过CNI的, 这其实跟是不是flannel没有关系,由于部署完flannel后,flanneld进程会为每个节点都分配一段IP,IP信息存储在etcd中并保证节点间不会重复

由于同节点上的pod分配到的ip都在一个网段, 且cni0充当了node上所有pod的网桥,所有pod的veth一头都插在cni0上,那自然是可以直接通信的,因此,当请求从源pod的eth0网口出来后,到达cni0, cni0发现其目的地址与自己同属一个网络,就直接转到目的pod中去了.

跨节点

来看一张图,如果你能看明白,那基本不需要再往下看了,请直接滑走

假如node1上的pod1 10.224.1.2 ,要访问node2上的pod3 10.224.2.2,那么这条访问是怎样的呢?

首先数据包从pod1内的eth0出来到达cni0网桥,cni0网桥接收到数据包后发现目的IP跟自己不在一个网段,那么自然需要转发出去,而Linux Bridge有个特殊规则: 网桥不会将这个数据包转发给任何设备,而是直接转交给主机的三层协议栈进行处理, 因此通过本机的route得知,目的地址为10.224.1.0段的数据包都将转到flannel.1

1
2
3
4
5
[node1]# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
10.224.0.0 0.0.0.0 255.255.255.0 U 0 0 0 cni0
10.224.1.0 10.224.1.0 255.255.255.0 UG 0 0 0 flannel.1

我们抛开所有因素不谈,先说一个前提,两台节点通信,不管虚拟网络上怎么实现,最终还是需要通过物理网卡进行

flannel为overlay的容器网络,是个大二层互通的解决方案, 但最终网络包还是要借助物理网卡出去

任何一个VXLAN设备创建时都会指定一个三层物理网络设备作为VTEP,flannel.1也不例外, 可通过以下命令进行查看

1
2
ip -d link show flannel.1
# 在输出中可看到flannel.1是基于eth0上

当数据包到达flannel.1后, 它如果要将这个包转到目的节点上去,它需要对vxlan报文进行填充

在源节点上flannel填充这些信息的过程就叫封包,在目标节点上解开这些信息就叫解包

先来看一下vxlan的报文形式

右边的为原始报文,左边的即为vxlan封装报文,我们一一来介绍一下.

Original Ethernet Frame

首先, Original Ethernet Frame是原始的报文,也就是pod1访问pod2的报文,因为是个正常网络报文,包含IP header、Ethernet header、及playload。

playload不多说,就是数据

IP header 很自然也就是pod1及pod2的ip地址信息

而Ethernet header需要注意的是,不是pod1及pod2的MAC地址,而应该是两端flannel.1的MAC地址,因为报文到flannel.1后通过route -n得到下一跳的地址为10.224.2.0/32,需要得到10.224.2.0的mac地址,这部分信息在flanneld中进行维护,叫ARP表,即通过IP可得到对应的MAC地址,如下:

1
2
[node1]# ip neigh show dev flannel.1
10.224.2.0 lladdr 92:8d:c4:85:16:ad PERMANENT
Vxlan Header

Vxlan header这里只需要关注一个字段,那就是VNI,前文简单提到过, 在目标node上的flannel.1上会对这个VNI字段进行check,看是否与自己的VNI一致,一致的话才会进行处理.

UDP Header

从上图中的颜色可以看出, UDP是把整个Original Ethernet Frame及Vxlan Header都囊括在一起了,我们知道,udp header中包含有源端口,目的端口,如图所示

所以很自然Src.port为node1上的flannel.1的端口,该端口是根据封装的内部数据帧计算出的一个哈希值

Dst.port(上面也显示为VxlanPort)为node2上flannel.1的端口,Linux内核中默认为VXLAN分配的UDP监听端口为8472

Outer IP header

上面的信息其实还都是在flannel中, 上面说过任何虚拟出来的网络最终都是要经过实体网卡设备出去,目前封装出来的udp header是不能在宿主机网络中传递的,只能进一步把udp再封装成正常的网络包通过节点物理网络发送出去,根据tcp/ip协议,有了UDP header自然是需要封装在ip报文中,所以有ip header

ip header中包含有源ip及目的ip,源ip即为flannel.1所绑定的物理ip,即node1节点的eth0 ip

而目标ip,那肯定是node2的eth0 ip了, 这个ip是需要根据目标flannel.1的mac地址获得,这部分信息同样维护在flanneld中的,可通过以下命令查询

1
2
[node1 ~]# bridge fdb show dev flannel.1 | grep 92:8d:c4:85:16:ad
92:8d:c4:85:16:ad dev flannel.1 dst 192.168.2.91 self permanent

192.168.2.19即为目标ip

可以总结一下,flanneld中维护了这两部分信息:

  • flannel.1的ip与mac地址对应关系,通过flannel.1的ip可以查询到flannel.1 的mac地址
  • flannel.1的mac地址及其所在node ip对应关系,通过flannel.1的mac地址可以查询到node ip
Outer MAC Header

而ip header则又需要由封装在mac header中,通过上面的查询,mac header 自然就是两台node的mac信息了

这样的话,整个封装包组成了标准的tcp/ip协议包,可以在物理网络上传递了

解包

当数据包到达node2的8472端口后(实际上就是VXLAN模块),VXLAN模块就会比较这个VXLAN Header中的VNI和本机的VTEP(VXLAN Tunnel End Point,就是flannel.1)的VNI是否一致,然后比较Inner Ethernet Header中的目的MAC地址与本机的flannel.1是否一致,都一致后,则去掉数据包的VXLAN Header和Inner Ethernet Header,然后把数据包从flannel.1网卡进行发送。

然后,在node2上会有如下的路由(由flanneld维护),根据路由判断要把数据包发送到cni0网卡上

1
2
3
4
5
[node2 ~]# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
...
10.224.2.0 0.0.0.0 255.255.255.0 U 0 0 0 cni0

最后通过 inner ip header中的ip知道需要由10.224.2.2的pod进行响应.

vxlan在内核中进行封装、解封装的过程,致使flannel vxlan的性能有所下降.

<完>

参考文章:

转载请注明出处https://izsk.me

Z.S.K. wechat
Scan Me To Read on Phone
I know you won't do this,but what if you did?