Flannel本身是一个框架,真正提供网络功能是他的后端实现。目前支持三种后端实现:
从图里看每个宿主机都有一个flannel1的设备,就是VXLAN所需的VTEP设备(就是flannel1“用于VXLAN报文的封装和解封装”),它既有IP地址也有MAC地址。现在我们是container1 访问 container2,当container1发出请求后,这个目的的地址是10.244.1.3的IP包,会先出现在cni0网桥,然后被路由到本机flanner1设备上处理,也就是说,来到了“隧道”的出口。既目的宿主机的VTEP设备(就是flannel1 设备)。
当所有Node启动后,我们可以在Node1 上可以看到多个flannel1 网卡的路由信息,是因为flanneld启动后创建的。
[root@node-0 ~]# ifconfig
flannel.1: flags=4163 mtu 1450
inet 10.244.0.0 netmask 255.255.255.255 broadcast 0.0.0.0
ether 8a:bf:bf:7e:b7:f6 txqueuelen 0 (Ethernet)
RX packets 28929 bytes 1676230 (1.5 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 12085 bytes 42372533 (40.4 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@node-0 ~]# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
...
10.244.1.0 10.244.1.0 255.255.255.0 UG 0 0 0 flannel.1
....
从上图看到10.244.1.0就是Node2的VTEP设备(flannel1)的IP地址,而这些VTEP设备之间通讯就需要想办法组成一个虚拟的二层网络,既:通过二层数据帧进行通信,而Node1上的VTEP设备收到原始报文后,就要想办法把原始报文加一个目的MAC地址,封装成二层数据帧,然后发送给目的VTEP设备。这里需要解决一个问题目的VTEP设备的MAC地址是什么?
根据路由表信息我们知道了目的VTEP设备的IP地址,而根据三层IP地址查询二层MAC地址正是ARP表的功能。而这里用ARP表的记录,也就是flanneld进程在Node2节点启动时,自动添加到Node1上的。如下:
[root@node-0 ~]# ip neigh show dev flannel.1
10.244.1.0 lladdr b2:ba:aa:a5:10:1a PERMANENT
有了这个MAC地址linux内核就可以开始二层封装了,上面提到的MAC地址,对宿主机的二层网络没有任何意义,所以上述封装的数据帧不能在宿主机的二层网络里传输,为了方便概述,我们把上述数据帧称为内部数据帧。所以Linux内核还要把内部数据帧进一步封装成宿主机网络的一个普通数据帧,好让他载着内部数据帧,通过eth0网卡进行传输。这次封装我们称为外部数据帧,为了实现这个搭便车的机制,Linux内核在封装内部数据帧前面,加上特殊的VXLAN头,用来表示这个乘客实际上是VXLAN使用的数据帧。而这个VXLAN头里有一个重要的标志VNI,它是识别某个数据帧是不是应该归属自己处理的标志。而flannel中,VNI的值是1,这也是为什么宿主机的VTEP设备都叫做flannel1的原因。这个时候linux内核会把这数据帧封装一个UDP报文在转发出去。虽然node1的flannel1知道node2的flannel2的MAC地址,但是不知道node2MAC的地址,也就是UDP该发往那台主机,实际上flannel1还要扮演一个网桥的角色,在二层网络进行UDP转发,而在Linux内核里面,网桥设备进行转发的依据来自FDB的转发数据库。这个flannel网桥对应的FDB信息,就是flannel进程维护的,他的内容如下:
[root@node-0 ~]# bridge fdb show flannel.1 | grep b2:ba:aa:a5:10:1a
b2:ba:aa:a5:10:1a dev flannel.1 dst 172.16.138.41 self permanent
我们可以看到发往的IP地址是172.16.138.41的主机,显然这台主机就是 Node2,UDP要转发的目的也找到了。接下来就是宿主机网络封包的过程了。
下面让我们来看看,当有一个EventAdded到来时,flanneld如何进行配置,以及封包是如何在flannel网络中流动的。
如上图所示,当主机B加入flannel网络时,它会将自己的subnet 10.1.16.0/24和Public IP 192.168.0.101写入etcd中,它还会将vtep设备flannel.1的mac地址也写入etcd中。
之后,主机A会得到EventAdded事件,并从中获取主机B添加至etcd的各种信息。这个时候,它会在本机上添加三条信息:
[root@node-0 ~]# ip route list
...
10.1.16.0/24 via 10.1.16.0 dev flannel.1 onlink
...
[root@node-0 bin]# ip neigh show dev flannel.1
10.1.16.0 lladdr b2:ba:aa:a5:10:1a PERMANENT
[root@node-0 bin]# bridge fdb show flannel.1 | grep b2:ba:aa:a5:10:1a
b2:ba:aa:a5:10:1a dev flannel.1 dst 192.168.0.101 self permanent
[root@node-0 bin]# arp -v
Address HWtype HWaddress Flags Mask Iface
...
10.1.16.0 ether b2:ba:aa:a5:10:1a CM flannel.1
...