flannel

flannel是常见的cni插件之一,Kubernetes CNI插件是由kubelet维护管理的,因为kubelet要借助于CNI插件设置Pods网络接口,添加网络以及激活网络

安装Kubernetes集群时,我用的是kubeadm,以致于除了docker和kubelet其他组件基本都是托管在k8s之上,所以运行flannel也是一样

从flannel官方给的资源清单文件中,可以看到它主要做了这么几件事

  1. 创建一个名为flannel的集群角色,并设置了资源访问权限,它授权了两种资源,PODS、NODES,对于pods只开放了get,而对于node开放了list watch,同时针对特定的nodes/status资源开放了patch的权限

  2. 创建一个名为flannel的ServiceAccount

  3. 创建集群角色绑定,将名为flannel的sa和flannel集群角色绑定在一起

  4. 创建一个configMap资源,里面存储了flannel的配置文件,配置文件里定义了flannel相关的参数

  5. 创建了DaemonSet资源,运行flannel网络插件,这里面有几个有意思的地方

    • 通过设置tolerations,让包括所有节点,让不参与的master也运行了一份flannel
    • flannel容器启动前,通过初始化容器,将容器内的配置文件,通过hostPath挂到宿主机上,以便于让kubelet使用
    • 通过设置hostNetwork为True,让flannel共享宿主机网络名称空间
    • flannel官方的资源文件中,关于DaemonSet是定义了5份,它们之间大体都是相同的,这让我一时间有些困惑,直到我把它们粘贴到对比工具,才发现它们关键的不同点,在于nodeSelector这块,他会根据集群节点的系统平台不同,应用不同的镜像创建flannel,例如,我的系统是amd64,它就会选择flannel:v0.10.0-amd64来运行
    • 在flannel的Pods中,有一个特殊的挂在卷/run,我不知道这是为了什么?

flannel 架构图

flannel 配置文件

net-conf.json

{
  "Network": "10.244.0.0/16",
  "Backend": {
    "Type": "vxlan"
  }
}
  • Network: flannel使用的CIDR格式的网络地址,用于为Pod配置网络功能,10.244.0.0是16位的,每个节点分配的网段都是顺序+1,我这里一共三个节点,各自分配的网段为,master 10.244.0.0/24, node002 10.244.1.0/24, node003 10.244.2.0/24,对应主机上都会有一块cni0网卡,地址为10.244.0.1,10.244.1.1,10.244.2.1,而对应主机创建的Pods都是按照宿主机分配的网段分配地址,同时Pods的网关就是宿主机的cni0网卡地址。这同时带来一个小问题,24位掩码可分配的地址255个,减去宿主机一个,那么是不是说每个节点只能运行最多254个Pod呢? 这点有待考证~,不过要解决这个问题应该不难,将Network配置10.0.0.0/8,这样就支持6万多个Pods,但是要注意别让Service没有地址可用了
  • Subnetlen: 把network切分成子网给节点时,默认使用多长掩码进行切分,默认24位,调大该值,会减少节点所运行的Pods最大数,但是会增加最大节点数,调小则相反
  • Subnetmin: 指定用于分配给节点子网的起始地址,例如10.244.10.0,则第一个开始的网段就是10.0,第二个为11.0,而后顺延
  • Subnetmax: 指定用于分配给节点子网的结束地址

flannel 相关网卡

  • docker0: 默认docker0桥
  • flannel.1: flannel边界网卡 10.244.2.0/32
  • cni0: Pods网关网卡,所有veth都会桥接到这个虚拟网桥上来
  • veth*: Pods网卡的另一半,每启动一个flannel.1网段的Pods,都会生成一对veth pair,一端桥接到cni0上,一端配置在容器中作为eth0
# brctl show
bridge name    bridge id        STP enabled    interfaces
cni0        8000.0a580af40201    no        veth3925a2f3
                            veth8ef2d145
docker0        8000.0242cce0c895    no                                    veth8ef2d145

flannel 路由规则

node001(master)

# route -n
10.244.0.0      0.0.0.0         255.255.255.0   U     0      0        0 cni0
10.244.1.0      10.244.1.0      255.255.255.0   UG    0      0        0 flannel.1
10.244.2.0      10.244.2.0      255.255.255.0   UG    0      0        0 flannel.1

node002(node)

# route -n
10.244.0.0      10.244.0.0      255.255.255.0   UG    0      0        0 flannel.1
10.244.1.0      0.0.0.0         255.255.255.0   U     0      0        0 cni0
10.244.2.0      10.244.2.0      255.255.255.0   UG    0      0        0 flannel.1

node003(node)

