赞
踩
Flannel官网:https://github.com/coreos/flannel
Flannel是由CoreOS开源的针对k8s的网络服务,其目的是为解决k8s集群中各主机上Pod之间的通信问题,其借助etcd维护网络IP地址分配,并为每个Node节点分配一个不同的IP地址段。
Flannel在每个节点运行一个名为flanneld的二进制代理程序,它负责从预留的网络中按照指定或者默认的掩码长度为当前节点申请分配一个子网,并将网络配置、已分配的子网和辅助数据(比如主机的公网IP等)存储在Kubernetes API或独立的etcd中。Flannel通过不同的后端来实现跨节点Pod间的通信,目前支持的后端如下:
Flannel官方的部署文件默认使用vxlan后端,相关配置定义在kube-flannel名称空间下configmap/kube-flannel-cfg资源对象中,内容如下:
net-conf.json: |
{
"Network": "10.244.0.0/16",
"Backend": {
"Type": "vxlan"
}
}
如上所示,其配置是json格式,常用的键有如下几个:
另外,flannel还会在运行的节点上生成一个环境变量文件,默认是/run/flannel/subnet.env,其包含本节点使用的子网、mtu等信息。例如下面的示例:
root@master-01:~# cat /run/flannel/subnet.env
FLANNEL_NETWORK=10.244.0.0/16 #flannel全局网段
FLANNEL_SUBNET=10.244.0.1/24 #本节点子网
FLANNEL_MTU=1450 #容器接口mtu值
FLANNEL_IPMASQ=true #地址映射
在vxlan后端下,flannel会在每个节点创建一个flannel.1的接口做为本节点的隧道出入口的VTEP设备,其中的1表示VNI,因此所有节点上的VTEP均属于同一个大二层域,它们依赖二层网关进行通信。Flannel采用分布式网关模型,它把每个节点都视为到达该节点pod子网的二层网关,相应的路由信息由flanneld自动生成。
Flannel需要在每个节点运行一个flanneld进程,它会基于网络配置获取适用于当前节点的子网租约,还要根据其他节点的子网生成路由信息,以正确的路由数据报文。官方提供的部署文件中,flanneld以Daemonset方式在每个节点运行。
如上图所示,两个Pod的通信流程大致如下:
在cni0上抓包如下:
flannel.1上抓包如下:
在ens33上抓包如下图所示:
在上面的抓取VXLAN报文中,外层报文目标地址是node-02的ens33接口的地址,但是本地节点上并没有任何路由信息帮助指向目标节点,由flanneld生成的路由中仅指明了到达隧道出口时flannel.1接口的IP地址,那么外层报文的目标地址是如何获取的呢?
此时还存在两个问题:
错,Flannel并不依赖ARP进行MAC地址学习,而是由节点上的flanneld进程动态生成相应的解析记录。例如下面的解析记录是在node-01节点上查询的,它们分别指明了集群上其它节点flannel.1接口的MAC地址,PERMANENT表示永久有效
事实上Flannel把flannel.1接口也作为网桥设备使用,该设备上附加了一个同样由flanneld维护的称为FDB的转发数据库,FDB指定了到达目标节点flannel.1接口需要经由的下一跳IP,该IP是目标Pod所在节点的某接口的IP(在上面的报文中是node-02的ens33接口IP),即VXLAN外部报文的目标IP。
例如下图的转发条目是在node-01上查询的,这些条目分别指定了到达集群中其它节点flannel.1接口时需要经由的下一跳IP地址。
VXLAN后端支持DirectRouting模式,即在集群的各节点上添加必要的路由信息,让Pod间的报文通过节点的二层网络直接传送。如下图所示,只有通信双方Pod所在节点不在同一个二层网络时才启用传统的VXLAN隧道方式转发流量。假如k8s集群的节点都位于同一个二层网络中,DirectRouting模式下的Pod通信基本接近于直接使用二层网络。即使节点分布在不同的网络中,合理使用也可以节省一部分隧道开销。
修改kube-flannel名称空间下configmap/kube-flannel-cfg资源,为VXLAN后端添加Directrouting: true键值对就可以开启DirectRouting模式。如下图:
修改完成后可以逐个删除之前的flannel Pod以触发更新。更新完成后节点上的路由规则也会发生相应的变动,到达与本节点同一二层网络的其它节点,Pod子网的下一跳地址会由对端flannel1.1接口的地址变为宿主机的物理接口地址,本地用于发出报文的接口也从flannel.1变为本地物理接口。
以node-01为例,启用Directrouting模式后,节点上的路由变成如下图,
此时,node-01上的Pod访问node-02上的Pod就不需要通过VXLAN封装报文了,直接通过路由即可实现。例如下面抓取的报文所示:
但是显然,这种模式无法满足跨二层网络节点上Pod的通信需求,因为到达Pod子网的下一跳地址无法指向另一个二层网络中的节点地址。所以节点上依然保留flannel.1接口用于跨二层网络节点上Pod的通信需求。
host-gw后端通过添加路由信息,使用节点上的二层网络直接发送Pod间的通信报文,其工作方式类似于VXLAN后端的DirectRouting模式,但不具备DirectRouting模式中VXLAN隧道转发能力,这意味着host-gw后端下所有节点必须位于同一个二层网络中。host-gw后端工作模型示意图如下:
同样,直接修改kube-flannel名称空间下configmap/kube-flannel-cf资源对象,将Backend.Type的值修改为host-gw,然后重建Pod即可启用host-gw后端,如下所示:
配置完成后,各节点上就会生成类似于VXLAN后端直接路由模式的路由规则,以转发Pod的通信报文,它完全省去了隧道转发的额外开销,所以也不在需要flannel.1接口。但是,如果节点处于不同的二层网络,host-gw后端就无法实现Pod间的通信。因此,相对来说,VXLAN的DirectRouting模式兼具VXLAN后端和host-gw后端的优势,既能保证传输性能,又可以跨二层网络转发Pod报文。
此外,Flannel并不支持为Pod网络添加网络策略以控制Pod间通信的能力,它只能借助额外的支持网络策略的插件实现此功能,Canal网络插件就是为此目的而设立的。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。