请暂时抛弃使用 eBPF 取代服务网格和 sidecar 模式的幻想

标签: ebpf 取代 服务 | 发表时间:2022-06-11 11:08 | 作者:
出处:https://jimmysong.io/blog/

最近 eBPF 技术在云原生社区中持续火热,在我翻译了《 什么是 eBPF 》之后,当阅读“云原生环境中的 eBPF”之后就一直在思考 eBPF 在云原生环境中究竟处于什么地位,发挥什么样的作用。当时我评论说“eBPF 开启了上帝视角,可以看到主机上所有的活动,而 sidecar 只能观测到 pod 内的活动,只要搞好进程隔离,基于 eBPF 的 proxy per-node 才是最佳选择”,再看到 William Morgan 的 这篇文章 1之后,让我恍然大悟。下面节选翻译了文章我比统同意的观点,即 eBPF 无法替代服务网格和 sidecar,感兴趣的读者可以阅读 William 的原文。

什么是 eBPF

在过去,如果你想让应用程序处理网络数据包,那是不可能的。因为应用程序运行在 Linux 用户空间,它是不能直接访问主机的网络缓冲区。缓冲区是由内核管理的,受到内核保护,内核需要确保进程隔离,进程之间不能直接读取对方的网络数据包。正确的做法是,应用程序通过系统调用(syscall)来请求网络数据包信息,这本质上是内核 API 调用——应用程序调用 syscall,内核检查应用程序是否有权限获得其请求的数据包;如果有,就把返回数据包。

有了 eBPF 之后,应用程序不再需要 syscall,数据包不需要在内核空间和用户空间之间来回交互传递。而是我们将代码直接交给内核,让内核自己执行,这样就可以让代码全速运行,效率更高。eBPF 允许应用程序和内核以安全的方式共享内存,eBPF 允许应用程序直接向内核提交代码,目标都是通过超越系统调用的方式来实现性能提升。

eBPF 不是银弹,你不能用 eBPF 运行任意程序,实际上 eBPF 可以做的事情是非常有限的。

eBPF 的局限性

eBPF 的局限性也是因为内核造成的。内核中运行的应用程序应当有自己的租户,这些租户之间会争抢系统的内存、磁盘和网络,内核的职责就是隔离和调度这些应用程序的资源,同时内核还要保护确认应用程序的权限,保护其不被其他程序破坏。

因为我们直接将 eBPF 代码交给内核执行,这绕过了内核安全保护(如 syscall),内核将面临直接的安全风险。为了保护内核,所有 eBPF 程序要想运行都必须先通过一个 验证器。但是要想自动验证程序是很困难的,验证器可能会过度限制程序的功能。比如 eBPF 程序不能是阻塞的,不能有无限循环,不能超过预定的大小;其复杂性也受到限制,验证器会评估所有可能的执行路径,如果 eBPF 程序不能在某些范围内完成,或者不能证明每个循环都有一个退出条件,那么验证器就不会允许该程序运行。有很多应用程序都违反了这些限制,要想将它们作为 eBPF 程序来运行的话,要么重写以满足验证器的需求,要么给内核打补丁,来绕过一些验证(这可能比较困难)。不过随着内核版本的升级,这些验证器也变得更加智能,限制也逐渐变得宽松,也有一些创造性的方法来绕过这些限制。

但总的来说,eBPF 程序能做的事情非常有限。对于一些重量级事件的处理,例如处理全局范围内的 HTTP/2 流量,或者 TLS 握手协商不能在纯 eBPF 环境中完成。充其量,eBPF 可以做其中的一小部分工作,然后调用用户空间应用程序来处理对于 eBPF 来说过于复杂而无法处理的部分。

eBPF 与服务网格的关系

因为上文所述的 eBPF 的各项限制,七层流量仍然需要用户空间的网络代理来完成,eBPF 并不能替代服务网格。eBPF 可以与 CNI(容器网络接口)一起运行,处理三层/四层流量,而服务网格处理七层流量。

每个主机一个代理的模式比 sidecar 更糟

对于每个主机一个代理(per-host)的模式,服务网格的早期实践者 Linkerd 1.x 就是这么用的,笔者也是从那个时候开始关注服务网格,Linkerd 1.x 还使用了 JVM 虚拟机!但是经过 Linkerd 1.x 的用户实践证明,这种模式相对于 sidecar 模式,对于运维和安全来说会更糟糕。

