深度剖析!istio共享代理新模式ambient mesh-4008云顶国际网站
作者:华为云云原生团队 | githubid:@hzxuzhonghu @zirain
今年9月份,istio社区宣布ambient mesh开源,由此引发国内外众多开发者的热烈讨论。实际上,通过与istio toc成员linsun(https://github.com/linsun)的交流,我们得知早在2021年,solo.io已经开始共享代理的研究和设计,同样也是在2021年google内部也在探索共享代理模式。因此,两家公司一拍即合,今年4~5月份开始以协作开发的方式,加速共享代理模式的发展。
目前ambient mesh已经发布预览版本,感兴趣的读者可以按需体验。由于篇幅限制,本文主要针对ambient mesh架构及四层流量治理的流程进行深度剖析,关于七层流量治理的详解,请关注后续文章。
简单来讲,ambient mesh是istio服务网格的一种共享代理的新模式。它是由 google 和 solo.io 联合开发的一种新的数据面模式,旨在简化操作、提升应用兼容性并降低基础设施成本。ambient模式可在放弃引入 sidecar 的情况下,保持 istio 的零信任安全、流量管理和遥测等核心功能。
开始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弹性伸缩策略,不再与应用耦合,提供更加灵活的扩展性并可以在一定程度上提升资源的使用率。
我们知道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_internalcluster选择的是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进行一个概要的总结,我们发现在通信的过程中,实际参加工作的模块并不多:
1. 发送侧的路由、iptables:将流量拦截到ztunnel的15001端口
2. 发送侧ztunnel:两个监听器和对应的两个cluster
3. 接收侧的路由、iptables:将流量拦截到ztunnel的15008端口
4. 接收ztunnel:virtual_inbound监听器及关联的cluster
sidecar是 istio 的特色,利用 sidecar,对应用进行非常小的修改就可以享受服务网格带来的好处,减少运维负担;但是 sidecar 模式也有一些限制:
1. 侵入性:sidecar 容器是以admission webhook的方式来注入,与应用容器属于同一个pod,因此sidecar的升级,必须伴随着业务容器的重建。对应用负载来可能是破坏性的(例如:长连接场景下滚动升级可能造成浪涌)。
2. 资源利用率低:sidecar 与应用一一对应,且必须预留足够的cpu和内存,可能导致整个集群资源利用率偏低;弹性扩缩容只能针对整个工作负载进行,无法单独对 sidecar 进行。
3. 流量中断:流量的捕获和 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的第二选择。
扫描二维码 | 加入云原生技术交流群
- 点赞
- 收藏
- 关注作者
评论(0)