适配器(Adapter)模式将一个异构的容器化系统变成一个具有标准化和规范化格式的一致的、统一的接口,可以被外部世界使用。适配器模式继承了 Sidecar 的所有特性,但其唯一的目的是为应用程序提供适应性访问。

问题描述

容器允许我们以统一的方式打包和运行用不同库和语言编写的应用程序。今天,我们经常看到多个团队使用不同的技术,创建由异构组件组成的分布式系统。当其他系统必须以统一的方式处理所有组件时,这种异构性会造成困难。适配器模式提供了一个解决方案,它隐藏了系统的复杂性,并提供了对系统的统一访问。

解决方案

说明这种模式的最好方法是通过一个例子。成功运行和支持分布式系统的一个主要前提是提供详细的监控和警报。此外,如果我们有一个由多个服务组成的分布式系统,我们想要监控,我们可以使用外部监控工具从每个服务中轮询指标并记录它们。

然而,用不同语言编写的服务可能具有不同的功能,并且可能不会以监控工具所期望的相同格式暴露度量。这种多样性给从单一的监控解决方案中监控这样一个异构的应用程序带来了挑战,因为该解决方案期望对整个系统有一个统一的视图。通过适配器模式,可以通过导出以下内容来提供统一的监控界面。

将来自不同应用容器的度量信息转换为一种标准格式和协议。在图 16-1 中,一个适配器容器将本地存储的度量信息翻译成监控服务器能理解的外部格式。
image.png
图 16-1 适配器模式示例

采用这种方法,除了主应用容器外,每个由 Pod 代表的服务都会有另一个容器,它知道如何读取特定于应用的自定义指标,并以监控工具可理解的通用格式公开它们。我们可以有一个 Adapter 容器知道如何通过 HTTP 导出基于 Java 的度量指标,而另一个不同 Pod 的 Adapter 容器则通过 HTTP 导出基于 Python 的度量。对于监控工具来说,所有的指标都可以通过 HTTP 来实现,而且是通用的标准化格式。

对于这种模式的具体实现,让我们重温一下我们的随机生成器示例应用程序,并创建图 16-1 所示的适配器。当配置得当时,它会用随机数生成器写出一个日志文件,并包括创建随机数所花费的时间。我们要用 Prometheus 监控这个时间。不幸的是,日志格式与 Prometheus 期望的格式不一致。另外,我们需要通过 HTTP 端点提供这些信息,以便 Prometheus 服务器可以刮取该值。

对于这种用例,Adapter 是一个完美的选择:一个 Sidecar 容器启动一个小型的 HTTP 服务器,在每个请求中,读取自定义的日志文件,并将其转换为 Prometheus 可理解的格式。例 16-1 显示了一个带有这样一个适配器的部署。这种配置允许在主应用程序不需要了解任何有关 Prometheus 的情况下,进行解耦的 Prometheus 监控设置。我们 GitHub 仓库中的完整示例演示了这种设置和 Prometheus 安装。

  1. # 例 16-1 提供符合 Prometheus 标准的输出的适配器
  2. ---
  3. apiVersion: apps/v1
  4. kind: Deployment
  5. metadata:
  6. name: random-generator
  7. spec:
  8. replicas: 1
  9. selector:
  10. matchLabels:
  11. app: random-generator
  12. template:
  13. metadata:
  14. labels:
  15. app: random-generator
  16. spec:
  17. containers:
  18. # 主应用容器,随机发生器服务暴露在 8080 上
  19. - image: k8spatterns/random-generator:1.0
  20. name: random-generator
  21. env:
  22. # 包含随机数生成时间信息的日志文件的路径
  23. - name: LOG_FILE
  24. value: /logs/random.log
  25. ports:
  26. - containerPort: 8080
  27. protocol: TCP
  28. # 与 Prometheus 适配器容器共享的目录
  29. volumeMounts:
  30. - mountPath: /logs
  31. name: log-volume
  32. # --------------------------------------------
  33. # Prometheus Exporter 镜像, 输出端口为 9889
  34. - image: k8spatterns/random-generator-exporter
  35. name: prometheus-adapter
  36. env:
  37. # 主应用程序记录到的同一日志文件的路径
  38. - name: LOG_FILE
  39. value: /logs/random.log
  40. ports:
  41. - containerPort: 9889
  42. protocol: TCP
  43. # 共享卷也被安装在适配器容器中
  44. volumeMounts:
  45. - mountPath: /logs
  46. name: log-volume
  47. volumes:
  48. # 文件通过节点的文件系统中的 emptyDir 卷共享
  49. - name: log-volume
  50. emptyDir: {}

这种模式的另一个用途是记录。不同的容器可能以不同的格式和详细程度记录信息。适配器可以通过使用第 13 章中描述的自我意识(Self Awareness)模式对这些信息进行规范化、清理、用上下文信息丰富这些信息,然后使其可供集中式日志聚合器接收。

一些讨论

适配器是第 15 章中解释的 Sidecar 模式的特殊化。它作为异构系统的反向代理,将系统的复杂性隐藏在一个统一的接口后面。使用一个不同于通用的 Sidecar 模式的名称,可以让我们更精确地传达这个模式的目的。

在下一章中,你将了解另一个 Sidecar 的变体:大使(Ambassador)模式,它作为外部世界的代理。

参考资料