eBPF、sidecars 和服务网格的未来
首页>>云原生>>正文

目录

eBPF 最近很火热,因为可以为云原生世界提供很多东西。由于 Cilium 之类的项目,它一直是 Kubernetes 集群的 CNI 层的流行选择。Linkerd 等服务网格通常与 Cilium 等 CNI 层一起部署,将 Linkerd 强大的 L7 处理与 Cilium 超快的 L3/4 处理相结合。
但是,eBPF 的网络技术到底有多强大?例如,它能否让我们完全替换 Linkerd 的 sidecars 代理,而只在内核中做所有事情?
在本文中,我将尽我所能评估这种可能性——尤其是当它与对用户的影响有关时。我将描述什么是 eBPF 以及它可以做什么和不能做什么。我将深入研究 sidecar 与其他模型,并从操作和安全角度对它们进行对比。最后,我将就我们 Linkerd 团队所相信的与 eBPF 相关的服务网格的未来给出我的结论。

我是谁?

大家好,我是威廉·摩根。我是 Linkerd(第一个服务网格)‍ 的创建者之一,也是定义术语本身的人。我也是 Buoyant 的首席执行官,该公司帮助世界各地的组织采用 Linkerd。您可能还记得我从诸如服务网格之类的冗长而书呆子的信件中:每个软件工程师需要了解的关于世界上最被过度炒作的技术和Kubernetes 工程师的 mTLS 指南:为了乐趣和利润而进行的相互身份验证。
我非常关心 Linkerd,这是我的偏见。但我也很高兴对其实施保持务实。最终,Linkerd 的目标是为我们的用户提供最简单的服务网格,而 Linkerd 如何实现这种简单性是一个实现细节。例如,今天的 Linkerd 使用 sidecar,但早期的 1.x 版本的 Linkerd 被部署为pre-host的代理,我们出于操作和安全原因进行了更改。
eBPF 可能允许我们进一步简化 Linkerd 的想法——尤其是在操作上——是引起我注意的事情。

什么是 eBPF?

在我们进入服务网格细节之前,让我们从 eBPF 开始。什么是席卷 Tweet-o-sphere 的热门新技术?
eBPF 是 Linux 内核的一项功能,它允许应用程序在内核本身中执行某些类型的工作。eBPF 起源于网络世界,虽然它不限于网络,但它的亮点在于:除其他外,eBPF 解锁了一整类网络可观察性,这在过去由于对性能的影响而根本不可能实现。
假设您希望您的应用程序处理网络数据包。您不能直接访问主机的网络缓冲区。这个缓冲区由内核管理,内核必须保护它——例如,它必须确保一个进程不能读取另一个进程的网络数据包。相反,应用程序可以通过syscall请求网络数据包信息,这本质上是一个内核 API 调用:您的应用程序调用 syscall,内核检查您是否有权获取您请求的数据包;如果有权限,内核将返回你的请求。
系统调用是可移植的——你的代码可以在非 Linux 机器上运行——但是它们很慢。在现代网络环境中,您的机器每秒可能处理数千万个数据包,编写基于系统调用的代码来处理每个数据包是站不住脚的。
当我们有了eBPF,会发生什么?我们的代码不是在一个紧密的循环中调用系统调用,而是在“内核空间”和“用户空间”之间来回传递,而是将我们的代码直接提供给内核并告诉它自己执行!瞧:没有更多的系统调用,我们的应用程序可以全速运行。(当然,正如我们将在下面看到的那样,事情并没有这么简单。)
eBPF 是最近的内核特性之一,比如io_uring(Linkerd 大量使用)改变了应用程序和内核交互的方式。(ScyllaDB 的 Glauber Costa 对此有一篇很好的文章:How io_uringand eBPF Will Revolutionize Programming in Linux。)这些特性以非常不同的方式工作:io_uring使用允许应用程序和内核以安全方式共享内存的特定数据结构;eBPF 通过允许应用程序直接向内核提交代码来工作。但在这两种情况下,目标都是通过超越系统调用方法来提高性能。
eBPF 是一个很大的进步,但它不是灵丹妙药。您不能将任意应用程序作为 eBPF 运行。事实上,你可以用 eBPF 做的事情是非常有限的,这是有充分理由的。