# route -n
10.244.0.0      10.244.0.0      255.255.255.0   UG    0      0        0 flannel.1
10.244.1.0      10.244.1.0      255.255.255.0   UG    0      0        0 flannel.1
10.244.2.0      0.0.0.0         255.255.255.0   U     0      0        0 cni0

flannel 抓包

178 -> 179 ICMP

发包: eth0 -> veth* -> cni0 -> flannel.1 -> eth0(ens32)

收包: eth0(ens32) -> flannel.1 -> cni0 -> veth* -> eth0

隧道前(解包后)

很干净的icmp包

19:43:53.725476 IP 10.244.1.91 > 10.244.2.178: ICMP echo request, id 4352, seq 0, length 64
19:43:53.725505 IP 10.244.2.178 > 10.244.1.91: ICMP echo reply, id 4352, seq 0, length 64
19:43:54.725567 IP 10.244.1.91 > 10.244.2.178: ICMP echo request, id 4352, seq 1, length 64
19:43:54.725601 IP 10.244.2.178 > 10.244.1.91: ICMP echo reply, id 4352, seq 1, length 64

隧道后(解包前)

可以看到UDP和OTV、overlay相关信息

[root@node003 ~]# tcpdump -i eth0 -nn host 172.31.117.179 -vv
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
19:38:17.872360 IP (tos 0x0, ttl 64, id 49871, offset 0, flags [none], proto UDP (17), length 134)
    172.31.117.179.41479 > 172.31.117.178.8472: [no cksum] OTV, flags [I] (0x08), overlay 0, instance 1
IP (tos 0x0, ttl 63, id 56068, offset 0, flags [DF], proto ICMP (1), length 84)
    10.244.1.91 > 10.244.2.178: ICMP echo request, id 4096, seq 58, length 64
19:38:17.872452 IP (tos 0x0, ttl 64, id 51846, offset 0, flags [none], proto UDP (17), length 134)
    172.31.117.178.56745 > 172.31.117.179.8472: [no cksum] OTV, flags [I] (0x08), overlay 0, instance 1
IP (tos 0x0, ttl 63, id 62999, offset 0, flags [none], proto ICMP (1), length 84)
    10.244.2.178 > 10.244.1.91: ICMP echo reply, id 4096, seq 58, length 64

主流后端

  • vxlan: 扩展vlan,更多的逻辑网络,突破 VLAN的最多 4096个终端的数量现在,vxlan(2**24=~1000w),解决 STP在大型网络设备带宽浪费和收敛性能变慢的缺陷。
    • directrouting: 同一子网内node,直接通过宿主机网卡,直达对端宿主机网卡
  • host-gw: 据说性能比calico还好,但是不支持网络策略

配置使用 vxlan-Directrouting

!!!不建议在生产上修改已经创建好的flannel网络的Kubernetes集群!!!

下载flannel资源清单

# wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

修改configMap资源中net-conf.json的内容

net-conf.json: |
  {
    "Network": "10.244.0.0/16",
    "Backend": {
      "Type": "vxlan",
      "Directrouting": true
    }
  }

删除已有flannel网络

# kubectl delete -f kube-flannel.yml

创建新的flannel网络

# kubectl apply -f kube-flannel.yml

创建好了可以创建一些测试Pods

# kubectl apply -f deploy-demo.yaml

此时路由条目会发现变更,原先需要走flannel.1的路由,现在都直接经过宿主机eth0

# ip r
10.244.0.0/24 dev cni0  proto kernel  scope link  src 10.244.0.1 
10.244.1.0/24 via 172.31.117.179 dev eth0 
10.244.2.0/24 via 172.31.117.178 dev eth0 

# route -n
10.244.1.0      172.31.117.179  255.255.255.0   UG    0      0        0 eth0
10.244.2.0      172.31.117.178  255.255.255.0   UG    0      0        0 eth0
169.254.0.0     0.0.0.0         255.255.0.0     U     1002   0        0 eth0

此时需要注意一个问题,如果环境是在阿里云VPC网络,则需要在单独配置下各node网络路由,不然会超时

重建flannel应用Directrouting后,再次抓包测试,很干净的icmp包

# tcpdump -i eth0 -nn icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
22:10:16.696441 IP 10.244.1.89 > 10.244.2.180: ICMP echo request, id 8192, seq 21, length 64
22:10:16.696487 IP 10.244.2.180 > 10.244.1.89: ICMP echo reply, id 8192, seq 21, length 64
22:10:17.696535 IP 10.244.1.89 > 10.244.2.180: ICMP echo request, id 8192, seq 22, length 64

results matching ""

    No results matching ""