kubernetes flannel之Vxlan原理

kubernetes网络通信

  • 容器间的通信 pod内的容器通信(lo)
  • Pod之间的通信 pod IP <—–> pod IP(flannel、calico)
  • Pod与Service之间的通信 podIP <—–> ClusterIP(iptables、ipvs)
  • Service与集群外部的通信 ClusterIP <—–> 集群外部

CNI插件:

  • flannel
  • calico
  • canel
  • kube-router

Flannel

Flannel本身是一个框架,真正提供网络功能是他的后端实现。目前支持三种后端实现:

  • VXLAN
  • host-gw
  • UDP
    注释:只要有kubelet的节点就要安装flannel网络,因为这是pod和pod间通讯用的。

flannel-1

从图里看每个宿主机都有一个flannel1的设备,就是VXLAN所需的VTEP设备(就是flannel1“用于VXLAN报文的封装和解封装”),它既有IP地址也有MAC地址。现在我们是container1 访问 container2,当container1发出请求后,这个目的的地址是10.244.1.3的IP包,会先出现在cni0网桥,然后被路由到本机flanner1设备上处理,也就是说,来到了“隧道”的出口。既目的宿主机的VTEP设备(就是flannel1 设备)。

当所有Node启动后,我们可以在Node1 上可以看到多个flannel1 网卡的路由信息,是因为flanneld启动后创建的。

1
2
3
4
5
6
7
8
[root@node-0 ~]# ifconfig
flannel.1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> 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
1
2
3
4
5
6
[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上的。如下:

1
2
[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进程维护的,他的内容如下:

1
2
[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要转发的目的也找到了。接下来就是宿主机网络封包的过程了。

flannel-2

下面让我们来看看,当有一个EventAdded到来时,flanneld如何进行配置,以及封包是如何在flannel网络中流动的。

flannel-3

如上图所示,当主机B加入flannel网络时,它会将自己的subnet 10.1.16.0/24和Public IP 192.168.0.101写入etcd中,它还会将vtep设备flannel.1的mac地址也写入etcd中。

之后,主机A会得到EventAdded事件,并从中获取主机B添加至etcd的各种信息。这个时候,它会在本机上添加三条信息:

  • 路由信息:所有通往目的地址10.1.16.0/24的封包都通过vtep设备flannel.1设备发出,发往的网关地址为10.1.16.0,即主机B中的flannel.1设备。
1
2
3
4
[root@node-0 ~]# ip route list
...
10.1.16.0/24 via 10.1.16.0 dev flannel.1 onlink
...
  • fdb信息:MAC地址为flannel的mac地址,发往10.1.16.0的数据包都将通过vxlan首先发往目的地址192.168.0.101,即主机B
1
2
[root@node-0 bin]#  ip neigh show dev flannel.1
10.1.16.0 lladdr b2:ba:aa:a5:10:1a PERMANENT
1
2
[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
  • arp信息:网关地址10.1.16.0的MAC地址为flannel的mac地址
1
2
3
4
5
[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
...

参数说明:

  • Network flannel使用CIDR格式(10.244.0.0/16)的网络地址,用于为pod的配置网络功能
  • SubnetLen表示每个主机分配的subnet大小,我们可以在初始化时对其指定,否则使用默认配置。在默认配置的情况下SubnetLen配置为24(表示24位子网掩码)。
  • SubnetMin是集群网络地址空间中最小的可分配的subnet,可以手动指定,否则默认配置为集群网络地址空间中第一个可分配的subnet。例如对于”10.1.0.0/16″,当SubnetLen为24时,第一个可分配的subnet为”10.1.1.0/24″。
  • SubnetMax表示最大可分配的subnet,对于”10.1.0.0/16″,当subnetLen为24时,SubnetMax为”10.1.255.0/24″
  • Backend.Type 为flannel指定使用的backend的类型,类型分三种:vxlan、host-gw、udp,如未指定,则默认为“vxlan”
  • –ip-masq=true 为网桥上的IP地址开启IP伪装(代表需要为其配置SNAT)
    注意:Backend为vxlan时,其中会存储vtep设备的mac地址至etcd中

kubernetes flannel之Vxlan原理
https://system51.github.io/2019/08/26/kubernetes-flannel-Vxlan/
作者
Mr.Ye
发布于
2019年8月26日
许可协议