摘要:今年9月份,Istio社区宣布Ambient Mesh开源,由此引发国内外众多开发者的热烈讨论。
本文分享自华为云社区《深度剖析!Istio共享代理新模式Ambient Mesh》,作者:华为云云原生团队。
今年9月份,Istio社区宣布Ambient Mesh开源,由此引发国内外众多开发者的热烈讨论。实际上,通过与Istio TOC成员linsun(https://github.com/linsun)的交流,我们得知早在2021年,http://Solo.io已经开始共享代理的研究和设计,同样也是在2021年Google内部也在探索共享代理模式。因此,两家公司一拍即合,今年4~5月份开始以协作开发的方式,加速共享代理模式的发展。
目前Ambient Mesh已经发布预览版本,感兴趣的读者可以按需体验。由于篇幅限制,本文主要针对Ambient Mesh架构及四层流量治理的流程进行深度剖析,关于七层流量治理的详解,请关注后续文章。
1.Ambient Mesh 是什么
简单来讲,Ambient Mesh是Istio服务网格的一种共享代理的新模式。它是由 Google 和 http://Solo.io 联合开发的一种新的数据面模式,旨在简化操作、提升应用兼容性并降低基础设施成本。Ambient模式可在放弃引入 Sidecar 的情况下,保持 Istio 的零信任安全、流量管理和遥测等核心功能。
2.Ambient Mesh架构分析
开始Ambient的架构之前,我们先简单回顾一下Istio 的架构。其主要由两部分组成,分别是控制面和数据面。控制面Istiod进行基本的配置生成和推送,管理着所有的数据面;数据面引入 Sidecar 代理,接管应用的入口和出口流量。
图1 Istio架构
相比Sidecar,Ambient Mesh提供一种侵入性更低,升级管理更简单的选择。Ambient 将 Istio 的功能分成两个不同的层次,安全覆盖层(四层治理)和 七层 处理层(七层治理):
图2 Ambient mesh分a层
• 安全覆盖层:处理TCP路由、监控指标、访问日志,mTLS 隧道,简单的授权
• 七层处理层:除安全覆盖层的功能外,提供HTTP协议的路由、监控、访问日志、调用链、负载均衡、熔断、限流、重试等流量管理功能以及丰富的七层授权策略
Ambient Mesh下的负载可与 Sidecar 模式下的负载无缝互通,允许用户根据自己的需要来混合搭配使用两种模式。
• 四层治理架构:在 Sidecar 模式下,Istio 通过 InitContainer 或 Istio-CNI 实现流量拦截。Ambient Mesh下 Istio-CNI 是必选组件,下图展示了基本的 Ambient Mesh四层治理架构:
图3 Ambient mesh四层治理架构
Istio-CNI 中,新增 Ambient 的处理模块 ,该模块会监听 Namespace 以及 Pod 的变化,为所在节点的应用设置路由和iptables规则:
• 路由:设置路由表,将本节点应用发出的流量路由到 ztunnel,以及将本节点接收的流量路由到ztunnel。
• iptables:在ztunnel容器中设置iptables规则,将流量透明拦截至 ztunnel 对应的端口上。
ztunnel 是 Ambient 新引入的组件,以 Daemonset 的方式部署在每个节点上。ztunnel 为网格中的应用通信提供 mTLS、遥测、身份验证和 L4授权功能,不执行任何七层协议相关的处理。只有当ztunnel运行在工作负载相同的节点上时,控制面才会将工作负载证书颁发给该 ztunnel。因此 当ztunnel 被攻击时,只有运行在该节点上的负载的证书可能被盗用,安全风险相对可控,这和其他实现良好的节点共享基础设施类似。
• 七层流量治理架构:目前 Ambient Mesh需要通过定义一个 Gateway API 资源显式对某个服务启用七层处理。下图展示了Ambient七层治理的架构:
图4 Ambient mesh七层治理架构
与Ambient四层治理相比,七层治理架构中新增了waypoint组件。Pilot 中新增了waypoint 的处理模块 , 它监听 ServiceAccount、Deployment、Gateway API对象的变化,然后调协相关的 waypoint对象:
• ServiceAccount发生变化时,Pilot会尝试更新当前命名空间下所有的 waypoint
• Deployment发生变化时,通过其OwnerReference 关联的 Gateway对象,触发waypoint的维护
• Gateway发生变化时,更新关联的 waypoint 代理
当前 Ambient创建 waypoint 代理需要依赖类似下面的Gateway API 资源:
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: Gateway
metadata:
name: productpage
annotations:
istio.io/service-account: bookinfo-productpage
spec:
gatewayClassName: istio-mesh
gatewayClassName 值必须设置为 istio-mesh,否则可能会被忽略。每个 ServiceAccount 都有自己专用的 waypoint 代理,这点与 Sidecar 模型非常相似。建议每个服务使用自己单独的身份,避免带来额外的安全风险。
Pilot会将 七层七层 流量规则通过 xDS 更新至 waypoint 代理,实现 七层 相关流量治理能力。waypoint 代理不一定保证与其所服务的工作负载位于同一节点,这似乎会带来一定的性能问题。但是对于 Istio 来说,延迟更多来自于复杂的 七层 处理,预计最终Ambient模式的七层治理延迟与 Sidecar 模式接近。waypoint 代理通过单独Deployment部署,因此可为其单独配置所需要的 CPU、内存,设置相关 的HPA弹性伸缩策略,不再与应用耦合,提供更加灵活的扩展性并可以在一定程度上提升资源的使用率。
3.Ambient Mesh四层流量治理
我们知道ztunnel只能进行四层的流量治理,四层负载均衡以及TLS流量加密、基本的认证和鉴权等,而不能进行更高级的七层路由和认证鉴权。这里我们通过sleep应用访问bookinfo的例子,深入理解Ambient Mesh的四层流量是如何路由的。本例子的实际环境背景如下,sleep和productpage应用分别运行在两个不同的节点。
图5 Ambient mesh四层流量代理流程
• 在sleep容器内访问productpage服务,首先请求被拦截到同节点的ztunnel中,ztunnel做基本的四层负载均衡和TLS加解密,最后选择一个目标实例(productpage容器的IP)将本次请求转发出去。
• 本次请求进入productpage容器所在的节点,首先被拦截到ztunnel, ztunnel负责TLS流量的解密,然后执行用户指定的鉴权策略,最后将请求发往productpage容器。
以上就是Ambient mesh流量转发的一个基本流程,下面我们结合具体的xDS配置深入理解完整的通信流程。
3.1 sleep发送侧流量处理
(1)sleep访问productpage的流量被同节点的tunnel以TPROXY(透明代理)方式拦截转发到ztunnel(监听127.0.0.1:15001),使用TPROXY的好处是保留原始的目的地址,ztunnel做转发时必须依赖原始目的地址。
-A PREROUTING -i pistioout -p tcp -j TPROXY --on-port 15001 --on-ip 127.0.0.1 --tproxy-mark 0x400/0xfff
(2)ztunnel通过"ztunnel_outbound"监听器,监听在15001端口。ztunnel_outbound监听器与Istio Sidecar模式的监听器完全不同,它包含所有本节点上的服务到整个网格其他服务的过滤器链。
图6 ztunnel_outbound监听器
可以看到所有的过滤器链都没有设置匹配条件(默认全部匹配),那么这时ztunnel怎么根据流量特征选择目标过滤器链的呢?原来在监听器根上还有一种设置过滤器匹配条件的方式,通过下面匹配到源地址为10.244.1.4,目的地址为10.96.179.71,目的端口为9080的流量,交由"spiffe://cluster.local/ns/default/sa/sleep_to_http_productpage.default.svc.cluster.local_outbound_internal"过滤器处理,
图7 ztunnel_outbound过滤器链匹配
(3)"spiffe://cluster.local/ns/default/sa/sleep_to_http_productpage.default.svc.cluster.local_outbound_internal"过滤器关联到同名的Cluster。该Cluster一共包含两个Endpoint实例,根据负载均衡算法选择某一个Endpoint,并且最重要的是将metadata(tunnel的destination和address)传递给名为"outbound_tunnel_lis_spiffe://cluster.local/ns/default/sa/bookinfo-productpage" 的监听器处理。
图8 outbound_internal内部Cluster配置
图9 outbound_internal内部Cluster Endpoint
(4)“outbound_tunnel_lis_spiffe://cluster.local/ns/default/sa/sleep”监听器通过“set_dst_address”过滤器根据上一步的选择的Endpoint的metadata设置数据的目的地址。假如前面outbound_internal Cluster选择的是10.244.2.8:9080这个Endpoint,那么这里的tunnel监听器将把10.244.2.8:15008设置为目的地址。另外该监听器,只有一个TcpProxy,关联到名为“outbound_tunnel_clus_spiffe://cluster.local/ns/default/sa/ sleep”的Cluster,那么流量自然交由该Cluster处理。TCP过滤器上还设置了HTTP Connect隧道(承载发送到10.244.2.8:9080的流量),供后面productpage所在节点的ztunnel使用。HTTP隧道是Ambient Mesh 组件之间安全通信的承载协议。
图10 outbound_tunnel监听器配置
outbound_tunnel Cluster的类型为“ORIGINAL_DST”,并且配置有UpstreamTlsContext, 因此它负责流量TLS加密,然后直接发送到目的地址,即10.244.2.8:15008。
图11 outbound_tunnel cluster配置
3.2 productpage接收侧流量处理
(1)sleep访问productpage的流量(目的地址是“10.244.2.8:15008”)到达productpage所在的节点,以TPROXY(透明代理)方式被拦截到ztunnel(监听127.0.0.1:15008),使用TPROXY的好处是保留原始的目的地址,ztunnel做转发时必须依赖原始目的地址。
10.244.2.8 via 192.168.126.2 dev istioin table 100 src 10.244.2.1
-A PREROUTING -i pistioin -p tcp -m tcp --dport 15008 -j TPROXY --on-port 15008 --on-ip 127.0.0.1 --tproxy-mark 0x400/0xfff
(2)ztunnel上面“ztunnel_inbound”监听器监听在15008端口,因此流量首先经过ztunnel_inbound监听器的处理。ztunnel_inbound监听器上面设置了TLS,根据其配置与下游进行TLS握手,从而所有的ztunnel之间基于双向TLS加密通信。另外,从下面配置中可以看到,CONNECT 升级已经设置,那么Envoy就会代理HTTP的Connect请求。除此之外,RouteMatch中设置了connectMatcher,意味着将HTTP Connect请求交由“virtual_inbound”Cluster处理。
图12 ztunnel_inbound监听器配置
(3)virtual_inbound Cluster类型为ORIGINAL_DST,并且设置使用x-envoy-original-dst-host HTTP Header重写原始目的地址,而此Header恰恰由发送侧的“outbound_tunnel_lis_spiffe://cluster.local/ns/default/sa/sleep”监听器设置,值为10.244.2.8:9080。因此本次请求通过virtual_inbound最终成功发送给productpage容器。
图13 virtual_inbound cluster配置
3.3 Ambient Mesh四层流量治理小结
图14 完整的服务访问四层代理
sleep访问productpage的实例中,虽然我们使用的是HTTP协议,但是从Ambient所有的组件视角来看,其代理的为TCP流量。前面我们深入分析了ztunnel中每一个监听器、每一个Cluster的工作原理,看起来可能会很复杂。故在此通过图14进行一个概要的总结,我们发现在通信的过程中,实际参加工作的模块并不多:
- 发送侧的路由、iptables:将流量拦截到ztunnel的15001端口
- 发送侧ztunnel:两个监听器和对应的两个cluster
- 接收侧的路由、iptables:将流量拦截到ztunnel的15008端口
- 接收ztunnel:virtual_inbound监听器及关联的cluster
4. 未来展望
Sidecar是 Istio 的特色,利用 Sidecar,对应用进行非常小的修改就可以享受服务网格带来的好处,减少运维负担;但是 Sidecar 模式也有一些限制:
- 侵入性:Sidecar 容器是以Admission Webhook的方式来注入,与应用容器属于同一个Pod,因此Sidecar的升级,必须伴随着业务容器的重建。对应用负载来可能是破坏性的(例如:长连接场景下滚动升级可能造成浪涌)。
- 资源利用率低:Sidecar 与应用一一对应,且必须预留足够的CPU和内存,可能导致整个集群资源利用率偏低;弹性扩缩容只能针对整个工作负载进行,无法单独对 Sidecar 进行。
- 流量中断:流量的捕获和 HTTP 处理由 Sidecar 完成,成本高且可能破坏一些不兼容 HTTP 的实现。
当前 Ambient Mesh已经较好地解决了 Sidecar 模式下应用和 Sidecar 的部署依赖问题,不再需要注入Sidecar;服务网格的能力是通过 ztunnel 和 waypoint proxy 提供的,应用和网格组件的部署和升级不再相互依赖。
另外,Ambient共享模式可以大大减少网格组件本身的资源开销,这一点对资源敏感的用户来说是一个巨大的福音。
Ambient仍然处于预览状态,许多特性仍然在开发中,在官方文档中已经列出不少限制,此外,社区用户在使用过程中也有新的发现:
• 不支持IPV6
• 与Calico CNI不兼容,因为Ambient创建的iptables与Calico冲突。
同时,目前基于 envoy 的 ztunnel 在 xDS 效率、多租户、遥测方面可能存在性能问题,未来可能会基于rust重写一个更加轻量、高性能的ztunnel。
长期来看,Sidecar模式依然会是Istio的主流模式。Ambient共享模式为Istio社区或者服务网格业界带来了足够的刺激,相信基于社区所有开发者的共同努力,Ambient共享模式将会成为Istio的第二选择。