Flannel模式架构设计
Flannel模式下,ECS只有一个主网卡ENI,无其他附属网卡,ECS和节点上的Pod与外部通信都需要通过主网卡进行。
ACK Flannel会在每个节点创建cni0虚拟网卡作为Pod网络和ECS的主网卡eth0之间的桥梁。
集群的每个节点会启动一个Flannel Agent,并且会给每个节点预分配一个Pod CIDR,这个Pod CIDR是ACK集群的Pod CIDR的子集。
容器的网络命名空间内会有一个eth0的虚拟网卡,同时存在下一跳指向该网卡的路由,该网卡会作为容器和宿主内核进行数据交换的出入口,容器和宿主机之间的数据链路是通过veth pair进行交换的。
容器的网络命名空间中通过ip addr
得到一个eth0@ifxxx的标志位,其中‘xx'和ECS的OS的网络命名空间的veth pair相对应。
在ECS OS内通过ip addr | grep xx:
可以获得vethdxxx虚拟网卡,这个就是veth pair在ECS OS侧相对应的veth pair。
到目前为止容器内和OS数据链路已经建立连接了。通过OS Linux Routing可以得到,所有目的是Pod CIDR网段的流量都会被转发到cni0这张虚拟网卡,那么cni0是通过bridge方式将不同目的数据链路指向到不同的vethxxx。到这里为止,ECS OS和Pod的网络命名空间已经建立好完整的出入链路配置了。
Flannel模式器网络数据链路剖析
针对容器网络特点,可以将Flannel模式下的网络链路大体分为以Pod IP对外提供服务和以SVC对外提供服务两个大的SOP场景,进一步可以细分为10个不同的小的SOP场景。
对这10个场景的数据链路梳理合并,这些场景可以归纳为下面5类典型的场景:
Client和服务端Pod部署于同一个ECS
Client和服务端Pod部署于不同ECS
访问SVC External IP, ExternalTrafficPolicy 为Cluster时,Client和服务端Pod部署于不同ECS,其中Client为集群外
访问SVC External IP, ExternalTrafficPolicy 为Local时, Client和服务端Pod部署于不同ECS,其中Client为集群内
访问SVC External IP, ExternalTrafficPolicy 为Local时, Client和服务端Pod部署于不同ECS,其中Client为集群外
场景一:Client和服务端Pod部署于同一个ECS
此场景包含下面几个子场景,数据链路可以归纳为一种:
以Pod IP对外提供服务,Client和Pod部署于同一个节点。
以SVC Cluster IP对外提供服务,Client和SVC后端Pod部署于同一节点。
以SVC External IP对外提供服务,ExternalTrafficPolicy为Cluster/Local情况下,Client和SVC后端Pod部署于同一节点。
环境
xxx.10.0.0.180节点上存在两个Pod:centos-67756b6dc8-rmmxt IP地址172.23.96.23和nginx-7d6877d777-6jkfg和172.23.96.24。
内核路由
centos-67756b6dc8-rmmxt,IP地址172.23.96.23,该容器在宿主机表现的PID是503478,该容器网络命名空间有指向容器eth0的默认路由。
该容器eth0在ECS OS 内对应veth pair是vethd7e7c6fd。
通过上述类似的办法,可以得到nginx-7d6877d777-6jkfg,IP地址172.23.96.24,该容器在宿主机表现的PID是2981608,该容器eth0在ECS OS内对应veth pair是vethd3fc7ff4。
在ECS OS内,有指向Pod CIDR,下一跳为cni0的路由,以及cni0中有两个容器的vethxxx网桥信息。
小结
数据链路转发示意图:
数据链路:ECS1 Pod1 eth0 -> vethxxx1 -> cni0 -> vethxxx2 -> ECS1 Pod2 eth0。
场景二:Client和服务端Pod部署于不同ECS
此场景包含下面几个子场景,数据链路可以归纳为一种:
以Pod IP对外提供服务,Client和Pod部署于不同节点。
以SVC Cluster IP对外提供服务,Client和SVC后端Pod部署于不同节点。
以SVC External IP对外提供服务,ExternalTrafficPolicy为Cluster情况下,集群内Client和SVC后端Pod部署于不同节点。
环境
xxx.10.0.0.180节点上存在两个Pod:centos-67756b6dc8-rmmxt,IP地址172.23.96.23,以及nginx1-76c99b49df-7plsr,IP地址172.23.96.163。
Service nginx1的ExternalTrafficPlicy为Cluster。
源端Pod所在ECS的IPVS规则
源端数据链路访问SVC的Cluster IP 192.168.13.23时,如果链路到达ECS的OS内,会命中IPVS规则,被解析到SVC的后端Endpoint之一(本实例中只有一个Pod,所以Endpoint只有一个)。
小结
数据链路转发示意图:
VPC路由表会自动配置目的地址是Pod CIDR,下一跳为Pod网段所归属的ECS的自定义路由条目,该规则由ACK管控测通过OpenAPI调用VPC去配置,无需手动配置和删除。
Conntrack表信息(访问SVC情况)
Node1:
src是源Pod IP,dst是SVC的Cluster IP,并且期望是由SVC的其中一个Endpoint 172.23.96.163来回消息给源端Pod。
Node2:
目的Pod所在ECS上conntrack表记录是由源端Pod访问目的Pod,不会记录SVC的Cluster IP地址。
数据链路:ECS1 Pod1 eth0 ->vethxxx1 -> cni0 -> ECS 1 eth0 -> VPC -> ECS2 eth0 -> cni0 -> vethxxx2 -> ECS2 Pod2 eth0。
VPC路由表会自动配置目的地址是Pod CIDR,下一跳为Pod网段所归属的ECS的自定义路由条目,该规则由ACK管控测通过OpenAPI调用VPC进行配置,无需手动配置和删除。
如果访问的SVC的Cluster IP,或者是Cluster模式下,访问SVC的External IP。数据链路通过veth pair进到ECS OS内后,会命中相应的IPVS规则,并根据负载规则,选择IPVS的某一个后端,继而进入其中的一个SVC的后端Endpoint,SVC的IP只会在Pod的eth0 、veth pair和vethxxx被捕捉到,其他链路环节不会捕捉到SVC的IP。
场景三:ExternalTrafficPolicy为Local时,Client和服务端Pod部署于集群内不同ECS
此场景包含下面几个子场景,数据链路可以归纳为一种:以SVC External IP对外提供服务,ExternalTrafficPolicy为Local情况下,集群内Client和SVC后端Pod部署于不同节点。
环境
xxx.10.0.0.180节点上存在两个Pod:centos-67756b6dc8-rmmxt,IP地址172.23.96.23,以及nginx1-76c99b49df-7plsr,IP地址172.23.96.163。
Service nginx1 ExternalTrafficPolicy为Local。
源端Pod所在ECS的IPVS规则
源端数据链路访问SVC的External IP 8.xx.xxx.113时,如果链路到达ECS的OS内,会命中IPVS规则,但无External IP的Endpoint。所以链路达到OS后,会命中IPVS规则,但是没有后端Pod,所以会出现connection refused。
小结
数据链路转发示意图:
数据链路:ECS1 Pod1 eth0 -> vethxxx1 ->中断。
如果访问的SVC的External IP,或者是Local模式下,访问SVC的External IP,数据链路通过veth pair进到ECS OS内后,会命中相应的IPVS规则。但是由于Local模式下External IP的IPVS后端为空,所以命中规则无转发后端,整个链路会在IPVS终止,访问失败。所以,建议集群内采用K8s官方推荐的方式进行访问,即使用ClusterIP进行访问。
场景四:ExternalTrafficPolicy为Local时,Client来自于集群外
此场景数据链路可以归纳为一种:访问SVC External IP,ExternalTrafficPolicy为Local时,Client和服务端Pod部署于不同ECS,其中Client为集群外。
环境
Deployment为nginx1,共有三个Pod。其中,nginx1-76c99b49df-4zsdj和nginx1-76c99b49df-7plsr部署在 xxx.10.0.1.206 ECS上,第三个Pod nginx1-76c99b49df-s6z79部署在其他节点xxx.10.0.1.216上。
Service nginx1的ExternalTrafficPlicy为Local。
SLB相关配置
SLB后端的虚拟服务器组中只有两个ECS节点xxx.10.0.1.216和xxx.10.0.1.206。集群内的其他节点 ,例如xxx.10.0.0.180,并未被添加到SLB的后端虚拟服务器组中。服务器组的IP为ECS的IP,端口为Service中NodePort的端口32580。
故ExternalTrafficPolicy为Local模式下,只有Service后端Pod所在的ECS节点才会被加入到SLB的后端虚拟服务器组中,参与SLB的流量转发,集群内的其他节点不参与SLB的转发。
SLB虚拟服务器组ECS的IPVS规则
从SLB的虚拟服务器组中的两个ECS可知,NodeIp+NodePort的IPVS转发规则是不同的。ExternalTrafficPolicy为Local模式下,只有该节点上存在相应后端Pod,此Pod IP才会被加到该节点的IPVS转发规则中,其他节点上的后端Pod不会加进来,这样保证了被SLB转发的链路,只会被转到该节点上的Pod,不会转发到其他节点上。
Node1:xxx.10.0.1.206
Node2:xxx.10.0.1.216
小结
数据链路转发示意图:
该图示意了只有后端Pod所在ECS才会加到SLB后端中,从集群外部访问SVC的External IP(SLB IP)的情况,可见数据链路只会被转发到虚拟服务器组中的ECS,不会再被转发到集群内其他节点上。
Conntrack表信息
Node:
其中src是集群外部客户端IP,dst是节点IP,dport是SVC中的NodePort。并且期望是由该ECS上的Pod 172.23.96.82来回包给源端。
数据链路:Client -> SLB -> ECS eth0 + ECS NodePort -> cni0 -> vethxxx -> ECS1 Pod1 eth0。
ExternalTrafficPolicy为Local模式下,只有有Service后端Pod所在的ECS节点才会被加入到SLB的后端虚拟服务器组中,参与SLB的流量转发,集群内的其他节点不参与SLB的转发。
场景五:ExternalTrafficPolicy为Cluster时,Client来自于集群外
此场景数据链路可以归纳为一种:访问SVCExternal IP,ExternalTrafficPolicy为luster时,Client和服务端Pod部署于不同ECS,其中Client为集群外。
环境
Deployment为nginx1,共有三个Pod。其中,nginx1-76c99b49df-4zsdj和nginx1-76c99b49df-7plsr部署在 xxx.10.0.1.206 ECS上,第三个Pod nginx1-76c99b49df-s6z79部署在其他节点xxx-1.10.0.1.216上。
Service nginx2的ExternalTrafficPlicy为Cluster。
SLB相关配置
从SLB控制台,集群内所有节点xxx-1.10.0.0.180、xxx-1.10.0.1.216和xxx-1.10.0.1.206都被加到SLB的虚拟服务器组中。其中虚拟服务器组的IP为ECS的IP,端口为Service中NodePort的端口30875。
故ExternalTrafficPolicy为CLuster模式下,集群内所有的ECS节点都会被加入到SLB的后端虚拟服务器组中,参与SLB的流量转发。
SLB虚拟服务器组ECS的IPVS规则
从SLB的虚拟服务器组中的可以得到,对于NodeIp+NodePort的IPVS转发规则是一致的。ExternalTrafficPolicy为Cluster模式下,所有的Service后端Pod都会被加到所有节点的IPVS的转发规则中,即使是该节点有后端Pod,流量也不一定会被转发到该节点上Pod,可能会被转发到其他节点上的后端Pod。
Node1:xxx.10.0.1.206(该节点有后端Pod)
Node2:xxx.10.0.1.216(该节点有后端Pod)
Node3:xxx.10.0.0.180(该节无后端Pod)
小结
数据链路转发示意图:
该图示意了集群内所有ECS都会被加到SLB后端中,从集群外部访问SVC的External IP(SLB IP)的情况,数据流量可能会被转发到其他节点上。
Conntrack表信息
链路1:
xxx.10.0.0.180节点:
此时数据链路对应示意图中的链路1,数据链路被转到xxx.10.0.0.180节点,该节点上并没有Service的后端Pod,通过conntrack信息,可以得到:
其中src是集群外部客户端IP,dst是节点IP,dport是SVC中的NodePort。并且期望是172.23.96.163来回包给10.0.0.180。通过前述信息,可以得知172.23.96.163是nginx1-76c99b49df-7plsr的IP,此Pod部署在xxx.10.0.1.206。
xxx.10.0.1.206节点:
通过此节点conntrack表,可以得到src是node xxx.10.0.0.180,dst是172.23.96.163的80端口,回包也是直接回给node xxx.10.0.0.180。
综上可以得到src变换了多次,故在Cluster模式下,会存在丢失真实客户端IP的情况。
链路2:
其中src是集群外部客户端IP,dst是节点IP,dport是SVC中的NodePort。并且期望是由该ECS上的Pod 172.23.96.82来返回给172.23.96.65,此地址是SLB集群中的一个地址。
数据链路:
情景一:Client -> SLB -> ECS eth0 + ECS NodePort -> cni0 -> vethxxx -> ECS1 Pod1 eth0。
情景二:Client -> SLB -> ECS1 eth0 + ECS1 NodePort -> OS Routing -> ECS2 eth0 + Pod port -> cni0 -> vethxxx -> ECS2 Pod1 eth0。
ExternalTrafficPolicy为Cluster模式下,Kubernetes所有ECS节点都会被加入到SLB的后端虚拟服务器组中,参与SLB的流量转发,此时会存在数据路在集群内被多个ECS转发的场景。该情况下,可能存在真实客户端IP丢失的情况。