全景剖析阿里云容器网络数据链路(六):ASM Istio
本系列文章由余凯执笔创作,联合作者:阿里云容器服务 谢石 对本文亦有贡献
近几年,企业基础设施云原生化的趋势越来越明显,从最开始的 IaaS 化到现在的微服务化,客户的颗粒度精细化和可观测性的需求也更加强烈。容器网络为了满足客户更高性能和更高密度的需求,也一直在高速的发展和演进中,这必然给客户对云原生网络的可观测性带来了极高的门槛和挑战。为了提高云原生网络的可观测性,同时便于客户和前后线同学增加对业务链路的可读性,ACK 产研和 AES 联合共建,合作开发了 ack net-exporter 和云原生网络数据面可观测性系列,帮助客户和前后线同学了解云原生网络架构体系,简化对云原生网络的可观测性的门槛,优化客户运维和售后同学处理疑难问题的体验 ,提高云原生网络的链路的稳定性。
△ 服务网格示例
△ Istio 数据面示意图
Kubernetes 的横空出现打破了底层服务器、底层网络等计算资源的界限,给业务的灵活部署、快速恢复、弹性伸缩、资源效率最大化带来了无限可能。但是业务场景的‘贪婪’是无限的,随着微服务趋势大肆发展,业务上对于同一个 service,不同版本和流量控制有着更精细化的颗粒度的需求,最好能实现 Pod 维度的流量控制,可观测性等等。这些在 Kubernetes 上是无法实现的:
从流量角度,K8s 最小的控制维度是 service, 其他比如金丝雀等发布,借助各种 ingress controller 或者其他组件实现,并且这些也无法实现 Pod 之间的流量和连接状态的可观测性。
K8s 给服务微型化,小型化创造了条件, 如果前后端服务存在调用关心,他们如果使用共享通信库,则会在开发阶段就要求所有微服务使用相同的逻辑语言和堆栈,这从某种程度上又大大限制微服务的独立化,无法实现完全的‘漠不关心’
将原来集成在同一个 ECS 上的服务拆分成不同的模块,这些模块之间调用涉及跨 ECS 等,那么必然需要在代码开发阶段需要考虑超时,重试,连接失败等逻辑机制,而这些与微服务最核心的服务应用其实没有太大关系,但是开发工作往往耗费大量的经历在逻辑设计上。
那么,有没有办法实现上述和微服务的业务完全隔离呢?Istio 的出现给这个带来了相对完美的解决方案,让应用这和开发者更加关注业务本身的开发迭代。Istio 利用了 K8s 的 Pod 概念,会根据使用者的配置,在每个被注入的 Pod 部署时,自动注入 istio-proxy 容器和 initial 容器。initial 容器的目的是通过修改 Pod 单独网络命名空间的 iptables 规则,让需要代理的流量进入到 istio-proxy 监听的端口, istio-proxy 监听出入 两个端口,根据网格配置,来实现对出入流量的代理实现和干预。而被同一个 istio 注入的载体,都被视为同一个服务网格之内,他们之间的调用已经脱离了 service 的层面,会命中相关的 istio cluster 配置的 endpoint,这样我们就可以实现 Pod 维度的流量管理、观测性、安全性等配置。
本文是[全景剖析容器网络数据链路]第六部分,主要介绍 ASM Istio 模式下,数据面链路的转发链路,一是通过了解不同场景下的数据面转发链路,从而探知客户在不同的场景下访问结果表现的原因,帮助客户进一步优化业务架构;另一方面,通过深入了解转发链路,在遇到容器网络抖动时候,客户运维以及阿里云同学可以知道在哪些链路点进行部署观测手动,从而进一步定界问题方向和原因。
系列一:全景剖析阿里云容器网络数据链路(一):Flannel
系列二:全景剖析阿里云容器网络数据链路(二):Terway ENI
系列三:全景剖析阿里云容器网络数据链路(三):Terway ENIIP
系列四:全景剖析阿里云容器网络数据链路(四):Terway IPVLAN+EBPF
系列五:全景剖析阿里云容器网络数据链路(五):Terway ENI-Trunking
ASM Istio 流量代理
1.1 Pod 注入
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 已经实现了注入配置的可视化操作,具体请见**多种方式灵活开启自动注入 [ 1] **。
1.2 Pod 流量转发
通过 describe 被注入的 Pod, 可以发现 Pod 中除了设置好的业务 container,还多出两个容器:istio-proxy 和 init container:istio-init。这两个容器的镜像是一样的,只是运行的命令的不一样,这样的好处是只需要拉取一份镜像,节省了拉取镜像的时间。
Init Container
Init container 利用的是 K8s 的特性,一种具有特权的特殊容器,在 Pod 内的应用容器启动之前运行。Init 容器可以包括一些应用镜像中不存在的实用工具和安装脚本。每个 Pod 中可以包含多个容器和多个 Init 容器。他与普通容器很像,但是有自己独特点:
多个 init 容器是串行运行的。也就是说多个 init 容器会依序运行,等上一个 init 容器运行完毕结束后,才会开始运行下一个容器。
只有等到所有的 init 容器全部运行结束退出后,业务容器才开始启动,在这之前,pod 不会处于 ready。
如果 Pod 的 Init 容器失败,kubelet 根据 pod 设置的 restartPolicy 进行相应的 action。
既然现在了解了 Init container 的作用,那我们来看一下 istio-init 在启动的过程中做了哪些事情,可以通过下面的命令:
kubectl logs -n istio-inject productpage-v1-797d845774-dndmk -c istio-init
可以看到 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: 重定向入站端口中排除的端口列表
我们从 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 之间,流量会按照设置好的 istio 规则进行处理。
出方向流量转发
根据上文的 iptables 规则,我们可以归纳出被入方向代理转发的端口,比如 80 等,在 Pod 的网络命名空间 netfilter 模块经过流程是 APP > OUTPUT -> ISTIO_OUTPUT -> ISTIO_REDIRECT -> Envoy 15001(Outbound)-> OUTPUT -> ISTIO_OUTPUT -> POSTROUTING -> DST。这样就实现了出方向流量先被转发到 sidecar 容器后,在转发到目的监听端口。其中在步骤 d 和 e 之间,流量会按照设置好的 istio 规则进行处理。
入方向流量免转发
对于入方向的某些端口或者自定义端口,我们不需要它经过 sidecar 容器,iptables 规则会设置将符合条件的入方向流量避免转发到 15006 端口,直接转发到业务容器监听端口 RREROUTING -> ISTIO_INBOUND -> INPUT -> APP。
出方向流量免转发
对于出方向的某些端口或者自定义端口,我们不需要它经过 sidecar 容器,iptables 规则会设置将符合条件的入方向流量避免转发到 15001 端口,直接离开 Pod 的网络命名空间 APP -> OUTPUT -> ISTIO_OUTPUT -> POSTROUTING -> DST。
Istio-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://help.aliyun.com/document_detail/464794.html
在 TPROXY 模式下,Pod 的网络命名空间的 iptables 会有 mangle 配置。
ADS 聚合服务发现
我们已经知道了服务网格会在每个注入的 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_protocol
envoy-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 版本、必要端口等相关信息。
admin
istio-proxy 相关日志,管理端口等信息
dynamic_resources
ADS 相关配置信息,比如 api 协议,版本,超时时间等
static_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 服务器调用地址。
tracing
分布式链路跟踪,这里的 collector_cluster 是前面 static_resources 里面定义的 zipkin cluster。
访问日志分析
通过前文,我们已经知道两个互相被注入的 pod 访问,流量会被各自的 istio-proxy 所劫持并处理,那么只要分析客户端和服务端的 istio-proxy 日志并进行加工,就可以对流量进行可观测性解读。我们在这里还是以官方例子来举例。访问 http://<gatewayIP>/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 日志
请求接受方 details-v1-6758dd9d8d-dtbdc 的 istio-proxy 日志
日志内容解读
"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",
"protocol":"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/usage
UPSTREAM_HOST
上游主机的 host,表示从 envoy 发出的请求的目的端
通常来说,对于 outbound cluster,此值是「上游 pod-ip : pod-port」 ,而对于 inbound cluster,此值是「本 pod-ip : pod-port」
UPSTREAM_LOCAL_ADDRESS
上游连接中,当前 envoy 的本地地址
通常来说,对于 outbound cluster,此值是「本 pod-ip : 随机端口 2」 ,而对于 inbound cluster,此值是「127.0.0.6: 随机端口 3」,此处的 127.0.0.6 对应了 【1.2 Pod 流量转发-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 相对应
1.3 Envoy 配置简读(数据链路)
背景
还是用官方的示例, 以 productpage 访问 reviews 服务来举例。
通过 Kubernetes 集群资源,我们可一看到 reviews 有三个版本分别为 v1,v2,v3, pod 数量各一个。SVC reviews 是 ClusterIP 模式,svc 端口是 9080, targetport 是 pod 的 9080 端口,v1,v2,v3 都被加到了 reviews SVC 的 endpointslice。在未被 istio 注入的情况下, 集群内 productpage pod 访问 reviews.istio-inject 服务, 会被 netfilter 以 round-robin 的方式平均转发到 v1,v2,v3 三个 pod 上, 每个 pod 应该承受 1/3 的流量。
在传统的 K8s 集群中,是无法通过 K8s 的 resource 控制不同版本的流量分配的。但是实际的生产环境,我们是有这方面的需求的。比如 v1 版本是线上业务版本,承载了主要业务流量, v2 版本是开发完毕预上线版本, 本质上是不希望影响线上流量的,可能需要引流线上流量的 5%到预发版本进行一段时间的观察,来判断新版本是否有问题,之后再进一步扩大引流比例至 100%之后,v1 版本才下线,从而实现业务角度的平滑迁移。或者比如 v3 是测试版本,我们希望观察流量在网络波动超时情况下,业务的自我容灾和恢复情况的行为是否符合预期,以前这种需求需要通过在业务代码中写好熔断代码,不同熔断环境都需要重新发版,那么像这种流量控制在 ASM Istio 就可以很容易的实现。
下面就是一个 ASM Istio 中的 vs 和 dr 的配置。
其中在 reviews vs 的定义了集群内访问 reviews.istio-inject.svc.cluster.local 是的 http 协议的规则。其中指明了 v1 版本权重 10%,v2 版本权重 40%,v3 版本权重 50%
reviews dr 的定义了集群内 reviews 的几个版本,并定义了相关流量策略。其中 http2MaxRequests 表明 http 最大的请求数。maxRequestsPerConnection 表明每个连接最大的请求数。tcp 最大连接数是 100。在熔断配置中,每隔 5min 中检测一次,连续 7 次 5xx,把后端移除 endpoint 15min。
通过前文我们知道 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 做个呼应。
Bootstrap
Envoy 的初始化配置,与前文中的 envoy-rev0.json 是一致的。其中 drainDuration —— 热重启期间 Envoy 关闭连接的时间(以秒为单位),默认是 45s。
parentShutdownDuration —— 热重启期间,在完全关闭父进程之前,等到的最大时间,默认 60s。此数值应该大于 drainDuration。
terminationDrainDuration —— 默认 5s。proxy 在关闭之前,允许连接关闭时间。通过前文,我们知道 pod 流量先过 istio 再被转发到业务容器。当应用发版时候,如果保证现有连接优雅关闭,保证 istio-proxy 容器在业务容器完全关闭现有连接后,再退出是发版更新时候需要考虑的问题,此值是实现业务平滑更新需要考虑的。
static_resources
config_dump 中静态资源,是来自 envoy-rev0.json, 里面包含了 prometheus_stats、agent、sds-grpc、xds-grpc 和 zipkin 等配置
dynamic_resources
动态资源,是通过 xDS 接口下发到每个 istio-proxy 容器生效的 ASM Istio 的配置。也是上述 reviews dr,vs 配置后通过 ASM 管控侧下发的。我们接下来关注动态资源配置
Listeners
Envoy 采用的 listener 来接受到达 Envoy 的流量请求。Listener 和 IP Sock、Unix Domain Socket 绑定,也可以不绑定到具体的端口,而是接收从其他 listener 转发来的流量。ASM Istio 就是利用了 Envoy listener 的这一特性来实现转发给不同的服务请求交给不同的 Listeners 来处理。
还是以 productpage 访问 reviews 来举例, productpage 访问的是 reviews 的 9080 端口,根据上文我们知道 productpage container 访问外部的 9080 端口会被先转发到 15001 端口,所以我们先看下 15001 的端口 listeners。
VirtualOutbound
Envoy 在 15001 端口创建了 Listeners,所有被 iptables 转发的对外请求都会被转到 envoy 的 15001 端口。可以从配置看到,envoy 接受到了流量后,并不会做相关的业务动作,而是根据 "use_original_dst": true, 这个配置,依据请求的目的端口转发到相应的 listeners 进行处理。
那么肯定有个疑问了,如果请求的目的端口并没有配置相关的 listeners 设置,流量该如何进行处理呢?这个取决于 outboundTrafficPolicy 的配置,详情请见:
Outbound
outbound 监听命名是 0.0.0.0_9080, 表明发向任何 IP 地址的 9080 端口都被此监听涵盖。"bind_to_port”: false 此值表明监听没有绑定到 tcp 端口,流量是有 virtualOutbound 转发而来的。那么首先我们需要区别这个监听是为了入方向还是出方向呢?对于入方向,流量会经过 15006 端口的 virtualInbound 的 listeners,是不会进入 0.0.0.0_9080 的 listeners。
从配置上可以看到 filter 中并没有特殊的志敏筛选条件,说明接受任何流量,其中 config_source 为 ads,表明这个是来自动态发现。
根据前文可以可看到 revirews,ratings,details 几个 service 都是 9080 端口,这些应用都被同一个服务网格注入,那么 productpage 访问的目的地址的 9080,Envoy 如何刚知道是哪个 service?是如何判断如果目的端口未 9080 的地址不是网格内,该如何处理呢?通过上图"route_config_name": "9080" 可以看到存在一个‘9080’的路由规则,在这个路由规则中规定不同的请求目的地的不同的处理结果,下一小节我们将讨论。
Route
前文我们已经知道 productpage 应用访问 reviews 的 9080 端口会被 listeners outbound 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 服务,为什么 productpage envoy 配置会包含 ratings 的信息。这是因为 ASM Istio 控制面是无法感知到数据面各个服务之间是如何调用的,因此会将所有的配置信息都下发到被注入的 envoy 里面,这样保证了网格配置的一致性,但是随着网格服务配置的增多,每个 envoy 接受和本 envoy 不相关的配置信息就会变多,这样对 envoy 资源使用会有一定影响,如果小伙伴有很好的 envoy 开发能力,并且对业务之间调用非常熟悉,想去除掉本 pod 中 envoy 无关的规则,可以通过 sidecar 规则自定义配置对 egress 和 ingress 进行调整,详情请见:
https://istio.io/latest/docs/reference/config/networking/sidecar/
我们还是以 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-inject.svc.cluster.local"和"outbound|9080|v3|reviews.istio-inject.svc.cluster.local",权重分别为 10,40,50,名称是‘route’,看到这里是不是有点熟悉?对的,这和前文 [1.3 Envoy 配置简读-背景]中 reviews 的 VS 中的设置,故我们在 vs 中的相关配置信息,最终 envoy 会转为 route 的配置加载后生效。
通过前面我们还可以看到默认超时是 0s,默认重试次数是 2 次,重试条件是"connect-failure,refused-stream,unavailable,cancelled,retriable-status-codes"。
Cluster
outbound cluster
根据上一下小节,productpage 访问 reviews,会被 productpage 中的 istio-proxy 匹配到‘9080’路由-> 依据 vs 配置的相关信息,进入三个 cluster( "outbound|9080|v1|reviews.istio-inject.svc.cluster.local"、"outbound|9080|v2|reviews.istio-inject.svc.cluster.local"和"outbound|9080|v3|reviews.istio-inject.svc.cluster.local")中一个。这里我们就以"outbound|9080|v1|reviews.istio-inject.svc.cluster.local"cluster 为例
outbound|9080|v1|reviews.istio-inject.svc.cluster.local cluster 配置中可以看到,其类型为 EDS,即表示该 Cluster 的 endpoint 来自于动态发现,动态发现中 eds_config 则表明是由 ads 下发的。同样可以看到与前文[1.3 Envoy 配置简读-背景]中 reviews 的 dr 中的设置熟悉的配置,比如 connectionpool,outlierDetection 等这些相关配置信息,最终 envoy 会转为 cluster 的配置加载后生效。
接下来我们稍微探讨下其他几个特殊的 cluster。
BlackHoleCluster
Envoy 对于找不到后端处理请求的会默认丢弃,所以会有统一的一个 blackholecluster,没有任何指明的后端 svc,任何无匹配后端的流量会被转发到这个 cluster。
PassthroughCluster
和 BlackHoleCluter 正好相反,发向 PassthroughCluster 的请求会被直接发送到器请求连接中的原始目地的,type 类型是"type": "ORIGINAL_DST",表明其发到原始的目的地址:端口
Inbound Cluster
inbound Cluster 是为了 pod 上的入方向的请求,对于 reviews 来说,其对应的 Inbound Cluster 只有一个 inbound|9080。
Endpoint
从 endpoint 文件内容可以看到,reviews cluster “outbound|9080|v1|reviews.istio-inject.svc.cluster.local”只有 1 个 endpoint 地址,是 reviews-v1-74fb8fdbd8-qwsjq 的 pod ip 10.0.3.29。
至此,我们大概梳理完毕服务网格内两个服务之间访问,istio-proxy 日志解读和配置对应关系。
Tips
前文的 config_dump 文件太长,解读起来其实比较费力,服务网格提供了 asmctl 工具可以很方便的去解读 listeners,route,cluster,endpoint 等,详细信息请见:
https://help.aliyun.com/document_detail/313187.html
企业拥抱容器化总结
本篇文章主要聚焦在 ASM Istio 服务网格模式下,被注入 pod 的数据面流量转发链路情况。istio 灵活注入实现了在 Pod 维度对流量的定制化配置和观测性,带来了业务链路角度实现的更多种的可能。在服务网格中配置 gateway,virtualservice,destinationrule 等规则在通过 xDS 下发到 envoy 后,会通过 listeners, route、cluster、endpoint 等一个环节一个环节最终体现在流量转发规则上。那么在运用 ASM 遇到不符合预期情况时,这些环节都是需要考虑的方向。ASM 除了流量管理,还有安全,鉴权,可观测方面的便捷运用,这些方面的配置,最终也会体现在相关的网格服务资源配置上,感兴趣的小伙伴可以参考**ASM 官方文档 [ 2] **。
参考链接
https://istio.io/latest/docs/reference/config/networking/sidecar/
https://www.envoyproxy.io/docs/envoy/latest/configuration/observability/access_log/usage
[1] 多种方式灵活开启自动注入
https://help.aliyun.com/document_detail/186136.html
[2] 官方文档
版权声明: 本文为 InfoQ 作者【阿里巴巴中间件】的原创文章。
原文链接:【http://xie.infoq.cn/article/0f4456f13675cae563f771b6f】。文章转载请联系作者。
评论