1. 前言
近几年,企业基础设施云原生化的趋势越来越强烈,从最开始的IaaS化到现在的微服务化,客户的颗粒度精细化和可观测性的需求更加强烈。容器网络为了满足客户更高性能和更高的密度,也一直在高速的发展和演进中,这必然对客户对云原生网络的可观测性带来了极高的门槛和挑战。为了提高云原生网络的可观测性,同时便于客户和前后线同学增加对业务链路的可读性,ACK产研和AES联合共建,合作开发ack net-exporter和云原生网络数据面可观测性系列,帮助客户和前后线同学了解云原生网络架构体系,简化对云原生网络的可观测性的门槛,优化客户运维和售后同学处理疑难问题的体验 ,提高云原生网络的链路的稳定性。
鸟瞰容器网络,整个容器网络可以分为三个部分:Pod网段,Service网段和Node网段。 这三个网络要实现互联互通和访问控制,那么实现的技术原理是什么?整个链路又是什么,限制又是什么呢?Flannel, Terway有啥区别?不同模式下网络性能如何?这些,需要客户在下搭建容器之前,就要依据自己的业务场景进行选择,而搭建完毕后,相关的架构又是无法转变,所以客户需要对每种架构特点要有充分了解。比如下图是个简图,Pod网络既要实现同一个ECS的Pod间的网络互通和控制,又要实现不同ECS Pod间的访问, Pod访问SVC 的后端可能在同一个ECS 也可能是其他ECS,这些在不同模式下,数据链转发模式是不同的,从业务侧表现结果也是不一样的。
本文是[全景剖析容器网络数据链路]第二部分,主要介绍Kubernetes Terway ENI模式下,数据面链路的转转发链路,一是通过了解不同场景下的数据面转发链路,从而探知客户在不同的场景下访问结果表现的原因,帮助客户进一步优化业务架构;另一方面,通过深入了解转发链路,从而在遇到容器网络抖动时候,客户运维以及阿里云同学可以知道在哪些链路点进行部署观测手动,从而进一步定界问题方向和原因。
系列一:全景剖析阿里云容器网络数据链路(一)—— Flannel
系列二:全景剖析阿里云容器网络数据链路(二)—— Terway ENI
系列三:全景剖析阿里云容器网络数据链路(三)—— Terway ENIIP
系列四:全景剖析阿里云容器网络数据链路(四)—— Terway IPVLAN+EBPF
系列五:全景剖析阿里云容器网络数据链路(五)—— Terway ENI-Trunking
系列六:全景剖析阿里云容器网络数据链路(六)—— ASM Istio
2. Terway ENI 模式架构设计
Terway ENI 模式下,ENI的网络都是和VPC同样的网段,ENI网络就是从Aliyun的VPC网络中创建和绑定一个弹性网卡到ECS节点上, 然后Pod利用这个弹性网卡和别的网络互通,这里需要关注的是弹性网卡的数量是有限制的,具体的根据实例类型有不同的配额。
Pod 所使用的CIDR网段和节点的CIDR是同一个网段
Pod 内部可以看到是有两张网卡的,一个是eth0,另一个是veth1,其中eth0 的IP就是 Pod的IP,此网卡的MAC地址和控制台上的ENI的MAC地址可以匹配,说明此网卡就是附属ENI网卡,被直接挂载到了Pod的网络命名空间内。
Pod内有指向eth0的默认路由,同时还有指向目的网段为192.168.0.0/16, 下一跳为 veth1网卡的路由,其中192.168.0.0/16 网段为集群的service网段,说明集群内Pod访问SVC的clusterIP网段,数据链路会经过veth1 网卡到宿主机ECS的OS内进行下一步判断,其他情况是走eth0直接进入到VPC
如上图所示,我们可以容器的网络命名空间中通过ip addr 看到一个veth1@if19的标志位,其中 ‘19' 这个将会协助我们在ECS的OS内找到和容器网络命名空间中的veth pair相对一个。在ECS OS 内我们通过ip addr | grep 19: 可以找到cali38ef34581a9 这个虚拟网卡,这个就是veth pair在ECS OS侧相对的那一个。
到目前为止,容器访问SVC的ClusterIP时,容器和OS数据链路已经建立链接了,那么ECS OS内对于数据流量是怎么判断去哪个容器呢? 通过OS Linux Routing 我们可以看到,所有目的是 Pod CIDR 网段的流量都会被转发到Pod对应的calico虚拟往卡上,到这里为止,ECS OS 和Pod的网络命名空间已经建立好完整的出入链路配置了。
3. Terway ENI 模式容器网络数据链路剖析
针对容器网络特点,我们可以将Terway ENI模式下的网络链路大体分为以Pod IP对外提供服务和以SVC对外提供服务两个大的SOP场景,进一步细分可以拆分到8个不同的小的SOP场景。
对这8个场景的数据链路梳理合并,这些场景可以归纳为下面8类典型的场景:
TerwayENI架构下,不同的数据链路访问情况下,可以总结归纳为8类:
访问Pod IP,同节点访问pod
访问Pod IP,同节点pod间互访
访问Pod IP,异节点pod间互访
集群内访问SVC IP (Cluster IP),源端和SVC后端Pod为同一节点
集群内访问SVC IP( Cluster IP),源端和SVC后端Pod为不同节点
集群内访问SVC IP (External IP),源端和SVC后端Pod为同一节点
集群内访问SVC IP(External IP),源端和SVC后端Pod为不同节点
集群外访问SVC External IP
3.1 场景一:访问Pod IP,同节点访问pod
环境
ap-southeast-1.10.0.0.196 节点上存在 nginx1-5969d8fc89-9t99h 和 10.0.0.203
内核路由
nginx1-5969d8fc89-9t99h IP地址 10.0.0.203 ,该容器在宿主机表现的PID是1094736,该容器网络命名空间有指向容器eth0的默认路由 和 下一跳 为 veth1, 目的网段为service的 两条路由
该容器veth1在ECS OS 内对应veth pair是cali5068e632525
在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。
小结
可以访问到目的端
nginx1-5969d8fc89-9t99h netns veth1 可以抓到数据包
nginx1-5969d8fc89-9t99h cali5068e632525 可以抓到数据包
数据链路转发示意图:
数据链路是 ECS -> Linux routing -> calicxxx -> Pod net ns veth1。数据链路完成 宿主机ns切换至 pod ns
通过宿主机上的路由切换至pod所属的veth pair
该网卡为被分配的pod独占, 无法和其他pod进行共享
数据链路经过两次协议栈
3.2 场景二:访问Pod IP,同节点pod访问pod
环境
ap-southeast-1.10.0.0.196 节点上存在两个pod:centos-59cdc5c9c4-89f8x IP地址 10.0.0.202 和 nginx1-5969d8fc89-9t99h 和 10.0.0.203
内核路由
centos-59cdc5c9c4-89f8x IP地址 10.0.0.202 ,该容器在宿主机表现的PID是2314075,该容器网络命名空间有指向容器eth0的默认路由 和 下一跳 为 veth1, 目的网段为service的 两条路由
通过上述类似的办法,可以找到 nginx1-5969d8fc89-9t99h IP地址10.0.0.203,该容器在宿主机表现的PID是1094736
小结
可以访问到目的端
centos-59cdc5c9c4-89f8x netns eth1 可以抓到数据包
nginx1-5969d8fc89-9t99h netns eth1 可以抓到数据包
数据链路转发示意图:
数据链路是 pod1 netns eth1 -> VPC -> pod2 netns eth2。数据链路不经过宿主机host namespace,数据链路会先出ECS,到VPC再回到原来的ECS。
在pod 内的net namespace中,直接命中 默认路有规则,从eth0网卡出pod直接到VPC。 这里的eth0 其实就是附属网卡ENI,直接被挂载在了pod 的 net ns, 走了PCI网卡
该网卡为被分配的pod独占, 无法和其他pod进行共享
数据链路经过两次协议栈
3.3 场景三:访问Pod IP,异节点pod访问pod
环境
ap-southeast-1.10.0.0.196 节点上存在pod:centos-59cdc5c9c4-89f8x IP地址 10.0.0.202
ap-southeast-1.10.0.2.80 节点上存在pod:nginx-6f545cb57c-jmbrq 和 10.0.2.86
内核路由
centos-59cdc5c9c4-89f8x IP地址 10.0.0.202 ,该容器在宿主机表现的PID是2314075,该容器网络命名空间有指向容器eth0的默认路由 和 下一跳 为 veth1, 目的网段为service的 两条路由
通过上述类似的办法,可以找到 nginx-6f545cb57c-jmbrq IP地址 10.0.2.86,该容器在宿主机表现的PID是1083623
小结
可以访问到目的端
centos-59cdc5c9c4-89f8x netns eth0 可以抓到数据包
nginx-6f545cb57c-jmbrq netns eth0 可以抓到数据包
数据链路转发示意图:
数据链路是 ECS1 pod1 netns eth0 -> VPC -> ECS2 pod2 netns eth0。数据链路不经过宿主机host namespace,数据链路会先出ECS1,到AVS再回到ECS2。
在pod 内的net namespace中,直接命中 默认路有规则,从eth0网卡出pod直接到VPC。 这里的eth0 其实就是附属网卡ENI,直接被挂载在了pod 的 net ns, 走了PCI设备
该网卡为被分配的pod独占, 无法和其他pod进行共享
数据链路经过两次协议栈
3.4 场景四:集群内访问SVC IP (Cluster IP),源端和SVC后端Pod为同一节点
环境
ap-southeast-1.10.0.0.196 节点上存在两个pod:centos-59cdc5c9c4-89f8x IP地址 10.0.0.202 和 nginx1-5969d8fc89-9t99h 和 10.0.0.203
Service是 nginx1 集群内clusterIP是192.168.41.244, external IP是 8.219.175.179
内核路由
centos-59cdc5c9c4-89f8x IP地址 10.0.0.202 ,该容器在宿主机表现的PID是2314075,该容器网络命名空间有指向容器eth0的默认路由 和 下一跳 为 veth1, 目的网段为service的 两条路由
该容器eth0在ECS OS 内对应veth pair是cali38ef34581a9
通过上述类似的办法,可以找到 nginx1-5969d8fc89-9t99h IP地址10.0.0.203,该容器在宿主机表现的PID是1094736,该容器eth0在ECS OS 内对应veth pair是cali5068e632525
在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。
小结
可以访问到目的端
centos-59cdc5c9c4-89f8x netns veth1 可以抓到数据包
centos-59cdc5c9c4-89f8x netns cali38ef34581a9 可以抓到数据包
nginx1-5969d8fc89-9t99h netns veth1 可以抓到数据包
nginx1-5969d8fc89-9t99h netns cali5068e632525 可以抓到数据包
数据链路转发示意图:
数据链路是 ECS1 pod1 netns veth1 -> calixxx1 -> calixxx2 -> ECS2 pod2 netns veth1。
在pod 内的net namespace中,命中svc的路由,从veth1网卡出pod到ECS的 namespace,然后通过linux routing 转到另一个pod 的 calixx 网卡。 这里的veth1和calixxx是veth pair
源端pod所分配的veth,calicoxxx网卡可以捕获到svc IP和 源端pod IP。SVC IP 会在源端ECS host内命中ipvs/iptables规则,做了nat转化。
目的段pod所分配的veth,calicoxxx网卡可以捕获calicoxxx网卡默认ip和目的pod IP
该网卡为被分配的pod独占, 无法和其他pod进行共享
数据链路经过三次协议栈:Pod1, ECS OS 和Pod2
3.5 场景五:集群内访问SVC IP (Cluster IP),源端和SVC后端Pod为不同节点
环境
ap-southeast-1.10.0.0.196 节点上存在pod:centos-59cdc5c9c4-89f8x IP地址 10.0.0.202
ap-southeast-1.10.0.2.80 节点上存在pod:nginx-6f545cb57c-jmbrq 和 10.0.2.86
Service是 nginx 集群内clusterIP是192.168.204.233, external IP是 8.219.199.33
内核路由
centos-59cdc5c9c4-89f8x IP地址 10.0.0.202 ,该容器在宿主机表现的PID是2314075,该容器网络命名空间有指向容器eth0的默认路由 和 下一跳 为 veth1, 目的网段为service的 两条路由
该容器eth0在ECS OS 内对应veth pair是cali38ef34581a9
通过上述类似的办法,可以找到 nginx-6f545cb57c-jmbrq IP地址 10.0.2.86,该容器在宿主机表现的PID是1083623, 该pod网卡ENI是直接被挂载到了Pod的网络命名空间内。
小结
可以访问到目的端
数据链路转发示意图:
数据链路是 ECS1 pod1 netns veth1 -> cali38ef34581a9 -> ECS1 eth0 -> VPC -> ECS2 pod2 netns veth1
在客户端pod 内的net namespace中,命中svc的路由,从veth1网卡出pod到ECS的 namespace,然后通过linux routing 转到客户端ECS eth0 网卡, 然后进入到vpc转发到 目的 Pod所属的 eth网卡
源端pod所分配的veth,calicoxxx网卡可以捕获到svc IP和 源端pod IP。
SVC IP 会在源端ECS host内命中ipvs/iptables规则,做了fnat转化。在源端ECS 所属的eth0只能捕获到ipvs/iptables规则所分配的目的pod IP和源ECS IP
目的pod 内eth0所捕获的IP 是源端 ECS IP 和目的POD IP。(源POD IP 和 SVC IP不会体现)
该网卡为被分配的pod独占, 无法和其他pod进行共享
数据链路经过三次协议栈:Pod1, ECS1 OS 和Pod2
3.6 场景六:集群内访问SVC IP (External IP),源端和SVC后端Pod为同一节点
环境
ap-southeast-1.10.0.0.196 节点上存在两个pod:centos-59cdc5c9c4-89f8x IP地址 10.0.0.202 和 nginx1-5969d8fc89-9t99h 和 10.0.0.203
Service是 nginx1 集群内clusterIP是192.168.221.163, external IP是 10.0.2.89
内核路由
centos-59cdc5c9c4-89f8x IP地址 10.0.0.202 ,该容器在宿主机表现的PID是2314075,该容器网络命名空间有指向容器eth0的默认路由 和 下一跳 为 veth1, 目的网段为service 的 ClusterIP的 两条路由
SLB相关配置
在SLB控制台,可以看到虚拟服务器组的后端只有nginx1-5969d8fc89-9t99h的ENI eni-t4n6qvabpwi24w0dcy55
综上,可以判断如果访问的是SVC 的External IP, 是走默认路由 eth0,直接出ECS 进入到avs ,访问到 SLB的实例,再由SLB实例转发到后端eni上
小结
可以访问到目的端
数据链路转发示意图:
数据链路是 ECS1 pod1 netns eth0 -> VPC -> SLB -> VPC -> ECS1 pod2 netns eth0。数据链路不经过宿主机host namespace,数据链路会先出ECS1,到AVS再回到ECS1。
在pod 内的net namespace中,直接命中 默认路有规则,从eth0网卡出pod直接到VPC。 这里的eth0 其实就是附属网卡ENI,直接被挂载在了pod 的 net ns, 走了PCI设备
该网卡为被分配的pod独占, 无法和其他pod进行共享
与 2.4 场景可以看到非常大的不同,虽然都是 前后端Pod都是部署在同一个ECS访问SVC 的IP,但是可以看到如果访问的是SVC的ClusterIP,则数据链路会进入到ECS OS 层面,会经过三次协议栈;如果访问的是External IP,则不会经过ECS OS,直接出ECS,经过SLB转发到目的Pod上,只经过两次协议栈(Pod1 和Pod2)。
3.7 场景七:集群内访问SVC IP(External IP),源端和SVC后端Pod为不同节点
环境
ap-southeast-1.10.0.0.196 节点上存在pod:centos-59cdc5c9c4-89f8x IP地址 10.0.0.202
ap-southeast-1.10.0.2.80 节点上存在pod:nginx-6f545cb57c-jmbrq 和 10.0.2.86
Service是 nginx 集群内clusterIP是192.168.254.141, external IP是 10.0.2.90
内核路由
centos-59cdc5c9c4-89f8x IP地址 10.0.0.202 ,该容器在宿主机表现的PID是2314075,该容器网络命名空间有指向容器eth0的默认路由 和 下一跳 为 veth1, 目的网段为service 的 ClusterIP的 两条路由
SLB相关配置
在SLB控制台,可以看到lb-t4nih6p8w8b1dc7p587j9虚拟服务器组的后端只有nginx-6f545cb57c-jmbrq的ENI eni-t4n5kzo553dfak2sp68j
综上,可以判断如果访问的是SVC 的External IP, 是走默认路由 eth0,直接出ECS 进入到avs ,访问到 SLB的实例,再由SLB实例转发到后端eni上
小结
可以访问到目的端
数据链路转发示意图:
数据链路是 ECS1 pod1 netns eth0 -> VPC -> SLB -> VPC -> ECS2 pod2 netns eth0。数据链路不经过宿主机host namespace,数据链路会先出ECS1,到SLB再回到ECS2。
在pod 内的net namespace中,直接命中 默认路有规则,从eth0网卡出pod直接到VPC。 这里的eth0 其实就是附属网卡ENI,直接被挂载在了pod 的 net ns, 走了PCI设备
该网卡为被分配的pod独占, 无法和其他pod进行共享
与 2.5 场景可以看到非常大的不同,虽然都是 前后端Pod都是部署在不同ECS访问SVC 的IP,但是可以看到如果访问的是SVC的ClusterIP,则数据链路会进入到ECS OS 层面,通过ECS的eth0出ECS,进入到AVS,会经过三次协议栈;如果访问的是External IP,则不会经过ECS OS,直接通过Pod所属的的附属ENI 出ECS,经过SLB转发到目的Pod上,只经过两次协议栈(Pod1 和Pod2)。
3.8 场景八:集群外访问SVC External IP
环境
ap-southeast-1.10.0.2.80 节点上存在pod:nginx-6f545cb57c-jmbrq 和 10.0.2.86
ap-southeast-1.10.0.1.233 节点上存在pod:nginx-6f545cb57c-25k9z 和 10.0.1.239
Service是 nginx 集群内clusterIP是192.168.254.141, external IP是 10.0.2.90
SLB相关配置
在SLB控制台,可以看到lb-t4nih6p8w8b1dc7p587j9虚拟服务器组的后端服务器组是两个后端nginx pod 的的ENI eni-t4n5kzo553dfak2sp68j 和 eni-t4naaozjxiehvmg2lwfo
从集群外部角度看,SLB的后端虚拟服务器组是SVC的后端Pod所属的两个ENI网卡,内网的IP 地址就是Pod的地址,没有经过后端Pod所在的ECS的OS层面,直接进入到了OS的的协议栈
小结
可以访问到目的端
数据链路转发示意图:
数据链路:client -> SLB -> Pod ENI + Pod Port -> ECS1 Pod1 eth0
数据链路要经过一次内核协议栈,是Pod1 协议栈
4. 总结
本篇文章主要聚焦ACK 在Terway ENI模式下,不同SOP场景下的数据链路转发路径。伴随着客户对性能的极致追求的需求,在Terway ENI模式下,一共可以分为8个SOP场景,并对这八个场景的转发链路,技术实现原理,云产品配置等一一梳理并总结,这对我们遇到Terway ENI架构下的链路抖动、最优化配置,链路原理等提供了初步指引方向。在Terway ENI 模式下,ENI是以PCI方式直接挂载到Pod的命名空间内,这就以为ENI属于被分配的Pod独享,而ECS所能部署的Pod数量取决于ECS所能挂载ENI网卡数量的限制,而这个限制和ECS的实例规格类型有关,比如神龙ecs.ebmg7.32xlarge,128C 512GB也只支持最多32个ENI,这往往会造成资源的浪费和部署密度的降低,为了解决这个资源效率问题,ACK 带来了Terway ENIIP的方式,来实现ENI网卡可以被多个Pod所共享,这大大增加了单个ECS上的Pod数量quota,提升了部署密度,这也是目前线上集群采用最多的架构。 下一系列我们将进入到Terway ENIIP模式的全景解析——《全景剖析阿里云容器网络数据链路(三)—— Terway ENIIP》。
本系列联合作者 容器服务 @谢石