当前位置:   article > 正文

k8s网络插件之Flannel_k8s网络插件flannel

k8s网络插件flannel

Flannel简介

Flannel官网:https://github.com/coreos/flannel

Flannel是由CoreOS开源的针对k8s的网络服务,其目的是为解决k8s集群中各主机上Pod之间的通信问题,其借助etcd维护网络IP地址分配,并为每个Node节点分配一个不同的IP地址段。

Flannel在每个节点运行一个名为flanneld的二进制代理程序,它负责从预留的网络中按照指定或者默认的掩码长度为当前节点申请分配一个子网,并将网络配置、已分配的子网和辅助数据(比如主机的公网IP等)存储在Kubernetes API或独立的etcd中。Flannel通过不同的后端来实现跨节点Pod间的通信,目前支持的后端如下:

  • vxlan:使用Linux内核中的封装隧道报文,以Overlay模型支持跨节点的Pod通信,同时该后端支持直接路由模式,在该模式下,位于同一二层网络中的节点上的Pod间通信可通过路由模式直接发送,而跨二层网络的节点之上的Pod间通信仍要使用VXLAN隧道协议转发;因而VXLAN隶属于Overlay网络模型,或者混合网络模型。vxlan模型中,flanneld监听udp 8472端口接受和发送封装的数据包
  • host-gw:类似于VXLAN后端的直接路由模式,但不支持跨二层网络的节点,因此这种模式要求各节点处于同一个二层网络中,不太适用于规模较大的环境,但转发性能较好
  • udp:使用常规UDP报文封装完成隧道转发,性能比vxlan和host-gw相比较差,仅在不支持vxlan和host-gw时使用;UDP后端模式中,flanneld监听UDP 8285端口发送报文

Flannel配置文件

Flannel官方的部署文件默认使用vxlan后端,相关配置定义在kube-flannel名称空间下configmap/kube-flannel-cfg资源对象中,内容如下:

  net-conf.json: |
    {
      "Network": "10.244.0.0/16",	
      "Backend": {		
        "Type": "vxlan"
      }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

如上所示,其配置是json格式,常用的键有如下几个:

  • Network:Flannel全局使用的子网,即pod cidr的值
  • SubnetLen:子网分割的长度,在全局子网掩码小于24时(例如16),默认为24
  • SubnetMin:分配给节点使用的起始子网,默认为切割完成后的第一个子网
  • SubnetMax:分给给节点使用的最大子网,默认为切割完成后的最后一个子网
  • Backend:Flannel使用的后端,以及后端的配置

另外,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	#地址映射
  • 1
  • 2
  • 3
  • 4
  • 5

VXLAN后端

在vxlan后端下,flannel会在每个节点创建一个flannel.1的接口做为本节点的隧道出入口的VTEP设备,其中的1表示VNI,因此所有节点上的VTEP均属于同一个大二层域,它们依赖二层网关进行通信。Flannel采用分布式网关模型,它把每个节点都视为到达该节点pod子网的二层网关,相应的路由信息由flanneld自动生成。

Flannel需要在每个节点运行一个flanneld进程,它会基于网络配置获取适用于当前节点的子网租约,还要根据其他节点的子网生成路由信息,以正确的路由数据报文。官方提供的部署文件中,flanneld以Daemonset方式在每个节点运行。

Pod通信流程分析

在这里插入图片描述

如上图所示,两个Pod的通信流程大致如下:

  1. 在client Pod上向nginx Pod发起请求,因为它们不在同一网段,所以报文会根据默认路由到达cni0,此时
    src-ip:10.224.1.9(client-pod) dst-ip:10.224.2.5(nginx-pod)
    src-mac:86:8c:53:15:25:d4(client-pod) dst-mac:86:8c:53:15:25:d4(cni0)

在cni0上抓包如下:
在这里插入图片描述

  1. cni0发现目的地址并非本机Pod地址,自己不能转发。然后会匹配主机路由,发现到达10.244.2.0/24需要通过flannel.1,将报文转给flannel.1
  2. flannel.1收到报文后会将其封装为vxlan报文内层的数据帧,此时
    src-ip:10.224.1.9(client-pod) dst-ip:10.224.2.5(nginx-pod)
    src-mac:d6:60:8c:f3:ba:37(node-01 flannel.1) dst-mac:4a:4a:ee:b9:cb:2d(node-02 flannel.1)

flannel.1上抓包如下:
在这里插入图片描述

  1. 最后数据包通过内核vxlan模块封装成vxlan报文,然后通过节点网卡ens33发往node-02,此时
    inner-src-ip:10.224.1.9(client-pod ) inner-dst-ip:10.224.2.5(nginx-pod)
    inner-src-mac:d6:60:8c:f3:ba:37(node-01 flannel.1) inner-dst-mac:4a:4a:ee:b9:cb:2d(node-02 flannel.1)
    outer-src-ip:192.168.211.11(node-01 ens33) outer-dst-ip:192.168.211.12(node-02 ens33)
    outer-src-mac:00:0c:29:51:81:05(node-01 ens33) outer-dst-mac:00:0c:29:99:52:7b192.168.211.12(node-02 ens33)

在ens33上抓包如下图所示:
在这里插入图片描述

在上面的抓取VXLAN报文中,外层报文目标地址是node-02的ens33接口的地址,但是本地节点上并没有任何路由信息帮助指向目标节点,由flanneld生成的路由中仅指明了到达隧道出口时flannel.1接口的IP地址,那么外层报文的目标地址是如何获取的呢?

  1. node-02收到报文后进行vxlan解封装,然后再按照相反的顺序转发到nginx-pod

此时还存在两个问题:

  • node-01 的flannel.1是如何知道node-02的flannel.1的地址来进行报文封装的呢?通过ARP?

错,Flannel并不依赖ARP进行MAC地址学习,而是由节点上的flanneld进程动态生成相应的解析记录。例如下面的解析记录是在node-01节点上查询的,它们分别指明了集群上其它节点flannel.1接口的MAC地址,PERMANENT表示永久有效
在这里插入图片描述

  • 在node-01 的ens33接口抓取VXLAN报文中,外层报文目标地址是node-02的ens33接口的地址,但是本地节点上并没有任何路由信息帮助指向目标节点,由flanneld生成的路由中仅指明了到达隧道出口时flannel.1接口的IP地址,那么外层报文的目标地址是如何获取的呢?

事实上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后端

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网络插件就是为此目的而设立的。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/128337
推荐阅读
相关标签
  

闽ICP备14008679号