竞争性多租户很难

在我们理解为什么 eBPF 如此受限之前,我们需要先谈谈为什么内核本身如此受限。为什么存在系统调用之类的东西?为什么程序不能直接访问网络(或内存或磁盘)?
内核在竞争多租户的世界中运行。多租户意味着多个“租户”(例如人、帐户、其他形式的参与者)共享机器,每个人都运行自己的程序。竞争意味着这些租户不是朋友。他们不应该访问彼此的数据,或者能够相互干扰。内核需要强制执行该行为,同时允许它们执行任意程序。换句话说,内核需要隔离租户
这意味着内核不能真正信任它被指示运行的任何程序。在任何时候,一个租户的程序都可能试图对另一个租户的数据或程序做坏事。内核必须确保任何程序都不能停止或破坏另一个程序,或者拒绝它的资源,或者干扰它的运行能力,或者从内存、网络或磁盘读取它的数据,除非得到明确的许可。
这是一个关键要求!世界上几乎所有与软件相关的安全保证最终都归结为内核执行这些保护的能力。未经许可就可以读取另一个程序的内存或网络流量的程序是数据泄露或更糟的途径。可以写入另一个程序的内存或网络流量的程序是欺诈或更糟的途径。允许程序违反规则的内核漏洞利用非常重要。打破这些规则的最好方法之一是访问内核的内部状态——如果你可以读取或写入内核内存,那么你就可以绕过这些规则。
这就是为什么应用程序和内核之间的每一次交互都受到如此严格的审查。失败的后果非常严重。内核开发人员已经为这个问题倾注了"数千年的努力"。
这也是容器如此强大的原因——它们采用相同的隔离保证并将它们应用于任意应用程序包和依赖项。由于相对现代的内核原理,我们可以彼此隔离运行容器,充分利用内核处理竞争多租户的能力。使用虚拟机实现这种隔离的早期方法既慢又昂贵。容器的魔力在于它们以非常便宜的方式为我们(大部分)提供相同的保证。
我们所认为的“云原生”的几乎每个方面都依赖于这些隔离保证。

eBPF 是有限的

回到 eBPF。正如我们所讨论的,eBPF 允许我们交出内核代码并要求“请在内核中运行它”。从内核安全的角度来看,我们知道这是一件非常可怕的事情——它会绕过应用程序和内核之间的所有障碍(如系统调用),并将我们直接置于安全漏洞利用领域。
因此,为了确保安全,内核对其执行的代码施加了一些非常重要的约束。在它们可以运行之前,所有 eBPF 程序都必须通过一个验证器,该验证器检查它们是否有顽皮的行为。如果验证者拒绝该程序,内核将不会运行它。
程序的自动验证是困难的,验证者不得不在过于严格的方面犯错。因此,eBPF 程序非常有限。例如,他们不能阻止;它们不能有无限循环;并且它们不能超过预定义的大小。它们的复杂性也受到限制——验证器评估所有可能的执行路径,如果它不能在某个限制内完成,或者如果它不能证明每个循环都有退出条件,则程序不会通过。
有许多完美的安全程序违反了这些限制。如果您想将其中一个程序作为 eBPF 运行,那太糟糕了!您需要重写它以满足验证者的要求。1如果您是 eBPF 粉丝,好消息是随着验证器在每个内核版本中变得更加智能,这些限制会逐渐放松。还有一些创造性的方法可以解决这些限制。
但总的来说,eBPF 程序的功能非常有限。严肃的处理——例如处理全部范围的 HTTP/2 流量或协商 TLS 握手所需的那种——不能在纯 eBPF 中完成。充其量,eBPF 可以完成这项工作的一小部分,调用用户空间应用程序来处理在 eBPF 中过于复杂而无法处理的部分。

