行业研究报告哪里找 您所在的位置:网站首页 时代少年团成员名字缩写组成的句子 行业研究报告哪里找

行业研究报告哪里找

2023-04-18 08:45| 来源: 网络整理| 查看: 265

阿里云:云原生网络数据面可观测性最佳实践(2023)(300页).pdf

前言前言近几年,企业基础设施云原生化的趋势越来越强烈,从最开始的 IaaS 化到现在的微服务化,客户的颗粒度精细化和可观测性的需求更加强烈。容器网络为了满足客户更高性能和更高的密度,也一直在高速的发展和演进中,这必然对客户对云原生网络的可观测性带来了极高的门槛和挑战。鸟瞰容器网络,整个容器网络可以分为三个部分:Pod 网段,Service 网段和Node 网段。这三个网络要实现互联互通和访问控制,那么实现的技术原理是什么?整个链路又是什么,限制又是什么呢?Flannel,Terway 有啥区别?不同模式下网络性能如何?这些,需要客户在下搭建容器之前,就要依据自己的业务场景进行选择,而搭建完毕后,相关的架构又是无法转变,所以客户需要对每种架构特点要有充分了解。比如下图是个简图,Pod 网络既要实现同一个 ECS 的 Pod 间的网络互通和控制,又要实现不同 ECSPod 间的访问,Pod 访问 SVC 的后端可能在同一个 ECS也可能是其他 ECS,这些在不同模式下,数据链转发模式是不同的,从业务侧表现结果也是不一样的。为了提高云原生网络的可观测性,同时便于客户和前后线同学增加对业务链路的可读性,ACK 产研和 GTS-AES 联合共建,合作开发 ACK Net-Exporter 和云原生网络数据面可观测性系列,帮助客户和前后线同学了解云原生网络架构体系,简化对云原生网络的可观测性的门槛,优化客户运维和售后同学处理疑难问题的体验,提高云原生网络的链路的稳定性。目录一、容器网络内核原理.61.概述filter 框架.93.tc 子系统.184.eBPF 技术.26二、全景剖析阿里云容器网络数据链路.291.Flannel 模式架构设计.292.Terway ENI 模式架构设计.503.Terway ENIIP 模式架构设计.804.Terway IPVLAN EBPF 模式架构设计.1105.Terway ENI-Trunking 模式架构设计.1546.ASM Istio 模式架构.190三、容器网络常见观测工具及特点.2361.常见网络排查工具.2362.Net-Export 技术原理.240四、ACK Net-Exporter 快速上手.2431.Prometheus Grafana 配置.2442.ACK Net-Exporter 部署.2553.典型问题排查指南.267五、典型问题华山论剑.2741.某客户 nginx ingress 偶发性出现 4xx or 5xx.2742.某客户偶发 RTT 增高.2843.某客户反馈 pod 偶发性健康检查失败.2894.某客户偶发请求延迟.2945.某客户 SVC 后端负载不均.295容器网络内核原理6一、容器网络内核原理Linux 网络子系统是 Linux 系统最为基础的组成部分,理解 Linux 网络子系统的核心和基础架构,能够让我们在排查网络问题的过程中对问题有较为全局的认识,避免由于缺乏了解而多走弯路。本章节会以全景概览的方式对 Linux 网络子系统进行简单的描述。1.概述网络通信的本质是电磁波高低电位变化在物理介质上的传输,高低变化的电位形成二进制的数据传递给网络硬件设备,硬件网络设备则会根据特定的编码方式讲二进制的数据变成以太网报文,此时,物理网络的信息就被解调制成为了数据帧,在 OSI 七层网络协议的定义中,二进制的数据处于物理层,而以太网数据帧则处于数据链路层,对于 Linux内核来说,物理层和数据链路层之间的转换通常是由硬件设备的驱动完成,Linux 内核定义了与硬件设备驱动通信的标准,在完成数据链路层的收包后,硬件网络设备会将数据帧传递给操作系统 Linux 的内核进行处理,所以 Linux 网络协议栈的源头是数据链路层的数据帧报文。Linux 内核在处理数据帧报文是,按照数据帧的分片,TSO 等特性,将数据帧转化为可见的网络层报文,从而进行下一步的操作,内核在处理网络报文的时候,才用了一种非常高效的方式:内核通过一个 sk_buff 结构体,保存所有的报文数据。在网络层处理后传递给传输层的操作中,内核并不会为每一层进行复制,而是通过指针偏移的方式处理同一个 sk_buff 结构体。容器网络内核原理7下图是对 Linux 网络子系统的一个简单示意图:根据网络报文的流向,我们按照两个不同的方向对豹纹处理的流程进行概述。容器网络内核原理81)1)收包方向的报文处理收包方向的报文处理从上图中可以发现,当内核从网络驱动设备中获取到报文后:首先进行 TC 子系统的操作,在收包方向,不会有特别复杂的操作。完成了网络层报文的重组后,报文进入了网络层的处理,在网络层的处理中,比较重要的是,netfilter 框架和路由查找,这里实现了大量的功能,在云原生的场景中,netfilter 和路由子系统有着至关重要的作用。网络层完成处理后,会交由传输层进行处理,传输层的协议最常见的是 tcp 和 udp,其中 tcp 协议在传输层通过重传和序号校验等保证了连接的可靠性。传输层完成处理后,内核会将真正的报文数据提取出来并交给 socket 子系统,socket 子系统抽象了网络的所有操作,屏蔽了网络报文的细节,让用户程序可以按照文件 io 的方式读写网络数据。socket 子系统的数据最终会被用户程序读取,此时,一些编程语言的底层依赖库会进行一些封装,提供应用层协议的支持,如 http,mqtt 等,提供用户友好的操作体验。2)2)发包方向的报文处理发包方向的报文处理发包方向的处理,相比收包方向来说,一个重要的区别是,收包方向的操作是内核的软中端处理线程进行收包操作,而发包方向的操作则是由进程上下文进入内核态进行,因此,发包方向出现由于调度问题产生的偶发延迟都懂的概率比收包方向要小。应用程序通常都是调用编程语言或者第三方的类库提供的方法进行发包动作,而这些法宝动作最终都会调用 socket 子系统的写入调用来实现发送数据:应用程序写入 socket 后,在达到一定的条件,如内存充裕,tcp 发送窗口足够等情况下,内核会给当前需要发送的数据申请一个 sk_buff 结构体的内存,并将需要发送的数据填充到 sk_buff 的数据中。sk_buff 数据报文首先会经过传输层的处理,根据当前的系统状态,内核会给报文sk_buff 的 tcp 报头进行填充,然后调用网络层提供的方法进行发送。容器网络内核原理9网络层和收包方向类似,也会经历过 netfilter 框架的选取路由的动作,在这里实现了大量的雨网络抽象相关的逻辑。在网络层完成处理后,按照 OSI 七层网络定义,会进入数据链路层,实际上在 Linux 中,邻居子系统的信息填充,也会在路由子系统完成路由的选取后一并填入到报文的报头中,随后报文会进入发送方向的 TC 子系统。TC 子系统是实现网络流量整形的关键,和收包方向不同的是,发包方向的 TC 子系统会进行复杂的排序工作,通过数据包的类型与配置的规则进行匹配,实现网络流控的功能。TC 子系统会将优先级最高的报文传递给网络设备驱动。网络设备驱动的发送方法的实现逻辑细节已经不再属于 Linux 内核的范畴,通常在进入网络设备后,我们就可以认为数据包已经完成了发送。filter 框架netfilter 框架是 Linux 操作系统中内置的,通过向内核模块提供对协议栈中的网络数据包进行修改和操作的能力,来实现流量过滤,网络地址转换等高级功能。1)1)netfilternetfilter 如何工作如何工作对于网络数据报文,网络设备驱动通过将二层的以太网数据报文按照 Linux 内核定义的网络设备驱动规范,以 sk_buff 结构体的方式进行接收或者发送,即通常我们所描述的报文的最小单元 skb。内核通过将网络设备缓冲区环形队列中的 skb 取出,并按照以太网层,网络层,传输层的顺序处理后,将报文数据放置到对应的 Socket 缓冲区中,通知用户程序进行读取,从而完成收包。内核为 Socket 缓冲区的待发送数据封装为 skb,经过传输层,网络层和以太网层依次填充对应的报头后,调用网络设备驱动的方法将 skb 发送到网络上,从而完成发包。netfilter工作的核心原理则是在网络层,通过在五个不同的内核处理skb数据包的位置,执行注册到 netfilter 框架中的回调函数,并根据回调函数的返回来选择下一步的处理,容器网络内核原理10来实现复杂的功能。netfilternetfilter 触发触发的的时机时机netfilter 在内核网络数据包的处理流程中,注册了 5 个可以出发的实际,详情如下:/*IP Hooks*/*After promisc drops,checksum checks.*/#define NF_IP_PRE_ROUTING0/*If the packet is destined for this box.*/#define NF_IP_LOCAL_IN1/*If the packet is destined for another interface.*/#define NF_IP_FORWARD2/*Packets coming from a local process.*/#define NF_IP_LOCAL_OUT3/*Packets about to hit the wire.*/#define NF_IP_POST_ROUTING4#define NF_IP_NUMHOOKS5#endif/*!_KERNEL_*/根据源代码中的定义,我们可以参考下图:容器网络内核原理11从上面的代码定义和示意图中可以知道,在以下几个地方会调用 netfilter 定义好的方法对数据包进行处理:数据包从网卡进入协议栈后,所有的报文都会走到 NF_IP_PRE_ROUTING。数据包经过入向的路由选择后,确认是由本机的传输层进行处理的,会进入到NF_IP_LOCAL_IN。数据包经过入向的路由选择后,不是由本机处理,需要转发给其他机器的,会进入到 NF_IP_FORWARD。由本机的传输层发出的报文,都会经过 NF_IP_LOCAL_OUT。经过出向的路由选择后的报文,会经过 NF_IP_POST_ROUTING,包括从本机发出的和需要本机转发的。在以上五个时机,当数据包 skb 到达时,netfilter 框架定义的回调方法就会被内核执行。netfilternetfilter 如何操作网络数据如何操作网络数据使用 netfilter 框架的模块,需要按照 netfilter 定义的结构体来实现自己的行为,才能正确注册到 netfilter 框架中,并被内核调用,netfilter 约束的注册结构体的定义如下:struct nf_hook_ops/这是真正被内核执行的函数,会对 skb 进行读取和修改nf_hookfn*hook;struct net_device*dev;void*priv;u_int8_tpf;/hooknum 定义了回调函数生效的位置,从上文可知有五个位置可以选择unsigned inthooknum;/priority 定义了回调函数的优先级,通过每个 hook 时机都会有多个回调函数需要生效intpriority;以 ipvlan 模块为例:容器网络内核原理12static const struct nf_hook_ops ipvl_nfops=.hook=ipvlan_nf_input,.pf=NFPROTO_IPV4,.hooknum=NF_INET_LOCAL_IN,.priority=INT_MAX,#if IS_ENABLED(CONFIG_IPV6).hook=ipvlan_nf_input,.pf=NFPROTO_IPV6,.hooknum=NF_INET_LOCAL_IN,.priority=INT_MAX,#endif;我们可以看到,ipvlan 模块根据 IP 协议的版本定义了两个 hook 结构体,其中:hookfn 是核心的处理逻辑,ipvlan 模块注册了 ipvlan_nf_input 方法。pf 是 netfilter 的协议版本,ipvlan 模块分别注册了 IPv6 和 IPv4 对应的方法。hooknum 定义了这个 hook 在 netfilter 中生效的位置,ipvlan 模块将自己的回调方法注册到了 NF_INET_LOCAL_IN,也就是完成路由之后,进入传输层之前。priotity 定义了 hook 的优先级。那么,hookfn 作为真正核心的处理逻辑,他是如何工作的呢?以 ipvlan 注册在 NF_INET_LOCAL_IN 上的 hook 方法 ipvlan_nf_input 为例:unsigned int ipvlan_nf_input(void*priv,struct sk_buff*skb,const struct nf_hook_state*state)/参数中可以看到,有前一个生效的 hook 结构体,当前处理的 skb 报文本身以及当前netfilter 框架的上下文信息struct ipvl_addr*addr;unsigned int len;addr=ipvlan_skb_to_addr(skb,skb-dev);if(!addr)goto out;容器网络内核原理13skb-dev=addr-master-dev;len=skb-len ETH_HLEN;ipvlan_count_rx(addr-master,len,true,false);out:/这里返回了 netfilter 框架规定的返回码return NF_ACCEPT;从 ipvlan_nf_input 可以看到,注册到 netfilter 中的回调函数的核心在于两个约束:回调函数的入参定义,可以接受协议栈中真正的报文结构体 skb 以及 netfilter 的上下文状态为参数。回调函数的返回值,需要是 netfilter 规定好的返回值,他们的定义如下:/*Responses from hook functions.*/#define NF_DROP 0#define NF_ACCEPT 1#define NF_STOLEN 2#define NF_QUEUE 3#define NF_REPEAT 4#define NF_STOP 5/*Deprecated,for userspace nf_queue compatibility.*/#define NF_MAX_VERDICT NF_STOP从以上的分析不难看出,只要满足 netfilter 的注册条件,就可以在回调函数中直接对数据报文 skb 内容进行读取和修改操作,而通过返回值的定义,则可以借助 netfilter 框架完成对数据包的处理,比如丢弃,接收或者传递到用户态进行处理。netfilternetfilter 的内核实现的内核实现在负责对所有 hook 方法进行遍历处理的函数中,可以看到,netfilter 核心的工作流程就是在相应的触发时机调用这个时机上注册的所有方法,按照优先级进行处理,并根据每一次处理的结果进行操作,包括丢弃,传输给用户态等等:int nf_hook_slow(struct sk_buff*skb,struct nf_hook_state*state,const struct nf_hook_entries*e,unsigned int s)unsigned int verdict;int ret;容器网络内核原理14for(;s num_hook_entries;s )/在这里调用对应的 hook 时机上的所有注册的 hook 回调方法,然后根据结果选择是不是继续循环verdict=nf_hook_entry_hookfn(&e-hookss,skb,state);switch(verdict&NF_VERDICT_MASK)case NF_ACCEPT:break;case NF_DROP:kfree_skb(skb);ret=NF_DROP_GETERR(verdict);if(ret=0)ret=-EPERM;return ret;case NF_QUEUE:ret=nf_queue(skb,state,e,s,verdict);if(ret=1)continue;return ret;default:/*Implicit handling for NF_STOLEN,as well as any other*non conventional verdicts.*/return 0;return 1;2)2)netfilternetfilter 的常见应用的常见应用conntrackconntrack 连接跟踪连接跟踪conntrack 是 netfilter 提供的核心功能之一,通过对 tcp,udp 等协议的连接状态的记录,来实现连接的会话状态保持的功能,例如:对于 iptables 或者 ipvs 进行的 NAT 操作,可以记录单个已经建立的连接的 NAT信息,对于相同的 tcp 连接,可以减少 NAT 操作中分配五元组计算的频率,保持连接状态的存续。容器网络内核原理15对于没有建立完成的连接,也不是握手请求的情况,可以在差抄不到 conntrack 的情况下避免其进入协议栈,从而减少非必要的消耗。在 Linux 中,我们可以借助 conntrack-tools 工具提供的 conntrack 命令来管理conntrack 操作,常见的使用方法如下:#输出当前 netns 中所有的 conntrack 条目信息conntrack-L#通过 netlink stream 的方式实时观察 conntrack 的写入事件conntrack-E#查看按照 cpu 进行统计的 conntrack 数据conntrack-Sconntrack 在内核中也是通过注册在 netfilter 上的 hook 函数进行工作的,此外,conntrack机制还依赖于按照cpu的数量来为每一个cpu分配一块用于存放conntrack信息的内存,以下是 conntrack 机制在 Linux 上的实现:static const struct nf_hook_ops ipv4_conntrack_ops=.hook=ipv4_conntrack_in,.pf=NFPROTO_IPV4,.hooknum=NF_INET_PRE_ROUTING,.priority=NF_IP_PRI_CONNTRACK,.hook=ipv4_conntrack_local,.pf=NFPROTO_IPV4,.hooknum=NF_INET_LOCAL_OUT,.priority=NF_IP_PRI_CONNTRACK,.hook=ipv4_helper,.pf=NFPROTO_IPV4,.hooknum=NF_INET_POST_ROUTING,.priority=NF_IP_PRI_CONNTRACK_HELPER,.hook=ipv4_confirm,.pf=NFPROTO_IPV4,.hooknum=NF_INET_POST_ROUTING,.priority=NF_IP_PRI_CONNTRACK_CONFIRM,容器网络内核原理16,.hook=ipv4_helper,.pf=NFPROTO_IPV4,.hooknum=NF_INET_LOCAL_IN,.priority=NF_IP_PRI_CONNTRACK_HELPER,.hook=ipv4_confirm,.pf=NFPROTO_IPV4,.hooknum=NF_INET_LOCAL_IN,.priority=NF_IP_PRI_CONNTRACK_CONFIRM,;网络地址转换网络地址转换NAT 网络地址转换是 netfilter 框架提供的核心功能之一,NAT 作为网络中非常重要的概念,在云原生场景下提供很多功能,包括:在多种 cni 插件的数据面设计中,依赖 nat 实现跨节点的 pod 之间的通信。通过 nat 实现 service 与 pod 之间的负载均衡。iptables 和 ipvs 都可以实现 NAT 功能,其中 ipvs 通常都是用于对目的地址进行 NAT操作,也就是 DNAT,iptables 则具有包括 masquerade 在内的多种 NAT 组合而来的复杂功能,例如,在默认的 docker 容器访问公网的场景中,为了能够让节点内的,只有内网地址的 docker 容器可以正常访问公网,就需要添加如下的一条规则:#对于从 eth0 出节点的流量,访问目的为 123.12.23.43 的,自动将原地址切换为节点的出公网地址iptables-t nat-A POSTROUTING-o eth0-j SNAT-to 123.12.23.43iptables 的 NAT 有多个实现,目前版本较新并且被广泛采用的是基于 nft 的 iptables,对于 IPv4 协议,nft 实现的 NAT 功能在 netfilter 中注册的 hook 方法有如下几个:static const struct nf_hook_ops nf_nat_ipv4_ops=/*Before packet filtering,change destination*/.hook=nf_nat_ipv4_in,.pf=NFPROTO_IPV4,.hooknum=NF_INET_PRE_ROUTING,容器网络内核原理17.priority=NF_IP_PRI_NAT_DST,/*After packet filtering,change source*/.hook=nf_nat_ipv4_out,.pf=NFPROTO_IPV4,.hooknum=NF_INET_POST_ROUTING,.priority=NF_IP_PRI_NAT_SRC,/*Before packet filtering,change destination*/.hook=nf_nat_ipv4_local_fn,.pf=NFPROTO_IPV4,.hooknum=NF_INET_LOCAL_OUT,.priority=NF_IP_PRI_NAT_DST,/*After packet filtering,change source*/.hook=nf_nat_ipv4_fn,.pf=NFPROTO_IPV4,.hooknum=NF_INET_LOCAL_IN,.priority=NF_IP_PRI_NAT_SRC,;3)3)netfilternetfilter 在云原生中的应用在云原生中的应用基于基于 ipvsipvs 实现实现 ServiceServiceipvs 是基于 netfilter 框架实现的 Linux 内核态负载均衡器,通过 DNAT 方式来实现负载均衡,在云原生场景下,由于性能上的优势,ipvs 是实现 Service 功能的首选,我们可以通过以下命令来简单的查看 Service 真正产生在网络数据面的 ipvs 规则:#查看 ipvs connection 信息,在出节点是,ipvs connection 是独立并且优先于conntrack 机制的选择,即流量会优先匹配到 ipvs 的规则,如果没有命中,才会进入conntrack 的匹配逻辑ipvsadm-Lnc#添加一个 service 192.168.1.100:80,将 192.168.1.123 作为他的一个 realserver 后端ipvsadm-A-t 192.168.1.100:80-s rripvsadm-a-t 192.168.1.100:80-r 192.168.1.123-g-w 2容器网络内核原理18#查看不同的 ipvs service 的数据统计ipvsadm-Ln-stats基于基于 iptablesiptables 实现实现 NetworkPolicyNetworkPolicyNetworkPolicy 是云原生网络中非常重要的网络功能,其核心在于如何对流量进行权限管理,通常 cni 插件会采用 iptables 队 policy 未放行的流量进行屏蔽操作,实现NetworkPolicy 的功能。ipables 实现 NetworkPolicy 功能的数据面原理非常简单,通过白名单放行的方式,默认丢弃所有流量,只允许白名单中的流量,即可实现简单的 NetworkPolicy 功能,我们可以通过以下几个命令简单模拟 iptables 实现的 NetworkPolicy:#默认丢弃所有流量iptables-A INPUT-j DROP#将 192.168.1.100 的 80 端口进行放行iptables-A INPUT-s 192.168.1.100-p tcp-m tcp-dport 80-j ACCEPT3.tc 子系统Linux Traffic Control(TC)子系统是 Linux 操作系统中用于对从网络设备驱动进出的流量进行分配,整形,调度以及其他修改操作的子系统,借助对数据包比较直接的处理,可以实现流量控制,过滤,行为模拟和带宽限制等功能。1)1)LinuxLinux TrafficTraffic ControlControl 的核心原理的核心原理对于网络数据报文,网络设备驱动通过将二层的以太网数据报文按照 Linux 内核定义的网络设备驱动规范,以 sk_buff 结构体的方式进行接收或者发送,即通常我们所描述的报文的最小单元 skb。容器网络内核原理19内核通过将网络设备缓冲区环形队列中的 skb 取出,并按照以太网层,网络层,传输层的顺序处理后,将报文数据放置到对应的 Socket 缓冲区中,通知用户程序进行读取,从而完成收包。内核为 Socket 缓冲区的待发送数据封装为 skb,经过传输层,网络层和以太网层依次填充对应的报头后,调用网络设备驱动的方法将 skb 发送到网络上,从而完成发包。TC子系统通过工作在网络设备驱动操作和内核真正进行每一层的收包与发包动作之间,按照不同的模式对数据包进行处理,实现复杂的功能。TC 子系统比较常见的作用是对需要发送的数据包进行操作,由于作为收包一侧的 Linux内核,无法控制所有发送方的行为,因此 TC 子系统主要的功能实现都是围绕着发送方向,以下介绍也都是基于发送方向的 TC 子系统进行。TCTC 子系统的关键概念子系统的关键概念TC 子系统与 netfilter 框架工作在内核网络数据处理流程的不同位置,相比于 netfilter,TC 子系统工作的实际更加靠近网络设备,因此,在 TC 子系统的设计中,是与网络设备密不可分,在 TC 子系统中,有三个关键的概念用于对 TC 子系统的工作流程进行描述:Qdisc 是 queueing discipline 的简写,与我们理解的网卡的队列(queue)不同,qdisc 是 sk_buff 报文进行排队等待处理的队列,不同类型的 qdisc 有着不同的排队规则,TC 子系统会为每个网卡默认创建一个根队列,在跟队列的基础上,可以通过 Class 来创建不同的子队列,用于对流量进行分类处理。Class,如下图所示,class 将流量进行分类,不同分类的流量会进入不同的 qdisc进行处理。Filter,如下图所示,filter 通过制定匹配的规则来实现将流量进行分类的作用,filter与 class 配合之后就可以降流量按照特征,采用不同的 qdisc 进行处理。容器网络内核原理20不同的 qdisc 之间的主要差别就是他们对排队的数据包进行调度的算法的区别,你可以通过一下命令查看网卡的 qdisc 信息:#查看 eth0 的 class 为 2 的流量的默认 qdisc,其中 handle 指代 qdisc id,parent指代 class idtc qdisc show dev eth0 handle 0 parent 2常见的 qdisc 包含以下几种:mq(Multi Queue),即默认有多个 qdisc。fq_codel(Fair Queuing Controlled Delay),一种公平和随机分配流量带宽的算法,会根据数据包的大小,五元组等信息,尽量公平得分配不同的流之间的带宽。pfifo_fast,一种不分类的常见先进先出的队列,但是默认有三个不同的 band,可以支持简单的 tos 优先级。netem,network emulator 队列,常见的依赖 TC 子系统进行延迟,乱序和丢包模拟,都是通过 netem 来实现。clsact,这是 TC 子系统专门为了支持 eBPF 功能而提供的一种 qdisc 队列,在通过class 分配到这个 qdisc 之后,流量会触发已经挂载到 TC 子系统上的对应的 eBPF程序的处理流程。htb,一种通过令牌桶的算法对流量进行带宽控制的常用 qdisc,用于在单个往卡上对不同用户,场景的流量进行独立的带宽限流。容器网络内核原理21报文在报文在 TCTC 子系统的处理子系统的处理在 egress 方向,当以太网层完成数据报文 skb 的报头封装后,一个 skb 就可以直接调用网卡的方法进行发送了,而在 Linux 内核中,当以太网层完成封装并调用_dev_queue_xmit 时,会将 skb 放入他所在网络设备的 TC 队列中:static inline int c(struct sk_buff*skb,struct Qdisc*q,struct net_device*dev,struct netdev_queue*txq)if(q-flags&TCQ_F_NOLOCK)if(unlikely(test_bit(_QDISC_STATE_DEACTIVATED,&q-state)_qdisc_drop(skb,&to_free);rc=NET_XMIT_DROP;else/对于大多数数据包,都会从这里进入 qdisc 进行排队rc=q-enqueue(skb,q,&to_free)&NET_XMIT_MASK;qdisc_run(q);if(unlikely(to_free)kfree_skb_list(to_free);return rc;在入队动作发生后,内核一般都会直接进行一次 qdisc 的发包操作,将队列进行排序并按照规则发送符合条件的数据包:void _qdisc_run(struct Qdisc*q)int quota=dev_tx_weight;int packets;/每次 restart 都会发送数据包,直到发送完成,这并不意味着所有数据都发送完了,只是这次发送完成了条件while(qdisc_restart(q,&packets)quota-=packets;if(quota 22qdisc 每次被触发执行,都会将已经进入 qdisc 的数据进行入队操作,同时选择符合发送条件的数据包进行出队动作,也就是调用网卡的操作方法进行数据的发送,以pfifo_fast 为例:static int pfifo_fast_enqueue(struct sk_buff*skb,struct Qdisc*qdisc)/检测 Qdisc 队列数据包数量是否达到 dev 预定的最大值if(skb_queue_len(&qdisc-q)tx_queue_len)/确定数据包需要进入哪个通道int band=prio2bandskb-priority&TC_PRIO_MAX;struct pfifo_fast_priv*priv=qdisc_priv(qdisc);/获取通道列表的 headstruct sk_buff_head*list=band2list(priv,band);priv-bitmap|=(1 q.qlen ;/添加到通道队尾return _qdisc_enqueue_tail(skb,qdisc,list);return qdisc_drop(skb,qdisc);static struct sk_buff*pfifo_fast_dequeue(struct Qdisc*qdisc)struct pfifo_fast_priv*priv=qdisc_priv(qdisc);int band=bitmap2bandpriv-bitmap;if(likely(band=0)struct sk_buff_head*list=band2list(priv,band);struct sk_buff*skb=_qdisc_dequeue_head(qdisc,list);qdisc-q.qlen-;if(skb_queue_empty(list)priv-bitmap&=(1 23qdisc 流量控制由于设计非常复杂,所以很难简单概括其特性,通常在排查网络问题的过程中,我们需要了解的就是常见的 qdisc 的算法的大致工作原理,以及查看 qdisc 统计信息。2)Linux Traffic Control 在云原生中的应用基于基于 CgroupCgroup 的网络数据包的网络数据包 QosQosCgroup 子系统是容器技术的基础,通常我们对 cgroup 的理解都在于 cgroup 通过cgroupfs 文件接口,让内核在为应用程序提供 cpu 时间片分配和内存分配的过程中遵循一定的配额限制,实际上 cgroup 在较早的版本中已经支持对某个 cgroup 中的网络流量进行优先级的调整,以实现单个节点内不同 cgroup 之间的 Qos 动作。Cgroup 子系统中提供网络流量优先级的功能为 net_cls 和 net_prio,需要配合 TC 子系统一起生效,例如,我们给某一个容器所在的 cgroup 添加一个 net_cls 设置:mkdir/sys/fs/cgroup/net_cls/0echo 0 x100001/sys/fs/cgroup/net_cls/0/net_cls.classid在这里,我们选取了设定的 class 为 100001,然后,我们将 eth0 网卡的 root 根队列的 class 设置为 10,类型修改为 htb,用于进行限速:tc qdisc add dev eth0 root handle 10:htb我们在 10:这个根队列下,针对我们配置的 10:1 这个 class 配置带宽限流配置:tc class add dev eth0 parent 10:classid 10:1 htb rate 40mbit最后配置一个 filter,将 cgroup 流量引入到 10:1 的 class 中,完成对这个 cgroupnet_cls 的配置:tc filter add dev eth0 parent 10:protocol ip prio 10 handle 1:cgroup容器网络内核原理24而 net_prio 的原理则相对更加直观一点,通过在对应的 cgroup 路径中的 ifpriomap种配置网卡和对应的优先级数值,使对应的 cgroup 中管理的进程创建出来的 socket都具有priority属性,priority属性会成为sk_buff结构体的属性从而携带到进入qdisc,如果 qdisc 支持优先级调度,则会根据 priority 来完成流量的 Qos,操作如下:echo eth0 5 /cgroup/net_prio/iscsi/net_prio.ifpriomap基于基于 TCTC eBPFeBPF 的高性能可编程数据面实现的高性能可编程数据面实现从上文的介绍中,我们了解到,在 eBPF 的多个内核提供的可执行的触发点中,TC 子系统是其中原生支持的一种,实际上,许多开源的解决方案也都选择 TC 子系统作为 eBPF程序执行的触发点,包括 cilium 和 terway。我们通过一个简单的 eBPF 程序来对 TC 子系统支持 eBPF 的能力进行验证:首先,我们需要按照规范,在 TC 子系统提供的上下文环境中开发一个简单的 eBPF 程序:#include#include#include#include#ifndef _section#define _section(NAME)_attribute_(section(NAME),used)#endif#ifndef _inline#define _inlineinline _attribute_(always_inline)#endif#ifndef lock_xadd#define lock_xadd(ptr,val)(void)_sync_fetch_and_add(ptr,val)#endif#ifndef BPF_FUNC#define BPF_FUNC(NAME,.)容器网络内核原理25(*NAME)(_VA_ARGS_)=(void*)BPF_FUNC_#NAME#endifstatic void*BPF_FUNC(map_lookup_elem,void*map,const void*key);struct bpf_elf_map acc_map _section(maps)=.type=BPF_MAP_TYPE_ARRAY,.size_key=sizeof(uint32_t),.size_value=sizeof(uint32_t),.pinning=PIN_GLOBAL_NS,.max_elem=2,;static _inline int account_data(struct _sk_buff*skb,uint32_t dir)uint32_t*bytes;bytes=map_lookup_elem(&acc_map,&dir);if(bytes)lock_xadd(bytes,skb-len);return TC_ACT_OK;_section(ingress)int tc_ingress(struct _sk_buff*skb)return account_data(skb,0);_section(egress)int tc_egress(struct _sk_buff*skb)return account_data(skb,1);char _license _section(license)=GPL;随后我们创建一个 clsact 类型的 qdisc,并且将流量全部定位到这个 qdisc 中:clang-g-O2-Wall-target bpf-I/iproute2/include/-c tc-example.c-o tc-example.o#创建一个 clsact 类型的 qdisc 作为 root 根 qdisc,然后加载 ebpf 程序到发送方向tc qdisc add dev enp3s0 clsact容器网络内核原理26tc filter add dev enp3s0 egress bpf da obj tc-example.o sec egress#通过 filter show 可以查看到网卡在 egress 上家在的 ebpf 程序tc filter show dev enp3s0 egress4.eBPF 技术eBPF 是 Linux 内核提供可以在不借助内核模块的场景下,对内核进行观测,注入来实现高阶功能的机制。eBPF 技术作为内核当前最为突破性的技术,具有轻量级,无侵入的特性,在排查网络问题上可以提供很多帮助,在当前的 eBPF 生态中,bpftrace 和 bcc 都提供了很多出色的功能协助我们进行观测,本章节会简单介绍 eBPF 的实现原理以及 eBPF 在云原生场景下的应用的简单介绍。eBPF 能够在实现接近内核模块的功能的基础上,具备上述的有点,得益于内核为 eBPF提供的多个改变:提供了高效的 jit,eBPF 的代码在内核中会被编译为机器码从而向真正的内核代码一样被执行。bpf()系统调用和map机制以及bpf helper辅助函数的提供,让内核操作更加便捷。内核在高频通用的代码中提供了安全的注入点,让 eBPF 程序只需要关注于代码逻辑。下图是 eBPF 程序的生命流程概述。容器网络内核原理27对于一个 eBPF 程序来说,他的完整的生命流程包括:使用 eBPF 兼容的 C 语言子集进行代码开发,然后通过 clang 进行编译。通过各种开发框架进行初步的检查,然后通过 bpf()系统调用进行加载,在这个过程中会完成 map 的创建和替换以及符号的重定位。加载到内核的过程中,内核的 verifier 会对程序进行校验,如果通过了校验,则可以被 JIT 编译为字节码然后被添加到指定的位置。当内核代码执行到某个位置,内核会自动执行已经完成加载和attach的eBPF程序,例如 socket 的读取和写入会触发 sockops 这个执行点的 eBPF 程序的执行,完成流量的统计或者劫持动作。eBPF 在在安全,网络和可观测行上都有很广泛的应用,也诞生了许多影响力较大的开源项目。容器网络内核原理28Linux 内核为提升可观测性而提供了多个可执行的点,我们常用的包括:kprobe,kretprobe,fentry,fexit 通过执行到某个函数是,触发 INT3 中断,使得eBPF 程序可以在进程现场状态下观测到信息。tracepoint 内核 的 debugfs 子系 统提供 的可供 执行的 点,内核 在固定 的tracepoint 会执行注册的 eBPF 程序。我们可以通过一些开源的项目很快体验到 eBPF 的价值,例如通过 bpftrace,我们能够很快看到所有经过内核的数据报文在 netfilter 中的返回值:bpftrace-e kretprobe:nf_hook_slow printf(%d%sn,retval,comm)此外,eBPF 在容器网络中也扮演着越来越关键的角色,包括 cilium,terway,calico 等多个知名的网络插件都开始使用 eBPF 来取代传统的 netfilter 框架等机制的作用,达到更加高效的抽象。全景剖析阿里云容器网络数据链路29二、全景剖析阿里云容器网络数据链路鸟瞰容器网络,整个容器网络可以分为三个部分:Pod 网段,Service 网段和 Node 网段。这三个网络要实现互联互通和访问控制,那么实现的技术原理是什么?整个链路又是什么,限制又是什么呢?Flannel,Terway 有啥区别?不同模式下网络性能如何?这些,需要客户在下搭建容器之前,就要依据自己的业务场景进行选择,而搭建完毕后,相关的架构又是无法转变,所以客户需要对每种架构特点要有充分了解。比如下图是个简图,Pod网络既要实现同一个ECS的Pod间的网络互通和控制,又要实现不同ECSPod间的访问,Pod 访问 SVC 的后端可能在同一个 ECS 也可能是其他 ECS,这些在不同模式下,数据链转发模式是不同的,从业务侧表现结果也是不一样的。1.Flannel 模式架构设计Flannel 模式下,ECS 只有一个主网卡 ENI,无其他附属网卡,ECS 和节点上的 Pod 与外部通信都需要通过主网卡进行。ACK Flannel 会在每个节点创建 cni0 虚拟网卡作为Pod 网络和 ECS 的主网卡 eth0 之间的桥梁。全景剖析阿里云容器网络数据链路30集群的每个节点会起一个 flannel agent,并且会给每个节点预分配一个 Pod CIDR,这个 Pod CIDR 是 ACK 集群的 Pod CIDR 的子集。容器的网络命名空间内会有一个 eth0 的虚拟网卡,同时存在下一跳指向该网卡的路由,该网卡会作为容器和宿主内核进行数据交换的出入口。容器和宿主机之间的数据链路是通过 veth pair 进行交换的,现在我们已经找到 veth pair 其中一个,如何去找另一个veth 呢?全景剖析阿里云容器网络数据链路31如上图所示,我们可以容器的网络命名空间中通过 ip addr 看到一个 eth0if8 的标志位,其中81 这个将会协助我们在 ECS 的 OS 内找到找到和容器网络命名空间中的 vethpair 相对一个。在 ECS OS 内我们通过 ip addr|grep 81:可以找到 vethd7e7c6fd 这个虚拟网卡,这个就是 veth pair 在 ECS OS 侧相对的那一个。到目前为止容器内和 OS 数据链路已经建立链接了,那么 ECS OS 内对于数据流量是怎么判断去哪个容器呢?通过 OS Linux Routing 我们可以看到,所有目的是 Pod CIDR 网段的流量都会被转发到 cni0 这张虚拟网卡,那么 cni0 是通过 bridge 方式将不同目的的数据链路指向到不同的 vethxxx。到这里为止,ECS OS 和 Pod 的网络命名空间已经建立好完整的出入链路配置了。全景剖析阿里云容器网络数据链路321)1)FlannelFlannel 模式容器网络数据链路剖析模式容器网络数据链路剖析针对容器网络特点,我们可以将 Flannel 模式下的网络链路大体分为以 Pod IP 对外提供服务和以 SVC 对外提供服务两个大的 SOP 场景,进一步细分可以拆分到 10 个不同的小的 SOP 场景。对这 10 个场景的数据链路梳理合并,这些场景可以归纳为下面 5 类典型的场景:Client 和服务端 Pod 部署于同一个 ECS;Client 和服务端 Pod 部署于不同 ECS;全景剖析阿里云容器网络数据链路33访问 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 为集群外;2)2)场景一:场景一:ClientClient 和服务端和服务端 PodPod 部署于同一个部署于同一个 ECSECS此场景包含下面几个子场景,数据链路可以归纳为一种:以 Pod IP 对外提供服务,Client 和 Pod 部署于同一个节点;以 SVC ClusterIP 对外提供服务,Client 和 SVC 后端 Pod 部署于同一节点;以 SVC ExternalIP 对外提供服务,ExternalTrafficPolicy 为 Cluster/Local 情况下,Client 和 SVC 后端 Pod 部署于同一节点;环境环境ap-southeast-1.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 的默认路由。全景剖析阿里云容器网络数据链路34该容器 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 网桥信息。全景剖析阿里云容器网络数据链路35小结小结可以访问到目的端数据链路转发示意图:全景剖析阿里云容器网络数据链路36内核协议栈示意图:数据链路:ECS1 Pod1 eth0-vethxxx1-cni0-vethxxxx2-ECS1 Pod2 eth0;数据链路要经过三次内核协议栈,分别是 Pod1 协议栈,ECS OS 协议栈和 Pod2 协议栈;3)3)场景二:场景二:ClientClient 和服务端和服务端 PodPod 部署于不同部署于不同 ECSECS此场景包含下面几个子场景,数据链路可以归纳为一种:以 Pod IP 对外提供服务,Client 和 Pod 部署于不同节点;以 SVC ClusterIP 对外提供服务,Client 和 SVC 后端 Pod 部署于不同节点;以 SVC ExternalIP 对外提供服务,ExternalTrafficPolicy 为 Cluster 情况下,集群内 Client 和 SVC 后端 Pod 部署于不同节点;环境环境全景剖析阿里云容器网络数据链路37ap-southeast-1.10.0.0.180 节点上存在两个 pod:centos-67756b6dc8-rmmxt IP地址 172.23.96.23 和 nginx1-76c99b49df-7plsr IP 地址 172.23.96.163Service nginx1 的 ExternalTrafficPlicy 为 Cluster。内核路由内核路由Pod 网络空间和 ECS OS 网络空间的数据交换在 2.1 场景一中已经做了详细描述,此处不再果断篇幅描述。源端源端 PodPod 所在所在 ECSECS 的的 IPVSIPVS 规则规则可以看到,源端数据链路访问 svc 的 clusterip 192.168.13.23 时,如果链路到达 ECS的 OS 内,会命中 ipvs 规则,被解析到 svc 的后端 endpoint 之一(本实例中只有一个pod,所以 endpoint 只有一个)。小结小结可以成功访问到目的端数据链路转发示意图:全景剖析阿里云容器网络数据链路38VPC 路由表会自动配置目的地址是 pod CIDR,下一跳为 Pod 网段所归属的 ECS 的自定义路由条目,该规则由 ACK 管控测通过 openapi 调用 VPC 去配置,无需手动配置和删除。内核协议栈示意图:全景剖析阿里云容器网络数据链路39Conntack 表信息(访问 SVC 情况)Node1:src 是源 pod IP,dst 是 svc 的 ClusterIP,并且期望是由 svc 的其中一个 endpoint172.23.96.163 来回消息给源端 pod。Node2:目的 pod 所在 ECS 上 conntrack 表记录是由源端 pod 访问目的 pod,不会记录 svc的 clusterip 地址。数据链路:ECS1 Pod1 eth0-vethxxx1-cni0-ECS 1 eth0-VPC-ECS2eth0-cni0-vethxxxx2-ECS2 Pod2 eth0;数据链路要经过四次内核协议栈,分别是 Pod1 协议栈,ECS1 OS 协议栈,ECS2 OS协议栈和 Pod2 协议栈;VPC 路由表会自动配置目的地址是 pod CIDR,下一跳为 Pod 网段所归属的 ECS的自定义路由条目,该规则由 ACK 管控测通过 openapi 调用 VPC 去配置,无需手动配置和删除;如果访问的 SVC 的 cluster IP,或者是 Cluster 模式下,访问 SVC 的 externalIP,数据链路通过 veth pair 进到 ECS OS 内后,会命中相应的 IPVS 规则,并根据负载规则,选择 IPVS 的某一个后端,进而打到其中的一个 SVC 的后端 endpoint,SVC的 IP 只会再 Pod 的 eth0,veth pair vethxxx 被捕捉到,其他链路环节不会捕捉到 svc 的 IP;全景剖析阿里云容器网络数据链路404)4)场景三:场景三:ExternalTrafficPolicyExternalTrafficPolicy 为为 LocalLocal 时,时,ClientClient 和服务端和服务端 PodPod 部部署于集群内不同署于集群内不同 ECSECS此场景包含下面几个子场景,数据链路可以归纳为一种:以 SVC ExternalIP 对外提供服务,ExternalTrafficPolicy 为Local 情况下,集群内 Client和 SVC 后端 Pod 部署于不同节点;环境环境ap-southeast-1.10.0.0.180 节点上存在两个 pod:centos-67756b6dc8-rmmxt IP地址 172.23.96.23 和 nginx1-76c99b49df-7plsr IP 地址 172.23.96.163Service nginx1 ExternalTrafficPolicy 为 Local。内核路由内核路由Pod 网络空间和 ECS OS 网络空间的数据交换在 2.1 场景一中已经做了详细描述,此处不再果断篇幅描述。全景剖析阿里云容器网络数据链路41源端源端 PodPod 所在所在 ECSECS 的的 IPVSIPVS 规则规则可以看到,源端数据链路访问 svc 的 externalip 8.219.164.113 时,如果链路到达 ECS的 OS 内,会命中 ipvs 规则,但是我们可以看到 EcternalIP 并没有相关的后端endpoint,链路达到 OS 后,会命中 IPVS 规则,但是没有后端 pod,所以会出现connection refused。小结小结不可以访问到目的端,此时会访问失败,Connection refused数据链路转发示意图:内核协议栈示意图:全景剖析阿里云容器网络数据链路42数据链路:ECS1 Pod1 eth0-vethxxx1-;数据链路要经过一次半内核协议栈,分别是 Pod1 协议栈,半个 ECS1 OS 协议栈;如果访问的 SVC 的 External IP,或者是 Local 模式下,访问 SVC 的 externalIP,数据链路通过veth pair进到ECS OS内后,会命中相应的IPVS规则,但是由于Local模式,External IP 的 IPVS 为空,所以命中规则但是无转发后端,整个链路会在 ipvs终止,访问失败。所以建议集群内采用 clusterip 访问,这也是 k8s 官方推荐的最佳实践;5)场景四:场景四:ExternalTrafficPolicyExternalTrafficPolicy 为为 LocalLocal 时,时,ClientClient 来自于集群外来自于集群外此场景包含下面几个子场景,数据链路可以归纳为一种:A.访问 SVC External IP,ExternalTrafficPolicy 为 Local 时,Client 和服务端 Pod 部署于不同 ECS,其中 client 为集群外。环境Deployment 为 nginx1,分别为三个 pod nginx1-76c99b49df-4zsdj 和nginx1-76c99b49df-7plsr 部署在 ap-southeast-1.10.0.1.206ECS 上,最后一个pod nginx1-76c99b49df-s6z79 部署在其他节点 ap-southeast-1.10.0.1.216 上Service nginx1 的 ExternalTrafficPlicy 为 Local。全景剖析阿里云容器网络数据链路43内核路由内核路由Pod 网络空间和 ECS OS 网络空间的数据交换在 2.1 场景一中已经做了详细描述,此处不再果断篇幅描述。SLBSLB 相关配置相关配置从 SLB 控制台,可以看到 SLB 后端的虚拟服务器组中只有两个 ECS 节点ap-southeast-1.10.0.1.216 和 ap-southeast-1.10.0.1.206。集群内的其他节点,比如 ap-southeast-1.10.0.0.180 并未被加到 SLB 的后端虚拟服务器组中。虚拟服务器组的 IP 为 ECS 的 IP,端口为 service 里面的 nodeport 端口 32580。故故 ExternalTrafficPolicyExternalTrafficPolicy 为为 LocalLocal 模式下模式下,只有有只有有 ServiceService 后端后端 podpod 所在的所在的 ECSECS 节点节点才会被加入到才会被加入到 SLBSLB 的后端虚拟服务器组中,参与的后端虚拟服务器组中,参与 SLBSLB 的流量转发,集群内的其他节点的流量转发,集群内的其他节点不参与不参与 SLBSLB 的转发的转发。SLBSLB 虚拟服务器组虚拟服务器组 ECSECS 的的 IPVSIPVS 规则规则从 SLB 的虚拟服务器组中的两个 ECS 可以看到,对于 nodeip nodeport 的 ipvs 转发规则是不同。ExternalTrafficPolicy 为 Local 模式下,只有该节点上的护短 pod 才会被加到该节点的 ipvs 转发规则中,其他节点上的后端 pod 不会加进来,这样保证了被全景剖析阿里云容器网络数据链路44SLB 转发的链路,只会被转到该节点上的 pod,不会转发到其他节点上。node1:ap-southeast-1.10.0.1.206node1:ap-southeast-1.10.0.1.216小结小结可以访问到目的端数据链路转发示意图:该图示意了只有后端 pod 所在 ECS 才会加到 SLB 后端中,从集群外部访问 SVC 的externalIP(SLB IP)的情况,可见数据链路只会被转发到虚拟服务器组中的 ECS,不会再被转发到集群内其他节点上。全景剖析阿里云容器网络数据链路45内核协议栈示意图:Conntack 表信息Node:src 是集群外部客户端 IP,dst 是节点 IP,dport 是 SVC 中的 nodeport。并且期望是由该 ECS 上的 pod 172.23.96.82 来回包给源端。数据链路:client-SLB-ECS eth0 ECS nodeport-cni0-vethxxxxx-ECS1Pod1 eth0;数据链路要经过两次内核协议栈,分别是 Pod1 协议栈,ECS1 OS 协议栈;ExternalTrafficPolicy 为 Local 模式下,只有有 Service 后端 pod 所在的 ECS 节点才会被加入到 SLB 的后端虚拟服务器组中,参与 SLB 的流量转发,集群内的其他节点不参与 SLB 的转发;全景剖析阿里云容器网络数据链路466)场景五:场景五:ExternalTrafficPolicyExternalTrafficPolicy 为为 ClusterCluster 时,时,ClientClient 来自于集群外来自于集群外此场景包含下面几个子场景,数据链路可以归纳为一种:访问 SVCExternal IP,ExternalTrafficPolicy 为 Cluster 时,Client 和服务端 Pod 部署于不同 ECS,其中 client 为集群外。环境环境Deployment 为 nginx1,分别为三个 pod nginx1-76c99b49df-4zsdj 和nginx1-76c99b49df-7plsr 部署在 ap-southeast-1.10.0.1.206ECS 上,最后一个pod nginx1-76c99b49df-s6z79 部署在其他节点 ap-southeast-1.10.0.1.216 上Service nginx2 的 ExternalTrafficPlicy 为 Cluster。内核路由内核路由Pod 网络空间和 ECS OS 网络空间的数据交换在 2.1 场景一中已经做了详细描述,此处不再果断篇幅描述。SLBSLB 相关配置相关配置从 SLB 控制台,集群内所有所有节点 ap-southeast-1.10.0.0.180、ap-southeast-1.10.0.1.216和ap-southeast-1.10.0.1.206都被加到SLB的虚拟服务全景剖析阿里云容器网络数据链路47器组中。其中虚拟服务器组的 IP 为 ECS 的 IP,端口为 service 里面的 nodeport 端口30875。故故ExternalTrafficPolicExternalTrafficPolicy y 为为CLusteCLuster r 模式下模式下,集群内所有集群内所有的的ECECS S节点都会被加入节点都会被加入到到SLSLB B的后端虚拟服务器组中,参与的后端虚拟服务器组中,参与 SLBSLB 的流量转发。的流量转发。SLBSLB 虚拟服务器组虚拟服务器组 ECSECS 的的 IPVSIPVS 规则规则从 SLB 的虚拟服务器组中的可以看到,对于 nodeip nodeport 的 ipvs 转发规则是一致的。ExternalTrafficPolicy 为 CLuster 模式下,所有的 service 后端 pod 都会被加到所有节点的 ipvs 的转发规则中,即使是该节点有后端 pod,流量也不一定会被转发到该节点上 pod,可能会被转发到其他节点上的后端 pod。node1:ap-southeast-1.10.0.1.206(该节点有后端 pod)node1:ap-southeast-1.10.0.1.216(该节点有后端 pod)node3:ap-southeast-1.10.0.0.180(该节无后端 pod)全景剖析阿里云容器网络数据链路48小结小结可以访问到目的端数据链路转发示意图:该图示意了集群内所有 ECS都会被加到SLB 后端中,从集群外部访问SVC 的externalIP(SLB IP)的情况,数据流量可能会被转发到其他节点上。内核协议栈示意图:内核协议栈示意图已经在 2.4 场景一中已经做了详细描述,此处不再过多篇幅描述。Conntack 表信息链路 1:ap-southeast-1.10.0.0.180:此时数据链路对应示意图中的链路 1,可以看到数据链路被转到全景剖析阿里云容器网络数据链路49ap-southeast-1.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-7plsrPod,部署在 ap-southeast-1.10.0.1.206。ap-southeast-1.10.0.1.206:通过此节点 conntrack 表,可以看到 src 是 node ap-southeast-1.10.0.0.180,dst是 172.23.96.163 的 80 端口,回包也是直接回给 node ap-southeast-1.10.0.0.180。综上可以看到综上可以看到 srcsrc 变换了多次,故在变换了多次,故在 CLusterCLuster 模式下,会存在丢失真实客户端模式下,会存在丢失真实客户端 IPIP 的情的情况况。链路 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-vethxxxxx-ECS1Pod1 eth0;情景二:client-SLB-ECS1 eth0 ECS1 nodeport-VPC Routing-ECS2 eth0 Pod port-cni0-vethxxxxx-ECS2 Pod1 eth0;数据链路要经过三次内核协议栈,分别是 ECS1 OS、ECS2 OS 协议栈和 Pod 协议栈;全景剖析阿里云容器网络数据链路50ExternalTrafficPolicy 为 CLuster 模式下,kubernetes 所有 ECS 节点都会被加入到 SLB 的后端虚拟服务器组中,参与 SLB 的流量转发,此时会存在数据路在集群内被多个 ECS 转发的场景,该情况下会丢失真实客户端 IP 的情况;7)7)小结小结本节主要聚焦 ACK 在 Flannel 模式下,不同 SOP 场景下的数据链路转发路径。随着微服务化和云原生化,网络场景日趋复杂,作为 kubernetes 原生的网络模型Flannel,不同的访问环境,一共可以分为 10 个 SOP 场景。通过深入简出的剖析,可以归纳为 5个场景,并对这五个场景的转发链路,技术实现原理,云产品配置等一一梳理并总结,这对我们遇到 Flannel 架构下的链路抖动、最优化配置,链路原理等提供了初步指引方向。2.Terway ENI 模式架构设计Terway ENI 模式下,ENI 的网络都是和 VPC 同样的网段,ENI 网络就是从 Aliyun 的VPC 网络中创建和绑定一个弹性网卡到 ECS 节点上,然后 Pod 利用这个弹性网卡和别的网络互通,这里需要关注的是弹性网卡的数量是有限制的,具体的根据实例类型有不同的配额。全景剖析阿里云容器网络数据链路51Pod 所使用的的 CIDR 网段和节点的 CIDR 是同一个网段。pod 内部可以看到是有两张网卡的,一个是 eth0,另一个是 veth1,其中 eth0 的 IP就是 Pod 的 IP,此网卡的 MAC 地址和控制台上的 ENI 的 MAC 地址可以匹配,说明此此网卡就是附属网卡就是附属 ENIENI 网卡,被直接挂载到了网卡,被直接挂载到了 PodPod 的网络命名空间内。的网络命名空间内。Pod 内有指向 eth0 的默认路由,同时还有指向目的网段为 192.168.0.0/16,下一跳为veth1 网卡的路由,其中 192.168.0.0/16 网段为集群的 service 网段,说明集群内 Pod全景剖析阿里云容器网络数据链路52访问 SVC 的 clusterIP 网段,数据链路会经过 veth1 网卡到宿主机 ECS 的 OS 内进行下一步判断,其他情况是走 eth0 直接进入到 VPC。如上图所示,我们可以容器的网络命名空间中通过 ip addr 看到一个 veth1if19 的标志位,其中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 的网络命名空间已经建立好完整的出入链路配置了。全景剖析阿里云容器网络数据链路531 1)TerwayTerway ENIENI 模式容器网络数据链路剖析模式容器网络数据链路剖析针对容器网络特点,我们可以将 Terway ENI 模式下的网络链路大体分为以 Pod IP 对外提供服务和以 SVC 对外提供服务两个大的 SOP 场景,进一步细分可以拆分到 8 个不同的小的 SOP 场景。对这 8 个场景的数据链路梳理合并,这些场景可以归纳为下面 8 类典型的场景:TerwayENI 架构下,不同的数据链路访问情况下,可以总结归纳为为 8 类:访问 Pod IP,同节点访问 pod;全景剖析阿里云容器网络数据链路54访问 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;2 2)场景一:访问场景一:访问 PodPod IPIP,同节点访问,同节点访问 podpod环境环境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 的两条路由。全景剖析阿里云容器网络数据链路55该容器 veth1 在 ECS OS 内对应 veth pair 是 cali5068e632525。在 ECS OS 内,有指向 Pod IP,下一跳为为 calixxxx 的路由,通过前文可以知道 calixxx网卡是和每个 pod 内的 veth1 组成的 pair,所以,pod 内访问 SVC 的 CIDR 会有指向veth1 的路由,不会走默认的 eth0 路由。故:calixx 网卡在这里的主要作用是用于:节点访问 Pod 2.当节点或者 Pod 访问 SVC 的 CIDR 时,会走 ECS OS 内核协议栈转换,走到 calixxx 和 veth1 访问 pod。全景剖析阿里云容器网络数据链路56小结小结可以访问到目的端nginx1-5969d8fc89-9t99h netns veth1 可以抓到数据包。nginx1-5969d8fc89-9t99h cali5068e632525 可以抓到数据包。全景剖析阿里云容器网络数据链路57数据链路转发示意图:数据链路是 ECS-Linux routing-calicxxx-Pod net ns veth1。数据链路完成,宿主机 ns 切换至 Pod ns;通过宿主机上的路由切换至 pod 所属的 veth pair;该网卡为被分配的 pod 独占,无法和其他 pod 进行共享;数据链路经过两次协议栈;3)3)场景二:访问场景二:访问 PodPod IPIP,同节点,同节点 podpod 访问访问 podpod环境环境全景剖析阿里云容器网络数据链路58ap-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-9t99hIP 地址 10.0.0.203,该容器在宿主机表现的 PID 是 1094736。小结小结可以访问到目的端全景剖析阿里云容器网络数据链路59centos-59cdc5c9c4-89f8x netns eth1 可以抓到数据包。nginx1-5969d8fc89-9t99h netns eth1 可以抓到数据包。数据链路转发示意图:数据链路转发示意图:全景剖析阿里云容器网络数据链路60数据链路是 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 进行共享;数据链路经过两次协议栈;4)4)场景三:访问场景三:访问 PodPod IPIP,异节点,异节点 podpod 访问访问 podpod环境环境全景剖析阿里云容器网络数据链路61ap-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。全景剖析阿里云容器网络数据链路62小结小结可以访问到目的端centos-59cdc5c9c4-89f8x netns eth0 可以抓到数据包。nginx-6f545cb57c-jmbrq netns eth0 可以抓到数据包。全景剖析阿里云容器网络数据链路63数据链路转发示意图:数据链路转发示意图:数据链路是 ECS1 Pod1 netns eth0-VPC-ECS2 Pod2 netns eth0。数据链路不经过宿主机 host namespace,数据链路会先出 ECS1,到 AVS 再回到 ECS2;全景剖析阿里云容器网络数据链路64在 pod 内的 net namespace 中,直接命中默认路有规则,从 eth0 网卡出 pod 直接到 VPC。这里的 eth0 其实就是附属网卡 ENI,直接被挂载在了 pod 的 net ns,走了 PCI 设备;该网卡为被分配的 pod 独占,无法和其他 pod 进行共享;数据链路经过两次协议栈;5)5)场景四:集群内访问场景四:集群内访问 SVCSVC IPIP(ClusterCluster IPIP),源端和,源端和 SVCSVC 后端后端 PodPod 为为同一节点同一节点环境环境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 的两条路由。全景剖析阿里云容器网络数据链路65该容器 eth0 在 ECS OS 内对应 veth pair 是 cali38ef34581a9。通过上述类似的办法,可以找到 nginx1-5969d8fc89-9t99hIP 地址 10.0.0.203,该容器在宿主机表现的 PID 是 1094736,该容器 eth0 在 ECS OS 内对应 veth pair 是cali5068e632525。全景剖析阿里云容器网络数据链路66在 ECS OS 内,有指向 Pod IP,下一跳为为 calixxxx 的路由,通过前文可以知道 calixxx网卡是和每个 pod 内的 veth1 组成的 pair,所以,pod 内访问 SVC 的 CIDR 会有指向veth1 的路由,不会走默认的 eth0 路由。故 calixx 网卡在这里的主要作用是用于:节点访问 Pod 2.当节点或者 Pod 访问 SVC的 CIDR 时,会走 ECS OS 内核协议栈转换,走到 calixxx 和 veth1 访问 pod。全景剖析阿里云容器网络数据链路67小结小结可以访问到目的端centos-59cdc5c9c4-89f8x netns veth1 可以抓到数据包。centos-59cdc5c9c4-89f8x netns cali38ef34581a9 可以抓到数据包。全景剖析阿里云容器网络数据链路68nginx1-5969d8fc89-9t99h netns veth1 可以抓到数据包。nginx1-5969d8fc89-9t99h netns cali5068e632525 可以抓到数据包。全景剖析阿里云容器网络数据链路69数据链路转发示意图:数据链路转发示意图:数据链路是 ECS1 Pod1 netns veth1-calixxx1-calixxx2-ECS2 Pod2 netnsveth1;在 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;全景剖析阿里云容器网络数据链路706)6)场景五:集群内访问场景五:集群内访问 SVCSVC IPIP(ClusterCluster IPIP),源端和,源端和 SVCSVC 后端后端 PodPod 为为不同节点不同节点环境环境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。全景剖析阿里云容器网络数据链路71通过上述类似的办法,可以找到 nginx-6f545cb57c-jmbrqIP 地址 10.0.2.86,该容器在宿主机表现的 PID 是 1083623,该 pod 网卡 ENI 是直接被挂载到了 Pod 的网络命名空间内。小结小结可以访问到目的端全景剖析阿里云容器网络数据链路72数据链路转发示意图:数据链路转发示意图:数据链路是 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;7)7)场景六场景六:集群内访问集群内访问 SVCSVC IPIP(ExternalExternal IPIP),源端和源端和 SVCSVC 后端后端 PodPod 为为同一节点同一节点环境环境全景剖析阿里云容器网络数据链路73ap-southeast-1.10.0.0.196 节点上存在两个 pod:centos-59cdc5c9c4-89f8x IP 地址 10.0.0.202 和 nginx1-5969d8fc89-9t99h 和 10.0.0.203Service 是 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 的两条路由。SLBSLB 相关配置相关配置在 SLB 控制台,可以看到虚拟服务器组的后端只有 nginx1-5969d8fc89-9t99h 的 ENIeni-t4n6qvabpwi24w0dcy55。综上,可以判断如果访问的是 SVC 的 External IP,是走默认路由 eth0,直接出 ECS 进全景剖析阿里云容器网络数据链路74入到 avs,访问到 SLB 的实例,再由 SLB 实例转发到后端 eni 上。小结小结可以访问到目的端数据链路转发示意图:数据链路转发示意图:数据链路是 ECS1 Pod1 netns eth0-VPC-SLB-VPC-ECS1 Pod2 netnseth0。数据链路不经过宿主机 host namespace,数据链路会先出 ECS1,到 AVS再回到 ECS1;在 pod 内的 net namespace 中,直接命中默认路有规则,从 eth0 网卡出 pod 直接到 VPC。这里的 eth0 其实就是附属网卡 ENI,直接被挂载在了 pod 的 net ns,走了 PCI 设备;全景剖析阿里云容器网络数据链路75该网卡为被分配的 pod 独占,无法和其他 pod 进行共享;与 2.4 场景可以看到非常大的不同,虽然都是前后端 Pod 都是部署在同一个 ECS访问 SVC 的 IP,但是可以看到如果访问的是 SVC 的 ClusterIP,则数据链路会进入到 ECS OS 层面,会经过三次协议栈;如果访问的是 External IP,则不会经过 ECSOS,直接出 ECS,经过 SLB 转发到目的 Pod 上,只经过两次协议栈(Pod1 和 Pod2);8)8)场景七:集群内访问场景七:集群内访问 SVCSVC IPIP(ExternalExternal IPIP),源端和,源端和 SVCSVC 后端后端 PodPod 为为不同节点不同节点环境环境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 的两条路由。全景剖析阿里云容器网络数据链路76SLBSLB 相关配置相关配置在 SLB 控制台,可以看到 lb-t4nih6p8w8b1dc7p587j9 虚拟服务器组的后端只有nginx-6f545cb57c-jmbrq 的 ENI eni-t4n5kzo553dfak2sp68j。综上,可以判断如果访问的是 SVC 的 External IP,是走默认路由 eth0,直接出 ECS 进入到 avs,访问到 SLB 的实例,再由 SLB 实例转发到后端 eni 上。全景剖析阿里云容器网络数据链路77小结小结可以访问到目的端数据链路转发示意图:数据链路转发示意图:数据链路是 ECS1 Pod1 netns eth0-VPC-SLB-VPC-ECS2 Pod2 netnseth0。数据链路不经过宿主机 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);9)9)场景八:集群外访问场景八:集群外访问 SVCSVC ExternalExternal IPIP环境环境全景剖析阿里云容器网络数据链路78ap-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。SLBSLB 相关配置相关配置在 SLB 控制台,可以看到 lb-t4nih6p8w8b1dc7p587j9 虚拟服务器组的后端服务器组是两个后端 nginxPod 的的 ENI eni-t4n5kzo553dfak2sp68j 和eni-t4naaozjxiehvmg2lwfo。从集群外部角度看,SLB 的后端虚拟服务器组是 SVC 的后端 Pod 所属的两个 ENI 网卡,内网的 IP 地址就是 Pod 的地址。没有经过后端 Pod 所在的 ECS 的 OS 层面,直接进入到了 OS 的的协议栈。全景剖析阿里云容器网络数据链路79小结小结可以访问到目的端数据链路转发示意图:数据链路转发示意图:数据链路:client-SLB-Pod ENI Pod Port-ECS1 Pod1 eth0;数据链路要经过一次内核协议栈,是 Pod1 协议栈;10)10)小结小结本篇文章主要聚焦 ACK 在 Terway ENI 模式下,不同 SOP 场景下的数据链路转发路径。伴随着客户对性能的极致追求的需求,在 Terway ENI 模式下,一共可以分为 8 个 SOP场景,并对这八个场景的转发链路,技术实现原理,云产品配置等一一梳理并总结,这对我们遇到 Terway ENI 架构下的链路抖动、最优化配置,链路原理等提供了初步指引方向。在 Terway ENI 模式下,ENI 是以 PCI 方式直接挂载到 Pod 的命名空间内,这就以为 ENI 属于被分配的 Pod 独享,而 ECS 所能部署的 Pod 数量取决于 ECS 所能挂载 ENI 网卡数量的限制,而这个限制和 ECS 的实例规格类型有关,比如神龙 ecs.ebmg7.32xlar全景剖析阿里云容器网络数据链路80ge,128C 512GB 也只支持最多 32 个 ENI,这往往会造成资源的浪费和部署密度的降低,为了解决这个资源效率问题,ACK 带来了 Terway ENIIP 的方式,来实现 ENI 网卡可以被多个 Pod 所共享,这大大增加了单个 ECS 上的 Pod 数量 quota,提升了部署密度,这也是目前线上集群采用最多的架构。下一系列我们将进入到 Terway ENIIP 模式的全景解析。3.Terway ENIIP 模式架构设计弹性网卡(ENI)支持配置多个辅助 IP 的功能,单个弹性网卡(ENI)根据实例规格可以分配6-20 个辅助 IP,ENI 多 IP 模式就是利用了这个辅助 IP 分配给容器,从而大幅提高了Pod 部署的规模和密度。在网络联通的方式上,Terway 支持选择 Veth pair 策略路由和 ipvlan l 两种方案,Terway 主要考虑了这些:在节点上如何把弹性网卡(ENI)的辅助 IP 的流量都走对应的弹性网卡出去,并使用弹性网卡本身的 mac 地址而不被丢包;2.如何兼容容器服务目前广泛的 Centos 7.x 的 3.10 的版本的内核;全景剖析阿里云容器网络数据链路81Pod 所使用的的 CIDR 网段和节点的 CIDR 是同一个网段。pod 内部可以看到是有一张网卡的,一个是 eth0,其中 eth0 的 IP 就是 Pod 的 IP,此网卡的 MAC 地址和控制台上的 ENI 的 MAC 地址不一致,同时 ECS 上有多张 ethx 的网卡,说明 ENI 附属网卡并不是直接挂在到了 Pod 的网络命名空间。全景剖析阿里云容器网络数据链路82Pod 内有只有指向 eth0 的默认路由,说明说明 PodPod 访问任何地址段都是从访问任何地址段都是从 eth0eth0 为统一的为统一的出入口。出入口。如上图所示,我们可以容器的网络命名空间中通过 ip addr 看到一个 eth0if63 的标志位,其中63 这个将会协助我们在 ECS 的 OS 内找到找到和容器网络命名空间中的veth pair 相对一个。在 ECS OS 内我们通过 ip addr|grep 63:可以找到cali44ae9fbceeb 这个虚拟网卡,这个就是 veth pair 在 ECS OS 侧相对的那一个。ECS OS 内对于数据流量是怎么判断去哪个容器呢?通过 OS Linux Routing 我们可以看到,所有目的是 Pod IP 的流量都会被转发到 Pod 对应的 calico 虚拟往卡上,到这里为止,ECS OS 和 Pod 的网络命名空间已经建立好完整的出入链路配置了。全景剖析阿里云容器网络数据链路83在 veth pair 中实现了多个 Pod 共享一个 ENI 的方式来提升了 ECS 的 Pod 部署密度,那么如何知道 Pod 是被分配到哪个 ENI 呢?TerwayPod 是通过 daemonset 的方式部署在每个节点上的,通过下面命令可以看到每个节点上的 TerwayPod。通过 terway-clishow factory 命令可以看到节点上的附属 ENI 数量、MAC 地址以及每个 ENI 上的 IP。全景剖析阿里云容器网络数据链路84故 Terway ENIIP 模式总体可以归纳为:在网络联通的方式上,采用选择 Veth pair 策略路由。一对 veth pair 来联通宿主机和 pod 的网络空间,pod 的地址是来源于弹性网卡的辅助 IP 地址,并且节点上需要配置策略路由来保证辅助 IP 的流量经过它所属的弹性网卡。同主机上的容器通信直接通过主机上的路由到同一个主机上别的容器对应的 veth上。不同主机的容器通信经过 VPC 的网络进行转发到对应的机器上,再通过机器上的路由转发到容器中。容器和其所在的宿主机之间的通信直接通过连接到宿主机 namespace 的 vethpair 和路由打通。容器到其他主机通过 VPC 的网络转发到对应的机器,其他主机到容器通过 VPC 网络转发到对应的弹性网卡,然后通过路由转发到容器的 Veth 上。容器到专线和共享服务也都是通过 VPC 的网络转发。容器到公网的访问经过 VSwitch 配置的 SNAT 网关直接将源 IP 转换成 EIP 的地址到外部网络。弹性网卡(ENI)支持配置多个辅助 IP 的功能,单个弹性网卡(ENI)根据实例规格可以分配 6-20 个辅助 IP,ENI 多 IP 模式就是利用了这个辅助 IP 分配给容器,从而大幅提高了 Pod 部署的规模和密度。1)1)TerwayTerway ENIIPENIIP 模式容器网络数据链路剖析模式容器网络数据链路剖析针对容器网络特点,我们可以将 Terway ENI 模式下的网络链路大体分为以 Pod IP 对外提供服务和以 SVC 对外提供服务两个大的 SOP 场景,进一步细分,可以归纳为 7 个不同的小的 SOP 场景。全景剖析阿里云容器网络数据链路85对这 8 个场景的数据链路梳理合并,这些场景可以归纳为下面 8 类典型的场景:TerwayENI 架构下,不同的数据链路访问情况下,可以总结归纳为为 8 类:访问 Pod IP,同节点访问 Pod访问 Pod IP/SVC IP(Cluster or Local),同节点 pod 间互访(pod 属于同 or 不同ENI)访问 PodIP,异节点 pod 间互访集群内非 SVC 后端 pod 所在节点访问 SVC ClusterIPCluster 模式,集群内非 SVC 后端 pod 所在节点访问 SVC External IPLocal 模式,集群内非 SVC 后端 pod 所在节点访问 SVC External IP集群外访问 SVC External IP2)2)场景一:访问场景一:访问 PodPod IPIP,同节点访问,同节点访问 podpod环境环境全景剖析阿里云容器网络数据链路86cn-hongkong.10.0.1.82 节点上存在 nginx-7d6877d777-zp5jg 和 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。全景剖析阿里云容器网络数据链路87小结小结可以访问到目的端nginx-7d6877d777-zp5jg netns eth0 可以抓到数据包。nginx-7d6877d777-zp5jg calif03b26f9a43 可以抓到数据包。全景剖析阿里云容器网络数据链路88数据链路转发示意图:数据链路转发示意图:会经过calicao网卡,每个非hostnetwork的pod会和calicao网卡形成veth pair,用于和其他 pod 或 node 进行通信。整个链路不会和请求不会经过pod所分配的ENI,直接在OS的ns中命中Ip rule 被转发。整个请求链路是 OS-calixxxxx-ECSPod net eth0。整个链路会经过两次内核协议栈:ECS OS 和 Pod。数据链路要经过两次内核协议栈,是 Pod1 协议栈、ECS1 协议栈。全景剖析阿里云容器网络数据链路893 3)场景二:访问场景二:访问 PodPod IP/SVCIP/SVC IP(ClusterIP(Cluster oror Local)Local),同节点,同节点 podpod 访访问问podpod(podpod 属于同属于同 oror 不同不同 ENIENI)环境环境cn-hongkong.10.0.1.82 节点上存在 nginx-7d6877d777-zp5jg 和 10.0.1.104cn-hongkong.10.0.1.82 节点上存在 centos-67756b6dc8-h5wnp 和 10.0.1.91Service 是 nginx,ClusterIP 是 192.168.2.115 ExternalIP 是 10.0.3.62。内核路由内核路由nginx-7d6877d777-zp5jg IP 地址 10.0.1.104,该容器在宿主机表现的 PID 是1094736,该容器网络命名空间有指向容器 eth0 的默认路由。该容器 eth0 在 ECS OS 内对应 veth pair 是 calif03b26f9a43。全景剖析阿里云容器网络数据链路90用上述类似办法可以发现 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。全景剖析阿里云容器网络数据链路91说明相关的路由转发是在 ECS OS 层面进行的,Pod 的 calixx 网卡起到了一个桥梁和连通的作用。源端源端 ECSECS 上的上的 IPVSIPVS 规则(如果访问的是规则(如果访问的是 SVCSVC IPIP)如果同节点上访问的是 SVC 的 IP(ClusterIP or ExternalIP),在节点上我们查看 SVC的相关 IPVS 转发规则:ServiceService 的的 ExternalTrafficPolicyExternalTrafficPolicy 是是 LocalLocalSVC nginx CLusterIP 是 192.168.2.115,ExternalIP 是 10.0.3.62。后端是 10.0.1.104和 10.0.3.58。全景剖析阿里云容器网络数据链路92cn-hongkong.10.0.1.82对于 SVC 的 ClusterIP,可以看到 SVC 的后端两个 Pod 都会被加到 IPVS 的转发规则。对于 SVC 的 ExternalIP,可以看到 SVC 的后端,只有该节点的后端 Pod 10.0.1.104 才会被加到 IPVS 的转发规则在在LoadBalanceLoadBalancer r 的的SVSVC C模式下模式下,如如果果ExternalTrafficPolicExternalTrafficPolicy y 为为LocalLocal,对对于于ClusterIClusterIP P来说,会把所有来说,会把所有 SVCSVC 后端后端 PodPod 都会加到该节点的都会加到该节点的 IPVSIPVS 转发规则;对于转发规则;对于 ExternalIPExternalIP,只会把该节点上的只会把该节点上的 SVCSVC 后端后端 PodPod 才会加到才会加到 IPVSIPVS 规则中。如果该节点没有规则中。如果该节点没有 SVCSVC 后后端端PodPod,则该节点上的,则该节点上的 PodPod 访问访问 SVCSVC 的的 ExternalIPExternalIP 将会是失败。将会是失败。ServiceService 的的 ExternalTrafficPolicyExternalTrafficPolicy 是是 ClusterClusterSVC nginx1 CLusterIP 是 192.168.2.253,ExternalIP 是 10.0.3.63,后端是 10.0.1.104和 10.0.3.58全景剖析阿里云容器网络数据链路93cn-hongkong.10.0.1.82对于 SVC 的 ClusterIP,可以看到 SVC 的后端两个 Pod 都会被加到 IPVS 的转发规则。对于 SVC 的 ExternalIP,可以看到 SVC 的后端两个 Pod 都会被加到 IPVS 的转发规则。在在 LoadBalancerLoadBalancer 的的 SVCSVC 模式下,如果模式下,如果 ExternalTrafficPolicyExternalTrafficPolicy 为为 ClusterCluster,对,对于于ClusterIPClusterIP 或或 ExternalIPExternalIP 来说,会把所有来说,会把所有 SVCSVC 后端后端 PodPod 都会加到该节点的都会加到该节点的 IPVSIPVS 转发转发规则。规则。小结小结可以访问到目的端全景剖析阿里云容器网络数据链路94ConntrackConntrack 表信息表信息ServiceService nginxnginx 的的 ExternalTrafficPolicyExternalTrafficPolicy 是是 LocalLocal。SVC nginx CLusterIP 是 192.168.2.115,ExternalIP 是 10.0.3.62。后端是 10.0.1.104和 10.0.3.58。如果访问的是 SVC 的 ClusterIP,通过 conntrack 信息,可以看到 src 是源端 Pod10.0.1.91,dst 是 SVC ClusterIP 192.168.2.115,dport 是 SVC 中的 port。并且期望是 10.0.1.104 来回包给 10.0.1.91。如果访问的是 SVC 的 ExternalIP,通过 conntrack 信息,可以看到 src 是源端 Pod10.0.1.91,dst 是 SVC ExternalIP 10.0.3.62。dport 是 SVC 中的 port。并且期望是 10.0.1.104 来回包给 10.0.1.91。Service nginx1 的 ExternalTrafficPolicy 是 Cluster。SVC nginx1 CLusterIP 是 192.168.2.253,ExternalIP 是 10.0.3.63,后 端 是10.0.1.104 和 10.0.3.58。如果访问的是 SVC 的 ClusterIP,通过 conntrack 信息,可以看到 src 是源端 Pod10.0.1.91,dst 是 SVC ClusterIP 192.168.2.253,dport 是 SVC 中的 port。并且期望是 10.0.1.104 来回包给 10.0.1.91。如果访问的是 SVC 的 ExternalIP,通过 conntrack 信息,可以看到 src 是源端 Pod10.0.1.91,dst 是 SVC ExternalIP 10.0.3.63,dport 是 SVC 中的 port。并且期望是节点 ECS 的 IP 10.0.1.82 来回包给 10.0.1.91。全景剖析阿里云容器网络数据链路95综上可以看到 src 变换了多次,故在 Cluster 模式下,会存在丢失真实客户端 IP 的情况。数据链路转发示意图:数据链路转发示意图:会经过calicao网卡,每个非hostnetwork的pod会和calicao网卡形成veth pair,用于和其他 pod 或 node 进行通信;整个链路不会和请求不会经过pod所分配的ENI,直接在OS的ns中命中Ip rule 被转发;整个请求链路是ECS1 Pod1 eth0-Pod1 calixxxx-Pod2 calixxxx-ECS1 Pod2eth0;访问 SVC IP,SVC 会在源端 pod eth0 和 calixxx 网卡捕捉到,在目的端 pod 的eth0 和 calixxx 时捕捉不到;在 LoadBalancer 的 SVC 模式下,如果 ExternalTrafficPolicy 为 Local,对于ClusterIP 来说,会把所有 SVC 后端 Pod 都会加到该节点的 IPVS 转发规则;对于ExternalIP,只会把该节点上的 SVC 后端 Pod 才会加到 IPVS 规则中;全景剖析阿里云容器网络数据链路96在 LoadBalancer 的 SVC 模式下,如果 ExternalTrafficPolicy 为 Cluster,对于ClusterIP 或 ExternalIP 来说,会把所有 SVC 后端 Pod 都会加到该节点的 IPVS 转发规则,同时无法保留 src 地址;数据链路要经过三次内核协议栈,是 Pod1 协议栈、ECS1 协议栈、Pod2 协议栈;4)4)场景三:访问场景三:访问 PodIPPodIP,异节点,异节点 podpod 间互访间互访环境环境cn-hongkong.10.0.1.82 节点上存在 centos-67756b6dc8-h5wnp 和 10.0.1.91cn-hongkong.10.0.3.49 节点上存在 nginx-7d6877d777-lwrfc 和 10.0.3.58。内核路由内核路由centos-67756b6dc8-h5wnp IP 地址 10.0.1.104,该容器在宿主机表现的 PID 是2211426,该容器网络命名空间有指向容器 eth0 的默认路由。用上述类似办法可以发现 centos-67756b6dc8-h5wnp 的 veth pair 的cali44ae9fbceeb,Pod 网络空间只有默认路由。全景剖析阿里云容器网络数据链路97在 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。全景剖析阿里云容器网络数据链路98小结小结可以访问到目的端数据链路转发示意图:数据链路转发示意图:会经过calicao网卡,每个非hostnetwork的pod会和calicao网卡形成veth pair,用于和其他 pod 或 node 进行通信;整个链路请求会经过 pod 所分配的 ENI,直接在 OS 的 ns 中命中 Ip rule 被转发;出 ECS 后,根据要访问的 pod 和该 pod ENI 所属 vswitch,命中 VPC 路由规则或者直接 VSW 上的二层转发;整个请求链路是 ECS1 Pod1 eth0-ECS1 Pod1 calixxxxx-ECS1 ethx-vpcroute rule(如有)-ECS2 ethx-ECS2 Pod2 calixxxxx-ECS2 Pod2 eth0;数据链路要经过四次内核协议栈,Pod1 协议栈、ECS1 协议栈、Pod2 协议栈、ECS2协议栈;全景剖析阿里云容器网络数据链路995)5)场景四:群内非场景四:群内非 SVCSVC 后端后端 podpod 所在节点访问所在节点访问 SVCSVC ClusterIPClusterIP环境环境cn-hongkong.10.0.3.49 节点上存在 nginx-7d6877d777-h4jtf 和 10.0.3.58cn-hongkong.10.0.1.82 节点上存在 centos-67756b6dc8-h5wnp 和 10.0.1.91。Service1 是 nginx,ClusterIP 是 192.168.2.115 ExternalIP 是 10.0.3.62。Service2 是 ngin1,ClusterIP 是 192.168.2.253 ExternalIP 是 10.0.3.63。内核路由内核路由内核路由部分已经在 2.2 和 2.3 小结中详细说明,这里不再进行过多阐述。源端源端 ECSECS 上的的上的的 IPVSIPVS 规则规则根据 2.2 小结中的源端 ECS 上的 IPVS 规则,我们可以得到:无论在哪种 SVCSVC 模式下模式下,对于对于 ClusterIPClusterIP 来说,会把所有来说,会把所有 SVCSVC 后端后端 PodPod 都会加到该节点的都会加到该节点的 IPVSIPVS 转发规则转发规则。小结小结可以访问到目的端全景剖析阿里云容器网络数据链路100Conntrack 表信息Service nginx 的 ExternalTrafficPolicy 是 LocalSVC nginx CLusterIP 是 192.168.2.115,ExternalIP 是 10.0.3.62。后端是 10.0.1.104和 10.0.3.58cn-hongkong.10.0.1.82源端 ECS 上 src 是源端 Pod 10.0.1.91,dstdst 是是 SVCSVC ClusterIPClusterIP 192.168.2.115192.168.2.115,dport是 SVC 中的 port。并且期望是 10.0.3.58 来回包给 10.0.1.91。cn-hongkong.10.0.3.49目的端 ECS 上 src 是源端 Pod 10.0.1.91,dstdst 是是 PodPod 的的 IPIP 10.0.3.5810.0.3.58,port 是 pod 的port。并且期望此 pod 来回包给 10.0.1.91。Service nginx1 的 ExternalTrafficPolicy 是 ClusterCluster。SVC nginx1 CLusterIP 是 192.168.2.253,ExternalIP 是 10.0.3.63,后端是 10.0.1.104和 10.0.3.58。cn-hongkong.10.0.1.82源端 ECS 上 src 是源端 Pod 10.0.1.91,dstdst 是是 SVCSVC ClusterIPClusterIP 192.168.2.115192.168.2.115,dport是 SVC 中的 port。并且期望是 10.0.3.58 来回包给 10.0.1.91。全景剖析阿里云容器网络数据链路101cn-hongkong.10.0.3.49目的端 ECS 上 src 是源端 Pod 10.0.1.91,dstdst 是是 PodPod 的的 IPIP 10.0.3.5810.0.3.58,dport 是 pod的 port。并且期望此 pod 来回包给 10.0.1.91。对于 ClusterIP 来说,源端 ECS 会把所有 SVC 后端 Pod 都会加到该节点的 IPVS 转发规则,目的端 ECS 是捕获不到任何 SVC ClusterIP 信息的,只能捕获到源端 Pod 的 IP,所以回包的时候会回到源端 Pod 的附属网卡上。数据链路转发示意图:数据链路转发示意图:会经过calicao网卡,每个非hostnetwork的pod会和calicao网卡形成veth pair,用于和其他 pod 或 node 进行通信;整个链路请求会经过 pod 所分配的 ENI,直接在 OS 的 ns 中命中 Ip rule 被转发;出 ECS 后,根据要访问的 pod 和该 pod ENI 所属 vswitch,命中 VPC 路由规则或者直接 VSW 上的二层转发;整个请求链路是去方向:ECS1 Pod1 eth0-ECS1 Pod1 calixxxxxx-ECS1 主网卡 eth0-vpc route全景剖析阿里云容器网络数据链路102rule(如有)-ECS2 附属网卡 ethx-ECS2 Pod2 calixxxxx-ECS2 Pod2 eth0;回方向:ECS2 Pod2 eth0-ECS2 Pod2 calixxxxx-ECS2 附属网卡 ethx-vpc routerule(如有)-ECS1 附属网卡 eth1-ECS1 Pod1 calixxxxxx-ECS1 Pod1 eth0;对于 ClusterIP 来说,源端 ECS 会把所有 SVC 后端 Pod 都会加到该节点的 IPVS 转发规则,目的端 ECS 是捕获不到任何 SVC ClusterIP 信息的,只能捕获到源端 Pod的 IP,所以回包的时候会回到源端 Pod 的附属网卡上;数据链路要经过四次内核协议栈,Pod1 协议栈、ECS1 协议栈、Pod2 协议栈、ECS2协议栈;6 6)场景五:场景五:ClusterCluster 模式,集群内非模式,集群内非 SVCSVC 后端后端 podpod 所在节点访问所在节点访问 SVCSVCExternalExternal IPIP环境环境cn-hongkong.10.0.3.49 节点上存在 nginx-7d6877d777-h4jtf 和 10.0.3.58cn-hongkong.10.0.1.82 节点上存在 centos-67756b6dc8-h5wnp 和 10.0.1.91Service2 是 ngin1,ClusterIP 是 192.168.2.253 ExternalIP 是 10.0.3.63。内核路由内核路由内核路由部分已经在 2.2 和 2.3 小结中详细说明,这里不再进行过多阐述。全景剖析阿里云容器网络数据链路103源端源端 ECSECS 上的上的 IPVSIPVS 规则规则根据 2.2 小结中的源端 ECS 上的 IPVS 规则,我们可以得到:ExternalTrafficPolicy 为Cluster 模式下,对于 ExternalIP 来说,会把所有 SVC 后端 Pod 都会加到该节点的 IPVS转发规则。小结小结可以访问到目的端Conntrack 表信息Service nginx1 的 ExternalTrafficPolicy 是 Cluster。SVC nginx1 CLusterIP 是 192.168.2.253,ExternalIP 是 10.0.3.63,后端是 10.0.1.104和 10.0.3.58。cn-hongkong.10.0.1.82源端 ECS 上 src 是源端 Pod 10.0.1.91,dst 是 SVC ExternalIP 10.0.3.63,dport 是SVC 中的 port。并且期望是 10.0.3.58 来回包给源端 ECS 的地址 10.0.1.82。cn-hongkong.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。全景剖析阿里云容器网络数据链路104在在 ExternalTrafficPolicyExternalTrafficPolicy 为为 ClusterCluster 下,对于下,对于 ExternalIPExternalIP 来说,源端来说,源端 ECSECS 会把所会把所有有SVCSVC 后端后端 PodPod 都会加到该节点的都会加到该节点的 IPVSIPVS 转发规则,目的端转发规则,目的端 ECSECS 是捕获不到任何是捕获不到任何 SVCSVCExternalIPExternalIP 信息的信息的,只能捕获到源端只能捕获到源端 PodPod 所在的所在的 ECSECS 的的 IPIP,所以回包的时候会回到源所以回包的时候会回到源端端 PodPod 所在的所在的 ECSECS 的主网卡上,这一点明显和的主网卡上,这一点明显和 2.42.4 小结中访问小结中访问 CusterIPCusterIP 有很明显区有很明显区别。别。数据链路转发示意图:数据链路转发示意图:会经过calicao网卡,每个非hostnetwork的pod会和calicao网卡形成veth pair,用于和其他 pod 或 node 进行通信;整个链路请求会经过 pod 所分配的 ENI,直接在 OS 的 ns 中命中 Ip rule 被转发;出 ECS 后,根据要访问的 pod 和该 pod ENI 所属 vswitch,命中 VPC 路由规则或者直接 VSW 上的二层转发;整个请求链路是 ECS1 Pod1 eth0-ECS1 Pod1 calixxxx-ECS1 主网卡 ENI eth0-vpc route rule(如有)-ECS2 附属网卡 ethx-ECS2 Pod2 calixxx-ECS2Pod2 eth0;在 ExternalTrafficPolicy 为 Cluster 下,对于 ExternalIP 来说,源端 ECS 会把所有SVC 后端 Pod 都会加到该节点的 IPVS 转发规则,目的端 ECS 是捕获不到任何 SVCExternalIP 信息的,只能捕获到源端 Pod 所在的 ECS 的 IP,所以回包的时候会回到源端 Pod 所在的 ECS 的主网卡;全景剖析阿里云容器网络数据链路105数据链路要经过四次内核协议栈,Pod1 协议栈、ECS1 协议栈、Pod2 协议栈、ECS2协议栈;7 7)场景六:场景六:LocalLocal 模式,集群内非模式,集群内非 SVCSVC 后端后端 podpod 所在节点访问所在节点访问 SVCSVCExternalExternal IPIP环境环境cn-hongkong.10.0.3.49 节点上存在 nginx-7d6877d777-h4jtf 和 10.0.3.58cn-hongkong.10.0.1.82 节点上存在 centos-67756b6dc8-h5wnp 和 10.0.1.91Service1 是 nginx,ClusterIP 是 192.168.2.115 ExternalIP 是 10.0.3.62。内核路由内核路由内核路由部分已经在 2.2 和 2.3 小结中详细说明,这里不再进行过多阐述。源端 ECS 上的的 IPVS 规则Service 的 ExternalTrafficPolicy 是 LocalSVC nginx CLusterIP 是 192.168.2.115,ExternalIP 是 10.0.3.62。后端是 10.0.1.104和 10.0.3.58。全景剖析阿里云容器网络数据链路106cn-hongkong.10.0.1.82对于 SVC 的 ExternalIP,可以看到 SVC 的后端,无任何转发规则。根据 2.2 小结中的源端 ECS 上的 IPVS 规则,我们可以得到:ExternalTrafficPolicExternalTrafficPolicy y为为 LocalLocal 模式下模式下,对于对于 ExternalIPExternalIP 来说来说,只会把本节点上的只会把本节点上的 SVCSVC 的后端的后端 PodPod 加到节点加到节点上的上的 IPVSIPVS 转发规则,如果该节点没有转发规则,如果该节点没有 SVCSVC 后端,则不会有任何可以转发的规则。后端,则不会有任何可以转发的规则。小结小结不可以访问到目的端Conntrack 表信息Service 的 ExternalTrafficPolicy 是 LocalSVC nginx1 CLusterIP 是 192.168.2.253,ExternalIP 是 10.0.3.63,后端是 10.0.1.104和 10.0.3.58。全景剖析阿里云容器网络数据链路107cn-hongkong.10.0.1.82 无任何 conntrack 记录表生成。数据链路转发示意图:数据链路转发示意图:会经过calicao网卡,每个非hostnetwork的pod会和calicao网卡形成veth pair,用于和其他 pod 或 node 进行通信;整个链路请求不会经过 pod 所分配的 ENI,直接在 OS 的 ns中命中 Ip rule 被转发;整 个 请 求 链 路 是 ECS1 Pod1 eth0-ECS1 Pod1 calixxxx-ECS host 空 间ipvs/iptables 规则,无后端转发 ep 终止链路;ExternalTrafficPolicy 为 Local 模式下,对于 ExternalIP 来说,只会把本节点上的SVC 的后端 Pod 加到节点上的 IPVS 转发规则,如果该节点没有 SVC 后端,则不会有任何可以转发的规则;全景剖析阿里云容器网络数据链路1088 8)场景七:集群外访问场景七:集群外访问 SVCSVC ExternalExternal IPIP环境环境cn-hongkong.10.0.3.49 节点上存在 nginx-7d6877d777-h4jtf 和 10.0.3.58。cn-hongkong.10.0.1.47 节点上存在 nginx-7d6877d777-kxwdb 和 10.0.1.29。Service1 是 nginx,ClusterIP 是 192.168.2.115 ExternalIP 是 10.0.3.62。SLBSLB 相关配置相关配置在 SLB 控制台,可以看到 lb-j6cw3daxxukxln8xccive 虚拟服务器组的后端服务器组是两个后端 nginxPod 的的 ENI eni-j6c4qxbpnkg5o7uog5kr 和eni-j6c6r7m3849fodxdf5l7。从集群外部角度看,SLB 的后端虚拟服务器组是 SVC 的后端 Pod 所属的两个 ENI 网卡,内网的 IP 地址就是 Pod 的地址。全景剖析阿里云容器网络数据链路109小结小结可以访问到目的端数据链路转发示意图:数据链路转发示意图:数据链路:client-SLB-Pod ENI Pod Port-ECS1 Pod1 eth0;数据链路要经过二次内核协议栈,Pod1 协议栈和 ECS 协议栈;9 9)小结小结本篇文章主要聚焦 ACK 在 Terway ENIIP 模式下,不同 SOP 场景下的数据链路转发路径。伴随着客户对性能的极致追求的需求,在 Terway ENIIP 模式下,一共可以分为 7个 SOP 场景,并对这七个场景的转发链路,技术实现原理,云产品配置等一一梳理并总结,这对我们遇到 Terway ENIIP 架构下的链路抖动、最优化配置,链路原理等提供了初步指引方向。在 Terway ENIIP 模式下,利用 veth pair 来联通宿主机和 pod 的网络空间,pod 的地址是来源于弹性网卡的辅助 IP 地址,并且节点上需要配置策略路由来保证辅助 IP 的流量经过它所属的弹性网卡,通过此种方式可以实现 ENI 多 Pod 共享,大大提升了 Pod的部署密度,但是 veth pair 必然会利用 ECS 的内核协议栈进行转发,此架构下性能必然不如 ENI 模式,ACK 产研为了提升性能,结合内核的 ebpf 和 ipvlan 技术,开发了全景剖析阿里云容器网络数据链路110Terway ebpf ipvlan 架构。下一系列我们将进入到 Terway ENIIP 模式的全景解析4.Terway IPVLAN EBPF 模式架构设计弹性网卡(ENI)支持配置多个辅助 IP 的功能,单个弹性网卡(ENI)根据实例规格可以分配6-20 个辅助 IP,ENI 多 IP 模式就是利用了这个辅助 IP 分配给容器,从而大幅提高了Pod 部署的规模和密度。在网络联通的方式上,Terway 支持选择 Veth pair 策略路由和 ipvlan l 两种方案,Linux 在 4.2 以上的内核中支持了 ipvlan 的虚拟网络,可以实现单个网卡虚拟出来多个子网卡用不同的 IP 地址,而 Terway 便利用了这种虚拟网络类型,将弹性网卡的辅助 IP 绑定到 IPVlan 的子网卡上来打通网络,使用这种模式使 ENI多 IP 的网络结构足够简单,性能也相对 veth 策略路由较好。Pod 所使用的的 CIDR 网段和节点的 CIDR 是同一个网段全景剖析阿里云容器网络数据链路111Pod 内部可以看到是有一张网卡的,一个是 eth0,其中 eth0 的 IP 就是 Pod 的 IP,此网卡的 MAC 地址和控制台上的 ENI 的 MAC 地址不一致,同时 ECS 上有多张 ethx 的网卡,说明 ENI 附属网卡并不是直接挂在到了 Pod 的网络命名空间。Pod 内有只有指向 eth0 的默认路由,说明说明 PodPod 访问任何地址段都是从访问任何地址段都是从 eth0eth0 为统一的为统一的出入口。出入口。那么 Pod 是如何 ECS OS 进行通信呢?在 OS 层面,我们一看到 ipvl_x 的网卡,可以看到是附属于 eth1 的,说明在 OS 层面会给每个附属网卡创建一个 ipvl_x 的网卡,用于建立 OS 和 Pod 内的连接隧道。全景剖析阿里云容器网络数据链路112ECS OS 内对于数据流量是怎么判断去哪个容器呢?通过 OS Linux Routing 我们可以看到,所有目的是 Pod IP 的流量都会被转发到 Pod 对应的 ipvl_x 虚拟往卡上,到这里为止,ECS OS 和 Pod 的网络命名空间已经建立好完整的出入链路配置了。到目前为止介绍了 IPVLAN 在网络架构上实现了。对于 eni 多 IP 的实现,这个类似于Terway ENIIP 模式架构原理,TerwayPod 是通全景剖析阿里云容器网络数据链路113过 daemonset 的方式部署在每个节点上的,通过下面命令可以看到每个节点上的TerwayPod。通过 terway-cli show factory 命令可以看到节点上的附属 ENI 数量、MAC 地址以及每个 ENI 上的 IP。那么对于 SVC 来说,是如何实现的呢?看过前面 四个系列的朋友,应该知道对于 Pod 访问 SVC,容器是利用各种办法将请求转发到 Pod 所在的 ECS 层面,由 ECS 内的 netfilter 模块来实现 SVC IP 的解析,这固然是个好办法,但是由于数据链路需要从 Pod 的网络命名空间切换到 ECS 的 OS 的网络命名空间,中间经过了 2 次内核协议栈,必然会产生性能损失,如果对高并发和高性能有机制追求,可能并不完全满足客户的需求。那么对于高并发和延迟敏感业务,该如何实现呢?有没有办法让 Pod 访问 SVC 直接在 Pod 的网络命名空间中就实现了后端解析,这样结合 IPVLAN 这样至实现了一次内核协议栈。在 4.19 版本内核中,ebpf 的出现,很好的实现了这个需求,这里不对 ebpf 做过多说明,感兴趣的可以访问官方链接,小伙伴们只需要知道 ebpf 是一种可以安全在内核层面运行的安全沙盒,当触发内核的指定行为,ebpf 设定程序会被执行。利用这个特性,我们可以实现在 tc 层面对访问 SVC IP 的数据包进行修改。全景剖析阿里云容器网络数据链路114例如,同上图,可以看到集群内有一个名为 nginx 的 svc,clusterIP 是 192.168.27.242,后端 pod IP 是 10.0.3.38.通过 cilium bpf lb list 可以看到在 ebpf 程序中对于clusterIP 192.168.27.242 的访问会被转到 10.0.3.38 这个 IP 上,而 Pod 内只有一个默认路由。此处说明,此处说明,IPVLAN EBPFIPVLAN EBPF 模式下,如果模式下,如果 PodPod 访问访问 SVCSVC IPIP,SVCIPSVCIP 在在 PoPod d的网络命名空间内就会被的网络命名空间内就会被 ebpfebpf 转为某个转为某个 SVCSVC 后端后端 podpod 的的 IPIP,之后数据链路被发,之后数据链路被发出出PodPod。也就是说。也就是说 SVCIPSVCIP 只会在只会在 PodPod 内被捕获,在源端内被捕获,在源端 ECSECS,目的端,目的端 PodPod 和目的端和目的端的的PodPod 所在所在 ECSECS 都无法被捕获到。都无法被捕获到。假如一个 SVC 后后段有 100 Pod,因为 ebpf 存在,Pod 外无法捕获到 SVCIP,所在一旦出现网络抖动,对于抓包该抓那个后端 IP 或该在哪个后端 Pod 出抓包呢?想一想,是不是一个非常头疼又无解非常头疼又无解的场景?目前容器服务和 AES 共创了 ACK Net-Exporter容器网络可观测性工具,可以针对此场景进行持续化的观测和问题判断。故故 TerwayTerway IPVLAN EBPFIPVLAN EBPF 模式总体可以归纳为:模式总体可以归纳为:4.2 以上内核中支持了 ipvlan 的虚拟网络,可以实现单个网卡虚拟出来多个子网卡用不同的 IP 地址,而 Terway 便利用了这种虚拟网络类型,将弹性网卡的辅助 IP绑定到 IPVlan 的子网卡上来打通网络,使用这种模式使 ENI 多 IP 的网络结构足够简单,性能也相对 veth 策略路由较好。节点访问pod 需要经过host 的协议栈,pod 和pod 间访问不经过host的协议栈。IPVLAN EBPF 模式下,如果 Pod 访问 SVC IP,SVCIP 在 Pod 的网络命名空间内就会被ebpf转为某个SVC 后端pod的IP,之后数据链路被发出Pod。也就是说SVCIP只会在 Pod 内被捕获,在源端 ECS,目的端 Pod 和目的端的 Pod 所在 ECS 都无法被捕获到。1)TerwayTerway IPVLAN EBPFIPVLAN EBPF 模式容器网络数据链路剖析模式容器网络数据链路剖析针对容器网络特点,我们可以将 Terway IPVLAN EBPF 模式下的网络链路大体分为以Pod IP 对外提供服务和以 SVC 对外提供服务两个大的 SOP 场景,进一步细分,可以归纳为 12 个不同的小的 SOP 场景。全景剖析阿里云容器网络数据链路115对这 15 个场景的数据链路梳理合并,这些场景可以归纳为下面 11 类典型的场景:TerwayENI 架构下,不同的数据链路访问情况下,可以总结归纳为为 11 类:访问 Pod IP,同节点访问 Pod;访问 Pod IP,同节点 pod 间互访(pod 属于同 ENI);访问 Pod IP,同节点 pod 间互访(pod 属于不同 ENI);不同节点间 Pod 之间互访;集群内 Pod 访问的 SVC ClusterIP(含 Terway 版本1.2.0,访问 ExternalIP),SVC后端 Pod 和客户端 Pod 配属同一个 ENI;集群内 Pod 访问的 SVC ClusterIP(含 Terway 版本1.2.0,访问 ExternalIP),SVC后端 Pod 和客户端 Pod 配属不同 ENI(同 ECS);集群内 Pod 访问的 SVC ClusterIP(含 Terway 版本1.2.0,访问 ExternalIP),SVC后端 Pod 和客户端 Pod 不属于不同 ECS;集群内 Pod 访问的 SVC ExternalIP(Terway 版本1.2.0),SVC 后端 Pod 和客户端 Pod 配属同一个 ENI;集群内 Pod 访问的 SVC ExternalIP(Terway 版本1.2.0),SVC 后端 Pod 和客户端 Pod 配属不同 ENI(同 ECS);集群内 Pod 访问的 SVC ExternalIP(Terway 版本1.2.0),SVC 后端 Pod 和客户端 Pod 部署于不同 ECS;全景剖析阿里云容器网络数据链路116集群外访问 SVC ExternalIP;2)2)场景一:访问场景一:访问 PodPod IPIP,同节点访问,同节点访问 podpod环境环境cn-hongkong.10.0.3.15 节点上存在 nginx-7d6877d777-j7dqz 和 10.0.3.38。内核路由内核路由nginx-7d6877d777-j7dqz IP 地址 10.0.3.38。该容器在宿主机表现的 PID 是 329470,该容器网络命名空间有指向容器 eth0 的默认路由。该容器 eth0 在 ECS OS 内是通过 ipvlan 隧道的方式和 ECS 的附属 ENI eth1 建立的隧道,同时附属 ENI eth1 还有个虚拟的 ipvl_8eth1 网卡。全景剖析阿里云容器网络数据链路117通过 OS Linux Routing 我们可以看到,所有目的是 Pod IP 的流量都会被转发到 Pod对应的 ipvl_x 虚拟往卡上,这样就建立完毕 ECS 和 Pod 之间的连接隧道了。全景剖析阿里云容器网络数据链路118小结小结可以访问到目的端nginx-7d6877d777-zp5jg netns eth0 可以抓到数据包。ECS 的 ipvl_8 可以抓到数据包。全景剖析阿里云容器网络数据链路119数据链路转发示意图:数据链路转发示意图:不会经过分配给 pod 的附属网卡;整个链路是通过查找路由表进入 ipvl_xxx 不需要经过 ENI;整个请求链路是 node-ipvl_xxx-ECS1 Pod1;3)3)场景二:访问场景二:访问 PodPod IPIP,同节点,同节点 podpod 间互访(间互访(podpod 属于同属于同 ENIENI)环境环境cn-hongkong.10.0.3.15 节点上存在 nginx-7d6877d777-j7dqz 和全景剖析阿里云容器网络数据链路120centos-6c48766848-znkl8 两个 pod,IP 分别为 10.0.3.38 和 10.0.3.5。通过此节点的 terwayPod,我们可以利用 terway-cli show factory 的命令看到 这两个 IP(10.0.3.5 和 10.0.3.38)都属于同一个 MAC 地址 00:16:3e:04:08:3a,说明这两个 IP 属于同一个 ENI,进而可以推断出 nginx-7d6877d777-j7dqz 和centos-6c48766848-znkl8 属于同一个 ENI 网卡。内核路由内核路由centos-6c48766848-znkl8 IP 地址 10.0.3.5,该容器在宿主机表现的 PID 是 2747933,该容器网络命名空间有指向容器 eth0 的默认路由。有且只有一条,说明 pod 访问所有地址都需要通过该默认路由。nginx-7d6877d777-j7dqz IP 地址 10.0.3.38。该容器在宿主机表现的 PID 是 329470,该容器网络命名空间有指向容器 eth0 的默认路由。全景剖析阿里云容器网络数据链路121该容器 eth0 在 ECS OS 内是通过 ipvlan 隧道的方式和 ECS 的附属 ENI eth1 建立的隧道,同时附属 ENI eth1 还有个虚拟的 ipvl_8eth1 网卡。全景剖析阿里云容器网络数据链路122小结小结可以访问到目的端centos-6c48766848-znkl8 netns eth0 可以抓到数据包。nginx-7d6877d777-zp5jg netns eth0 可以抓到数据包。全景剖析阿里云容器网络数据链路123ipvl_8 网卡并没有捕获到相关的数据流量包。数据链路转发示意图:数据链路转发示意图:不会经过分配给 pod 的附属网卡。不会经过任何宿主机 ECS 的网络空间的中间节点;整个链路不会和请求不会经过pod所分配的ENI,直接在OS的ns中命中Ip rule 被转发到对端 pod;整个请求链路是 ECS1 Pod1-ECS1 Pod2(发生在 ECS 内部),和 IPVS 相比,避免了 calico 网卡设备的两次转发,性能是更好的;全景剖析阿里云容器网络数据链路1244)4)场景三:访问场景三:访问 PodPod IPIP,同节点,同节点 podpod 间互访(间互访(podpod 属于不同属于不同 ENIENI)环境环境cn-hongkong.10.0.3.15 节点上存在 nginx-7d6877d777-j7dqz 和busybox-d55494495-8t677 两个 pod,IP 分别为 10.0.3.38 和 10.0.3.22。通过此节点的 terwayPod,我们可以利用 terway-cli show factory 的命令看到 这两个 IP(10.0.3.22 和 10.0.3.38)都属于同一个 MAC 地址 00:16:3e:01:b7:bd 和 00:16:3e:04:08:3a,说明这两个 IP 属于不同 ENI,进而可以推断出 nginx-7d6877d777-j7dqz 和 busybox-d55494495-8t677 属于不同 ENI 网卡。内核路由内核路由busybox-d55494495-8t677 IP 地址 10.0.3.22,该容器在宿主机表现的 PID 是2956974,该容器网络命名空间有指向容器 eth0 的默认路由。有且只有一条,说明 pod访问所有地址都需要通过该默认路由。全景剖析阿里云容器网络数据链路125nginx-7d6877d777-j7dqz IP 地址 10.0.3.38。该容器在宿主机表现的 PID 是 329470,该容器网络命名空间有指向容器 eth0 的默认路由。该容器 eth0 在 ECS OS 内是通过 ipvlan 隧道的方式和 ECS 的附属 ENI eth1 建立的隧道,通过 mac 地址一样可以看到,nginx-7d6877d777-j7dqz和busybox-d55494495-8t677 分别被分配eth1和eth2。全景剖析阿里云容器网络数据链路126小结小结可以访问到目的端busybox-d55494495-8t677 netns eth0 可以抓到数据包。nginx-7d6877d777-zp5jg netns eth0 可以抓到数据包。全景剖析阿里云容器网络数据链路127数据链路转发示意图:数据链路转发示意图:不会经过分配给 pod 的附属网卡。不会经过任何宿主机 ECS 的网络空间的中间节点;整个链路是需要从客户端 pod 所属的 ENI 网卡出 ECS 再从目的 POD 所属的 ENI网卡进入 ECS;整个请求链路是 ECS1 Pod1-ECS1 eth1-VPC-ECS1 eth2-ECS1 Pod2;5)5)场景四:不同节点间场景四:不同节点间 PodPod 之间互访之间互访环境环境cn-hongkong.10.0.3.15 节点上存在 nginx-7d6877d777-j7dqz,IP 分为 10.0.3.38。全景剖析阿里云容器网络数据链路128cn-hongkong.10.0.3.93 节点上存在 centos-6c48766848-dz8hz,IP 分为10.0.3.127。通过此节点的 terwayPod,我们可以利用 terway-cli show factory 的命令看到nginx-7d6877d777-j7dqz IP 10.0.3.5 属于cn-hongkong.10.0.3.15 上的MAC地址为 00:16:3e:04:08:3a 的 ENI 网卡。通过此节点的 terwayPod,我们可以利用 terway-cli show factory 的命令看到centos-6c48766848-dz8hz IP10.0.3.127 属于 cn-hongkong.10.0.3.93 上的MAC 地址为 00:16:3e:02:20:f5 的 ENI 网卡。内核路由内核路由centos-6c48766848-dz8hz IP 地址 10.0.3.127,该容器在宿主机表现的 PID 是1720370,该容器网络命名空间有指向容器 eth0 的默认路由。有且只有一条,说明 pod访问所有地址都需要通过该默认路由。全景剖析阿里云容器网络数据链路129nginx-7d6877d777-j7dqz IP 地址 10.0.3.38。该容器在宿主机表现的 PID 是 329470,该容器网络命名空间有指向容器 eth0 的默认路由。ECS OS 内是通过 ipvlan 隧道的方式和 ECS 的附属 ENI eth1 建立的隧道,通过 mac地址一样可以看到两个 pod 分配的 ENI 地址 centos-6c48766848-dz8hz。全景剖析阿里云容器网络数据链路130nginx-7d6877d777-j7dqz全景剖析阿里云容器网络数据链路131小结小结可以访问到目的端此处不再对抓包进行展示,从客户端角度,数据流可以在 centos-6c48766848-dz8hz的网络命名空间 eth0,以及 此 pod 所部署的 ECS 对应的 ENI eth1 上可以被捕获到;从服务端角度,数据流可以在 nginx-7d6877d777-j7dqz 的网络命名空间 eth0,以及此 pod 所部署的 ECS 对应的 ENI eth1 上可以被捕获到。数据链路转发示意图:数据链路转发示意图:不会经过任何宿主机 ECS 的网络空间的中间节点;整个链路是需要从客户端 pod 所属的 ENI 网卡出 ECS 再从目的 POD 所属的 ENI网卡进入 ECS;整个请求链路是 ECS1 Pod1-ECS1 ethx-VPC-ECS2 ethy-ECS2 Pod2;全景剖析阿里云容器网络数据链路1326)6)场景五:集群内场景五:集群内 PodPod 访问的访问的 SVCSVC ClusterIPClusterIP(含(含 TerwayTerway 版本版本 1.2.01.2.0,访问访问 ExternalIPExternalIP),SVCSVC 后端后端 PodPod 和客户端和客户端 PodPod 配属同一个配属同一个 ENIENI环境环境cn-hongkong.10.0.3.15 节点上存在 nginx-7d6877d777-j7dqz 和centos-6c48766848-znkl8 两个 pod,IP 分别为 10.0.3.38 和 10.0.3.5。通过此节点的 terwayPod,我们可以利用 terway-cli show factory 的命令看到 这两个 IP(10.0.3.5 和 10.0.3.38)都属于同一个 MAC 地址 00:16:3e:04:08:3a,说明这两个 IP 属于同一个 ENI,进而可以推断出 nginx-7d6877d777-j7dqz 和centos-6c48766848-znkl8 属于同一个 ENI 网卡。通过 describe svc 可以看到 nginxPod 被加入到了 svc nginx 的后端。SVC 的CLusterIP 是 192.168.27.242。如果是集群内访问 External IP,对于 Terway 版本1.20 来说,集群内访问 SVC 的 ClusterIP 或 External IP,整个链路架构是一致的,此小节不在针对 External IP 单独说明,统一用 ClusterIP 作为示例(Terway 版本 1.20情况下,访问 External IP,会在后续小节说明)。全景剖析阿里云容器网络数据链路133内核路由内核路由centos-6c48766848-znkl8 IP 地址 10.0.3.5,该容器在宿主机表现的 PID 是 2747933,该容器网络命名空间有指向容器 eth0 的默认路由。有且只有一条,说明 pod 访问所有地址都需要通过该默认路由。nginx-7d6877d777-j7dqz IP 地址 10.0.3.38。该容器在宿主机表现的 PID 是 329470,该容器网络命名空间有指向容器 eth0 的默认路由。全景剖析阿里云容器网络数据链路134在 ACK 中,是利用 cilium 去调用 ebpf 的能力,可以通过下面的命令可以看到nginx-7d6877d777-j7dqz 和 centos-6c48766848-znkl8 identity ID 分别是 634 和1592。通过 centos-6c48766848-znkl8Pod,可以找到此 pod 所在的 ECS 的 TerwayPod 为terway-eniip-6cfv9,在 TerwayPod 中运行下面的 cilium bpf lb list|grep-A5192.168.27.242 命令可以看到 ebpf 中对于 CLusterIP 192.168.27.242:80 记录的后端是 10.0.3.38:80。这上述的一切都是通过 EBPF 记录到了源端 Podcentos-6c48766848-znkl8Pod 的 tc 中。全景剖析阿里云容器网络数据链路135通过以上,可以理论推断出,如果集群内的 pod 访问 SVC 的 CLusterIP or External IP地址(Terway 1.20),数据流会在 pod 的网络命名空间内就被转化为相应的 SVC 的后端 Pod IP 后,再被从 Pod 网络命名空间的 eth0 发出 pod,进入到 pod 所在的 ECS,然后通过 IPVLAN 隧道,转发到同 ECS 或通过相应的 ENI 出 ECS。也就是说,我们如果抓包,不管在 pod 内抓包还是在 ECS 抓包,都无法捕获到 SVC 的 IP,只能捕获到 PodIP。EBPF 技术让集群内访问避开了 ECS OS 内部的内核协议栈和减少了部分 pod 内核协议栈,大大提高了网络性能和 Pod 密度,带来了不弱于单独 ENI 的网络性能,但是此方式会对我们观测带来巨大的改变和影响。试想一下,如果您的集群内存在互相调用情况,这个调用的 IP 是 SVC 的 IP,加入此SVC 后端所引用的 Pod 有几十上百个。源端 pod 调用时候出现问题,一般情况下报错是connect to failed 等类似信息,传统的抓包手段是在源端 Pod 内,目的Pod,ECS 上等进行抓包,筛选 SVC IP 来串起来不同包之间的同一个数据流,可是 ebpf情况下由于上述技术实现,造成无法捕获 SVC IP,是不是对偶发抖动情况下的观测带来了巨大挑战呢?小结小结可以访问到目的端从客户端 Pod centos-6c48766848-znkl8 访问 SVC,我们可以看到访问成功。全景剖析阿里云容器网络数据链路136客户端的 centos-6c48766848-znkl8 网络命名空间内 eth0 抓包,抓包地址是目的SVC 的 IP 和 SVC 的后端 POD IP。可以看到只能抓到 SVC 后端 Pod IP,无法捕获到 SVCIP。全景剖析阿里云容器网络数据链路137目的端 SVC 的后端 POD nginx-7d6877d777-zp5jg 网络命名空间 eth0 抓包,抓包地址是目的 SVC 的 IP 和 Pod IP。可以看到只能抓到客户端 Pod IP。cilium 提供了一个 monitor 的功能,我们使用 cilium monitor-related-to,可以看到,源端 POD IP 访问 SVCIP 192.168.27.242,之后被解析到SVC 的后端 POD IP 10.0.3.38。说明 SVC IP 直接在 tc 层做了转发,这也解释了为什么抓包无法抓到 SVC IP,因为抓包是在 netdev 上抓的,此时已经过了协议栈和 tc。后续小节如果涉及 SVC IP 的访问,如有类似,不再做详细的抓包展示。全景剖析阿里云容器网络数据链路138数据链路转发示意图:数据链路转发示意图:不会经过任何宿主机 ECS 的网络空间的中间节点;整个链路不会和请求不会经过pod所分配的ENI,直接在OS的ns中命中Ip rule 被转发到对端 pod;整个请求链路是 ECS1 Pod1-ECS1 Pod2(发生在 ECS 内部),和 IPVS 相比,避免了 calico 网卡设备的两次转发,性能是更好的;ECS1 Pod1 的 eth0 网卡无法捕捉到 SVC IP,SVC IP 在 Pod 网络命名空间内已经通过 ebpf 转换成了 SVC 后端 Pod 的 IP;8)场景六:集群内场景六:集群内 PodPod 访问的访问的 SVCSVC ClusterIPClusterIP(含(含 TerwayTerway 版本版本 1.2.01.2.0,访访问问 ExternalIPExternalIP),SVSVC C 后后端端 PoPod d 和客户和客户端端 PoPod d 配属不配属不同同 ENIENI(同同 ECSECS)环境环境全景剖析阿里云容器网络数据链路139cn-hongkong.10.0.3.15 节点上存在 nginx-7d6877d777-j7dqz 和busybox-d55494495-8t677 两个 pod,IP 分别为 10.0.3.38 和 10.0.3.22。通过此节点的 terwayPod,我们可以利用 terway-cli show factory 的命令看到 这两个 IP(10.0.3.22 和 10.0.3.38)都属于同一个 MAC 地址 00:16:3e:01:b7:bd 和00:16:3e:04:08:3a,说明这两个 IP 属于不同 ENI,进而可以推断出nginx-7d6877d777-j7dqz 和 busybox-d55494495-8t677 属于不同 ENI 网卡。通过describe svc 可以看到 nginxPod 被加入到了 svc nginx 的后端。SVC 的 CLusterIP 是 192.168.27.242。如果是集群内访问 External IP,对于 Terway版本 1.20 来说,集群内访问 SVC 的 ClusterIP 或 External IP,整个链路架构是一致的,此小节不在针对 External IP 单独说明,统一用 ClusterIP 作为示例(Terway 版本 1.20 情况下,访问 External IP,会在后续小节说明)。全景剖析阿里云容器网络数据链路140内核路由内核路由busybox-d55494495-8t677 IP 地址 10.0.3.22,该容器在宿主机表现的 PID 是2956974,该容器网络命名空间有指向容器 eth0 的默认路由。有且只有一条,说明 pod访问所有地址都需要通过该默认路由。全景剖析阿里云容器网络数据链路141nginx-7d6877d777-j7dqz IP 地址 10.0.3.38。该容器在宿主机表现的 PID 是 329470,该容器网络命名空间有指向容器 eth0 的默认路由。在 ACK 中,是利用 cilium 去调用 ebpf 的能力,可以通过下面的命令可以看到nginx-7d6877d777-j7dqz 和busybox-d55494495-8t677 identity ID 分别是634和3681。全景剖析阿里云容器网络数据链路142通过 busybox-d55494495-8t677Pod,可以找到此 pod 所在的 ECS 的 TerwayPod为 terway-eniip-6cfv9,在 TerwayPod 中运行下面的 cilium bpf lb list|grep-A5192.168.27.242 命令可以看到 ebpf 中对于 CLusterIP 192.168.27.242:80 记录的后端是 10.0.3.38:80。这上述的一切都是通过 EBPF 记录到了源端 Podcentos-6c48766848-znkl8Pod 的 tc 中。这里不再过多对于 svc ClusterIP 的 ebpf 转发进行描述,详细信息可以参考 2.5 小节。中的描述,从上述描述情况,可以得知被访问的 SVC 的 IP 在 客户端 busybox 的网络命名空间中已经被 ebpf 转为 svc 的后端 pod 的 IP,在任何 dev 上都无法捕获到客户端访问的 SVC 的 IP。故此场景和 2.3 小节的网络架构非常类似,只是在客户端内会由cilium ebpf 转发的动作。全景剖析阿里云容器网络数据链路143小结小结数据链路转发示意图:数据链路转发示意图:不会经过任何宿主机 ECS 的网络空间的中间节点;整个链路是需要从客户端 pod 所属的 ENI 网卡出 ECS 再从目的 POD 所属的 ENI网卡进入 ECS;整个请求链路是 ECS1 Pod1-ECS1 eth1-VPC-ECS1 eth2-ECS1 Pod2;在客户端/服务端 Pod 内或者 ECS 的 ENI 网卡都无法捕捉到 SVC IP,SVC IP 在 客户端 Pod 网络命名空间内已经通过 ebpf 转换成了 SVC 后端 Pod 的 IP;8)8)场景七:集群内场景七:集群内 PodPod 访问的访问的 SVCSVC ClusterIPClusterIP,SVCSVC 后端后端 PodPod 和客户和客户端端PodPod 不属于不同不属于不同 ECSECS环境环境全景剖析阿里云容器网络数据链路144cn-hongkong.10.0.3.15 节点上存在 nginx-7d6877d777-j7dqz,IP 分为 10.0.3.38。cn-hongkong.10.0.3.93 节点上存在 centos-6c48766848-dz8hz,IP 分为10.0.3.127。通过此节点的 terwayPod,我们可以利用 terway-cli show factory 的命令看到nginx-7d6877d777-j7dqz IP 10.0.3.5 属于cn-hongkong.10.0.3.15 上的MAC地址为 00:16:3e:04:08:3a 的 ENI 网卡。通过此节点的 terwayPod,我们可以利用 terway-cli show factory 的命令看到centos-6c48766848-dz8hz IP10.0.3.127 属于 cn-hongkong.10.0.3.93 上的MAC 地址为 00:16:3e:02:20:f5 的 ENI 网卡。通过 describe svc 可以看到 nginxPod 被加入到了 svc nginx 的后端。SVC 的CLusterIP 是 192.168.27.242。如果是集群内访问 External IP,对于 Terway 版本1.20 来说,集群内访问 SVC 的 ClusterIP 或 External IP,整个链路架构是一致的,此小节不在针对 External IP 单独说明,统一用 ClusterIP 作为示例(Terway 版本 1.20情况下,访问 External IP,会在后续小节说明)。全景剖析阿里云容器网络数据链路145内核路由内核路由Pod 访问 SVC 的 Cluster IP,而 SVC 的后端 Pod 和 Pod 部署在不同 ECS 上,此架构类似 2.4 小节中的不同 ECS 节点上的 Pod 间互访情况,只不此场景是 Pod 访问 SVC 的ClusterIP,要注意此处是访问 ClusterIP,如果是访问 External IP,那么场景会进一步复杂了,本门的后面几个小节会详细说明。对于 ClusterIP 的 ebpf 转发进行描述,详细信息可以参考 2.5 小节。中的描述,和前面几个小节一样,在任何 dev 上都无法捕获到客户端访问的 SVC 的 IP。小结小结数据链路转发数据链路转发示意图:示意图:全景剖析阿里云容器网络数据链路146不会经过任何宿主机 ECS 的网络空间的中间节点;整个链路是需要从客户端 pod 所属的 ENI 网卡出 ECS 再从目的 POD 所属的 ENI网卡进入 ECS;整个请求链路是 ECS1 Pod1-ECS1 eth1-VPC-ECS2 eth1-ECS2 Pod2;在客户端/服务端 Pod 内或者 ECS 的 ENI 网卡都无法捕捉到 SVC IP,SVC IP 在 客户端 Pod 网络命名空间内已经通过 ebpf 转换成了 SVC 后端 Pod 的 IP;9 9)场景八场景八:集群内集群内 PodPod 访问的访问的 SVCSVC ExternalIPExternalIP(TerwayTerway 版本版本 1.2.01.2.0),SVCSVC 后端后端 PodPod 和客户端和客户端 PodPod 配属同一个配属同一个 ENIENI环境环境此处环境和2.5 小节 情况类似,不做过多描述,只是此小节是在terway 版本小于1.2.0情况下,访问 External IP 47.243.139.183。全景剖析阿里云容器网络数据链路147内核路由内核路由请参考 2.5 小节。由于客户端 Pod 和被访问的 SVC 的后端 Pod 同属于同一个 ENI,那么在 terway 版本小于 1.2.0 的情况下,访问 External IP,实际上数据链路会通过 ENI 出 ECS 到 ExternalIP 的 SLB,在被转发到同一个 ENI 上。四层 SLB 目前是不支持同一个 EI 同时作为客户端和服务端,所以会形成回环,详细信息可以参考下面连接:https:/ ECS1 Pod1-ECS1 eth1-VPC-SLB-中断;Terway 版本小于 1.2.0 时,集群内访问 external IP,会出 ECS ENI 到 SLB,再由SLB 转发到 ECS ENI 上,如果源 pod 所属的 ENI 和被转发的 ENI 为同一个,将访问不成功,原因是四层 SLB 会形成回环;解决方案(任何一个):通过 SVC annotation 将 SLB 配置为 7 层监听;将 Terway 版本升级之 1.2.0 以及上,并开启集群内负载均衡。Kube-Proxy 会短路集群内访问 ExternalIP、LoadBalancer 的流量,即集群内访问这些外部地址,实际流量不会到外部,而会被转为对应后端的 Endpoint 直接访问。在 TerwayIPvlan 模式下,Pod 访问这些地址流量由 Cilium 而不是 kube-proxy 进行处理,在 Terway v1.2.0 之前版本并不支持这种链路的短路。在 Terway v1.2.0 版本发布后,新建集群将默认开启该功能,已创建的集群不会开启。(此处就是 2.5 小节场景);https:/ PodPod 访问的访问的 SVCSVC ExternalIPExternalIP(TerwayTerway 版本版本 1.2.01.2.0),SVCSVC 后端后端 PodPod 和客户端和客户端 PodPod 配属不同配属不同 ENIENI(同(同 ECSECS)环境环境此处环境和2.6 小节 情况类似,不做过多描述,只是此小节是在terway 版本小于1.2.0情况下,访问 External IP 47.243.139.183。全景剖析阿里云容器网络数据链路149内核路由内核路由请参考 2.6 和 2.8 小节。由于客户端 Pod 和被访问的 SVC 的后端 Pod 虽然同属于同一个 ECS,但是不属于同一个 ENI,那么在 terway 版本小于 1.2.0 的情况下,访问 External IP,实际上数据链路会通过客户端 pod ENI 出 ECS 到 External IP 的 SLB,在被转发到另一个一个 ENI 上。虽然从外部感知上看 两个客户端 Pod 和 SVC 的后端 Pod 都是在同一个 ECS,但是由于属于不同 ENI,所以不会形成回环,可以访问成功,此处的结果和 2.8 小节完全不同,需要注意。小结小结数据链路转发示意图:整个请求链路是 ECS1 Pod1-ECS1 eth1-VPC-SLB-ECS1 eth2-ECS1Pod2;Terway 版本小于 1.2.0 时,集群内访问 external IP,会出 ECS ENI 到 SLB,再由SLB 转发到 ECS ENI 上,如果源 pod 所属的 ENI 和被转发的 ENI 为同一个,将访问不成功,原因是四层 SLB 会形成回环;如果源 pod 所属的 ENI 和被转发的 ENI 为是同一个节点上的不同 ENI,可以访问成功;全景剖析阿里云容器网络数据链路1501111)场景十场景十:集群内集群内 PodPod 访问的访问的 SVCSVC ExternalIPExternalIP(TerwayTerway 版本版本 1.2.01.2.0),SVCSVC 后端后端 PodPod 和客户端和客户端 PodPod 部署于不同部署于不同 ECSECS环境环境此处环境和2.6 小节 情况类似,不做过多描述,只是此小节是在terway 版本小于1.2.0情况下,访问 External IP 47.243.139.183。内核路由内核路由请参考 2.7 和 2.9 小节。此处和 2.7 的架构场景相似,都是客户端 Pod 和 SVC 的后端 Pod 不属于不同的 ECS 节点,客户端去访问 SVC 的 External IP。只有 Terway 的版本不同,2.7 小节 Terway 版本是1.2.0,此小节是1.2.0,仅仅是 Terway 版本和 eniconfig 的不同,两者访问链路一个会经过 SLB,一个则不会经过 SLB,这一点需要关注。置于不同的原因是因为1.2.0 Terway 版本之后开启集群内负载均衡,对于访问 ExternalIP 会被负载到Service 网段,具体信息请见 2.8 小节。全景剖析阿里云容器网络数据链路151小结小结数据链路转发示意图:数据链路转发示意图:整个请求链路是 ECS1 Pod1-ECS1 eth1-VPC-SLB-ECS2 eth1-ECS2Pod2;Terway 版本小于 1.2.0 时,集群内访问 external IP,会出 ECS ENI 到 SLB,再由SLB 转发到 ECS ENI 上,如果源 pod 所属的 ENI 和被转发的 ENI 为同一个,将访问不成功,原因是四层 SLB 会形成回环;1212)场景十一:集群外访问场景十一:集群外访问 SVCSVC ExternalIPExternalIP环境环境cn-hongkong.10.0.3.15 节点上存在 nginx-7d6877d777-j7dqz,IP 分为 10.0.3.34通过 describe svc 可以看到 nginxPod 被加入到了 svc nginx 的后端。SVC 的CLusterIP 是 192.168.27.242。全景剖析阿里云容器网络数据链路152内核路由内核路由在 SLB 控制台,可以看到 lb-j6cj07oi6uc705nsc1q4m 虚拟服务器组的后端服务器组是两个后端 nginxPod 的的 ENI eni-j6cgs979ky3evp81j3n8。从集群外部角度看,SLB 的后端虚拟服务器组是 SVC 的后端 Pod 所属的 ENI 网卡,内网的 IP 地址就是 Pod 的地址。全景剖析阿里云容器网络数据链路153小结小结数据链路转发示意图:数据链路转发示意图:ExternalTrafficPolicy 为 Local 或 Cluster 模式下,SLB 只会将 Pod 分配的 ENI挂在到 SLB 的虚拟服务器组;数据链路:client-SLB-Pod ENI Pod Port-ECS1 Pod1 eth0;13)13)小结小结本篇文章主要聚焦 ACK 在 Terway IPVLAN EBPF 模式下,不同 SOP 场景下的数据链路转发路径。伴随着客户对性能的极致追求的需求,在 Terway IPVLAN EBPF 相比Terway ENI,有更高的 Pod 密度;相比 Terway ENIIP,有更高的性能,但因此也带了网络链路的复杂性和可观测性带来了调整,此场景可以分为 11 个 SOP 场景,并对这11 个场景的转发链路,技术实现原理,云产品配置等一一梳理并总结,这对我们遇到Terway IPVLAN 架构下的链路抖动、最优化配置,链路原理等提供了初步指引方向。在 Terway IPVLAN 模式下,利用 EBPF 和 IPVLAN 隧道,避免了数据链路在 ECS OS 内核协议栈的转发,这必然带来了更高的性能,同时也有 ENIIP 模式一样的多 IP 共享 ENI的方式来保证 Pod 密度。但是随着业务场景越来越趋于复杂,业务的 ACL 管控也更加全景剖析阿里云容器网络数据链路154趋于 Pod 维度去管理,比如需要针对 Pod 维度进行安全 ACL 规则设置的需求等。下一系列我们将进入到 Terway ENI-Trunking 模式的全景解析。5.Terway ENI-Trunking 模式架构设计弹性网卡中继 Trunk ENI 是一种可以绑定到专有网络 VPC 类型 ECS 实例上的虚拟网卡。相比弹性网卡 ENI,Trunk ENI 的实例资源密度明显提升。启用 Terway Trunk ENI 功能后,指定的 Pod 将使用 Trunk ENI 资源。为 Pod 开启自定义配置是可选功能,默认情况下创建的 Pod,未开启 Terway Trunk ENI 功能,使用的是共享 ENI 上的 IP 地址。只有当您主动声明为指定 Pod 开启自定义配置后,相应的 Pod 才能使用 Pod 自定义配置能力,Terway 才可以同时使用共享 ENI 以及 Trunk ENI 为 Pod 分配 IP。两种模式共享节点最大 Pod 数量配额,总部署密度和开启前一致。金融、电信,政府等行业对数据信息安全有着非常严格的数据安全要求,通常,重要的核心数据会放在自建的机房内,并且对访问此数据的客户端有严格的白名单控制,通常会限制具体的 IP 访问源。业务架构上云时,往往是通过专线,VPN 等打通自建机房和云上资源打通,由于传统容器中 PodIP 是不固定的,NetworkPolicy 只能在集群内生效,这对客户的白名单设置有了非常大的挑战。ENI 在 Trunk 模式下,可以配置独立的安全组、vSwitch 能力,带来更为细化的网络配置能力,提供极具竞争力的容器网络解决方案。全景剖析阿里云容器网络数据链路155在 trunking 的命名空间内可以看到相关的 pod 信息和节点信息,其中 pod 应用的 IP的网络我们稍后会详细说明。全景剖析阿里云容器网络数据链路156Pod 内有只有指向 eth0 的默认路由,说明说明 PodPod 访问任何地址段都是从访问任何地址段都是从 eth0eth0 为统一的为统一的出入口。出入口。那么 Pod 是如何 ECS OS 进行通信呢?在 OS 层面,我们一看到 calicxxxx 的网卡,可以看到是附属于 eth1 的,对于节点和 Pod 的通信连接,这个类似于Terway ENIIP 模式架构群内非 SVC 后端 pod 所在节点访问 SVC ClusterIP。通过 OS Linux Routing我们可以看到,所有目的是 Pod IP 的流量都会被转发到 Pod 对应的 calico 虚拟往卡上,到这里为止,ECS OS 和 Pod 的网络命名空间已经建立好完整的出入链路配置了。让我们把目光聚焦 ENI Trunking 本身。ENI Truning 是如何实现 Pod 的交换机和安全组的配置呢?Terway 增加一种名为 PodNetworking 的自定义资源来描述网络配置。您可以创建多个 PodNetworking,来规划不同网络平面。创建 PodNetworking 资源后,Terway 将同步网络配置信息,只有 status 成为 Ready全景剖析阿里云容器网络数据链路157后,该网络资源才能对 Pod 生效。如下图所示,类型为 Elastic,只要 namespce 的标签的符合 tryunking:zoneb,就给 pod 使用指定的安全组和交换机。创建 Pod 时,Pod 将通过标签去匹配 PodNetworking。如果 Pod 没有匹配到任何PodNetworking,则 Pod 将使用默认的共享 ENI 上的 IP。如果 Pod 有匹配到PodNetworking,则将使用 PodNetworking 中定义的配置分配 ENI。关于 Pod 标签的相关内容,请参见标签。Terway 会为这类 Pod 创建相应的名为 PodENI 的自定义资源,用于跟踪 Pod 所使用的资源,该资源由 Terway 管理,您不可修改该资源。如下 trunking 命名空间下的centos-59cdc5c9c4-l5vf9Pod 匹配了相应的 podnetworking 设置,被分配了相应的memeber ENI、对应的 Trunking ENI,安全组,交换机和被绑定的 ECS 实例,这样就实现了 Pod 维度的交换机,安全组的配置和管理。全景剖析阿里云容器网络数据链路158通过 ECS 的控制台,我们也可以清楚的看到 memenber ENI 和 Trunking ENI 之间的关系,相应的安全组交换机等等信息。通过上面的配置,我们了解如何去给每个 Pod 单独配置交换机,安全组等信息,让每个 pod 在通过 Trunking ENI 出 ECS 后,可以自动走到对应的配置 Member ENI 上,全景剖析阿里云容器网络数据链路159让这些配置生效。那么所有的配置其实落到宿主机上都是通过相关的策略实现的,Trunking ENi 网卡是如何知道把对应 Pod 的流量转发到正确的对应的 Member ENI 上的呢?这其实通过的 vlan 来实现的。在 tc 层面可以看到 VLAN ID。所以在 egress 或者 ingress 的阶段会打上或者去除 VLAN ID。、故 Terway ENI-Trunking 模式总体可以归纳为:弹性网卡中继 Trunk ENI 是一种可以绑定到专有网络 VPC 类型 ECS 实例上的虚拟网卡。相比弹性网卡 ENI,Trunk ENI 的实例资源密度明显提升Terway Trunk ENI 支持为每个 Pod 配置固定 IP、独立的虚拟交换机、安全组,能提供精细化流量管理、流量隔离、网络策略配置和 IP 管理能力。使用 Terway 插件,您需要选择较高规格和较新类型的 ECS 神龙机型,即 5 代或者6 代的 8 核以上机型,且机型要支持 Trunk ENI。更多信息,请参见实例规格族。单节点所支持的最大 Pod 数取决于该节点的弹性网卡(ENI)数。共享 ENI 支持的最大 Pod 数=(ECS 支持的 ENI 数-1)单个 ENI 支持的私有 IP 数。Pod 安全组规则不会应用到同节点 Pod 间流量及同节点上节点与 Pod 间流量。如果您需要限制,可以通过 NetworkPolicy 进行配置。Pod 和对应 MemeberENI 流量对应是通过 VLAN ID 来实现的。1)1)TerwayTerway ENI-TrunkingENI-Trunking 模式容器网络数据链路剖析模式容器网络数据链路剖析可以看到由于可以实现 Pod 维度的安全组,交换机设置,那么宏观上不同链路访问必然更加趋于复杂,我们可以将 Terway ENI-TRunking 模式下的网络链路大体分为以Pod IP 对外提供服务和以 SVC 对外提供服务两个大的 SOP 场景,进一步细分,可以归全景剖析阿里云容器网络数据链路160纳为 10 个不同的小的 SOP 场景。对这 11 个场景的数据链路梳理合并,这些场景可以归纳为下面 10 类典型的场景:通节点访问 Pod(相同 or 不同安全组);同节点同安全组 TrunkPod 互访(含访问 SVC IP,源端和 svc 后端部署在同一节点);同节点不同安全组 TrunkPod 互访(含访问 SVC IP,源端和 svc 后端部署在同一节点);不同节点同安全组 TrunkPod 互访;不同节点不同安全组 TrunkPod 互访;集群内源端访问 SVC IP(源端和 SVC 后端不同节点,相同安全组,含 Local 模式访问 external IP);集群内源端访问 SVC IP(源端和 SVC 后端不同节点,不同安全组,含 Local 模式访问 external IP);Cluster 模式下,集群内源端访问 SVC ExternalIP(源端和 SVC 后端不同节点,不同安全组);Cluster 模式下,集群内源端访问 SVC ExternalIP(源端和 SVC 后端不同节点,相同安全组);全景剖析阿里云容器网络数据链路161集群外访问 SVC IP;2 2)场景一:通节点访问场景一:通节点访问 PodPod(相同(相同 oror 不同安全组)不同安全组)环境环境cn-hongkong.10.0.4.22 节点上存在 nginx-6f545cb57c-kt7r8 和 10.0.4.30。内核路由内核路由nginx-6f545cb57c-kt7r8 IP 地址 10.0.4.30,该容器在宿主机表现的 PID 是 1734171,该容器网络命名空间有指向容器 eth0 的默认路由。该容器 eth0 在 ECS OS 内是通过 ipvlan 隧道的方式和 ECS 的附属 ENI eth1 建立的隧道,同时附属 ENI eth1 还有个虚拟的 calxxx 网卡。全景剖析阿里云容器网络数据链路162在 ECS OS 内,有指向 Pod IP,下一跳为为 calixxxx 的路由,通过前文可以知道 calixxx网卡是和每个 pod 内的 veth1 组成的 pair,所以,pod 内访问 SVC 的 CIDR 会有指向veth1 的路由,不会走默认的 eth0 路由。故:calixx 网卡在这里的主要作用是用于:节点访问 Pod;当节点或者 Pod 访问 SVC 的 CIDR 时,会走 ECS OS 内核协议栈转换,走到 calixxx和 veth1 访问 pod;trunking 命名空间下的nginx-6f545cb57c-kt7r8 Pod匹配了相应的podnetworking设置,被分配了相应的 memeber ENI、对应的 Trunking ENI,安全组,交换机和被绑定的 ECS 实例,这样就实现了 Pod 维度的交换机,安全组的配置和管理。全景剖析阿里云容器网络数据链路163在 tc 层面可以看到 VLAN ID 1027,所以数据流量在 egress 或者 ingress 的阶段会打上或者去除 VLAN ID。ENI 的网卡所属的安全组可以看到只允许了指定的 IP 可以访问 nginxPod 的 80 端口。全景剖析阿里云容器网络数据链路164置于数据面流量在 OS 层面的流量转发逻辑,这个类似于Terway ENIIP 模式架构群内非 SVC 后端 pod 所在节点访问 SVC ClusterIP,不在这里做过多的叙述。小结小结可以访问到目的端数据链路转发示意图:数据链路转发示意图:全景剖析阿里云容器网络数据链路165会经过calicao网卡,每个非hostnetwork的pod会和calicao网卡形成veth pair,用于和其他 pod 或 node 进行通信;整个链路不会和请求不会经过pod所分配的ENI,直接在OS的ns中命中Ip rule 被转发 1;整个请求链路是 ECS1 OS-calixxxx-ECS1 Pod1;因为是通过 os 内核 routing 转发,不经过 member eni,所以安全组不生效,此链路与 pod 所属的 member eni 的安全组无关;3)3)场景二场景二:同节点同安全组同节点同安全组 TrunkPodTrunkPod 互访互访(含访问含访问 SVCSVC IPIP,源端和源端和 svsvc c后端部署在同一节点)后端部署在同一节点)环境环境cn-hongkong.10.0.4.22 节点上存在 nginx-6f545cb57c-kt7r8,10.0.4.30 和busybox-87ff8bd74-g8zs7,10.0.4.24。内核路由内核路由nginx-6f545cb57c-kt7r8 IP 地址 10.0.4.30,该容器在宿主机表现的 PID 是 1734171,该容器网络命名空间有指向容器 eth0 的默认路由。全景剖析阿里云容器网络数据链路166该容器 eth0 在 ECS OS 内是通过 ipvlan 隧道的方式和 ECS 的附属 ENI eth1 建立的隧道,同时附属 ENI eth1 还有个虚拟的 calixxxx 网卡。在 ECS OS 内,有指向 Pod IP,下一跳为为 calixxxx 的路由,通过前文可以知道 calixxx网卡是和每个 pod 内的 veth1 组成的 pair,所以,pod 内访问 SVC 的 CIDR 会有指向veth1 的路由,不会走默认的 eth0 路由。故 calixx 网卡在这里的主要作用是用于:节点访问 Pod;当节点或者 Pod 访问 SVC 的 CIDR 时,会走 ECS OS 内核协议栈转换,走到 calixxx和 veth1 访问 pod;全景剖析阿里云容器网络数据链路167trunking 命名空间下的 busybox-87ff8bd74-g8zs7 和 nginx-6f545cb57c-kt7r8Pod 匹配了相应的 podnetworking 设置,被分配了相应的 memeber ENI、对应的Trunking ENI,安全组,交换机和被绑定的 ECS 实例,这样就实现了 Pod 维度的交换机,安全组的配置和管理。全景剖析阿里云容器网络数据链路168在 tc 层面可以看到 VLAN ID 1027,所以数据流量在 egress 或者 ingress 的阶段会打上或者去除 VLAN ID。ENI 的网卡所属的安全组可以看到只允许了指定的 IP 可以访问 nginxPod 的 80 端口。全景剖析阿里云容器网络数据链路169置于数据面流量在 OS 层面的流量转发逻辑,这个类似于Terway ENIIP 模式架构群内非 SVC 后端 pod 所在节点访问 SVC ClusterIP,不在这里做过多的叙述。小结小结可以访问到目的端数据链路转发示意图:数据链路转发示意图:会经过calicao网卡,每个非hostnetwork的pod会和calicao网卡形成veth pair,用于和其他 pod 或 node 进行通信;整个链路不会和请求不会经过pod所分配的ENI,直接在OS的ns中命中Ip rule 被转发;整个请求链路是 ECS1 Pod1 eth0-cali1xxxxxx-cali2xxxxxx-ECS1 Pod2eth0;pod 属于同 or 不同 ENI,链路请求是一致的,不经过 ENI;全景剖析阿里云容器网络数据链路170因为是通过 os 内核 routing 转发,不经过 member eni,所以安全组不生效,此链路与 pod 所属的 member eni 的安全组无关;访问 Pod IP 和访问 SVC IP(external ipor clusterip)的区别是:访问 SVC IP,SVC会在源端 pod eth0 和 calixxx 网卡捕捉到,在目的端 pod 的 eth0 和 calixxx 时捕捉不到;4 4)场景三:同节点不同安全组场景三:同节点不同安全组 TrunkPodTrunkPod 互访(含访问互访(含访问 SVCSVC IPIP,源端,源端和和svcsvc 后端部署在同一节点)后端部署在同一节点)环境环境cn-hongkong.10.0.4.244 节点上存在 nginx-96bb9b7bb-wwrdm,10.0.5.35 和centos-648f9999bc-nxb6l,10.0.5.18。内核路由内核路由相关的 Pod 的容器网络命名空间,路由等不在进行过多描述,详情可以见前面两小节。通过 podeni 可以看到 centos-648f9999bc-nxb6l 所分配的 ENI,安全组 sg,交换机vsw 等。全景剖析阿里云容器网络数据链路171通过安全组 sg-j6ccrxxxx 可以看到 centos 的 pod 可以访问外部所有的地址。同理,可以查看出服务端 Pod 的 nginx-96bb9b7bb-wwrdm 的安全组sg-j6ccrze8utxxxxx 是只允许 192.168.0.0/16 可以访问。全景剖析阿里云容器网络数据链路172小结小结可以访问到目的端数据链路转发示意图:数据链路转发示意图:会经过calicao网卡,每个非hostnetwork的pod会和calicao网卡形成veth pair,用于和其他 pod 或 node 进行通信;整个链路不会和请求不会经过pod所分配的ENI,直接在OS的ns中命中Ip rule 被转发;整个请求链路是 ECS1 Pod1 eth0-cali1xxxxxx-cali2xxxxxx-ECS1 Pod2eth0;pod 属于同 or 不同 ENI,链路请求是一致的,不经过 ENI;全景剖析阿里云容器网络数据链路173因为是通过 os 内核 routing 转发,不经过 member eni,所以安全组不生效,此链路与 pod 所属的 member eni 的安全组无关;访问 Pod IP 和访问 SVC IP(external ipor clusterip)的区别是:访问 SVC IP,SVC会在源端 pod eth0 和 calixxx 网卡捕捉到,在目的端 pod 的 eth0 和 calixxx 时捕捉不到;5)5)场景四:不同节点同安全组场景四:不同节点同安全组 TrunkPodTrunkPod 互访互访环境环境cn-hongkong.10.0.4.20 节点上存在客户端 centos-59cdc5c9c4-l5vf9 和 IP10.0.4.27。cn-hongkong.10.0.4.22 节点上存在服务端 nginx-6f545cb57c-kt7r8 和 IP10.0.4.30。内核路由内核路由相关的 Pod 的容器网络命名空间,路由等不在进行过多描述,详情可以见前面两小节。通过 podeni 可以看到 centos-59cdc5c9c4-l5vf9 所分配的 ENI,安全组 sg,交换机vsw 等。通过安全组 sg-j6cf3sxrlbuwxxxxx 可以看到 centos 和 nginx 的的 pod 属于同一个安全组 sg-j6cf3sxrlbuxxxxx。全景剖析阿里云容器网络数据链路174全景剖析阿里云容器网络数据链路175小结小结是否可以访问取决于安全组配置数据链路转发示意图:数据链路转发示意图:会经过calicao网卡,每个非hostnetwork的pod会和calicao网卡形成veth pair,用于和其他 pod 或 node 进行通信;整个链路不会和请求不会经过pod所分配的ENI,直接在OS的ns中命中Ip rule 被转发;出 ECS 后,根据要访问的 pod 和该 pod ENI 所属 vswitch,命中 VPC 路由规则或者直接 VSW 上的二层转发;整 个 请 求 链 路 是 ECS1 Pod1 eth0-cali1xxx Trunk eni(ECS1)-Pod1member eni-vpc route rule(如有)-Pod2 member eni-Trunk eni(ECS2)cali2 xxx-ECS2 Pod1 eth0;因为是通过 os 内核 routing 转发,经过 member eni,因为 member eni 属于同一个安全组,所以安全组内默认是互通的;全景剖析阿里云容器网络数据链路1766)6)场景五:不同节点不同安全组场景五:不同节点不同安全组 TrunkPodTrunkPod 互访互访环境环境cn-hongkong.10.0.4.20 节点上存在客户端 centos-59cdc5c9c4-l5vf9 和 IP10.0.4.27。cn-hongkong.10.0.4.244 节点上存在服务端 nginx-96bb9b7bb-wwrdm 和 IP10.0.5.35。内核路由内核路由相关的 Pod 的容器网络命名空间,路由等不在进行过多描述,详情可以见前面两小节。通过 podeni 可以看到 centos-59cdc5c9c4-l5vf9 所分配的 ENI,安全组 sg,交换机vsw 等。通过安全组 sg-j6cf3sxrlbuwxxxxx 可以看到centos的 pod可以访问外部所有的地址。全景剖析阿里云容器网络数据链路177同理,可以查看出服务端 Pod 的 nginx-96bb9b7bb-wwrdm 的安全组sg-j6ccrze8utxxxxx 是只允许 192.168.0.0/16 可以访问。全景剖析阿里云容器网络数据链路178小结小结是否可以访问取决于安全组配置数据链路转发示意图:数据链路转发示意图:会经过calicao网卡,每个非hostnetwork的pod会和calicao网卡形成veth pair,用于和其他 pod 或 node 进行通信;整个链路不会和请求不会经过pod所分配的ENI,直接在OS的ns中命中Ip rule 被转发;整 个 请 求 链 路 是 ECS1 Pod1 eth0-cali1xxx Trunk eni(ECS1)-Pod1member eni-vpc route rule(如有)-Pod2 member eni-Trunk eni(ECS2)cali2 xxx-ECS2 Pod1 eth0;因为是通过 os 内核 routing 转发,流量会经过 member eni,是否可以访问成功,安全组配置对此有着决定性的作用;全景剖析阿里云容器网络数据链路1797)7)场景六:集群内源端访问场景六:集群内源端访问 SVCSVC IPIP(源端和(源端和 SVCSVC 后端不同节点,相同安后端不同节点,相同安全组,含全组,含 LocalLocal 模式访问模式访问 externalexternal IPIP)环境环境cn-hongkong.10.0.4.20 节点上存在客户端 centos-59cdc5c9c4-l5vf9 和 IP10.0.4.27。cn-hongkong.10.0.4.22 节点上存在服务端 nginx-6f545cb57c-kt7r8 和 IP10.0.4.30。nginx 的 svc 的 ClusterIP 是 192.168.81.92 External IP 是 8.210.162.178。内核路由内核路由ENI-Trunking 相比较 ENIIP 来说,只是在 VPC 侧增加了对应的 Truning 和 MemberENI,在 OS 内并无区别,此处可以参考 Terway ENIIP 模式架构 群内非 SVC 后端 pod所在节点访问 SVC ClusterIP。全景剖析阿里云容器网络数据链路180小结小结是否可以访问取决于安全组配置数据链路转发示意图:数据链路转发示意图:会经过calicao网卡,每个非hostnetwork的pod会和calicao网卡形成veth pair,用于和其他 pod 或 node 进行通信;整个链路不会和请求不会经过pod所分配的ENI,直接在OS的ns中命中Ip rule 被转发;出 ECS 后,根据要访问的 pod 和该 pod ENI 所属 vswitch,命中 VPC 路由规则或者直接 VSW 上的二层转发;整个请求链路是:去方向:ECS1 Pod1 eth0-cali1xxx ECS eth0-Pod1 member eni-vpcroute rule(如有)-Pod2 member eni-Trunk eni(ECS2)cali2 xxx-ECS2Pod1 eth0;回方向:ECS2 Pod1 eth0-Trunk eni(ECS2)cali2 xxx-Pod2 member eni-vpc route rule(如 有)-Pod1 member eni-Trunk eni(ECS1)-cali1xxx-ECS1 Pod1 eth0;全景剖析阿里云容器网络数据链路181经过 ipvs 规则 fnat 转化,数据包是以源 pod IP 从 ECS eth0 出,请求目的 pod IP。(访问 SVC clusterIP,以及 Local 模式下访问 External IP);这个经过的 ENI 有 ECS1 的 eth0,Pod1 member eni,Pod2 member eni。所以这三个网卡的安全组的配置都会影响数据链路的连通性;8)8)场景七:集群内源端访问场景七:集群内源端访问 SVCSVC IPIP(源端和(源端和 SVCSVC 后端不同节点,不同安后端不同节点,不同安全组,含全组,含 LocalLocal 模式访问模式访问 externalexternal IPIP)环境环境cn-hongkong.10.0.4.20 节点上存在客户端 centos-59cdc5c9c4-l5vf9 和 IP10.0.4.27。cn-hongkong.10.0.4.244 节点上存在服务端 nginx-96bb9b7bb-wwrdm 和 IP10.0.5.35。nginx 的 svc 的 ClusterIP 是 192.168.31.83 External IP 是 47.243.87.204。内核路由内核路由ENI-Trunking 相比较 ENIIP 来说,只是在 VPC 侧增加了对应的 Truning 和 MemberENI,在 OS 内并无区别,此处可以参考Terway ENIIP 模式架构Cluster 模式,集群内非 SVC 后端 pod 所在节点访问 SVC External IP。全景剖析阿里云容器网络数据链路182小结小结是否可以访问取决于安全组配置数据链路转发示意图:数据链路转发示意图:会经过calicao网卡,每个非hostnetwork的pod会和calicao网卡形成veth pair,用于和其他 pod 或 node 进行通信;整个链路不会和请求不会经过pod所分配的ENI,直接在OS的ns中命中Ip rule 被转发;出 ECS 后,根据要访问的 pod 和该 pod ENI 所属 vswitch,命中 VPC 路由规则或者直接 VSW 上的二层转发;整个请求链路是:去方向:ECS1 Pod1 eth0-cali1xxx ECS eth0-Pod1 member eni-vpcroute rule(如有)-Pod2 member eni-Trunk eni(ECS2)cali2 xxx-ECS2Pod1 eth0;全景剖析阿里云容器网络数据链路183回方向:ECS2 Pod1 eth0-Trunk eni(ECS2)cali2 xxx-Pod2 member eni-vpc route rule(如 有)-Pod1 member eni-Trunk eni(ECS1)-cali1xxx-ECS1 Pod1 eth0;经过 ipvs 规则 fnat 转化,数据包是以源 pod IP 从 ECS eth0 出,请求目的 pod IP。(访问 SVC clusterIP,以及 Local 模式下访问 External IP);这个经过的 ENI 有 ECS1 的 eth0,Pod1 member eni,Pod2 member eni。所以这三个网卡的安全组的配置都会影响数据链路的连通性。需要保证安全组互相放通Pod 和 ECS 的响应 IP;9)9)场景八场景八:ClusterCluster 模式下模式下,集群内源端访问集群内源端访问 SVCSVC ExternalIPExternalIP(源端和源端和 SVSVC C后端不同节点,不同安全组)后端不同节点,不同安全组)环境环境全景剖析阿里云容器网络数据链路184cn-hongkong.10.0.4.20 节点上存在客户端 centos-59cdc5c9c4-l5vf9 和 IP10.0.4.27。cn-hongkong.10.0.4.244 节点上存在服务端 nginx-96bb9b7bb-wwrdm 和 IP10.0.5.35。nginx 的 svc 的 ClusterIP 是 192.168.31.83 External IP 是 47.243.87.204,ExternalTrafficPolicy 是 Cluster 模式。内核路由内核路由ENI-Trunking 相比较 ENIIP 来说,只是在 VPC 侧增加了对应的 Truning 和 MemberENI,在 OS 内并无区别,此处可以参考Terway ENIIP 模式架构。小结小结是否可以访问取决于安全组配置数据链路转发示意图:数据链路转发示意图:会经过calicao网卡,每个非hostnetwork的pod会和calicao网卡形成veth pair,用于和其他 pod 或 node 进行通信;全景剖析阿里云容器网络数据链路185整个链路不会和请求不会经过pod所分配的ENI,直接在OS的ns中命中Ip rule 被转发;出 ECS 后,根据要访问的 pod 和该 pod ENI 所属 vswitch,命中 VPC 路由规则或者直接 VSW 上的二层转发;整个请求链路是 ECS1 Pod1 eth0-cali1xxx ECS eth0-vpc route rule(如有)-Pod2 member eni-Trunk eni(ECS2)cali2 xxx-ECS2 Pod1 eth0;经过 ipvs 规则 fnat 转化,数据包是以源 pod IP 从 ECS eth0 出,请求目的 pod IP。(访问 SVC clusterIP,以及 Local 模式下访问 External IP);这个经过的 ENI 有 ECS1 的 eth0,Pod2 member eni。所以这两个网卡的安全组的配置都会影响数据链路的连通性。需要保证安全组互相放通 Pod 和 ECS 的响应IP;10)10)场景九:场景九:ClusterCluster 模式下,集群内源端访问模式下,集群内源端访问 SVCSVC ExternalIPExternalIP(源端(源端和和SVCSVC 后端不同节点,相同安全组)后端不同节点,相同安全组)环境环境全景剖析阿里云容器网络数据链路186cn-hongkong.10.0.4.20 节点上存在客户端 centos-59cdc5c9c4-l5vf9 和 IP10.0.4.27。cn-hongkong.10.0.4.22 节点上存在服务端 nginx-6f545cb57c-kt7r8 和 IP10.0.4.30。nginx 的 svc 的 ClusterIP 是 192.168.81.92 External IP 是 8.210.162.178ExternalTrafficPolicy 为 Cluster。内核路由内核路由ENI-Trunking 相比较 ENIIP 来说,只是在 VPC 侧增加了对应的 Truning 和 MemberENI,在 OS 内并无区别,此处可以参考Terway ENIIP 模式架构Cluster 模式,集群内非 SVC 后端 pod 所在节点访问 SVC External IP。全景剖析阿里云容器网络数据链路187小结小结是否可以访问取决于安全组配置数据链路转发示意图:数据链路转发示意图:会经过calicao网卡,每个非hostnetwork的pod会和calicao网卡形成veth pair,用于和其他 pod 或 node 进行通信;整个链路不会和请求不会经过pod所分配的ENI,直接在OS的ns中命中Ip rule 被转发;出 ECS 后,根据要访问的 pod 和该 pod ENI 所属 vswitch,命中 VPC 路由规则或者直接 VSW 上的二层转发;整个请求链路是 ECS1 Pod1 eth0-cali1xxx ECS eth0-vpc route rule(如有)-Pod2 member eni-Trunk eni(ECS2)cali2 xxx-ECS2 Pod1 eth0;经过 ipvs 规则 fnat 转化,数据包是以源 pod IP 从 ECS eth0 出,请求目的 pod IP。(访问 SVC clusterIP,以及 Local 模式下访问 External IP);这个经过的 ENI 有 ECS1 的 eth0,Pod2 member eni。所以这两个网卡的安全组的配置都会影响数据链路的连通性。需要保证安全组互相放通 Pod 和 ECS 的响应全景剖析阿里云容器网络数据链路188IP;11)11)场景十:集群外访问场景十:集群外访问 SVCSVC IPIP环境环境cn-hongkong.10.0.4.20 节点上存在客户端 centos-59cdc5c9c4-l5vf9 和 IP10.0.4.27。cn-hongkong.10.0.4.22 节点上存在服务端 nginx-6f545cb57c-kt7r8 和 IP10.0.4.30。nginx 的 svc 的 ClusterIP 是 192.168.81.92 External IP 是 8.210.162.178ExternalTrafficPolicy 为 Cluster。SLBSLB 相关配置相关配置在 SLB 控制台,可以看到 lb-j6cmv8aaojf7nqdai2a6a 虚拟服务器组的后端服务器组是两个后端 nginxPod 的的 ENI eni-j6cgrqqrtvcwhhcyuc28,全景剖析阿里云容器网络数据链路189eni-j6c54tyfku5855euh3db 和 eni-j6cf7e4qnfx22mmvblj0,这几个 ENI 都是member ENI。小结小结是否可以访问取决于安全组配置数据链路转发示意图:数据链路转发示意图:会经过calicao网卡,每个非hostnetwork的pod会和calicao网卡形成veth pair,用于和其他 pod 或 node 进行通信;数据链路:client-SLB-Pod Member ENI Pod Port-Trunking ENI-ECS1Pod1 eth0;全景剖析阿里云容器网络数据链路190ExternalTrafficPolicy 为Local或Cluster模式下,SLB只会将Pod分配的memberENI 挂在到 SLB 的虚拟服务器组;SLB 转发请求只会转发到目标 member ENI 上,然后通过 vlan 发送到 Trunk ENI,再由 Trunk ENI 转发到 Pod;6.ASM Istio 模式架构近几年,企业基础设施云原生化的趋势越来越强烈,从最开始的 IaaS 化到现在的微服务化,客户的颗粒度精细化和可观测性的需求更加强烈。容器网络为了满足客户更高性能和更高的密度,也一直在高速的发展和演进中,这必然对客户对云原生网络的可观测性带来了极高的门槛和挑战。为了提高云原生网络的可观测性,同时便于客户和前后线同学增加对业务链路的可读性,ACK 产研和 AES 联合共建,合作开发 ack net-exporter 和云原生网络数据面可观测性系列,帮助客户和前后线同学了解云原生网络架构体系,简化对云原生网络的可观测性的门槛,优化客户运维和售后同学处理疑难问题的体验,提高云原生网络的链路的稳定性。图:服务网格示例全景剖析阿里云容器网络数据链路191图 Istio 数据面示意图Kubernetes 的横空出现打破了底层服务器、底层网络等计算资源的界限,给业务的灵活部署、快速恢复、弹性伸缩,资源效率最大化带来了无限可能。但是业务场景的贪婪是无限的,随着微服务趋势大肆发展,业务上对于同一个 service,不同版本版本和流量控制有着更精细化的颗粒度的需求,最好能实现 Pod 维度的流量控制,可观测性等等。这些在 kubernetes 上是无法实现的:从流量角度,k8s 最小的控制维度是 service,其他比如金丝雀 等发布,借助各种ingress controller 或者其他组件实现,并且这些也无法实现 Pod 之间的流量和连接状态的可观测性。k8s 给服务微型化,小型化创造了条件,如果前后端服务存在调用关心,他们如果使用共享通信库,则会在开发阶段就要求所有微服务使用相同的逻辑语言和堆栈,这从某种程度上又大大限制微服务的独立化,无法实现完全的漠不关心将原来集成在同一个 ECS 上的服务拆分成不同的模块,这些模块之间调用涉及跨ECS 等,那么必然需要在代码开发阶段需要考虑超时,重试,连接失败等逻辑机制,全景剖析阿里云容器网络数据链路192而这些与微服务最核心的服务应用其实没有太大关系,但是开发工作往往耗费大量的经历在逻辑设计上。那么,有没有办法实现上述和微服务的业务完全隔离呢?Istio 的出现给这个带来了相对完美的解决方案,让应用这和开发者更加关注业务本身的开发迭代。Istio 利用了 k8s的 Pod 概念,会根据使用者的配置,在每个被注入的 Pod 部署时,自动注入 istio-proxy容器和 initial 容器。Initial 容器的目的是通过修改 Pod 单独网络命名空间的 iptables 规则,让需要代理的流量进入到 istio-proxy 监听的端口,istio-proxy 监听出入 两个端口,根据网格配置,来实现对出入流量的代理实现和干预。而被同一个 istio 注入的载体,都被视为同一个服务网格之内,他们之间的调用已经脱离了 service 的层面,会命中相关的 istio cluster配置的 endpoint,这样我们就可以实现 Pod 维度的流量管理、观测性、安全性等配置。1)PodPod 注入注入ASM 默认提供了一个 Webhook 控制器,可以将 Sidecar 代理自动添加到可用的 Pod中。通过下面的命令可以看到 ASM 注入的集群有个 istio-sidecar-injector-1-15-3 的mutatingwebhookconfiguration,查看 webhook 内容,可以看到其中一条就是有istio-inject:enabled 标签的 namespace里的 pod 创建时候会自动注入。除了命名空间维度,还有 Pod 维度,其他注解方式等多种维度实现 K8s 集群是否被加入到 Istio 服务网格中。为了充分利用服务网格的所有特性,服务网格中 ACK 集群的应用 Pod 必须包含一个 Sidecar 代理。除了手动注入方式外,通常建议启用自动注入的方式来简化部署,ASM 已经实现了注入配置的可视化操作,具体请见多种方式灵活开启自动注入。全景剖析阿里云容器网络数据链路1932)PodPod 流量转发流量转发通过 describe 被注入的 Pod,可以发现 Pod 中除了设置好的业务 container,还多出两个容器:istio-proxy 和 init container:istio-init。这两个容器的镜像是一样的,只是运行的命令的不一样,这样的好处是只需要拉取一份镜像,节省了拉取镜像的时间。全景剖析阿里云容器网络数据链路1943)3)InitInit ContainerContainerInit container 利用的是 k8s 的特性,一种具有特权的特殊容器,在 Pod 内的应用容器启动之前运行。Init 容器可以包括一些应用镜像中不存在的实用工具和安装脚本。每个Pod 中可以包含多个容器和多个 Init 容器。他与普通容器很像,但是有自己独特点:多个 init 容器是串行运行的。也就是说多个 init 容器会依序运行,等上一个 init 容器运行完毕结束后,才会开始运行下一个容器。只有等到所有的 init 容器全部运行结束退出后,业务容器才开始启动,在这之前,pod 不会处于 ready。如果 Pod 的 Init 容器失败,kubelet 根据 pod 设置的 restartPolicy 进行相应的action。既然现在了解了 Init container 的作用,那我们来看一下 istio-init 在启动的过程中做了全景剖析阿里云容器网络数据链路195哪些事情,可以通过下面的命令:kubectl logs-n istio-inject productpage-v1-797d845774-dndmk-c istio-init。全景剖析阿里云容器网络数据链路196可以看到 istio-init 在启动过程中进行了一连串的 iptables 规则的生成和配置,比如出方向转发到 15001 端口;入方向转发到 15006 端口;访问 15008 端口,直接 return不进行流量劫持等等。那有什么办法可以自定义配置么?查看 pod 的信息可以看到相关配置的启动参数,也就通过相关规则实现了出入流量重定向到设置的端口。-p:所有出方向的流量被 iptables 重定向到 15001 端口-z:所有入方向的流量被 iptables 重定向到 15006 端口-u:用于排除用户 ID 为 1337,可以视为 envoy 应用本身使用 UID 1337-m:流量重定向模式,“REDIRECT”或“TPROXY”-i:重定向出方向的地址范围,“*”表示重定向所有出站流量。-x:指将从重定向出方向中排除的 IP 地址范围-b:重定向入站端口列表-d:重定向入站端口中排除的端口列表全景剖析阿里云容器网络数据链路197我们从 Pod 的视角去观察,将 Pod 视为一个整体,里面有 istio-proxy 容器和业务容器APP container。入方向流量转发入方向流量转发根据上文的 iptables 规则,我们可以归纳出被入方向代理转发的端口,比如 80 等,在Pod 的 网 络 命 名 空 间 netfilter 模 块 经 过 流 程 是 Client-RREROUTING-ISTIO_INBOUND-ISTIO_IN_REDIRECT-INPUT-Envoy 15006(Inbound)-OUTPUT-ISTIO_OUTPUT-POSTROUTING-APP。这样就实现了入方向流量先被转发到 sidecar 容器后,在转发到业务容器的监听端口。其中在步骤 5 和 6 之间,流全景剖析阿里云容器网络数据链路198量会按照设置好的 istio 规则进行处理。出方向流量转发出方向流量转发根据上文的 iptables 规则,我们可以归纳出被入方向代理转发的端口,比如 80 等,在Pod 的网络命名空间 netfilter 模块经过流程是 APP OUTPUT-ISTIO_OUTPUT-ISTIO_REDIRECT-Envoy 15001(Outbound)-OUTPUT-ISTIO_OUTPUT-POSTROUTING-DST。这样就实现了出方向流量先被转发到 sidecar 容器后,在转发到目的监听端口。其中在步骤 d 和 e 之间,流量会按照设置好的 istio 规则进行处理。全景剖析阿里云容器网络数据链路199入方向流量免转发入方向流量免转发对于入方向的某些端口或者自定义端口,我们不需要它经过 sidecar 容器,iptables 规则会设置将符合条件的入方向流量避免转发到 15006 端口,直接转发到业务容器监听端口 RREROUTING-ISTIO_INBOUND-INPUT-APP。全景剖析阿里云容器网络数据链路200出方向流量免转发出方向流量免转发对于出方向的某些端口或者自定义端口,我们不需要它经过 sidecar 容器,iptables 规则会设置将符合条件的入方向流量避免转发到 15001 端口,直接离开 Pod 的网络命名空间 APP-OUTPUT-ISTIO_OUTPUT-POSTROUTING-DST。全景剖析阿里云容器网络数据链路2014)4)Istio-proxyIstio-proxy可以看到 15001 和 15006 被 envoy 应用所监听,而 envoy 应用就是 istio-proxy 容器程序。Init 容器启动的时候根据所设置的参数中指定将出入站流量重定向到 Envoy的模式为“REDIRECT”或者“TPROXY”。使用 REDIRECT 方式,一旦 Pod 注入了 Sidecar 代理之后,所有入站流量都是从 Envoy重定向,Envoy 将流量发送到绑定了本地地址(127.0.0.1)的应用程序,所以应用看不到真正的原始 IP。在服务网格环境下如何保持服务访问时的客户端源 IP 呢?可以使用 TPROXY 模式,目前 ASM 已经支持了 TPROXY 模式,具体详情请见https:/ TPROXY 模式下,Pod 的网络命名空间的 iptables 会有 mangle 配置。ADSADS 聚合服务发现聚合服务发现全景剖析阿里云容器网络数据链路202我们已经知道了服务网格会在每个注入的 Pod 内注入两个容器:istio-init 和istio-proxy。一旦在网格控制面进行相关配置的修改,会通过 pilot 下发到每个istio-proxy 容器去生效。而 istio 是通过 xDS 服务接口去实现相关配置的动态下发的,其中 xDS 包含了 LDS(Listener Discover Service)、CDS(Cluster Discover Service)、EDS(Endpoint Discovery Service)和 RDS(Route Discover Service)。一般情况下,在更新配置过程中应该先更新 Cluster-之后 CLuster 的 Endpoint 开始更新-开始更新 Cluster 和 Endpoint 相对应的 Listener-Route 开始更新新配置的Listener 信息-最后删除不在使用 Cluster 和 Endpoint 以保证更新过程中流量无损。但是这些 xDS 接口是相互独立,所以在配置下发的时候,存在某些依赖关系的 DS 因配置生效前后关系造成了部分流量被丢弃,这在某些生产环境中是无法接受的。为了保证数据面配置的一致性,服务网格利用 gRPC 流来进行 ADS 聚合发现服务,通过一个 gRPC 流来保证各个 xDS 接口的调用顺序,避免各个接口独立性造成数据配置的不匹配。详细信息可以参考:https:/www.envoyproxy.io/docs/envoy/latest/api-docs/xds_protocolenvoy-rev.jsonenvoy-rev.json可以看到 istio-proxy 启动了 pilot-agent 程序,pilot-agent 作为父进程启动了子进程/usr/local/bin/envoy。其中/etc/istio/proxy/envoy-rev.json 是 envoy 初始化的配置文件。Node包含了 istio-proxy 所在节点,当前 Pod,istio 版本、ACK 集群 ID、ASM 版本、必要端口等相关信息。全景剖析阿里云容器网络数据链路203administio-proxy 相关日志,管理端口等信息。dynamic_resourcesADS 相关配置信息,比如 api 协议,版本,超时时间等。全景剖析阿里云容器网络数据链路204static_resources包含了 prometheus_stats、agent、sds-grpc、xds-grpc 和 zipkin 五个 cluster 和一个在15090上监听的listener,xds-grpc cluster对应前面dynamic_resources中ADS配置。prometheus_stats cluster 和 15090 用于对外提供 prometheus 采集端口。zipkin cluster 是外部的 zipkin 服务器调用地址。全景剖析阿里云容器网络数据链路205tracing分布式链路跟踪,这里的 collector_cluster 是前面 static_resources 里面定义的 zipkincluster。访问日志分析访问日志分析通过前文,我们已经知道两个互相被注入的 pod 访问,流量会被各自的 istio-proxy 所劫持并处理,那么只要分析客户端和服务端的 istio-proxy 日志并进行加工,就可以对流量进行可观测性解读。我们在这里还是以官方例子来举例。访问 http:/productpage,productpage 应用会自动调用 details 服务,reviews 服务。我们以 productpage 和details 之间链路来进行举例分析。productpage-v1-797d845774-dndmk IP 是 10.0.1.130,details 应用的 svc 的名称是 details,svc 地址是 192.168.1.125,svc 端口是 9080。请求发送方 productpage-v1-797d845774-dndmk 的 istio-proxy 日志upstream_host:10.0.1.127:9080,downstream_remote_address:10.0.1.130:49586,downstream_local_address:192.168.1.125:9080,duration:6,upstream_cluster:outbound|9080|details.istio-inject.svc.cluster.local,path:/details/0,protocol:HTTP/1.1,upstream_local_address:10.0.1.130:50026,method:GET,user_agent:Mozilla/全景剖析阿里云容器网络数据链路2065.0(Windows NT 10.0;Win64;x64)AppleWebKit/537.36(KHTML,like Gecko)Chrome/109.0.0.0Safari/537.36,route_name:default,request_id:834147c2-435f-94a7-af11-8491df9ab4f8,start_time:2023-01-31T14:23:20.603Z,upstream_transport_failure_reason:null,upstream_service_time:5,response_flags:-,bytes_received:0,authority_for:details:9080,authority:details:9080,requested_server_name:null,istio_policy_status:null,trace_id:9712c9f3da936a8c927f227bfe536c16,response_code:200,x_forwarded_for:null,bytes_sent:178请求接受方 details-v1-6758dd9d8d-dtbdc 的 istio-proxy 日志。x_forwarded_for:null,start_time:2023-01-31T14:23:20.608Z,method:GET,response_flags:-,route_name:default,istio_policy_status:null,requested_server_name:outbound_.9080_._.details.istio-inject.svc.cluster.local,bytes_received:0,request_id:834147c2-435f-94a7-af11-8491df9ab4f8,response_code:200,upstream_host:10.0.1.127:9080,trace_id:9712c9f3da936a8c927f227bfe536c16,downstream_remote_address:10.0.1.130:50026,protocol:HTTP/1.1,bytes_sent:178,upstream_transport_failure_reason:null,downstream_local_address:10.0.1.127:9080,upstream_local_address:127.0.0.6:46225,authority:details:9080,authority_for:details:9080,upstream_service_time:0,upstream_cluster:inbound|9080|,duration:1,path:/details/0,user_agent:Mozilla/5.0(Windows NT 10.0;Win64;x64)AppleWebKit/537.36(KHTML,like Gecko)Chrome/109.0.0.0Safari/537.36日志内容解读upstream_host:10.0.1.127:9080,对于 outbound,此是上游某个Endpoint 的地址和端口;downstream_remote_address:10.0.1.130:49586,对于 outbound,此为本 pod-ip:随机端口 1;downstream_local_address:192.168.1.125:9080,对于 outbound,此为目的 svc-ip:svc-port;duration:6,整个请求时间,单位 ms;upstream_cluster:outbound|9080|details.istio-inject.svc.cluster.local,cluster 信息;path:/details/0;全景剖析阿里云容器网络数据链路207protocol:HTTP/1.1;upstream_local_address:10.0.1.130:50026,对于 outbound,此为本pod-ip:随机端口 2;method:GET;user_agent:Mozilla/5.0(Windows NT 10.0;Win64;x64)AppleWebKit/537.36(KHTML,like Gecko)Chrome/109.0.0.0 Safari/537.36;route_name:default,路由名称;request_id:834147c2-435f-94a7-af11-8491df9ab4f8;start_time:2023-01-31T14:23:20.603Z;upstream_transport_failure_reason:null;upstream_service_time:5,上游返回请求时间,单位 ms;response_flags:-,返回标志,关于连接或返回的详细信息;bytes_received:0;authority_for:details:9080;authority:details:9080;requested_server_name:null;istio_policy_status:null;trace_id:9712c9f3da936a8c927f227bfe536c16,此 ID 为唯一值,可以在上游 istio-proxy 对应;response_code:200,返回状态码;x_forwarded_for:null;bytes_sent:178;日志解读可以详细见官方连接:https:/www.envoyproxy.io/docs/envoy/latest/configuration/observability/access_log/usageUPSTREAM_HOST上游主机的 host,表示从 envoy 发出的请求的目的端。通常来说,对于 outbound cluster,此值是上游 pod-ip:Pod-port,而对于inbound cluster,此值是本 pod-ip:Pod-port。全景剖析阿里云容器网络数据链路208UPSTREAM_LOCAL_ADDRESS上游连接中,当前 envoy 的本地地址。通常来说,对于 outbound cluster,此值是本 pod-ip:随机端口 2,而对于inbound cluster,此值是127.0.0.6:随机端口 3,此处的 127.0.0.6 对应了【1.2Pod 流量转发-Init Container】中的 iptables 会将来自 127.0.0.6 的流量免于 istio 代理,因为这个流量是从 sidecar 本身发出的。DONSTREAM_LOCAL_ADDRESS下游连接中,当前 envoy 的本地地址。通常来说,对于 outbound cluster,此值是 目的 service-ip:service-port,而 对 于inbound cluster,此 值 是 当 前pod-ip:Pod-port,此处和下游的 upstream_host 应该相对应。DOWNSTREAM_REMOTE_ADDRESS通常来说,对于 outbound cluster,此值是当前 pod-ip:随机端口 ,而对于inbound cluster,此 值 是 下 游 pod-ip:随 机 端 口 2 ,此 处 和 下 游 的upstream_local_address 相对应。5 5)EnvoyEnvoy 配置简读(数据链路)配置简读(数据链路)背景背景全景剖析阿里云容器网络数据链路209还是用官方的示例,以 productpage 访问 reviews 服务来举例。通过 Kubernets 集群资源,我们可一看到 reviews 有三个版本 分贝为 v1,v2,v3,Pod 数量各一个。SVC reviews 是 ClusterIP 模式,svc 端口是 9080,targetport 是pod 的 9080 端口,v1,v2,v3 都被加到了 reviews SVC 的 endpointslice。在未被 istio 注入的情况下,集群内 productpagePod 访问 reviews.istio-inject 服务,会被 netfilter 以 round-robin 的方式平均转发到 v1,v2,v3 三个 pod 上,每个 pod全景剖析阿里云容器网络数据链路210应该承受 1/3 的流量。在传统的 k8s 集群中,是无法通过 k8s 的 resource 控制不同版本的流量分配。但是实际的生产环境,我们是有这方面的需求的。比如 v1 版本是线上业务版本,承载了主要业务流量,v2 版本是开发完毕预上线版本,本质上是不希望影响线上流量的,可能需要引流线上流量的 5%到预发版本进行一段时间观察,来判断新版本是否有问题,之后再进一步扩大引流比例直至 100%之后,v1 版本才进行下线,从而实现从业务角度的平滑迁移。或者比如 v3 是测试版本,我们希望观察流量在网络波动超时情况下,业务的自我容灾和恢复情况的行为是否符合预期,以前这种需求需要通过在业务代码中写好熔断代码,不同熔断环境都需要重新发版。那么像这种流量控制在 ASM Istio 就可以很容易的实现。下面就是一个 ASM Istio 中的 vs 和 dr 的配置。apiVersion:networking.istio.io/v1beta1kind:VirtualServicemetadata:creationTimestamp:2023-01-30T06:25:21Zgeneration:1name:reviewsnamespace:istio-injectresourceVersion:651722274uid:63f715c9-b253-4fbb-8351-5313371df14espec:hosts:-reviews.istio-inject.svc.cluster.localhttp:-name:routeroute:-destination:host:reviewssubset:v1weight:10-destination:host:reviewssubset:v2weight:40-destination:host:reviewssubset:v3weight:50全景剖析阿里云容器网络数据链路211其中在 reviews vs 的定义了集群内访问 reviews.istio-inject.svc.cluster.local 是的http 协议的规则。其中指明了 v1 版本权重 10%,v2 版本权重 40%,v3 版本权重 50%apiVersion:networking.istio.io/v1beta1kind:DestinationRulemetadata:creationTimestamp:2023-01-30T06:28:46Zgeneration:2name:reviewsnamespace:istio-injectresourceVersion:654863578uid:fdbdfcea-1fcd-453e-96fb-ce41c91ded9bspec:host:reviewssubsets:-labels:version:v1name:v1-labels:version:v2name:v2-labels:version:v3name:v3trafficPolicy:connectionPool:http:http2MaxRequests:1000maxRequestsPerConnection:10tcp:maxConnections:100outlierDetection:baseEjectionTime:15mconsecutive5xxErrors:7interval:5mreviews dr 的定义了集群内 reviews 的几个版本,并定义了相关流量策略。其中http2MaxRequests 表明 http 最大的请求数。maxRequestsPerConnection 表明每个连接最大的请求数。tcp 最大连接数是 100。在熔断配置中,每隔 5min 中检测一次,连续 7 次 5xx,把后端移除 endpoint 15min。全景剖析阿里云容器网络数据链路212通过前文我们知道 pilot 通过 xDS 接口将服务网格的配置下发到每个被注入的 pod 中的 istio-proxy 中。那么对于每个 pod 中的 istio-proxy,我们是否有办法去查看相关的加载的配置信息呢?istio-proxy 通过 15000 端口对外暴露管理端口,我们可以通过如图所示的命令获取到相关的配置信息。其中可以通过 curl 127.0.0.1:15000/config_dump 可以获取到完整的配置信息,由于此配置信息超过 1 万多行,我们就不在这里做全部的展示。感兴趣的同学可以自行研究下,下文会针对此 config_dump 信息中的 cluster,Listener,endpoint,route 等关键信息做个相关展示和简要说明,同时也和前文的 xDS做个呼应。kubectlexec-nistio-injectproductpage-v1-797d845774-dndmk-cistio-proxy-it-curl 127.0.0.1:15000/config_dumpBootstrapBootstrapEnvoy 的初始化配置,与前文中的 envoy-rev0.json 是一致的。其中drainDuration 热重启期间 Envoy 关闭连接的时间(以秒为单位),默认是 45s全景剖析阿里云容器网络数据链路213parentShutdownDuration 热重启期间,在完全关闭父进程之前,等到的最大时间,默认 60s。此数值应该大于 drainDuration。terminationDrainDuration 默认 5s。proxy 在关闭之前,允许连接关闭时间。通过前文,我们知道 pod 流量先过 istio 再被转发到业务容器。当应用发版时候,如果保证现有连接优雅关闭,保证 istio-proxy 容器在业务容器完全关闭现有连接后,再退出是发版更新时候需要考虑的问题,此值是实现业务平滑更新需要考虑的。static_resourcesstatic_resourcesconfig_dump 中静态资源,是来自 envoy-rev0.json,里面包含了 prometheus_stats、agent、sds-grpc、xds-grpc 和 zipkin 等配置。全景剖析阿里云容器网络数据链路214dynamic_resourcesdynamic_resources动态资源,是通过 xDS 接口下发到每个 istio-proxy 容器生效的 ASM Istio 的配置。也是上述 reviews dr,vs 配置后通过 ASM 管控侧下发的。我们接下来关注动态资源配置ListenersListenersEnvoy 采用的 listener 来接受到达 Envoy 的流量请求。Listener 和 IP Sock、UnixDomain Socket 绑定,也可以不绑定到具体的端口,而是接收从其他 listener 转发来的流量。ASM Istio 就是利用了 Envoy listener 的这一特性来实现转发给不同的服务请求交给不同的 Listeners 来处理。还是以 productpage 访问 reviews 来举例,productpage 访问的是 reviews 的 9080端口,根据上文我们知道 productpage container 访问 外部的 9080 端口会被先转发到 15001 端口,所以我们先看下 15001 的端口 listeners。全景剖析阿里云容器网络数据链路215VirtualOutboundVirtualOutbound ListenersListenersEnvoy 在 15001 端口创建了 Listeners,所有被 iptables 转发的对外请求都会被转到envoy 的 15001 端口。可以从配置看到,envoy 接受到了流量后,并不会做相关的业务动作,而是根据 use_original_dst:true,这个配置,依据请求的目的端口转发到相应的 listeners 进行处理。全景剖析阿里云容器网络数据链路216那么肯定有个疑问了,如果请求的目的端口并没有配置相关的 listeners 设置,流量该如何进行处理呢?这个取决于 outboundTrafficPolicy 的配置,详情请见https:/istio.io/latest/docs/reference/config/istio.mesh.v1alpha1/#MeshConfig-OutboundTrafficPolicy-ModeNameDescriptionREGISTRY_ONLY只有被注册到服务网格集群内的serviceentry才可以被成功转发出去。如果访问的目的端未被注册到服务网格集群内,请求会被转发到 BlackHoleCLuster,由于找不到匹配的 upstream host,则会被丢弃。ALLOW_ANY无论外部请求是否注册,都可以发送到目的地址。如果目的地址未被 listeners,则会将流量转发到 PassthroughCluster 的 TCPproxy filter,请求将会被发送到原始目的地址。OutboundOutbound ListenersListenersoutbound 监听命名是 0.0.0.0_9080,表明发向任何 IP 地址的 9080 端口都被此监听涵 盖。bind_to_port”:false 此 值 表 明 监 听 没 有 绑 定到 tcp 端 口,流 量 是 有virtualOutbound 转发而来的。那么首先我们需要区别这个监听是为了入方向还是出方向呢?对于入方向,流量会经过15006 端口的 virtualInbound 的 listeners,是不会进入 0.0.0.0_9080 的 listeners。全景剖析阿里云容器网络数据链路217从配置上可以看到 filter 中并没有特殊的志敏筛选条件,说明接受任何流量,其中config_source 为 ads,表明这个是来自动态发现。根据前文可以可看到 revirews,ratings,details 几个 service 都是 9080 端口,这些应用全景剖析阿里云容器网络数据链路218都被同一个服务网格注入,那么 productpage 访问的目的地址的 9080,Envoy 如何刚知道是哪个 service?是如何判断如果目的端口未 9080 的地址不是网格内,该如何处理呢?通过上图route_config_name:9080 可以看到存在一个9080的路由规则,在这个路由规则中规定不同的请求目的地的不同的处理结果,下一小节我们将讨论。RouteRoute前文我们已经知道 productpage 应用访问 reviews 的 9080 端口会被 listenersoutbound 0.0.0.0_9080 路由规则到 9080 的路由。以下是9080 路由的全部信息。我们可以看到一共有 5 个 virtual_hosts,分别是 allow_any、details、productpage、ratings、和 reviews。其中后面 4 个对应 4 个不同 outbound 的 cluster,allow_any对应的是 PassthroughCluster,当出方向请求找到相应的 Cluster 规则时候,会采用默认直接通过。可能有小伙伴很奇怪 productpage 不直接调用 ratings 服务,为什么 productpageenvoy 配置会包含 ratings 的信息。这是因为 ASM Istio 控制面是无法感知到数据面各个服务之间是如何调用的,因此会将所有的配置信息都下发到被注入的 envoy 里面,这样保证了网格配置的一致性,但是随着网格服务配置的增多,每个 envoy 接受和本 envoy 不相关的配置信息就会变多,这样对 envoy 资源使用会有一定影响,如果小伙伴有很好的 envoy 开发能力,并且对业务之间调用非常熟悉,想去除掉本 pod 中 envoy 无关的规则,可以通过 sidecar 规则自定义配置对 egress 和 ingress 进行调整,详情请见:https:/istio.io/latest/docs/reference/config/networking/sidecar/version_info:2023-01-30T06:25:21Z/19,route_config:type: productpage 调用 reviews 来举例,Envoy 会根据 HTTP header 中的 domains 来匹配 VirtualHost 中 domain,所以可以看到 domains 中列举了 reviews的集群内的长短域名,和 svc 的地址。match“/”会路由到三个 cluster outbound|9080|v1|reviews.istio-inject.svc.cluster.local、outbound|9080|v2|reviews.istio-i全景剖析阿里云容器网络数据链路226nject.svc.cluster.local和outbound|9080|v3|reviews.istio-inject.svc.cluster.local,权重分别为 10,40,50,名称是route,看到这里是不是有点熟悉?对的,这和前文 1.3 Envoy 配置简读-背景 中 reviews 的 VS 中的设置,故我们在 vs 中的相关配置信息,最

15人已浏览 2023-03-15 300页 5星级


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有