被称为“十二因素应用”的指南于十多年前首次发布。 自那时起,几乎所有强制性做法都已成为编写和部署 Web 应用程序事实上的标准方式。 尽管它们在应用程序组织和部署方式发生变化时仍然适用,但在某些情况下,需要额外的细微差别来理解这些实践如何应用于开发和部署应用程序的微服务模式。
本博客重点关注因素 3,将配置存储在环境中,其中指出:
当您转向微服务时,您仍然可以遵循这些准则,但并不总是以与十二要素应用程序的字面解释完全对应的方式。一些准则(例如将配置数据作为环境变量提供)可以很好地延续。 其他常见的微服务实践在尊重十二因素应用的核心原则的同时,更像是对它的扩展。 在本文中,我们将从因素 3 的角度来探讨微服务配置管理的三个核心概念:
在开始讨论将因素 3 应用于微服务之前,了解一些关键术语和概念会很有帮助。
通过单片应用,组织中的所有团队都在同一个应用和周围的基础设施上工作。 尽管从理论上讲,单片应用程序通常看起来比微服务更简单,但组织决定转向微服务有几个常见原因:
当然,微服务也有其自身的挑战——包括复杂性增加、可观察性降低以及需要新的安全模型——但许多组织,尤其是大型或快速发展的组织,认为这些挑战是值得的,因为它们可以为他们的团队提供更多自主权和灵活性,为他们为客户提供的体验创建可靠、稳定的基础。
当您将单体应用重构为微服务时,您的服务必须:
对于单片应用程序来说,流程中的微小不一致和对共享假设的依赖并不重要。 然而,由于存在大量独立的微服务,这些不一致和假设可能会带来很多麻烦和混乱。 使用微服务需要进行的许多更改都是技术上的必要性,但令人惊讶的是,许多更改涉及团队内部如何工作以及与其他团队如何互动。
采用微服务架构的显著组织变化包括:
我们需要扩展因素 3 的微服务架构的一个领域涉及需要明确定义有关服务的某些重要信息(包括其配置),并假设与其他服务具有最低限度的共享上下文。 因素 3 并未直接解决这个问题,但当大量独立的微服务对应用功能做出贡献时,它就显得尤为重要。
作为微服务架构中的服务所有者,您的团队拥有在整个系统中发挥特定作用的服务。 与您的服务交互的其他团队需要访问您的服务的存储库来阅读代码和文档以及做出贡献。
此外,软件开发领域的一个不幸的现实是团队成员经常变动,这不仅是因为开发人员加入和离开公司,还因为内部重组。 此外,特定服务的责任也经常在团队之间转移。
鉴于这些现实情况,您的代码库和文档需要非常清晰和一致,这可以通过以下方式实现:
许多应用程序框架提供了定义所需配置的方法。 例如,Node.js应用的convict
NPM 包使用存储在单个文件中的完整配置“模式”。 它是 Node.js 应用程序运行所需的所有配置的真实来源。
强大且易于发现的模式使您的团队成员和其他人可以轻松地与您的服务进行自信的交互。
明确定义应用需要哪些配置值后,您还需要注意已部署的微服务应用从中提取配置的两个主要来源之间的重要区别:
部署脚本是微服务架构中常见的代码组织模式。 由于它们是自十二因素应用程序首次发布以来的新内容,因此它们必然代表了它的扩展。
近年来,在与应用代码相同的存储库中拥有一个名为基础设施(或该名称的变体)的文件夹已变得很常见。 它通常包含:
乍一看,这似乎违反了因素 3 的规定,即配置与代码严格分离。
事实上,将其放置在应用旁边意味着基础设施文件夹实际上遵守规则,同时实现有价值的流程改进,这对于在微服务环境中工作的团队至关重要。
这种模式的好处包括:
请注意,此模式提供的好处增强了单个团队的自主性,同时还确保在部署和配置过程中应用额外的严格性。
实际上,您可以使用存储在基础结构文件夹中的部署脚本来管理脚本本身中明确定义的配置以及在部署时从外部源检索配置,通过为服务部署脚本:
您可以在基础设施文件夹中的文件中直接指定特定于您服务的特定部署且完全由您的团队控制的配置值。 一个例子可能是对应用程序启动的数据库查询的运行时间长度的限制。 可以通过修改部署文件并重新部署应用来更改此值。
这种方案的一个好处是,对此类配置的更改必须经过代码审查和自动测试,从而减少了错误配置的值导致中断的可能性。 经过代码审查的值的更改以及任何给定时间的配置键的值的更改都可以在源代码控制工具的历史记录中发现。
应用运行所需但不在您的团队控制范围内的值必须由部署应用的环境提供。 一个例子是服务连接到它所依赖的另一个微服务的主机名和端口。
由于该服务不属于您的团队,因此您无法对端口号等值做出假设。 这些值可能随时发生变化,并且需要在变化时向某个中央配置存储进行注册——无论该更改是手动完成的还是通过某些自动过程完成的。 然后依赖它们的应用就可以查询它们。
我们可以将这些准则总结为两种微服务配置的最佳实践。
在部署脚本中对某些值进行硬编码似乎是最简单的,例如您的服务与之交互的服务的位置。 实际上,对这种类型的配置进行硬编码是危险的,特别是在服务位置经常发生变化的现代环境中。 如果您不拥有第二项服务,那就特别危险了。
您可能认为您可以依靠自己的勤奋来在脚本中更新服务位置,或者更糟的是,您可以依靠拥有团队在位置发生变化时通知您。 在压力之下,勤奋常常会被忽视,而依赖人类的严谨性会让你的系统面临毫无预警地失败的风险。
无论位置信息是否是硬编码的,您的应用都不能依赖于位于某个位置的关键基础设施。 相反,新部署的服务需要向系统内的一些常见来源询问问题,例如“我的数据库在哪里?”,并收到关于该外部资源当前位置的准确答案。 每个服务在部署时都向系统注册自己,可以让事情变得简单得多。
正如系统需要回答“我的数据库在哪里?”和“我所依赖的‘服务 X’在哪里?”这些问题一样,服务必须以某种方式暴露给系统,以便其他服务可以轻松找到它并与其通信,而无需了解它是如何部署的。
微服务架构中的一个关键配置实践是服务发现:注册新的服务信息并在其他服务访问时动态更新该信息。 在解释了为什么服务发现对于微服务是必要的之后,让我们来探索一个如何使用 NGINX Open Source 和 Consul 来实现它的示例。
同时运行一个服务的多个实例(部署)是一种常见的做法。 这不仅可以处理额外的流量,还可以通过启动新的部署来更新服务而无需停机。 NGINX 等工具充当反向代理和负载均衡器,处理传入流量并将其路由到最合适的实例。 这是一个很好的模式,因为依赖于您的服务的服务只向 NGINX 发送请求,而不需要知道有关您的部署的任何信息。
举例来说,假设您在 NGINX 后面运行一个名为messenger的服务的单个实例,充当反向代理。
如果您的应用程序变得流行起来会怎样? 这被认为是好消息,但随后您会注意到,由于流量增加,信使实例消耗了大量 CPU,并且需要更长的时间来处理请求,而数据库似乎运行良好。 这表明您可能能够通过部署信使服务的另一个实例来解决问题。
当你部署通讯服务的第二个实例时,NGINX 如何知道它处于活动状态并开始向其发送流量? 手动向 NGINX 配置添加新实例是一种方法,但随着更多服务的扩大和缩小,它很快就会变得难以管理。
一种常见的解决方案是使用像Consul这样的高可用性服务注册表来跟踪系统中的服务。 新的服务实例在部署时向 Consul 注册。 Consul 通过定期发送健康检查来监控实例的状态。 当实例未通过健康检查时,它将从可用服务列表中删除。
NGINX 可以使用多种方法查询像 Consul 这样的注册表并相应地调整其路由。 回想一下,当充当反向代理或负载均衡器时,NGINX 会将流量路由到“上游”服务器。 考虑这个简单的配置:
# 定义一个名为“messenger_service”的上游组
upstream messenger_service {
server 172.18.0.7:4000;
server 172.18.0.8:4000;
}
server {
listen 80;
location /api {
# 将路径以“/api”开头的 HTTP 流量代理到上面的
# 'upstream' 块。 默认的负载平衡算法
# Round-Robin,在块中的两个服务器之间交替发送请求。
proxy_pass http://messenger_service;
proxy_set_header X-Forwarded-For $remote_addr;
}
}
默认情况下,NGINX 需要知道每个消息传递实例的精确 IP 地址和端口,以便将流量路由到它。 在这种情况下,172.18.0.7 和 172.18.0.8 上的端口都是 4000。
这就是 Consul 和Consul 模板发挥作用的地方。 Consul 模板与 NGINX 在同一个容器中运行,并与维护服务注册表的 Consul 客户端进行通信。
当注册信息发生变化时,Consul 模板会生成一个具有正确 IP 地址和端口的新版本的 NGINX 配置文件,将其写入 NGINX 配置目录,并告诉 NGINX 重新加载其配置。 NGINX 重新加载其配置时不会出现停机,并且新实例在重新加载完成后立即开始接收流量。
在这种情况下,使用 NGINX 之类的反向代理,有一个单一接触点可以向系统注册作为其他服务访问的地方。 您的团队可以灵活地管理单个服务实例,而不必担心其他服务失去对整个服务的访问权限。
不可否认,微服务增加了复杂性,无论是从服务的技术角度还是从与其他团队的关系的组织角度来说。 要享受微服务架构的好处,重要的是严格地重新审视为整体式架构设计的实践,以确保它们在应用于非常不同的环境时仍然提供相同的好处。 在这篇博客中,我们探讨了十二要素应用程序中的要素 3 如何在微服务环境中仍然提供价值,但可以从具体应用方式的微小变化中受益。
要了解有关将十二要素应用程序应用于微服务架构的更多信息,请查看 2023 年 3 月微服务第 1 单元(即将在博客上发布)。 免费注册即可参加关于此主题的网络研讨会和实践实验室。
“这篇博文可能引用了不再可用和/或不再支持的产品。 有关 F5 NGINX 产品和解决方案的最新信息,请探索我们的NGINX 产品系列。 NGINX 现在是 F5 的一部分。 所有之前的 NGINX.com 链接都将重定向至 F5.com 上的类似 NGINX 内容。”