eBPF 与服务网格

了解了 eBPF 的基础知识后,让我们回到服务网格。
服务网格处理现代云原生网络的复杂性。例如,Linkerd启动和终止双向 TLS;跨连接重试请求;透明地将代理之间的连接从 HTTP/1.x 升级到 HTTP/2,以提高性能;根据工作负载身份执行访问策略;跨 Kubernetes 集群边界发送流量;还有很多很多。
Linkerd 与大多数服务网格一样,通过在每个应用程序 pod 中插入一个代理来实现这一点,该代理拦截和增强与 pod 之间的 TCP 通信。这些代理在它们自己的容器中与应用程序容器一起运行——“sidecar”模型。在 Linkerd 的案例中,代理是超轻、超快、基于 Rust 的微型代理,但也存在其他方法。
十年前,在您的集群上部署数百或数千个代理并将它们连接起来以与每个应用程序的每个实例配对的想法将是一场操作噩梦。但是多亏了 Kubernetes,它突然变得非常容易。并且感谢 Linkerd 的巧妙工程它也是易于管理的:Linkerd 的微型代理不需要调整并且消耗最少的系统资源。
在这种情况下,eBPF 多年来一直在很好地使用服务网格。Kubernetes 给世界的礼物是一个层间界限清晰的可组合平台,eBPF 和服务网格之间的关系正好适合该模型:CNI 负责 L3/L4 流量,服务网格负责 L7。
服务网格非常适合平台所有者。它在平台级别提供 mTLS、请求重试、“黄金指标”等功能,这意味着他们不再需要依赖应用程序开发人员来构建这些功能。但当然,代价是到处添加大量代理。
回到我们最初的问题:我们能做得更好吗?我们能否在没有边车的情况下使用“eBPF 服务网格”来获得服务网格的功能?

eBPF 服务网格仍然需要代理

现在有了对 eBPF 的理解,我们可以跳入这些浑浊的水域,探索其中可能潜藏的东西。
不幸的是,我们很快就触底了:eBPF 的局限性意味着 L7 流量代理仍然需要用户空间网络代理来完成繁重的工作。换句话说,任何 eBPF 服务网格仍然需要代理。
pre-host的代理比边车差得多。
所以我们的 eBPF 服务网格需要代理。但它是否需要专门的 sidecar 代理?如果我们使用每台主机代理会怎样——这是否可以为我们提供一个无边车、由 eBPF 提供支持的服务网格?
不幸的是,我们对为什么在 Linkerd 1.x 中这是一个坏主意了解得太多了。(对不起,早期采用者!)与边车相比,每主机代理更不利于操作,更不利于维护,更不利于安全。
在 sidecar 模型中,应用程序的单个实例的所有流量都通过其 sidecar 代理处理。这允许代理充当应用程序的一部分,这是理想的:
代理资源消耗随应用程序的负载而变化。随着实例流量的增加,sidecar 会消耗更多资源,就像应用程序一样。如果应用程序占用的流量很少,sidecar 不需要消耗很多资源。(Linkerd 的代理在低流量水平下占用 2-3MB 内存。)Kubernetes 管理资源消耗的现有机制,例如资源请求和限制以及 OOM 终止,都可以继续工作。
代理故障的爆炸半径仅限于一个 pod。代理失败与应用程序失败相同,由现有的 Kubernetes 机制处理失败的 Pod。
代理维护,例如代理版本的升级,通过与应用程序本身相同的机制完成:Deployment的滚动更新等。
安全边界很清晰(而且很小):它在 pod 级别。Sidecar 在应用程序实例的相同安全上下文中运行。它是同一个Pod的一部分。它获得相同的IP地址。它强制执行策略并将 mTLS 应用于进出该 pod 的流量,并且它只需要该 pod 的密钥材料。
在每主机模型中,这些细节被忽略了。现在,代理不再是单个应用程序实例,而是处理 Kubernetes 决定在主机上调度的任何应用程序实例的一组有效随机的 Pod 的流量。代理现在与应用程序完全解耦,这引入了各种微妙和不那么微妙的问题:
  • 代理资源消耗现在是高度可变的:它取决于 Kubernetes 在任何时间点在主机上调度的内容。这意味着您无法有效地预测或推理特定代理的资源消耗,这意味着它最终会崩溃并且服务网格团队将受到指责。
  • 应用程序现在容易受到“嘈杂邻居”流量的影响。因为通过主机的所有流量都流经单个代理,单个高流量的 pod 可以消耗所有代理资源,代理必须确保公平,否则应用程序将面临饥饿的风险。
  • 代理的爆炸半径很大且不断变化。代理故障和升级现在会影响一组随机应用程序中的随机 pod 子集,这意味着任何故障或维护任务都会产生难以预测的影响。
  • 现在的安全故事要复杂得多。例如,要执行 TLS,pre-host的代理必须包含已在主机上调度的任何应用程序的密钥材料,使其成为易受混淆代理问题影响的新攻击向量——代理中的任何 CVE 或漏洞现在都是潜在的密钥泄漏。
