译者注:本文译自 Istio Ambient Waypoint Proxy Deployment Model Explained[1],作者 Lin Sun。Istio Ambient Waypoint Proxy 为服务网格的 L7 处理提供了灵活且高效的解决方案。通过了解不同的部署模式,团队可以根据自身需求选择最合适的架构,避免资源浪费和性能瓶颈。避免按节点部署 waypoint proxy,有助于降低故障域的影响,提升应用的稳定性和性能。正确地部署和配置 waypoint proxy,将有助于充分发挥 Istio Ambient 模式的优势,实现高效、安全的服务通信。阅读原文请转到:https://jimmysong.io/trans/istio-ambient-waypoint-proxy-deployment-model-explained/
本文阐述了 Istio Ambient Waypoint Proxy 的多种部署模式,解释了按节点部署的弊端,并通过实例说明了最佳实践。
Ambient 模式是 Istio 在 2022 年引入的新型无边车数据平面,并于今年 5 月达到 Beta[2] 状态。Istio 社区正努力在下一个 Istio v1.24 版本中将 Ambient 推向 GA(一般可用)状态。Ambient 将 Istio 的功能分为两个独立的层:安全覆盖层和第 7 层处理层。在与许多试用 Ambient 的用户合作时,我想澄清关于 waypoint proxy 的一些常见问题和困惑。它是一个可选的基于 Envoy 的组件,负责处理其管理的工作负载的 L7 事务。
Waypoint Proxy 的常见部署模式是什么?
理解 Waypoint Proxy
你可以将 waypoint proxy 简单地视为一组目的地的网关,这些目的地可以是来自一个或多个命名空间的一个或多个服务和工作负载。除了处理集群内部的 L7 流量外,它与你的入口或出口网关没有太大区别。这也是为什么在部署 waypoint proxy 时需要使用 Kubernetes 的 Gateway 资源的原因。
我非常喜欢 waypoint 架构的灵活性,你可以选择适合自己需求的架构。以下是一些常见的模式:
A: 针对命名空间的 Waypoint Proxy
最常见的模式是,每个团队在集群中拥有一个命名空间,并管理该命名空间内的服务和部署。在这种模式下,我们期望每个团队都有自己的 waypoint proxy,供命名空间内的服务使用。按照这种模式,我们将默认的 waypoint 部署设计为命名空间范围,供命名空间内的所有服务使用。在下图中,服务 A、B、C 位于同一命名空间内。所有到服务 A、B 或 C 的 Ambient Mesh 客户端流量将通过命名空间的 waypoint proxy,由客户端的 ztunnel 进行编程。
注意:为简洁起见,省略了目的地端的 ztunnel
B: 针对部分服务的 Waypoint Proxy
如果你不希望到服务 B 的流量经过 waypoint proxy 怎么办?一个常见的原因是,你只需要对服务 B 的流量进行 L4 层的控制,这样在调用它时就不需要通过 waypoint proxy。例如,你有一个调用 MySQL 数据库服务的 Web 服务,只需要对其进行 L4 控制。另一个例子是,当服务是 “内部” 的,只被命名空间内的其他服务调用,你只需要对跨命名空间边界的服务进行授权策略。例如,在著名的 Bookinfo 应用程序 [3] 中,你可以为 productpage 服务启用零信任,拒绝除端口 9080 上 GET 方法的流量之外的所有流量。对于所有内部服务,如 reviews 或 details 服务,你可以继续允许命名空间内的所有流量。
另一个用例是,服务 A 的流量非常大,你希望有一个专用的 waypoint proxy 来处理其 L7 处理,以便调整资源配置来应对高负载。你可以配置服务 B 或 C 使用不同的 waypoint,避免受到服务 A 的影响,或根据需要跳过它。我们将在下面的部分中详细讨论这一点。
C: 多个命名空间共享一个 Waypoint Proxy
你也可以通过为命名空间添加 istio.io/use-waypoint
标签,并在 Gateway 资源中配置 allowRoutes
,来让多个命名空间共享一个 waypoint proxy。如果你运行的是小型集群,想要优化资源效率,并且对嘈杂邻居问题不太担心,你可能希望为整个集群使用一个 waypoint proxy。这种情况下的一个常见例子是所谓的 K8S-at-the-edge[4]。
“当应用程序跨越太多命名空间时,使用 waypoint 为多个命名空间服务更具资源效率,通过提升无边车服务网格的概念,并在不同的命名空间中使用集中式的 L7 功能,而不影响性能和应用可用性”,Ahmad Al-Masry[5],DevSecOps 工程经理说道。
另一个例子是,一个团队拥有几个组成单一信任域的命名空间,你希望通过共享一个 waypoint proxy 来降低资源成本。在下图中,ns-1 和 ns-2 命名空间中的所有服务都使用部署在 ns-1 命名空间中的 waypoint proxy:
由于 ns-2 与 ns-1 共享相同的 waypoint proxy,任何在 ns-1 中部署并附加到整个 waypoint 的策略都会影响两个命名空间。例如,如果你部署了一个附加到整个 waypoint 的 AuthorizationPolicy
,该策略将在两个命名空间中的所有服务上由 waypoint 执行。
为什么不简单地为每个节点部署一个 Waypoint Proxy?
虽然将 waypoint proxy 配置为上述不同目的地范围的网关非常好,但你可能会想,为什么不保持简单,为每个节点部署一个 waypoint proxy 作为 Kubernetes DaemonSet[6] 来处理该节点的所有 L7 处理呢?
Waypoint proxy 需要高度可配置,因为应用程序可能有完全不同的性能要求和运行时自定义。例如,你可以插入针对特定服务的外部授权策略或 WASM 扩展。一个租户的错误 Envoy 配置可能会导致节点代理崩溃,影响该节点上的所有工作负载。
此外,需要在 waypoint proxy 上有大量处理的嘈杂邻居可能会导致另一个应用程序性能不佳,仅仅因为该应用程序也部署在同一节点上。通过为 waypoint proxy 每个节点部署 Envoy,实际上是强制节点上的所有应用程序共享相同的故障域,而不管它们的应用延迟或运行时要求。Envoy 没有租户控制,你无法划分其 CPU 或内存来防止嘈杂邻居抢占其他应用程序。具有复杂 L7 策略的高流量应用程序将需要更多的 CPU 和 waypoint 的内存。Kubernetes DaemonSet 的资源预留是固定的,无法在不增加所有 waypoint pod 的 CPU 和内存的情况下,根据流量负载水平水平或垂直扩展特定的 DaemonSet pod。成本分摊在此模型中也很困难,你无法正确地将 waypoint 引起的资源成本归因于每个租户。
让我们通过一个具体的例子来说明。我在两个命名空间中部署了 Bookinfo 应用程序,每个命名空间都有其默认配置的命名空间 waypoint。我将每个命名空间的 waypoint proxy 配置为与各自的 productpage
pod 共置。在每个命名空间中,我部署了一个简单的 L7 AuthorizationPolicy
,只允许特定命名空间执行 GET 方法:
注意:为简洁起见,省略了源和目的地端的 ztunnel
当我从 Fortio 向第一个命名空间的 productpage 服务发送 6500 RPS 的请求,并在 3 秒后向第二个命名空间的 productpage 服务发送相同的请求时,平均响应时间分别为 30.8ms 和 30.4ms,如下图所示:
命名空间 1:通过其 waypoint 向第一个命名空间的 productpage 服务发送 6500 QPS,650 个连接的 Fortio 测试
命名空间 2:通过其 waypoint 向第二个命名空间的 productpage 服务发送 6500 QPS,650 个连接的 Fortio 测试
由于两个 Bookinfo 应用程序都有非常大的负载,每个应用程序都有自己的 waypoint proxy 是合理的,这样它们不会相互争抢资源。那么,如果 waypoint proxy 改为按节点部署会怎样?
我可以手动将 waypoint proxy 作为 DaemonSet 部署,使用非常复杂的 Envoy 配置。在运行两个 productpage pod 的节点上,waypoint proxy pod 将被两个 productpage pod 使用。然而,这需要深入了解 Envoy 配置,这方面我并不擅长。一种简单的测试方法是,将两个命名空间配置为使用相同的 waypoint proxy,这对于不需要非常高负载或专用 waypoint proxy 的应用程序是推荐的(参见前面的模式 C 了解更多信息)。注意:对于这种情况,我不推荐模式 C,因为两个 Bookinfo 应用程序的负载非常大。
在确保 ns-1 命名空间中的 waypoint proxy pod 也部署在与两个 productpage pod 相同的节点上后,我进行了一个简单的更改,将两个命名空间都配置为使用 ns-1 命名空间中的 waypoint proxy。这使我能够快速测试一个 waypoint proxy pod,被部署在同一节点上的两个 productpage pod 使用,就像我将 waypoint 作为 DaemonSet 部署一样。
当我从 Fortio 负载客户端向第一个命名空间的 productpage 服务发送 6500 RPS 时,平均响应时间从 30ms 增加到了 59ms!在 3 秒后向第二个命名空间的 productpage 发送相同的负载(基本上重复之前的测试,但这次使用共享的 waypoint),它报告了 32% 的错误,从之前的 0% 增加了!当它们共享同一节点上的同一个 waypoint proxy 时,对两者的影响有多大!由于两个应用程序在高负载下都变得非常嘈杂,waypoint proxy 达到了其默认的 CPU 限制(2 核)和 上游连接限制 [7](1024),因此许多稍后开始的来自第二个命名空间的请求以高比例的错误失败。Kubernetes 工作节点仍然有充足的 CPU,在峰值时有约 50% 的 CPU 和 6% 的内存利用率。
命名空间 1:通过共享的 waypoint 向第一个命名空间的 productpage 服务发送 6500 QPS,650 个连接的 Fortio 测试
命名空间 2:通过共享的 waypoint 向第二个命名空间的 productpage 服务发送 6500 QPS,650 个连接的 Fortio 测试
这个实验表明,在节点上使用相同的 waypoint proxy 共享相同的故障域,可能很容易在嘈杂的邻居下触发故障场景,而这些可以通过为非常繁忙的租户提供专用的 waypoint 来避免。虽然在测试中使用了非常嘈杂的邻居,但也可能是错误的 Envoy 配置或特定的 Envoy 扩展,在多个租户共享相同的故障域时触发类似的问题。
引用链接
[1]
Istio Ambient Waypoint Proxy Deployment Model Explained: https://www.solo.io/blog/istio-ambient-waypoint-proxy-deployment-model-explained/[2]
Beta: https://istio.io/latest/blog/2024/ambient-reaches-beta/[3]
Bookinfo 应用程序: https://istio.io/latest/docs/examples/bookinfo/[4]
K8S-at-the-edge: https://events.linuxfoundation.org/kubecon-cloudnativecon-europe/co-located-events/kubernetes-on-edge-day/#about[5]
Ahmad Al-Masry: https://www.linkedin.com/in/ahmad-al-masry-9ab90858/[6]
DaemonSet: https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/[7]
上游连接限制: https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/cluster/v3/circuit_breaker.proto#envoy-v3-api-field-config-cluster-v3-circuitbreakers-thresholds-max-connections
获取更多云原生社区资讯,加入微信群,请加入云原生社区,点击阅读原文了解更多。