边车(Sidecar)容器在不改变原有容器的情况下,扩展和增强了它的功能。这种模式是基本的容器模式之一,它允许单一用途的容器紧密合作。在本章中,我们学习所有关于基本的 Sidecar 概念。专门的后续模式适配器(Adapter)和大使(Ambassador)模式分别在第 16 章和第 17 章讨论。
问题描述
容器是一种流行的打包技术,它允许开发人员和系统管理员以统一的方式构建、运输和运行应用程序。容器代表了一个功能单元的自然边界,它有一个独特的运行时间、发布周期、API 和拥有它的团队。一个合适的容器就像一个单一的 Linux 程序 — 解决了一个问题,并且做得很好,并且是以可替换性和重用性的理念来创建的。最后一部分是必不可少的,因为它允许我们通过利用现有的专门容器更快地构建应用程序。
今天,要进行一个 HTTP 调用,我们不需要写一个客户端库,而是使用一个现有的库。同样,要为一个网站提供服务,我们不需要为网络服务器创建一个容器,而是使用一个现有的容器。这种方法可以让开发人员避免重新造轮子,并创建一个生态系统,用较少数量的高质量容器来维护。然而,拥有单一用途的可重用容器需要扩展容器功能的方法和容器间协作的方法。Sidecar 模式描述了这种协作,即一个容器增强另一个已有容器的功能。
解决方案
在第 1 章中,我们介绍了 Pod 如何让我们将多个容器组合成一个单元。在幕后,在运行时,Pod 也是一个容器,但它是作为一个暂停的进程启动的(字面意思是使用 pause
命令),比 Pod 中的所有其他容器都要早。在 Pod 的整个生命周期中,它除了持有应用容器用来交互的所有 Linux 名称空间外,并没有做任何其他事情。除了这个实现细节,更有趣的是 Pod 抽象提供的所有特性。
Pod 是这样一个基本的资源,它以不同的名称存在于许多云原生平台形式中,但总是具有类似的功能。作为部署单元的 Pod 对属于它的容器施加了某些运行时约束。例如,所有的容器最终都会部署到同一个节点,并且它们共享相同的 Pod 生命周期。此外,一个 Pod 允许其容器共享卷,并通过本地网络或主机 IPC 进行通信。这些都是用户将一组容器放入 Pod 的原因。Sidecar(有些地方也叫 Sidekick)用来描述一个容器放入 Pod 中以扩展和增强另一个容器行为的场景。
用于演示这种模式的一个典型例子是用一个 HTTP 服务器和一个 Git 同步器。HTTP 服务器容器只专注于通过 HTTP 服务文件,并不知道文件是如何和从哪里来的。同样,Git 仓库同步容器的唯一目标是将数据从 Git 服务器同步到本地文件系统中。它并不关心同步后的文件如何处理,它唯一关心的是保持本地文件夹与远程 Git 服务器的同步。例 15-1 展示了一个 Pod 的定义,它将这两个容器配置为使用卷来交换文件。
# 例 15-1 带有 Sidecar 的 Pod
---
apiVersion: v1
kind: Pod
metadata:
name: web-app
spec:
containers:
- name: app
# 通过 HTTP 提供文件的主要应用容器
image: docker.io/centos/httpd
ports:
- containerPort: 80
volumeMounts:
# Sidecar 和主应用程序容器之间交换数据的共享位置
- mountPath: /var/www/html
name: git
- name: poll
# Sidecar 容器并行运行,并从 Git 服务器拉取数据
image: axeclbr/git
volumeMounts:
# Sidecar 和主应用程序容器之间交换数据的共享位置
- mountPath: /var/lib/data
name: git
env:
- name: GIT_REPO
value: https://github.com/mdn/beginner-html-site-scripted
command:
- "sh"
- "-c"
- "git clone $(GIT_REPO) . && watch -n 600 git pull"
workingDir: /var/lib/data
volumes:
- emptyDir: {}
name: git
这个例子展示了 Git 同步器如何增强 HTTP 服务器的行为与内容服务,并保持同步。我们也可以说,这两个容器相互协作,同等重要,但在 Sidecar 模式中,有一个主容器和一个辅助容器来增强集体行为。通常情况下,主容器是容器列表中列出的第一个容器,它代表了默认容器(例如,当我们运行命令:kubectl exec
)。
这种简单的模式,如图 15-1 所示,允许容器的运行时协作,同时,还可以分离两个容器的关注点,这两个容器可能由不同的团队拥有,使用不同的编程语言,具有不同的发布周期等。它还促进了容器的可替换性和重用性,作为 HTTP 服务器,Git 同步器可以作为 Pod 中的单个容器或再次与其他容器协作,在其他应用和不同配置中重用。
图 15-1 边车(Sidecar)模式示例
一些讨论
前面我们说过,容器镜像就像类,而容器就像面向对象编程(OOP)中的对象。如果我们继续这个类比,扩展容器以增强其功能类似于 OOP 中的继承,而在一个 Pod 中协作的多个容器类似于 OOP 中的组成。虽然这两种方法都允许代码重用,但继承涉及到容器之间更紧密的耦合,并代表了容器之间的 “is-a” 关系。
另一方面,Pod 中的组合代表的是一种 “has-a” 关系,它更灵活,因为它不在构建时将容器耦合在一起,使得以后可以在 Pod 定义中交换容器。另一方面,Pod 中的组成意味着你有多个容器(进程)在运行,健康检查,重启,并像主应用容器一样消耗资源。现代的 Sidecar 容器体积小,消耗的资源最少,但你必须决定是否值得运行一个单独的进程,还是将其合并到主容器中更好。
从另一个角度来看,容器组成类似于面向方面的编程,通过额外的容器,我们在不触及主容器的情况下,将正交的功能引入到 Pod 中。最近几个月,Sidecar 模式的使用变得越来越普遍,尤其是在处理服务的网络、监控和跟踪方面,每个服务也都会运送 Sidecar 容器。