简而言之,sidecar 方法保留了我们从迁移到容器中获得的隔离保证——内核可以在容器级别强制执行竞争多租户的所有安全性和公平性考虑,并且一切正常。pre-host模型将我们完全带出那个世界,给我们留下了竞争多租户的所有问题。
当然,pre-host代理确实有一些优势。您可以将请求必须遍历的代理数量从 Sidecar 模型中的每跳两个减少到每跳一个,这样可以节省延迟。您可以拥有更少、更大的代理,如果您的代理具有较高的基线成本,这可能会更好地消耗资源。(Linkerd 1.x 就是一个很好的例子——非常适合扩大到大流量;不适合缩小规模)。而且您的网络架构图“更简单”,因为您的盒子更少。
但与您遇到的操作和安全问题相比,这些优势微不足道。而且,除了网络图中的盒子更少之外,我们可以通过良好的工程来缓解这些差异——确保我们的边车尽可能快且尽可能小。

我们可以改进代理吗?

我们概述的pre-host代理的一些问题归结为我们的老朋友,即多租户。在 Sidecar 领域,我们使用内核现有的解决方案通过容器竞争多租户。在我们的每主机代理模型中,我们不能这样做——但是我们可以通过让每主机代理本身能够处理竞争的多租户来解决这些问题吗?例如,一种流行的代理是 Envoy。我们能否通过调整 Envoy 来处理竞争性多租户来解决pre-host代理的问题?
答案是不。答案是肯定的,在“它不会违背宇宙的物理定律”的意义上,但在“这将是大量的工作,不会很好地利用任何人的时间”的意义上说不是。Envoy 不是为竞争性多租户而设计的,它需要付出巨大的努力来改变它。有一个很长很有趣的推特帖子探讨了如果你想了解细节必须做的一些事情——这将需要大量非常棘手的项目工作,并且必须进行大量的改变不断权衡“每个租户只运行一个 Envoy”——即边车。
即使您完成了这项工作,最后,您仍然需要应对爆炸半径和安全问题。

服务网格的未来

