flannel
flannel是常见的cni插件之一,Kubernetes CNI插件是由kubelet维护管理的,因为kubelet要借助于CNI插件设置Pods网络接口,添加网络以及激活网络
安装Kubernetes集群时,我用的是kubeadm,以致于除了docker和kubelet其他组件基本都是托管在k8s之上,所以运行flannel也是一样
从flannel官方给的资源清单文件中,可以看到它主要做了这么几件事
创建一个名为flannel的集群角色,并设置了资源访问权限,它授权了两种资源,PODS、NODES,对于
pods
只开放了get
,而对于node
开放了list watch
,同时针对特定的nodes/status
资源开放了patch
的权限创建一个名为flannel的ServiceAccount
创建集群角色绑定,将名为flannel的sa和flannel集群角色绑定在一起
创建一个configMap资源,里面存储了flannel的配置文件,配置文件里定义了flannel相关的参数
创建了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