为什么说 sidecar 模式比 per-host 模式更好呢?因为 sidecar 模式有以下几个优势,这是 per-host 模式所不具备的:

  1. 代理的资源消耗随着应用程序的负载而变化。随着实例流量的增加,sidecar 会消耗更多的资源,就像应用程序一样。如果应用程序的流量非常小,那么 sidecar 就不需要消耗很多资源。Kubernetes 现有的管理资源消耗的机制,如资源请求和限制以及 OOM kill,都会继续工作。
  2. 代理失败的爆炸半径只限于一个 pod。代理失败与应用失败相同,由 Kubernetes 负责处理失败的 pod。
  3. 代理维护。例如代理版本的升级,是通过如滚动更新,灰度发布等应用程序本身相同的机制完成的。
  4. 安全边界很清楚(而且很小):在 pod 级别。Sidecar 在应用程序实例的同一安全上下文中运行。它是 pod 的一部分,与应用程序具有一样的 IP 地址。Sidecar 执行策略,并将 mTLS 应用于进出该 pod 的流量,而且它只需要该 pod 的密钥。

而对于 per-host 模式,就没有上述好处了。代理与应用程序 pod 完全解耦,处理主机上所有 pod 的流量,这样会代理各种问题:

  1. 代理消耗的资源是高度可变的,这取决于在某个时间点 Kubernetes 调度了多少个 pod 在该主机上。你无法有效的预测特定代理的资源消耗情况,这样代理就有崩溃的风险(原文是这么说的,这点笔者还是存疑的,希望有点读者能解帮忙解释下)。
  2. 主机上 pod 之间的流量争抢问题。因为主机上的所有流量都经过同一个代理,如果有一个应用程序 pod 的流量极高,消耗了代理的所有资源,主机上的其他应用程序就有被饿死的危险。
  3. 代理的爆炸半径很大,而且是不断变化的。代理的故障和升级现在影响到随机的应用程序集合中的一个随机的 pod 子集,意味着任何故障或维护任务都有难以预测的风险。
  4. 使得安全问题更加复杂。以 TLS 为例,主机上的代理必须包含该主机上所有应用程序的密钥,这使得它成为一个新的攻击媒介,容易受到 混淆代理 问题的影响——代理中的任何 CVE 或漏洞都是潜在的密钥泄露风险。

简而言之,sidecar 模式继续贯彻了容器级别的隔离保护——内核可以在容器级别执行所有安全保护和公平的多租户调度。容器的隔离仍然可以完美的运行,而 per-host 模式却破坏了这一切,重新引入了争抢式的多租户隔离问题。

当然 per-host 也不是一无是处,该模式最大的好处是可以成数量级的减少代理的数量,减少网络跳数,这也就减少了资源消耗和网络延迟。但是与该模式带来的运维和安全性问题相比,这些优势都是次要的。我们也可以通过持续优化 sidecar 来弥补 sidecar 模式在这方面的不足,而 per-host 模式的缺陷确是致命性的。

其实归根结底还是回到了争抢式多租户问题上,那么能否利用现有的内核解决方案,改进一下 per-host 模式中的代理,让其支持多租户呢?比如改造 Envoy 代理,使其支持多租户模式。虽然从理论来说这是可行的,但是工作量巨大,Matt Klein 也觉得不值得这样做 2,还不如使用容器来实现租户隔离。而且即使让 per-host 模式中的代理支持了多租户,仍然还有爆炸半径和安全问题需要解决。

总结

不管有没有 eBPF,在可预见的未来,服务网格都会基于运行在用户空间的 sidecar 代理(proxyless 模式除外)。Sidecar 模式虽然也有弊端,但它依然是既能保持容器隔离和操作的优势,又能处理云原生网络复杂性的最优方案。eBPF 的能力将来是否会发展到可以处理七层网络流量,从而替代服务网格和 sidecar,也许吧,但那一天可能很遥远。

参考


  1. William Morgan 的 eBPF, sidecars, and the future of the service mesh 这篇文章正好回答了我的关于 eBPF、sidecar 的疑问。  ↩︎

  2. 关于 per-host 模式中的代理改造问题,Twitter 上有一个精彩的 讨论 。  ↩︎

相关 [ebpf 取代 服务] 推荐:

请暂时抛弃使用 eBPF 取代服务网格和 sidecar 模式的幻想

- - Jimmy Song - 宋净超的个人博客 – 博客
最近 eBPF 技术在云原生社区中持续火热,在我翻译了《 什么是 eBPF 》之后,当阅读“云原生环境中的 eBPF”之后就一直在思考 eBPF 在云原生环境中究竟处于什么地位,发挥什么样的作用. 当时我评论说“eBPF 开启了上帝视角,可以看到主机上所有的活动,而 sidecar 只能观测到 pod 内的活动,只要搞好进程隔离,基于 eBPF 的 proxy per-node 才是最佳选择”,再看到 William Morgan 的 这篇文章.