综上所述,我们得出一个结论:无论是 eBPF 还是没有 eBPF,服务网格的可预见未来都是由在用户空间中运行的 sidecar 代理构建的
Sidecar 并非没有问题,但它们是我们目前处理云原生网络复杂性的全部范围同时保持容器提供的隔离保证的最佳解决方案。如果 eBPF 可以从服务网格中卸载工作,它应该通过使用 sidecar 代理而不是pre-host代理来做到这一点。“让现有的基于 sidecar 的方法更快,同时保留容器化的运营和安全优势”与“通过摆脱 sidecar 来解决服务网格复杂性和性能”并不完全具有相同的营销环,但从用户的角度来看,这是一场胜利。
eBPF 的能力最终会发展到不需要代理来处理服务网格提供的全部 L7 工作的地步吗?也许。内核将能够通过 eBPF 以外的机制来吸收该范围的工作吗?也许。这两种可能性似乎都不是特别近在咫尺,但如果有一天它们到来,告别边车代理可能是可行的。我们期待着这种可能性。
与此同时,从 Linkerd 的角度来看,我们将继续努力使我们的 sidecar 微型代理尽可能小、快速且在操作上可以忽略不计,包括在有意义的时候将工作卸载到 eBPF。我们的基本职责是对我们的用户及其对 Linkerd 的操作体验,并且我们必须始终通过这个镜头衡量每一个设计和工程权衡。

参考

  • https://buoyant.io/2022/06/07/ebpf-sidecars-and-the-future-of-the-service-mesh/#fn:2

给TA打赏
共{{data.count}}人
人已打赏

相关文章

Kalix:构建无服务器的云原生业务关键型应用程序,无需数据库

Kalix:构建无服务器的云原生业务关键型应用程序,无需数据库

Akka 背后的公司Lightbend最近推出了 Kalix,这是一种新的平台即服务产品,用于使用任何没有数据库的编程语言构建云原生、业务关键型应用程序。Kalix 是一个统一的应用层,它将编写软件所需的部分汇集在一起,并抽象出它们的实现细节。Lighbend 旨在为开发人员提供“创新的 NoOps 开发人员体验”。 Lightbend 的创始人兼首席执行官Jonas Bonér解释了 Kalix 的动机: 云生态系统的复杂性正在减缓工程和开发团队的速度。Kubernetes在管理、编排和确保容器的可用性和可扩展性

利用 eBPF 支撑大规模 Kubernetes Service

利用 eBPF 支撑大规模 Kubernetes Service

本文翻译自 2019 年 Daniel Borkmann 和 Martynas Pumputis 在 Linux Plumbers Conference 的一篇分享:《Making the Kubernetes Service Abstraction Scale using eBPF》。翻译时对大家耳熟能详或已显陈旧的内容(Kubernetes 介绍、Cilium 1.6 之前的版本对 Service 实现等)略有删减,如有需要请查阅原 PDF(文末有下载方式)。 实际上,一年之后 Daniel 和 Martyna

Cilium:基于 BPF/XDP 实现 Kubernetes Service 负载均衡

Cilium:基于 BPF/XDP 实现 Kubernetes Service 负载均衡

本文翻译自 2020 年 Daniel Borkmann 和 Martynas Pumputis 在 Linux Plumbers Conference 的一篇分享:《Kubernetes service load-balancing at scale with BPF & XDP》。文章介绍了 Kubernetes 的一些核心网络模型和设计、Cilium 对 Kubernetes Service 的实现、BPF/XDP 性能优化,以及他们从中得到的一些实践经验,全是干货。 去年我们也参加了这个大会(LPC

Life of a Packet in Cilium:实地探索 Pod-to-Service 转发路径及 BPF 处理逻辑

Life of a Packet in Cilium:实地探索 Pod-to-Service 转发路径及 BPF 处理逻辑

原载于:http://arthurchiao.art/blog/cilium-life-of-a-packet-pod-to-service-zh/ 引言 面临的问题 传统的基于二层转发(Linux bridge、Netfilter/iptables、OVS 等)和/或 三层路由的网络虚拟化方案中,数据包的转发路径通常非常清晰,通过一些常见工 具或命令就能判断包的下一跳(可能是一个端口或网络设备),最终能画出一张类似下 图的网络拓扑图
云原生

Kalix:构建无服务器的云原生业务关键型应用程序,无需数据库

2022-6-13 12:48:09

云原生后端开发

Lyft在多集群Kubernetes环境中运行300,000多个容器实践

2021-4-15 15:50:11

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索