Sidecar模式的学习参考资料
- 1: Azure 云设计模式之 Sidecar
- 2: oreilly 设计分布式系统之 Sidecar 模式
- 3: Beautifulcode Sidecar 模式介绍
- 4: 微软架构之 Sidecar 模式
- 5: Sidecar 模式
- 6: Sidecar 模式
- 7: Sidecar模式:该做的和不该做的
- 8: Sidecar 模式
- 9: 系统设计中的Sidecar设计模式
1 - Azure 云设计模式之 Sidecar
前言
https://docs.microsoft.com/en-us/azure/architecture/patterns/sidecar
网上没找到的中文翻译,以下是自行翻译。
Sidecar 模式
将应用程序的组件部署到单独的进程或容器中,以提供隔离和封装。这种模式也可以使应用程序由异构的组件和技术组成。
这种模式被命名为 Sidecar,因为它类似于连接在摩托车上的边车。在该模式中,sidecar 连接到父级应用,并为该应用提供支持功能。sidecar 与父级应用共享相同的生命周期,与父级应用一起被创建和销毁。sidecar 模式有时被称为 sidekick 模式,是一种解耦模式。
上下文和问题
应用程序和服务经常需要相关的功能,如监控、日志、配置和网络服务。这些外围任务可以实现为独立的组件或服务。
如果它们被紧密地集成到应用程序中,它们可以与应用程序在同一进程中运行,有效地利用共享资源。然而,这也意味着它们没有被很好地隔离,其中一个组件的中断会影响其他组件或整个应用程序。另外,它们通常需要使用与父级应用相同的语言来实现。因此,组件和应用程序之间有密切的相互依赖关系。
如果应用程序被分解成服务,那么每个服务可以使用不同的语言和技术来构建。虽然这提供了更多的灵活性,但这意味着每个组件都有自己的依赖关系,需要特定语言的类库来访问底层平台和与父级应用共享的任何资源。此外,将这些功能作为单独的服务来部署会增加应用程序的延迟。管理这些特定语言接口的代码和依赖性也会增加相当的复杂性,特别是在托管、部署和管理方面。
解决方案
将一组有凝聚力的任务与主应用程序放在一起,但将它们放在自己的进程或容器中,为跨语言的平台服务提供一个同质化的接口。
Sidecar 服务不一定是应用程序的一部分,但与它相连。父应用程序到哪里,它就到哪里。Sidecar 支持进程或服务,与主应用程序一起部署。在一辆摩托车上,sidecar 连接到摩托车上,每辆摩托车都可以有自己的 sidecar。以同样的方式,sidecar 服务共享其父级应用的命运。对于应用程序的每一个实例,都部署有一个 sidecar 实例,并与它一起托管。
使用 sidecar 模式的优点是:
-
在运行时环境和编程语言方面,sidecar 是独立于其主要应用的,所以不需要为每种语言开发 sidecar。
-
Sidecar 可以访问与主应用程序相同的资源。例如,Sidecar 可以监控 Sidecar 和主应用程序所共同使用的系统资源。
-
由于它贴近主应用程序,在它们之间进行通信时没有明显的延迟。
-
即使是那些不提供可扩展性机制的应用程序,你也可以使用 sidecar 来扩展功能,把它作为自己的进程附加到与主应用程序相同的主机或子容器中。
sidecar模式经常与容器一起使用,被称为 sidecar 容器或 sidekick 容器。
问题和考虑因素
-
考虑用于部署服务、进程或容器的部署和打包格式。容器特别适合于 sidecar 模式。
-
当设计 sidecar 服务时,要谨慎决定进程间的通信机制。尽量使用与语言或框架无关的技术,除非性能要求迫不得已。
-
在把功能放到 sidecar 中之前,考虑它是作为一个单独的服务还是作为一个更传统的守护程序来工作会更好。
-
还要考虑该功能是否可以作为类库或使用传统的扩展机制来实现。特定语言的类库可能有更深的集成度,而且网络开销更少。
何时使用此模式
在以下情况下使用该模式:
-
主应用程序使用一组异构的语言和框架。位于 sidecar 服务中的组件可以被使用不同语言和不同框架的应用程序所调用。
-
组件被远程团队或不同的组织所拥有。
-
组件或功能必须与应用程序共同位于同一主机上
-
需要一个与主应用程序共享整个生命周期,但可以独立更新的服务。
-
需要对特定资源或组件的资源限制进行精细的控制。例如,可能想限制特定组件使用的内存量。你可以将该组件部署为 sidecar,并独立于主应用程序管理内存使用。
这种模式可能不适合于:
-
当进程间通信需要优化时。父应用程序和 sidecar 服务之间的通信有一些开销,特别是调用中的延迟。对于苛刻的界面来说,这可能不是一个可接受的折衷。
-
对于小型应用来说,隔离带来的优势不足以抵消为每个实例部署一个 sidecar 服务的资源成本。
-
当服务需要以不同于或独立于主要应用程序的方式进行扩展时。如果是这样,将该功能部署为一个单独的服务可能更好。
示例
sidecar模式适用于许多场景。一些常见的例子:
-
基础设施 API。基础设施开发团队创建了服务,与每个应用程序一起部署,而不是用特定语言的客户端类库来访问基础设施。该服务作为 sidecar 加载,并为基础设施服务提供一个公共层,包括日志、环境数据、配置存储、发现、健康检查和看门狗服务。sidecar 还监控父应用程序的主机环境和进程(或容器),并将信息记录到一个集中的服务。
-
管理NGINX/HAProxy。用 sidecar 服务来部署NGINX,该服务监控环境状态,然后更新NGINX配置文件,并在需要改变状态时回收该进程。
-
Ambassador sidecar。部署 Ambassador 服务作为 sidecar。应用程序通过 Ambassador 调用,Ambassador 处理请求记录、路由、断路和其他与连接有关的功能。
-
卸载代理。在 node.js 服务实例前放置 NGINX 代理,以处理服务的静态文件内容。
2 - oreilly 设计分布式系统之 Sidecar 模式
前言
https://www.oreilly.com/library/view/designing-distributed-systems/9781491983638/ch02.html
以下是内容翻译。
第二章 Sidecar 模式
第一个单节点模式是 sidecar 模式。Sidecar 模式是一个由两个容器组成的单节点模式。第一个是应用容器。它包含了应用程序的核心逻辑。没有这个容器,应用程序就不会存在。除了应用容器之外,还有一个 sidecar 容器。sidecar的作用是增强和改进应用容器,通常是在应用容器不知情的情况下。在其最简单的形式中,sidecar 容器可以用来为可能难以改进的容器增加功能。Sidecar 容器通过原子容器组(如 Kubernetes 中的 pod API 对象)被共同调度到同一台机器上。除了被调度到同一台机器上之外,应用容器和 sidecar 容器还共享一些资源,包括文件系统部分、主机名和网络,以及许多其他命名空间。图 2-1 是这种 sidecar 模式的通用图像:
图2-1. 通用sidecar模式
Sidecar的例子: 给传统服务添加HTTPS
例如,考虑一个传统的网络服务。几年前,当它被建立时,内部网络安全对公司来说并不那么重要,因此,应用程序只通过未加密的HTTP而不是HTTPS来服务请求。由于最近的安全事件,…
3 - Beautifulcode Sidecar 模式介绍
前言
https://www.beautifulcode.co/blog/55-what-is-sidecar-pattern
以下是内容翻译。
场景
让我们假设我们已经建立了以下基于微服务的电子商务应用程序。所有的服务都是用同一种语言编写的,比如说Ruby。
我们想把所有的日志推送给 LogParser
服务。我们可以做的是,我们可以写 log_exporter.rb
脚本,它定期运行并将日志文件的内容推送给 LogParser
服务。我们可以把这个脚本放在每个单独的服务中。
随着时间的推移,我们意识到我们需要为产品服务提供更大的吞吐量,因为它被多次调用以获得产品列表。我们将产品服务的实现从 Ruby 切换到 GoLang。现在我们有另一个 GoLang
版本的脚本 log_exporter.rb
。问题是,当我们在基于微服务的应用程序中使用更多的语言时,我们必须在该语言中维护另一个版本的导出器脚本。在未来,如果我们想对我们的脚本做任何改变,我们必须对所有语言的脚本进行修改。另一个问题是,我们在应用程序中编写导出日志的逻辑,尽管它与应用程序的逻辑无关。
我们解决这个问题的一个方法是借助于sidecar模式。
什么是 sidecar 模式?
在这种模式中,有两个容器。其中一个是应用容器,包含主要的应用逻辑。没有这个容器,应用程序就不存在。第二个容器被称为 sidecar 容器,通常情况下,应用容器不知道有这样一个容器的存在。Sidecar 容器被用来为应用层提供额外的功能。
应用容器和sidecar容器都被部署在同一个 pod 上。由于这种编排,两个容器都共享一些资源,如本地文件系统和网络。这个 sidecar 容器的生命周期是与应用容器相联系的。
使用 sidecar 模式
我们架构中的日志都在本地文件系统上。我们可以部署脚本,将这些日志导出到一个单独的容器中。这个容器可以和每个应用容器一起部署在同一个pod中,而不管应用逻辑是用哪种语言编写的。由于sidecar容器被部署在同一个pod中,它可以访问本地存储中的日志文件。
使用sidecar模式的优势
-
应用容器的功能可以在没有紧耦合的情况下得到增强。
-
每个容器都有单一的责任。
-
即使 sidecar 容器出现任何故障,应用容器也不会受到影响。
-
我们可以重复使用容器,而不管应用逻辑是用什么语言写的。
-
因为与应用容器的距离很近,所以应该有较少的延迟。
何时使用sidecar模式
-
当功能或服务必须在同一主机上共处时
-
如果你希望一个服务与主应用程序共享相同的生命周期,但可以独立更新。
什么时候不使用sidecar模式
-
如果应用容器很小,会导致不必要的复杂情况和成本。
-
当 sidecar 和应用容器的通信之间不应该有任何延迟时。例如:当输出日志时,不应该有任何延迟。
-
当延迟的容忍范围非常小的时候
-
当你想独立于应用容器来扩展 sidecar 时。
实施过程中需要注意的事项
容器的参数化
让 sidecar 容器模块化和可重复使用是很重要的。例如,在我们导出日志的方案中,容器可以接受两个参数作为输入,一个是日志文件的位置,另一个是频率。这将有助于在不同的服务中重复使用该容器。
docker run -e=FREQUENCY=60 -e=LOG_PATH=/path/to/log/file
创建和维护容器的API
API接口是用来配置 sidecar 容器的,因此它们的定义很重要。
对API的任何改变都可能导致破坏性的改变或非破坏性的改变。破坏性变化的例子是将API的参数名称从 “FREQUENCY” 改为 “TIME_PERIOD”。 非破坏性变化的例子是,如果我们将接受的频率值从秒改为分钟。这种变化不会破坏任何东西,但不会导致 sidecar 像预期那样工作。
将容器的运维文档化
文档将有助于其他人理解如何使用这个 sidecar。写文档的最好地方是docker文件。
# FREQUENCY值决定了sidecar读取和上传日志的间隔时间,单位是秒
env frequency="60"
# LOG_PATH决定了sidecar读取日志文件的位置。
ENV LOG_PATH="/path/to/log/file"
示例
给传统服务添加HTTPS
在 sidecar 模式的帮助下,我们可以为一个遗留服务添加 HTTPS,由于某些原因,我们无法在新的构建过程中构建该服务。我们可以只在 localhost 上运行遗留的软件,并添加一个NGINX sidecar。这个sidecar容器可以作为一个代理来处理所有对传统服务的https请求。由于主容器和sidecar容器在同一个pod上,sidecar容器可以将请求转发给运行在localhost上的遗留服务。因此,未加密的流量只存在于内部网络中。
Git同步
我们可以实现一个 sidecar,它总是定期从主分支拉取最新的代码,我们可以配置主应用服务器来自动加载最新的变化。
连接到谷歌云SQL
我们可以通过添加Cloud SQL Proxy Docker镜像作为sidecar,从运行在Google Kubernetes Engine上的应用程序连接到Google Cloud SQL。通过这种方法,代理容器与应用程序在同一个pod中,这使得应用程序可以使用本地主机连接到代理,从而提高安全性。
4 - 微软架构之 Sidecar 模式
前言
https://medium.com/nerd-for-tech/microservice-design-pattern-sidecar-sidekick-pattern-dbcea9bed783
以下是内容翻译。
微软架构:sidecar 模式
在微服务架构中,有多个服务/应用经常需要通用的功能,如日志、配置、监控和网络服务,这是非常常见的。这些功能可以作为一个单独的服务在同一个容器内或在一个单独的容器内实现和运行。
-
在同一个应用程序中实现核心逻辑和支持功能:
当它们在同一个应用程序中实现时,它们通过有效利用共享资源,紧密联系并在同一进程中运行。在这种情况下,这些组件没有被很好地隔离,它们是相互依赖的,这可能会导致一个组件的失败,进而影响另一个组件或整个应用程序。
-
在一个单独的应用程序中实现核心逻辑和支持功能:
当应用程序被分离成服务时,每个服务都可以用不同的语言和技术来开发最适合的功能。在这种情况下,每个服务都有自己的依赖关系/库,以访问底层平台和与主应用程序的共享资源。当我们在不同的主机上部署两个应用程序时,它还会增加应用程序的延迟,并在托管、部署和管理方面增加复杂性。
Sidecar模式(或)Sidekick模式?
Kubernetes 中的 Sidecar 概念越来越流行。它是容器世界中的一个通用原则,即容器应该解决一个单一的问题,并且应该把它做好。Sidecar 模式通过将核心业务逻辑与扩展原始功能的额外任务解耦来实现这一原则。
Sidecar模式是一个由两个容器组成的单节点模式:
-
第一个是应用容器,它包含了应用的核心逻辑(主应用)。没有这个容器,应用程序就不会存在。
-
此外,还有一个Sidecar容器,通过在同一容器组(Pod)上并行运行另一个容器来扩展/增强主应用程序的功能。由于sidecar与主应用容器在同一个Pod上运行,它共享资源–文件系统、磁盘、网络等。
-
它还允许将同一个应用程序的组件(用不同的技术实现)部署到一个独立的、隔离的和封装的容器中。当在整个微服务架构中共享公共组件(如:日志、监控、配置属性等)有优势时,它被证明非常有用。
什么是Pod?
Pod 是 Kubernetes(K8S)中部署的一个基本原子单元。
在K8S中,Pod是一组具有共享存储和网络的一个或多个容器。Sidecar 在 pod 中充当一个实用工具容器,它与主要的应用容器松散地耦合在一起。Pod可以被认为是运行多个容器的消费者组(用Kafka术语)。
什么时候Sidecar模式是有用的?
-
当服务/组件是用多种语言或技术实现的。
-
服务/组件必须位于同一个容器组(pod)或主要应用程序运行的主机上。
-
服务/组件由远程团队或不同的组织拥有。
-
服务可以在不依赖主应用程序的情况下独立更新,但与主应用程序共享相同的生命周期。
-
如果我们需要控制某个组件或服务的资源限制。
示例
- 将HTTPS添加到一个传统的服务中
- 使用 sidecar 的动态配置
- 使用Sidecar的日志聚合器
为传统服务添加HTTPS
考虑到一个传统的网络服务,它通过未加密的HTTP服务请求。我们有一个要求,即在未来加强同一遗留系统,为HTTPS的请求提供服务。
遗留应用被配置为只在 localhost 上提供请求,这意味着只有与服务器共享本地网络的服务能够访问遗留应用。除了主容器(遗留应用程序),我们还可以添加 Nginx Sidecar 容器,它与主容器运行在同一个网络命名空间,这样它就可以访问运行在localhost上的服务。
同时,Nginx在pod的外部IP地址上终止HTTPS流量,并将该流量委托给传统应用程序。
使用Sidecars的动态配置
当遗留应用程序启动时,它从文件系统加载其配置。
当配置管理器启动时,它检查存储在本地文件系统上的配置与存储在云上的配置之间的差异。如果存在差异,那么配置管理器就会将新的配置下载到本地文件系统,并通知传统应用程序使用新的配置重新配置自己(例如:可以使用EDD或协调机制来挑选新的配置变化)。
带有Sidecar的日志聚合器
考虑到我们有一个Web服务器,它正在生成访问/错误日志,这些日志在特定的时间间隔/内存空间之外,并不那么关键,不需要在卷上持久保存。然而,访问/错误日志有助于调试应用程序的错误/漏洞。
根据关注点分离原则,我们可以通过部署一个单独的容器来实现Sidecar模式,以捕获并将访问/错误日志从网络服务器传输到日志聚合器。
网络服务器很好地完成了它的任务,为客户请求提供服务,而Sidecar容器则处理访问/错误日志。由于容器运行在同一个pod上,我们可以使用一个共享卷来读/写日志。
5 - Sidecar 模式
前言
Sidecar Design Pattern in Your Microservices Ecosystem
讨论 sidecar 模式背后的概念,它如何适合微服务,以及它如何在应用中发挥作用。
https://dzone.com/articles/sidecar-design-pattern-in-your-microservices-ecosy-1
以下是内容翻译。
Sidecar 设计模式在社区内越来越受欢迎,并被广泛采用。构建一个高度可扩展、有弹性、安全和可观察的微服务架构是具有挑战性的。服务网格的演变改变了游戏规则。它将与微服务架构相关的复杂性转移到一个独立的基础设施层,并提供了很多功能,如负载均衡、服务发现、流量管理、断路、遥测、故障注入等。
阅读我的上一篇文章,了解服务网背后的概念,为什么你的云原生应用需要它,以及它流行的原因:服务网格的崛起。
什么是Sidecar模式?
将应用程序的功能分离到一个单独的进程中,可以被看作是一种 Sidecar 模式。sidecar 设计模式允许你为你的应用程序增加一些功能,而不需要为第三方组件增加配置代码。
就像一辆摩托车上挂着一个 sidecar 一样,在软件架构中,sidecar 也是挂在一个父级应用上,并扩展/增强其功能。Sidecar与主程序是松散耦合的。
让我用一个例子来解释这个问题。想象一下,你有六个微服务在互相交谈,以便确定一个包的成本。
每个微服务都需要有可观察性、监控、日志、配置、断路器等功能。所有这些功能都是在每个微服务内部使用一些行业标准的第三方库实现的。
但是,这难道不是多余的吗?它不会增加你的应用程序的整体复杂性吗?如果你的应用程序是用不同的语言编写的,会发生什么情况呢?你如何纳入第三方库,这些库通常是特定于某种语言的,如.NET、Java、Python等?
使用Sidecar模式的好处
-
通过将常见的基础设施相关功能抽象到不同的层,减少了微服务代码的复杂性。
-
减少了微服务架构中的代码重复,因为你不需要在每个微服务中编写配置代码。
-
在应用程序代码和底层平台之间提供松散耦合。
Sidecar模式是如何工作的?
服务网格层可以运行在一个与你的应用程序一起运行的 sidecar 容器中。同一个 sidecar 的多个副本被部署在每个应用程序旁边。
来自单个服务的所有传入和传出的网络流量都流经 sidecar 代理。因此,sidecar 管理着微服务之间的流量,收集遥测数据,并执行策略。在某种意义上,服务不知道网络,只知道连接的sidecar代理。这确实是 sidecar 模式工作的本质–它将网络的依赖性抽象并转移到 sidecar 上。
在服务网格中,我们有数据平面和控制平面的概念:
-
数据平面的职责是处理网格内的服务间通信,并负责服务发现、负载均衡、流量管理、健康检查等功能。
-
控制平面的职责是管理和配置 sidecar 代理,以执行策略和收集遥测数据。
-
在 Kubernetes 和 Istio 的世界里,你可以在 pod 里面注入 sidecar。Istio 使用的是以 Envoy 为代理的 sidecar 模型。
来自 Lyft 的 Envoy 是最流行的开源代理,专为云原生应用设计。Envoy 与每个服务一起运行,并以一种与平台无关的方式提供必要的功能。所有流向服务的流量都流经 Envoy 代理。
从单体到微服务的转变使企业能够独立和大规模地部署应用。在容器和 Kubernetes 世界中,sidecar 设计模式更加兼容。sidecar从应用中抽象出复杂性,并处理服务发现、流量管理、负载均衡、断路等功能。
你可以在这里了解更多关于sidecar模式的信息。
6 - Sidecar 模式
前言
https://www.magalix.com/blog/the-sidecar-pattern
以下是内容翻译。
Sidecar Pattern
做一件事,做到最好
Do One Thing, Do it Best
设计 UNIX 的基本思想是不要让一个复杂的单体工具做所有的事情。相反,UNIX使用了一些小的、可插拔的组件,这些组件单独使用并没有什么用。但是,当它们结合在一起时,可以执行强大的操作。
让我们以 ps 命令为例,ps 本身可以显示你的 UNIX/Linux 上当前运行的进程。它有相当数量的标志,允许你显示进程的许多方面。比如说:
-
启动进程的用户。
-
每个正在运行的进程正在使用多少CPU?
-
用来启动进程的命令是什么,还有很多。
ps
命令在显示运行进程的信息方面做得很好。然而,没有任何 ps
标志可以过滤其输出。缺乏这种功能并不是该工具的功能缺失,这是故意的。
有另一个工具可以很好地过滤输入的文本: grep
。因此,使用管道(|
)字符,你可以过滤 ps
的输出,只显示系统中运行的 SSH 进程,如:ps -ef | grep -i ssh
。ps
工具关注的是显示运行进程的每一个可能的方面。grep
命令关注的是提供过滤文本的能力,以许多不同的方式过滤任何文本。做一件事并把它做到最好,这就是 UNIX 的建立方式。
由于 UNIX 的强大和简单,除了操作系统之外,这一原则还被用于许多其他领域。例如,在 Kubernetes 中,每个容器应该只做一件事,而且要做得好。你可能想问,如果容器的工作需要额外的程序来帮助它或加强它呢?没有什么可担心的,因为就像我们把 ps
命令的输出管道到 grep
一样,我们可以用另一个容器放在同一个 Pod 中的主容器旁边。第二个容器执行第一个容器所需的辅助逻辑,使其正常运行。这第二个容器通常被称为 Sidecar。
Sidecar容器有什么作用?
Pod 是 Kubernetes 部署的基本原子单位。通常情况下,一个 Pod 包含一个容器。然而,多个容器也可以放在同一个 Pod 中。在同一个 Pod 上运行的所有容器都共享 Pod 的同一个卷和网络接口。实际上,Pod本身就是一个执行 pause
命令的容器。它的唯一目的是持有网络接口和运行其他容器所需的Linux命名空间。
![The Sidecar Pattern](images/the-sidecar-pattern/The Sidecar Pattern.webp)
Sidecar容器是添加到Pod定义中的第二个容器。为什么它必须被放在同一个Pod中,因为它需要使用主容器所使用的相同资源。让我们举个例子来证明这种模式的使用情况。
情景: 输送日志的sidecar
在这个场景下,我们有一个运行 nginx 镜像的 webserver 容器。webserver 产生的访问和错误日志并不重要,可以放在一个持久化的卷中。然而,开发人员需要访问过去24小时的日志,以便他们能够追踪问题和bug。因此,我们需要将网络服务器的访问和错误日志输送到日志聚合服务中。根据关注点分离原则,我们通过部署第二个容器来实现 Sidecar 模式,该容器从 nginx 发送错误和访问日志。Nginx只做一件事,而且做得很好:为网页服务。第二个容器也专注于它的任务:输送日志。由于容器运行在同一个Pod上,我们可以使用一个共享的 emptyDir 卷来读取和写入日志。这样Pod的定义文件可能看起来如下:
apiVersion: v1
kind: Pod
metadata:
name: webserver
spec:
volumes:
- name: shared-logs
emptyDir: {}
containers:
- name: nginx
image: nginx
volumeMounts:
- name: shared-logs
mountPath: /var/log/nginx
- name: sidecar-container
image: busybox
command: ["sh","-c","while true; do cat /var/log/nginx/access.log /var/log/nginx/error.log; sleep 30; done"]
volumeMounts:
- name: shared-logs
mountPath: /var/log/nginx
上面的定义是标准的 Kubernetes Pod 定义,只是它在同一个 Pod 中部署了两个容器。sidecar容器通常在定义中排在第二位,这样当你发出 kubectl 执行命令时,你就默认以主容器为目标。
主容器是一个 nginx 容器,它被指示将其日志存储在挂载于 /var/log/nginx
的卷上。在这个位置挂载一个卷,可以防止 Nginx 将其日志数据输出到标准输出,并迫使它将其写入 access.log
和 error.log
文件。
关于日志聚合的附带说明
请注意,Nginx 镜像的默认行为是将其日志存储到标准输出,以便被 Docker 的日志收集器选中。Docker将这些日志存储在主机上的 /var/lib/docker/containers/container-ID/container-ID-json.log
中。在同一台主机上运行多个容器(来自不同的Pod),并使用相同的位置来存储它们的日志,你可以使用 DaemonSet
来部署一个日志收集器容器,如 Filebeat
或 Logstash
来收集这些日志,并将它们发送到 ElasticSearch
等日志聚合器。你需要把 /var/lib/docker/containers
作为 hostPath
卷挂到 DaemonSet
Pod上,以便让日志收集器容器访问日志。
sidecar 容器与 nginx 容器在同一个Pod上运行。这使得 sidecar 容器能够访问与web服务器相同的卷。在上面的例子中,我们用cat命令来模拟每隔30秒将日志数据发送到一个日志收集器。
总结
-
Sidecar模式需要设计模块化的容器。模块化的容器可以插在多个地方而不怎么需要改动。
-
sidecar只是一个与应用容器运行在同一个Pod上的容器,因为它与主容器共享相同的volume和网络,它可以 “帮助” 或增强应用的运行方式。
-
Sidecar容器的常见例子有:日志输送、日志观察者、监控代理等等。
-
有一个单独的容器用于辅助任务,可以让你获得健康检查、自动重启以及 Kubernetes 为容器提供的其他功能。
-
在遵循 Sidecar 模式时,你应该考虑制作一个不消耗太多资源的小型 Sidecar 容器。如果你发现 sidecar 容器的逻辑越来越复杂和/或与主应用容器的耦合越来越紧密,那么它可能最好与主应用的代码集成在一起。记住,sidecar 容器的强项在于它的小型和可插拔的能力。
7 - Sidecar模式:该做的和不该做的
前言
以下是内容翻译。
SIDECAR PATTERN: THE DOS AND DON’TS
sidecar模式概述
sidecar模式旨在允许将应用程序的组件部署到独立的、隔离的和封装的进程或容器中。当微服务之间共享共同的组件有好处时,这种模式就特别有用,如日志工具、监控工具、配置例程等。
Sidecar 模式的名字是一个比喻,表示有时会在摩托车旁边栓上单座汽车。
Sidecar的优点
Sidecar有很多好处:
-
为每个组件使用多语言(polyglot)或技术。 如果一种语言在某一必要领域特别强大(例如,Python用于机器学习,或者R用于统计工作),或者如果可以利用开源解决方案来消除内部专业化(例如,使用 NGINX 来实现某些网络相关的功能),这一点就特别有用。
-
分离本来是一个单体的东西,如果使用得当,可以对相关服务进行故障隔离。
-
组件之间的概念上很容易的交互,类似于库所提供的交互,或者微服务之间的服务调用。
-
比传统的服务调用 “其他” 服务的延迟更低,因为 Sidecar 运行在相同的处理环境中(虚拟机或物理服务器)–尽管通常在一个单独的容器中。
-
类似于库的使用,允许个人团队的所有权和较大团队的组织扩展性。
-
与动态加载库的使用类似,允许团队独立发布各种共享使用组件。
Sidecar的缺点
不管是哪种实现方式(多语言或者单体),Sidecar与使用库相比都有一些缺点:
-
较高的进程间通信延迟–因为大多数实现都是服务调用,与通过内存的调用流的传输相比,系统上的环回接口(127.0.0.1)会增加延迟。
-
大小 - 特别是在多语言实现中,但即使是在单语言实现中 - 容器化导致类似库的多个副本,相对于使用库的可比操作,内存使用增加。
-
环境–如果没有容器化技术,就很难用 Sidecar 创建任何故障隔离的概念。 虚拟机技术(Sidecar在独立于主机或调用解决方案的虚拟机中)不是一种选择,因为它是一种 Fan Out 或Mesh 反模式,而不是本地调用。
何时使用Sidecar
对于那些与本地服务信息传递相关的延迟增加不会影响终端用户响应时间的情况,Sidecar是一个令人信服的替代库。 这方面的例子有异步记录、带外监控和异步消息传递功能。 断路器(基于时间的请求/响应超时)也是Sidecar实施的一个很好的例子。
何时应避免使用Sidecar
对于必须在生成用户响应之前完成的同步活动,千万不要使用 Sidecar 模式。这样做会给终端用户的响应时间增加一些延迟。
AKF还建议不要将 Sidecar 用于服务间的同步通信,因为这样做需要 Sidecar 知道每个服务的所有端点。 我们建议反对的一个具体例子是,让服务A的每个端点(实例)(如添加到购物车)知道服务B的每个端点(实例)(如取消-SKU)。 下面是这个例子的图片:
上面的图形表示的只是两个服务和组成该服务的实例之间的协调。 想象一下所有的服务都可以相互通信的情况(如更广泛的Mesh反模式)。试图隔离故障变得几乎不可能。
如果服务A有时在调用服务B时发生故障,你怎么知道哪个组件发生了故障? 是服务A、服务A的Sidecar Proxy还是服务B的故障? 更简单的方法是让更少的代理(尽管由于非本地通信,延迟成本较高)处理事务,从而更容易识别故障。
后记
我对这篇文章的部分观点表示不赞成。
8 - Sidecar 模式
前言
Sidecar Pattern
http://diego-pacheco.blogspot.com/2020/07/sidecar-pattern.html
以下是内容翻译。
当我们需要分发一个共享软件时,有几种架构模式可以遵循。我最喜欢和默认的模式是服务模式(Service Pattern)。然而,也有其他的软件分发模式。例如,如果我们考虑到初创企业,有一个流行的工具叫精益商业画布,在那里你可以对你的初创企业的商业模式进行建模,那里有许多维度,但有一个特别的维度叫 “分销渠道”,与本博文的主题高度相关。作为工程师,我们常常只考虑到一个维度,即服务或二进制共享库。然而,我们还可以探索其他维度。其他的选择有:工具、内部服务/自助服务平台、运行时平台和服务网格。所以在这篇博文中,我想多介绍一点 Sidecar 模式。
新现实中的旧想法
对于 Linux 来说,我们总是有非常小的、专门的程序在后台运行,等待对特定的任务做出反应,这些程序通常被称为 “daemons/守护进程”。对我来说,“daemon” 可能就是最早的 “sidecar”。所以,你可能会想,为什么我们不把守护进程放在首位,而要让自己开心呢?好吧,用C语言编写代码并遵循Linux模式不会给你带来什么,因为有一个不同的现实。现实是,我们在专门的空间和专门的硬件中运行软件。因此,大多数人(在云计算市场上占30%)都在云端运行工作负载,用计算解决方案运行软件,通常是虚拟化的(EC2或谷歌云计算)。然而,现在的趋势和现实是在容器(Docker、Kubernetes、RKT、OCI/OCR等)或甚至 MicroVMs/Serverless 中运行一些工作负载。因此,你有一个专门的内核/操作系统,用于你的软件或甚至专门的硬件。因此,Sidecar 意味着让我们在那里运行一个协同进程,即你将有两个进程。你的应用程序和 Sidecar。
Sidecar 不是解决所有问题的方法。而且,它们也不只适用于 Kubernetes。当然,Kubernetes 使得使用 sidecars 容易得多,因为在 POD 中,sidecar 只是另一个 Docker 容器。 然而,你可以在虚拟机中运行 sidecars。就像 Netflix 多年来使用 Priam、Dynomite Manager、Raigad,以及最近 Lyft 使用 Envoy 那样。
Sidecar架构
为了拥有 sidecar,你可以在你的 sidecar “内部” 拥有任何架构。你可以是RPC,事件驱动,IPC,或者任何你想要的,只要你是从应用运行时路径中剥离出来的。Sidecar 也可以用于瘦客户机模式,这很好,但请记住,Sidecar 的定义是在另一个进程中运行,因此不是嵌入在你的应用程序中。
Sidecars 不是嵌入式的,但也不是远程的。Sidecars 不是微服务,根本不是服务。然而,Sidecar 可以有 HTTP/REST 接口,可以通过 “sudo remote call” 被应用程序调用。我指的是sudo,因为对于应用程序来说,它看起来就像一个远程调用,但是因为 sidecar 是在应用程序的 sidecar 机器上运行,所以延迟要小得多。
Sidecar的优点
Sidecar架构模式有几个好处,比如:
- 隔离:sidecar 和应用程序不在同一个 “运行时进程空间” 中。
- 解耦: sidecar 不与应用程序的选择相耦合,反之亦然。
- 提供安全复用: 意味着没有二进制耦合(共享jar和框架的问题)。
- 封闭性:我们可以有封装的通用代码,可以输送到所有的服务/应用程序。
- 避免二进制耦合:对我来说,这是一个巨大的胜利,因为在规模上二进制耦合是很痛苦的。
- 技术多样性:可以自由选择任何语言、堆栈、lib或框架。
- 更新/部署的独立性:它们可以在应用的CI/CD生命周期中分开发生。
- 没有单点故障:因为每个服务/微服务都有1个sidecar,我们没有单点故障。
- 避免大规模的迁移:由于应用程序代码没有与sidecar耦合,所以没有大规模的代码迁移。
最后,我只想指出,Sidecars 与容器/Kubernetes 完美配合,因为以k8s为例,部署单元是 POD。POD 只是一组共享相同资源的容器,如网络接口和磁盘。这使得创建 sidecar 变得非常容易,因为它只是另一个 docker 容器。
然而,就像我之前说的,你可以在没有容器的情况下拥有 sidecar。这需要你付出更多的部署努力,但并不是不可能或很难。
Sidecar的缺点
就像软件架构中的所有东西一样,也是有取舍的。因此,sidecar 肯定有缺点。让我们来看看其中的一些:
- 如果不在K8s中,就会有更多的部署复杂性(EC2)。
- 需要有很好的可观察性,否则 sidecar 会变成黑盒子。
- 难以对应用进行调试。比方说,sidecar 是用RUST写的,而应用程序是用Java或Go写的。
- 可靠性路径: sidecar 现在成为可靠性路径的一部分。这意味着停机时间可能是一个大问题。
Sidecar 的使用范围很窄,比如说你不会用它来取代SOA中的服务,用于你的商业应用。然而,有一些问题使 Sidecar 成为很好的选择,如代理、路由、可观察性、审计、安全等等。然而,如果你能做一个适当的共享库,并注意依赖性,他们可能是一个更简单和有效的解决方案。
IMHO 拥有像 Go、Rust、Java、Python、C++ 这样的高技术多样性,肯定会使用 sidecar。但是如果你大量使用一种语言,比如说Java,你需要确保这是正确的使用情况。不同的语言和不同的库有不同的优势,所以要仔细分析权衡,因为离开默认语言可能是一个问题。
默认语言(比如说Java)通常意味着你有训练有素的人员来部署、监控、调整和处理复杂的工作负载或云,所以引入另一种语言可能意味着你将是孤独的,或者需要在内部建立这种能力,这超出了纯粹的技术决定,意味着还有更多。
何时使用sidecar
一个好的指标是有一个跨领域的关注,而不是你的业务逻辑,如可观察性、安全性、性能、可靠性、审计和基础设施/运维。另一个考虑点是,你可能想避免与应用程序的二进制耦合。另外,假设你真的会获得性能,或者你有其他语言的工具更适合这项工作,或者更快、更简单。
如果你的用例符合我上面描述的要求和架构目标,那么我认为你真的应该考虑把 sidecar 作为你的解决方案。
何时应避免使用边车
如果你需要极强的性能和超低的延迟,做一个 lib 肯定会比 sidecar 快,因为你会在应用程序上运行嵌入式。你需要仔细分析这些权衡,因为还有其他的东西可以让你的 sidecar 高效,比如使用IPC、反应式编程、像Rust这样的高性能语言。另一个避免使用 sidecar 的标准可能是,最终的解决方案并不复杂,或者 sidecar 的基础设施价格并不划算(假设你不是在K8s上运行,而是在Ec2上)。
如果你需要在应用程序之外扩展 sidecar,使用 sidecar 可能不是一个好主意。然而,你总是可以使用其他的外部组件来获得扩展性,如数据库和缓存,但你仍然需要考虑这个问题。特别是当工作负载主要发生在 sidecar 上的时候。
Sidecar是一个非常有趣的架构模式,我们可以在云原生应用程序中使用。然而,我们需要重新考虑使 “sidecar所有的东西”,否则我们不会有好处。请记住,没有一个放之四海而皆准的东西。
9 - 系统设计中的Sidecar设计模式
前言
Sidecar Design Pattern in System Design
https://iq.opengenus.org/sidecar-design-pattern/
以下是内容翻译。
在这篇文章中,我们探讨了系统设计中的Sidecar设计模式,以及它的优点和缺点,还有一个使用Sidecar设计模式的真实系统设计例子。
介绍
容器的受欢迎程度正在上升,因为它可以帮助打包一个应用程序,开发人员可以在任何地方移动和部署应用程序,而不需要太多的麻烦。容器有助于减少劳动强度,提高灵活性,提供敏捷性,总的来说使应用程序的管理变得更加容易。
然而,我们如何知道我们是否在有效地使用容器,这就是设计模式发挥作用的地方。设计模式的存在是为了帮助解决容器的常见问题,因为它提供了一个有计划的应用程序的架构,以便每个人都能理解正在发生的事情。
在这篇文章中,我们将探讨容器中的 sidecar 设计模式。
传统设计模式的问题
多个应用程序通常需要一些共同的功能,如监控、日志、配置等。如果它们在主应用程序中紧密耦合,服务之间就没有隔离,应用程序的停机会导致所有服务的停机。
这就导致了应用程序内部紧密的相互依存关系。
此外,让我们假设两个应用程序A和B在每个应用程序中都有一个监控服务,并与主应用程序互锁,为了升级监控服务,每个应用程序的监控服务都必须被升级,在停机的情况下,整个应用程序的服务都会停机。
考虑到上面的图片,应用程序A和B有相同的服务集成在它们里面,它们是紧密耦合的(虚线代表功能)。为了升级我们的监控服务,我们必须单独升级监控A和监控B(它们是同一类型的服务),如果应用程序A或B中的一个出现故障,与它们相关的其他服务也会出现故障。这个系统很容易发生故障,而且不灵活。
什么是SideCar设计模式?
将应用程序的功能分离成不同的进程可以被看作是sidecar模式。sidecar模式允许开发者在主程序中不需要任何额外的配置或第三方组件的情况下为应用程序添加多种能力。
sidecar模式的最简单的例子是一个单节点双容器架构。第一个容器是应用容器,它包含主应用或应用的核心逻辑。没有这个容器,应用程序将无法运行。第二个容器是sidecar容器,它为应用程序容器增加了功能。sidecar容器与应用容器共享一些资源,如卷、网络等。
sidecar 容器可以提供一些功能,如为传统的应用程序添加HTTPS,执行监控或记录等。
容器之间的通信是通过共享公共资源来实现的,最流行的是共享卷或网络。
共享卷
当主应用程序容器和 sidecar 容器使用一个共同的卷或磁盘时,它被称为共享卷。一个很好的例子是使用 fluentd 从主应用容器中读取日志,fluentd 会读取日志并以更简洁的格式生成。
在这个例子中,作为主应用程序的 file-app 容器写下了它的日志,而 fluentd 则解析了这些日志并以更好的模式输出。两个容器都共享主机中的文件目录。
共享网络
当主应用程序容器和 sidecar 容器共享同一个网络来进行通信时,这就是共享网络的例子。一个很好的例子是使用像 flask 这样的网络服务器和 rabbitmq 这样的消息队列。
在这里,flask 服务器在5000端口运行,rabbitmq容器在同一网络中与之并行(docker compose中的容器默认共享同一网络)。
SideCar设计的优势
-
sidecar容器是独立于主应用容器的,它不依赖于主容器所使用的框架或语言,因此没有必要为每一种语言创建不同的sidecar容器。
-
sidecar能够访问与主应用程序相同的资源。
-
sidecar在应用程序代码和平台之间提供松散的耦合。
-
在微服务架构中,由于不需要在每个容器内编写配置代码,所以代码的重复性会降低。
-
即使主应用程序可能出现停机,Sidecar容器仍在运行。
SideCar设计的缺点
- 容器之间有很多通信,在进程间的通信中很难调试或发现问题。
- 这种模式只能用于基于容器的环境。
- 由于大量的容器作为 sidecar 容器,内存需求非常高。
系统设计实例
让我们来看看这个设计的一个简单实现:
这是一个数据处理应用程序,主应用程序在中心,它连接到一个数据库。有两个sidecar容器,日志收集器与主应用程序共享一个公共卷。主应用程序将它的日志写入公共卷,而 sidecar 容器则读取日志并以GUI格式显示。
由于应用程序必须做大量的数据处理和建模,这是一个非常繁重的任务,它有一个数据处理器 sidecar 容器连接到它,它处理和清理数据,对其进行建模,并将结果返回给主应用程序。