使用ebpf跟踪rpcx微服务

- - IT瘾-dev
ebpf是一种创新的革命性技术,它能在内核中运行沙箱程序, 而无需修改内核源码或者加载内核模块. 将 Linux 内核变成可编程之后,就能基于现有的(而非增加新的)抽象层来打造更加智能、 功能更加丰富的基础设施软件,而不会增加系统的复杂度,也不会牺牲执行效率和安全性. BPF的第一个版本在1994年问世.

eBPF编程指北

- - IT瘾-dev
这里以 Ubuntu 20.04 为例构建 eBPF 开发环境:. 主流的发行版在对 LLVM 打包的时候就默认启用了 BPF 后端,因此,在大部分发行版上安 装 clang 和 llvm 就可以将 C 代码编译为 BPF 对象文件了. 用 LLVM 将 C 程序编译成对象文件(ELF). 用户空间 BPF ELF 加载器(例如 iproute2)解析对象文件.

聊聊最近很火的eBPF - 知乎

- -
如果非要说当前计算机领域最有前途的两个基础软件技术,那非eBPF和wasm莫属了. Linux内核一直是实现监视/可观察性,网络和安全性的理想场所. 不幸的是,这通常是不切实际的,因为它需要更改内核源代码或加载内核模块,并导致彼此堆叠的抽象层. eBPF是一项革命性的技术,可以在Linux内核中运行沙盒程序,而无需更改内核源代码或加载内核模块.

深入浅出eBPF - 你要了解的7个核心问题

- -
过去一年,ARMS基于eBPF技术打造了Kubernetes监控,提供多语言无侵入的应用性能,系统性能,网络性能观测能力,验证了eBPF技术的有效性. eBPF技术和生态发展很好,未来前景广大,作为该技术的实践者,本文目标是通过回答7个核心问题介绍eBPF技术本身,为大家解开eBPF的面纱. eBPF是一个能够在内核运行沙箱程序的技术,提供了一种在内核事件和用户程序事件发生时安全注入代码的机制,使得非内核开发人员也可以对内核进行控制.

基于 eBPF 的开源项目 eCapture 介绍:无需 CA 证书抓 https 网络明文通讯

- - IT瘾-dev
eCapture 是一款基于 eBPF 技术实现的用户态数据捕获工具. 不需要 CA 证书,即可捕获 https/tls 的通讯明文. 项目在 2022 年 3 月中旬创建,一经发布,广受大家喜爱,至今不到两周已经 1200 多个 Star. 不需要 CA 证书,即可捕获 HTTPS/TLS 通信数据的明文.

服务禁语

- tiancaicai - 白板报
前几天在一个公交汽车站拍到了一张规定,里面规定了服务禁语和礼貌用语,看了大乐. 3、乘车高峰车厢内拥挤时,禁语:“快往里走,站在前面又没有钞票检. ”文明语:“请尽量往里走,照顾没有上车的乘客”. 4、车子抛锚,禁语:“车子抛锚没有办法,人都要生毛病的,车子坏了也正常. ”文明语:“对不起,车子出现故障修一下,请大家理解.

服务熔断

- - CSDN博客推荐文章
服务熔断也称服务隔离,来自于Michael Nygard 的《Release It》中的CircuitBreaker应用模式,Martin Fowler在博文 CircuitBreaker中对此设计进行了比较详细说明. 本文认为服务熔断是服务降级的措施. 服务熔断对服务提供了proxy,防止服务不可能时,出现串联故障(cascading failure),导致雪崩效应.

取代点击操作

- 次亚 - 牛博山寨 编辑推荐
在分析N9的滑动手势时,分析其如何取代iPhone的Home键,提出“取代点击”的论点. 汇总之前几篇文章,强调这一设计趋势. 触摸屏的点击是沿用鼠标点击的操作,其本身具有诸多不利的因素:. 控件会占用显示控件,44像素的正方形对于手机界面也是宝贵的显示空间. 控件需要放置的特定的位置,由于屏幕过大和手持设备的姿势导致部分控件不容易点击到.

面向服务与微服务架构

- - CSDN博客推荐文章
最近阅读了 Martin Fowler 和 James Lewis 合著的一篇文章  Microservices, 文中主要描述和探讨了最近流行起来的一种服务架构模式——微服务,和我最近几年工作的实践比较相关感觉深受启发. 本文吸收了部分原文观点,结合自身实践经验来探讨下服务架构模式的演化. 面向服务架构 SOA 思想概念的提出已不是什么新鲜事,大概在10年前就有不少相关书籍介绍过.