Terway ENIIP模式架构设计
弹性网卡(ENI)支持配置多个辅助IP的功能,单个弹性网卡(ENI)根据实例规格可以分配6-20个辅助IP,ENI多IP模式就是利用了这个辅助IP分配给容器,从而大幅提高了Pod部署的规模和密度。在网络联通的方式上,Terway支持选择veth pair策略路由和ipvlanl两种方案,主要考虑了以下两点。
1.在节点上如何将弹性网卡(ENI)的辅助IP的流量都走对应的弹性网卡,并使用弹性网卡本身的MAC地址而不被丢包。
2.如何兼容容器服务目前广泛的Centos 7.x的3.10的版本的内核。
Pod所使用的CIDR网段和节点的CIDR是同一个网段。
Pod内部可以得到是有一张网卡的,一个是eth0,其中eth0的IP就是Pod的IP,此网卡的MAC地址和控制台上的ENI的MAC地址不一致同时ECS上有多张ethx的网卡。
同时ECS上有多张ethx的网卡,说明ENI附属网卡并不是直接挂载到了Pod的网络命名空间。
Pod内有只有指向eth0的默认路由,说明Pod访问任何地址段都是从eth0为统一的出入口。
容器的网络命名空间中通过ip addr
得到一个eth0@ifxxx的标志位,通过'xxx'可以得到ECS的OS内和容器网络命名空间中的相对应veth pair。在ECS OS内通过ip addr | grep xx:
可以查看cali44ae9fbceeb虚拟网卡,这个就是veth pair在ECS OS侧相对的网卡对。
通过OS Linux Routing可以得到,所有目的是Pod IP的流量都会被转发到Pod对应的calixx虚拟往卡上。因此,ECS OS和Pod的网络命名空间已经建立好完整的出入链路配置了。
在veth pair中实现了多个Pod共享一个ENI的方式来提升了ECS的Pod部署密度,Terway Pod是通过daemonset的方式部署在每个节点上的。
通过下面命令可以得到每个节点上的Terway Pod。通过terway-cli show factory
命令可以得到节点上的附属ENI数量、MAC地址以及每个ENI上的IP。
故Terway ENIIP模式总体可以归纳为:
在网络联通的方式上,采用选择veth pair策略路由。
一对veth pair来联通宿主机和Pod的网络空间,Pod的地址是来源于弹性网卡的辅助IP地址,并且节点上需要配置策略路由来保证辅助IP的流量经过它所属的弹性网卡。
同主机上的容器通信直接通过主机上的路由到同一个主机上别的容器对应的veth上。
不同主机的容器通信经过VPC的网络转发到对应的机器上,再通过机器上的路由转发到容器中。
容器和其所在的宿主机之间的通信直接通过连接到宿主机Namespace的veth pair和路由打通。
容器到其他主机通过VPC的网络转发到对应的机器,其他主机到容器通过VPC网络转发到对应的弹性网卡,然后通过路由转发到容器的veth上。
容器到专线和共享服务也都是通过VPC的网络转发。
容器到公网的访问经过vSwitch配置的SNAT网关直接将源IP转换成EIP的地址到外部网络。
弹性网卡(ENI)支持配置多个辅助IP的功能,单个弹性网卡(ENI)根据实例规格可以分配6-20个辅助IP,ENI多IP模式就是利用了这个辅助IP分配给容器,从而大幅提高了Pod部署的规模和密度。
Terway ENIIP模式容器网络数据链路剖析
以将Terway ENI模式下的网络链路大体分为以Pod IP对外提供服务和以SVC对外提供服务两个大的SOP场景,进一步细分,可以归纳为12个不同的小的SOP场景。
对这12个场景的数据链路梳理合并,这些场景可以归纳为下面7类典型的场景:
访问 Pod IP,同节点访问Pod。
访问Pod IP/SVC IP(Cluster or Local),同节点Pod间互访(Pod属于同or不同ENI)。
访问PodIP,异节点Pod间互访。
集群内非SVC后端Pod所在节点访问SVC Cluster IP。
Cluster模式,集群内非SVC后端Pod所在节点访问SVC External IP。
Local模式,集群内非SVC后端Pod所在节点访问SVC External IP。
集群外访问SVC External IP。
场景一:访问Pod IP,同节点访问Pod
环境
xxx.10.0.1.82节点上存在nginx-7d6877d777-zp5jg,IP地址10.0.1.104。
内核路由
nginx-7d6877d777-zp5jg,IP地址10.0.1.104,该容器在宿主机表现的PID是1094736,该容器网络命名空间有指向容器eth0的默认路由。
该容器eth0在ECS OS 内对应veth pair是calif03b26f9a43。
在ECS OS内,有指向Pod IP,下一跳为calixxxx的路由,通过前文可以知道calixxx网卡是和每个Pod内的veth1组成的pair。所以,Pod内访问SVC的CIDR会有指向veth1的路由,不会走默认的eth0路由。因此calixx网卡在这里的主要作用是用于:
1.节点访问Pod。
2.当节点或者Pod访问SVC的CIDR时,会走ECS OS内核协议栈转换,走到calixxx和veth1访问Pod。
小结
nginx-7d6877d777-zp5jg netns eth0可以抓到数据包。
nginx-7d6877d777-zp5jg calif03b26f9a43可以抓到数据包。
数据链路转发示意图:
会经过calixx网卡,每个非host network的Pod会和calixx网卡形成veth pair,用于和其他Pod或Node进行通信。
整个链路的请求不会经过Pod所分配的ENI,而是直接在OS的Namespace中命中IP规则被转发。
整个请求链路是OS -> calixxxxx -> ECS Pod net eth0。
整个链路会经过两次内核协议栈:ECS OS和Pod。
场景二:访问Pod IP/SVC IP(Cluster or Local),同节点Pod访问Pod(Pod属于同or不同ENI)
环境
xxx.10.0.1.82节点上存在nginx-7d6877d777-zp5jg,IP地址10.0.1.104。
xxx.10.0.1.82节点上存在centos-67756b6dc8-h5wnp,IP地址10.0.1.91。
Service是nginx,Cluster IP是192.168.2.115,External IP是10.0.3.62。
内核路由
nginx-7d6877d777-zp5jg IP地址10.0.1.104,容器在宿主机表现的PID是1094736,该容器网络命名空间有指向容器eth0的默认路由。
该容器eth0在ECS OS内对应veth pair是calif03b26f9a43。
用上述类似办法可以发现centos-67756b6dc8-h5wnp的veth pair的cali44ae9fbceeb,Pod网络空间只有默认路由。
在ECS OS内,有指向Pod IP,下一跳为calixxxx的路由,通过前文可以知道calixxx网卡是和每个Pod内的veth1组成的pair,所以,Pod内访问SVC的CIDR会有指向veth1的路由,不会走默认的eth0路由。因此calixx网卡在这里的主要作用是用于:
1.节点访问Pod。
2.当节点或者Pod访问 SVC的CIDR时,会走ECS OS内核协议栈转换,走到calixxx和eth0访问Pod。
说明相关的路由转发是在ECS OS层面进行的,Pod的calixx网卡起到了一个桥梁和连通的作用。
源端ECS上的IPVS规则(如果访问的是SVC IP)
如果同节点上访问的是SVC的IP(Cluster IP或External IP)。查看SVC的相关IPVS转发规则:
Service的ExternalTrafficPolicy是Local
SVC nginx Cluster IP是192.168.2.115,External IP是10.0.3.62,后端是10.0.1.104和10.0.3.58。
xxx.10.0.1.82节点:
对于SVC的Cluster IP,可以得到SVC的后端两个Pod都会被加到IPVS的转发规则。
对于SVC的External IP,可以得到SVC的后端,只有该节点的后端Pod 10.0.1.104才会被加到IPVS的转发规则。
在LoadBalancer的SVC模式下,如果ExternalTrafficPolicy为Local,对于Cluster IP来说,会将所有SVC后端Pod都会加到该节点的IPVS转发规则;对于External IP,只会将该节点上的SVC后端Pod才会加到IPVS规则中。如果该节点没有SVC后端Pod,则该节点上的Pod访问SVC的External IP将会失败。
Service的ExternalTrafficPolicy是Cluster
SVC nginx1 Cluster IP是192.168.2.253,External IP是10.0.3.63,后端是10.0.1.104和10.0.3.58。
xxx.10.0.1.82节点。
对于SVC的Cluster IP,可以得到SVC的后端两个Pod都会被加到IPVS的转发规则。
对于SVC的External IP,可以得到SVC的后端两个Pod都会被加到IPVS的转发规则。
在LoadBalancer的SVC模式下,如果ExternalTrafficPolicy为Cluster,对于Cluster IP或External IP来说,会将所有SVC后端Pod都会加到该节点的IPVS转发规则。
小结
Conntrack表信息
Service nginx的ExternalTrafficPolicy是Local
SVC nginx Cluster IP是192.168.2.115,External IP是10.0.3.62,后端是10.0.1.104和10.0.3.58。
如果访问的是SVC的Cluster IP,通过conntrack信息,可以得到src是源端Pod 10.0.1.91,dst是SVC Cluster IP 192.168.2.115,dport是SVC中的port。并且期望是10.0.1.104来回包给10.0.1.91。
如果访问的是SVC的External IP,通过conntrack信息,可以得到src是源端Pod 10.0.1.91,dst是SVC External IP为10.0.3.62中的port。并且期望是10.0.1.104来回包给10.0.1.91。
Service nginx1的ExternalTrafficPolicy是Cluster
SVC nginx1 Cluster IP是192.168.2.253,External IP是10.0.3.63,后端是0.0.1.104和10.0.3.58。
如果访问的是SVC的Cluster IP,通过conntrack信息,可以得到src是源端Pod 10.0.1.91,dst是SVC Cluster IP 192.168.2.253,dport是SVC中的port。并且期望是10.0.1.104来回包给10.0.1.91。
如果访问的是SVC的External IP,通过conntrack信息,可以得到src是源端Pod 10.0.1.91,dst是SVC External IP 10.0.3.63,dport是SVC中的port。并且期望是节点ECS的IP 10.0.1.82来回包给10.0.1.91。
综上可以得到src变换了多次,故在Cluster模式下,会存在丢失真实客户端IP的情况。
数据链路转发示意图:
会经过calixx网卡,每个非host network的Pod会和calixx网卡形成veth pair,用于和其他Pod或Node进行通信。
整个链路的请求不会经过Pod所分配的ENI,而是直接在OS的Namespace中命中IP规则被转发。
整个请求链路是ECS1 Pod1 eth0 -> Pod1 calixxxx -> Pod2 calixxxx -> ECS1 Pod2 eth0。
访问SVC IP,SVC会在源端Pod eth0和calixxx网卡捕捉到,在目的端Pod的eth0和calixxx时捕捉不到。
在LoadBalancer的SVC模式下,如果ExternalTrafficPolicy为Local,对于Cluster IP来说,会将所有SVC后端Pod都会加到该节点的IPVS转发规则;对于External IP,只会将该节点上的SVC后端Pod才会加到IPVS规则中。
在LoadBalancer的SVC模式下,如果ExternalTrafficPolicy为Cluster,对于Cluster IP或External IP来说,会将所有SVC后端Pod都会加到该节点的IPVS转发规则,同时无法保留src地址。
场景三:访问PodIP,异节点Pod间互访
环境
xxx.10.0.1.82节点上存在centos-67756b6dc8-h5wnp,IP地址10.0.1.91。
xxx.10.0.3.49节点上存在nginx-7d6877d777-lwrfc,IP地址10.0.3.58。
内核路由
centos-67756b6dc8-h5wnp,IP地址10.0.1.104,该容器在宿主机表现的PID是2211426,该容器网络命名空间有指向容器eth0的默认路由。
centos-67756b6dc8-h5wnp的veth pair的cali44ae9fbceeb,Pod网络空间只有默认路由。
在ECS OS内,有指向Pod IP,下一跳为calixxxx的路由,通过前文可以知道calixxx网卡是和每个Pod内的veth1组成的pair,所以Pod内访问SVC的CIDR会有指向veth1的路由,不会走默认的eth0路由。因此calixx网卡在这里的主要作用是用于:
1.节点访问Pod。
2.当节点或者Pod访问SVC的CIDR时,会走ECS OS内核协议栈转换,经过calixxx和eth0访问Pod。对于目的为外部地址,则经过Pod所属的ENI出ECS进入到了VPC。
小结
数据链路转发示意图:
会经过calixx网卡,每个非host network的Pod会和calixx网卡形成veth pair,用于和其他Pod或Node进行通信。
整个链路的请求不会经过Pod所分配的ENI,而是直接在OS的Namespace中命中IP规则被转发。
出ECS后,根据要访问的Pod和该Pod ENI所属Vswitch,命中VPC路由规则或者直接VSW上的二层转发。
整个请求链路是ECS1 Pod1 eth0-> ECS1 Pod1 calixxxxx-> ECS1 ethx -> vpc route rule(如有) -> ECS2 ethx -> ECS2 Pod2 calixxxxx -> ECS2 Pod2 eth0。
场景四:集群内非SVC后端Pod所在节点访问SVC Cluster IP
环境
xxx.10.0.3.49节点上存在nginx-7d6877d777-h4jtf,IP地址10.0.3.58。
xxx.10.0.1.82节点上存在centos-67756b6dc8-h5wnp,IP地址10.0.1.91。
Service1是nginx,Cluster IP是192.168.2.115,External IP是10.0.3.62。
Service2是nginx1,Cluster IP是192.168.2.253,External IP是10.0.3.63。
内核路由
内核路由部分,请参见场景二:访问Pod IP/SVC IP(Cluster or Local),同节点Pod访问Pod(Pod属于同or不同ENI)和场景三:访问PodIP ,异节点Pod间互访小结中详细说明。
源端ECS上的IPVS规则
根据场景二:访问Pod IP/SVC IP(Cluster or Local),同节点Pod访问Pod(Pod属于同or不同ENI)小结中的源端ECS上的IPVS规则,可以得到:无论在哪种SVC模式下,对于Cluster IP来说,会将所有SVC后端Pod都会加到该节点的IPVS转发规则。
小结
Conntrack表信息
Service nginx的ExternalTrafficPolicy是Local
SVC nginx Cluster IP是192.168.2.115,External IP是10.0.3.62,后端是10.0.1.104和10.0.3.58。
xxx.10.0.1.82节点:
源端ECS上src是源端Pod 10.0.1.91,dst是SVC Cluster IP 192.168.2.115,dport是SVC中的port,并且期望是10.0.3.58来回包给10.0.1.91。
xxx.10.0.3.49节点:
目的端ECS上src是源端Pod 10.0.1.91,dst是Pod的IP 10.0.3.58,dport是Pod的port。并且期望此Pod来回包给10.0.1.91。
Service nginx1的ExternalTrafficPolicy是Cluster
SVC nginx1 ClusterIP是192.168.2.253,External IP是10.0.3.63,后端是10.0.1.104和10.0.3.58。
xxx.10.0.1.82节点:
源端ECS上src是源端Pod 10.0.1.91,dst是SVC Cluster IP 192.168.2.115,dport是SVC中的port。并且期望是10.0.3.58来回包给10.0.1.91。
xxx.10.0.3.49节点:
目的端ECS上src是源端Pod 10.0.1.91,dst是Pod的IP 10.0.3.58,dport是Pod的port。并且期望此Pod来回包给10.0.1.91。
对于Cluster IP来说,源端ECS会将所有SVC后端Pod都会加到该节点的IPVS转发规则,目的端ECS是捕获不到任何SVC Cluster IP信息的,只能捕获到源端Pod的IP,所以回包的时候会回到源端Pod的附属网卡上。
数据链路转发示意图:
会经过calixx网卡,每个非host network的Pod会和calixx网卡形成veth pair,用于和其他Pod或Node进行通信。
整个链路的请求不会经过Pod所分配的ENI,而是直接在OS的Namespace中命中IP规则被转发。
出ECS后,根据要访问的Pod和该Pod ENI所属Vswitch,命中VPC路由规则或者直接VSW上的二层转发。
整个请求链路是:
去方向:
ECS1 Pod1 eth0 -> ECS1 Pod1 calixxxxxx -> ECS1主网卡 eth0 -> vpc route rule(如有)-> ECS2附属网卡ethx -> ECS2 Pod2 calixxxxx -> ECS2 Pod2 eth0。
回方向:
ECS2 Pod2 eth0 -> ECS2 Pod2 calixxxxx -> ECS2附属网卡ethx -> vpc route rule(如有) -> ECS1附属网卡eth1 -> ECS1 Pod1 calixxxxxx -> ECS1 Pod1 eth0。
对于Cluster IP来说,源端ECS会将所有SVC后端Pod都会加到该节点的IPVS转发规则,目的端ECS是捕获不到任何SVC Cluster IP信息的,只能捕获到源端Pod的IP,所以回包的时候会回到源端Pod的附属网卡上。
场景五:Cluster模式,集群内非SVC后端Pod所在节点访问SVC External IP
环境
xxx.10.0.3.49节点上存在nginx-7d6877d777-h4jtf ,IP地址10.0.3.58。
xxx.10.0.1.82节点上存在centos-67756b6dc8-h5wnp,IP地址10.0.1.91。
Service2是nginx1 ,Cluster IP是192.168.2.253,External IP是10.0.3.63。
内核路由
内核路由部分,请参见场景二:访问Pod IP/SVC IP(Cluster or Local),同节点Pod访问Pod(Pod属于同or不同ENI)和场景三:访问PodIP ,异节点Pod间互访小结中详细说明。
源端ECS上的IPVS规则
根据场景二:访问Pod IP/SVC IP(Cluster or Local),同节点Pod访问Pod(Pod属于同or不同ENI)小结中的源端ECS上的IPVS规则,可以得到:ExternalTrafficPolicy为Cluster模式下,对于External IP来说,会将所有SVC后端Pod都会加到该节点的IPVS转发规则。
小结
Conntrack表信息
Service nginx1 的ExternalTrafficPolicy是Cluster
SVC nginx1 Cluster IP是192.168.2.253,External IP是10.0.3.63,后端是10.0.1.104和10.0.3.58。
xxx.10.0.1.82节点:
源端ECS上src是源端Pod 10.0.1.91,dst是SVC External IP 10.0.3.63,dport是SVC中的port。并且期望是10.0.3.58来回包给源端ECS的地址10.0.1.82。
xxx.10.0.3.49节点:
目的端ECS上src是源端Pod所在的ECS地址10.0.1.82,dst是Pod的IP 10.0.3.58,dport是Pod的port。并且期望此Pod来回包给源端ECS的地址10.0.1.82。
在ExternalTrafficPolicy为Cluster下,对于External IP来说,源端ECS会将所有SVC后端Pod都会加到该节点的IPVS转发规则,目的端ECS是捕获不到任何SVC External IP信息的,只能捕获到源端Pod所在的ECS的IP,所以回包的时候会回到源端Pod所在的ECS的主网卡上,这一点明显和场景四:群内非SVC后端Pod所在节点访问SVC Cluster IP小结中访问CusterIP有很明显区别。
数据链路转发示意图:
会经过calixx网卡,每个非host network的Pod会和calixx网卡形成veth pair,用于和其他Pod或Node进行通信。
整个链路的请求不会经过Pod所分配的ENI,而是直接在OS的Namespace中命中IP规则被转发。
出ECS后,根据要访问的Pod和该Pod ENI所属Vswitch,命中VPC路由规则或者直接VSW上的二层转发。
整个请求链路是ECS1 Pod1 eth0 -> ECS1 Pod1 calixxxx -> ECS1主网卡ENI eth0 -> vpc route rule(如有) -> ECS2附属网卡ethx -> ECS2 Pod2 calixxx -> ECS2 Pod2 eth0。
在ExternalTrafficPolicy为Cluster下,对于External IP来说,源端ECS会将所有SVC后端Pod都会加到该节点的IPVS转发规则,目的端ECS是捕获不到任何SVC External IP信息的,只能捕获到源端Pod所在的ECS的IP,所以回包的时候会回到源端Pod所在的ECS的主网卡。
场景六:Local模式,集群内非SVC后端Pod所在节点访问SVC External IP
环境
xxx.10.0.3.49节点上存在nginx-7d6877d777-h4jtf IP地址10.0.3.58。
xxx.10.0.1.82节点上存在centos-67756b6dc8-h5wnp IP地址10.0.1.91。
Service1是nginx,Cluster IP是192.168.2.115 External IP是10.0.3.62。
内核路由
内核路由部分已经在场景二:访问Pod IP/SVC IP(Cluster or Local),同节点Pod访问Pod(Pod属于同or不同ENI)和场景三:访问PodIP ,异节点Pod间互访小结中详细说明,这里不再进行过多阐述。
源端ECS上的IPVS规则
Service的ExternalTrafficPolicy是Local
SVC nginx Cluster IP是192.168.2.115,External IP是10.0.3.62,后端是10.0.1.104和10.0.3.58。
xxx.10.0.1.82节点:
对于SVC的External IP,可以得到SVC的后端,无任何转发规则。
根据场景二:访问Pod IP/SVC IP(Cluster or Local),同节点Pod访问Pod(Pod属于同or不同ENI)小结中的源端ECS上的IPVS规则,可以得到:ExternalTrafficPolicy为Local模式下,对于External IP来说,只会将本节点上的SVC的后端Pod加到节点上的IPVS转发规则,如果该节点没有SVC后端,则不会有任何可以转发的规则。
小结
Conntrack表信息
Service的ExternalTrafficPolicy是Local
SVC nginx1 Cluster IP是192.168.2.253,External IP是10.0.3.63,后端是10.0.1.104和10.0.3.58。
xxx.10.0.1.82无任何conntrack记录表生成。
数据链路转发示意图:
会经过calixx网卡,每个非host network的Pod会和calixx网卡形成veth pair,用于和其他Pod或Node进行通信。
整个链路的请求不会经过Pod所分配的ENI,而是直接在OS的Namespace中命中IP规则被转发。
整个请求链路是ECS1 Pod1 eth0 -> ECS1 Pod1 calixxxx -> ECS host空间ipvs/iptables规则,无后端转发ep终止链路。
ExternalTrafficPolicy为Local模式下,对于External IP来说,只会将本节点上的SVC的后端Pod加到节点上的IPVS转发规则,如果该节点没有SVC后端,则不会有任何可以转发的规则。
场景七:集群外访问SVC External IP
环境
xxx.10.0.3.49节点上存在nginx-7d6877d777-h4jtf,IP地址10.0.3.58。
xxx.10.0.1.47节点上存在nginx-7d6877d777-kxwdb,IP地址10.0.1.29。
Service1是nginx,Cluster IP是192.168.2.115 External IP是10.0.3.62。
SLB相关配置
在SLB控制台,lb-xxxxx虚拟服务器组的后端服务器组是两个后端nginx Pod的ENI eni-j6c4qxbpnkgxxxxx和eni-j6c6r7mxxx。
从集群外部角度看,SLB的后端虚拟服务器组是SVC的后端Pod所属的两个ENI网卡,内网的IP地址就是Pod的地址。
小结
数据链路转发示意图:
数据链路:client -> SLB -> Pod ENI + Pod Port -> ECS1 Pod1 eth0。