《十二要素应用(twelve-factor app)》指南于十多年前首次发布。从那时起,几乎所有其规定的做法都成为了编写和部署网络应用的事实标准。尽管这些做法在应用的组织和部署方式发生变化后仍然适用,但在某些情况下,要理解这些做法如何应用于开发和部署应用的微服务模式,还需要注意一些额外的细微差别。
本文主要讲述要素 3 — 在环境中存储配置,其要义是:
对于微服务,您仍然可以遵守这些准则,但不一定完全拘泥于《十二要素应用》的字面含义。有些准则,例如将配置数据作为环境变量,完好地延续了下来。而其他常见的微服务实践,虽然遵循《十二要素应用》的核心原则,但更像是对它的扩展。在这篇文章中,我们将从要素 3 的角度来理解微服务配置管理的三个核心概念:
在讨论如何根据微服务调整要素 3 之前,了解一些关键术语和概念是很有帮助的。
在单体应用中,企业中的所有团队都使用同一个应用及其相关基础架构。尽管单体应用通常看起来比微服务简单,但由于以下几个常见原因,企业会决定迁移至微服务:
当然,微服务也有其自身的挑战,包括复杂性的增加、可观测性的降低以及对新安全模型的需求。但许多企业,尤其是大型企业或快速发展的企业,认为这些挑战是值得的,因为微服务可以让他们的团队拥有更高的自主权和灵活性,奠定可靠、稳定的基础以打造出色的客户体验。
当您将单体应用重构为微服务时,您的 service 必须:
对于单体应用来说,轻微的流程不一致和对共同假设的依赖不算是大问题。但对于许多独立的微服务来说,这些不一致和假设可能会带来很多麻烦和混乱。您对微服务进行的许多更改都是出于技术需要,但还有很多更改涉及到团队内外的工作方式。
微服务架构给企业带来的显著变化包括:
在微服务架构中,我们需要扩展要素 3,这就需要明确定义关于服务的某些重要信息,包括其配置,并假设它与其他服务共享极少的上下文。要素 3 并没有直接解决这个问题,但当应用功能涉及许多独立的微服务时,这个问题就显得尤为重要。
作为微服务架构中的服务所有者,您的团队拥有在整个系统中发挥特定作用的服务。当其他团队的服务与您的服务进行交互时,他们需要访问您的服务代码库,以读取代码和文档,并做出贡献。
但不幸的是,在软件开发领域,由于公司开发人员的频繁流动和内部重组,团队成员经常发生变化。另外,特定服务的职责也经常在团队之间转移。
鉴于以上现实,您的代码库和文档需要通过以下方式保持清晰一致:
许多应用框架提供了定义所需配置的方法。例如,Node.js 应用的 convict
NPM 包使用存储在单个文件中的完整配置“模式”。它充当了 Node.js 应用运行所需的所有配置的信源。
借助功能强大且易于发现的配置模式,您的团队和其他团队的成员可从容地与您的服务进行交互。
明确定义了应用所需的配置值后,您还需要注意已部署的微服务应用的两个主要配置来源之间的重要区别:
部署脚本是微服务架构中的一种常见代码组织模式。它们是在《十二要素应用》问世后推出的,因此代表了后者的延伸。
近年来,在应用代码所在的代码库中通常会发现一个名为“基础架构”(或类似命名)的文件夹。它通常包含:
乍一看,这似乎违反了要素 3 关于配置与代码严格分离的规定。
但事实上,贴近应用的部署不仅遵守这一规则,还提供了流程的改进,这对在微服务环境中工作的团队至关重要。
这种模式的优势包括:
请注意,这种模式可以帮助提高各个团队的自主性,同时也确保了部署和配置过程的严谨性。
在实践中,您可以使用存储在基础架构文件夹中的部署脚本来管理在脚本中明确定义的配置,并在部署时从外部来源检索配置,方法是使用服务的部署脚本:
针对特定服务部署并且完全由您的团队控制的配置值可以直接在基础架构文件夹中的文件中进行指定。例如,应用可以预定义数据库查询允许运行时长的上限。这个值可以通过修改部署文件和重新部署应用来更改。
这种方案的一个好处是,对这种配置的更改必须经过代码审查和自动测试,从而降低了配置错误导致停机的可能性。在源代码控制工具的历史记录中,可以看到在任何特定时间对经过代码审查的值和配置密钥的值所做的更改。
应用运行所需但不受团队控制的值,必须由部署应用的环境提供,例如服务连接到其所依赖的另一个微服务的主机名和端口。
因为该服务不属于您的团队,所以您不能对端口号等值进行预设。这些值可以随时更改,并且在更改时需要在一些中央配置存储中进行注册 — 无论是手动更改还是通过一些自动流程进行更改。然后,依赖这些值运行的应用便可以查询这些值。
我们可以将这些指南凝练成微服务配置的两个最佳实践。
在部署脚本中对某些值——例如与您的服务交互的服务的位置——进行硬编码看似轻而易举。但事实上,对这种类型的配置进行硬编码是存在危险的,特别是在服务位置经常更改的现代环境中。如果您不拥有这些服务的管理权,那么这种操作格外危险。
您可能会认为,您可以靠自己在脚本中更新服务位置,或者可以让拥有服务的团队在位置更改时通知您。然而忙中难免出纰漏,把系统的可靠性交给人类,依赖人的认真,只会使您的系统无征兆地直接停掉。
无论位置信息是否经过硬编码,应用都不能依赖于关键基础架构存在于某个位置。新部署的服务需要在系统中询问一些常见的源问题,比如“我的数据库在哪里?”,并获得关于外部资源当前位置的准确答案。让每个服务在部署时都在系统中进行注册,这会让事情变得简单得多。
正如系统需要回答“我的数据库在哪里?”和“我使用的 ‘某服务’ 在哪里?”,必须将服务暴露给系统,以便其他服务可以轻松地找到并与它通信,而不需要知道它是如何部署的。
微服务架构中的一个关键配置实践是服务发现:注册新的服务信息,并在其他服务访问时动态更新这些信息。在解释了为何微服务需要服务发现后,下面我们来看一个如何用 NGINX 开源版和 Consul 实现服务发现的示例。
同时运行一个服务的多个实例(部署)很常见。这样不仅可以处理额外的流量,还可以通过启动新的部署在不停机的情况下更新服务。作为反向代理和负载均衡器,NGINX 等工具会处理传入流量并将其路由到最合适的实例。这是一种很好的模式,因为依赖您服务运行的服务只向 NGINX 发送请求,而不需要了解您的部署。
举个例子,假设您有一个名为 messenger 的服务实例在充当反向代理的 NGINX 后面运行。
如果您的应用成为了热门应用,会怎样呢?这算是个好消息,但由于流量增加,信使实例会消耗大量 CPU 并花费更长的时间来处理请求,而数据库似乎运转良好。这表明您可以通过部署信使服务的另一个实例来解决这个问题。
当您部署信使服务的第二个实例时,NGINX 如何知道它当前可用并开始向它发送流量呢?您可以手动向 NGINX 配置中添加新实例,但随着更多服务扩展和缩减,这种方法很快就会变得难以管理。
一种常见的解决方案是使用高度可用的服务注册中心(如 Consul)在系统中跟踪服务。新的服务实例在部署时通过 Consul 进行注册。Consul 通过定期发送健康检查来监控实例的状态。当实例未通过健康检查时,它将从可用服务列表中删除。
NGINX 可以使用各种方法查询 Consul 等注册中心,并相应地调整其路由。当 NGINX 充当反向代理或负载均衡器时,它会将流量路由到“上游(upstream)”服务器。看一下这个简单的配置:
# Define an upstream group called "messenger_service"upstream messenger_service {
server 172.18.0.7:4000;
server 172.18.0.8:4000;
}
server {
listen 80;
location /api {
# Proxy HTTP traffic with paths starting with '/api' to the
# 'upstream' block above. The default load-balancing algorithm,
# Round-Robin, alternates requests between the two servers
# in the block.
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 如何在微服务环境中继续提供价值,并通过轻微更改具体应用方式而获益。
如欲了解有关将《十二要素应用》应用于微服务架构的更多信息,请参见 Microservices June 微服务之月 2023 第一单元的相关内容。微服务之月是 NGINX 一年一度的免费线上教学项目,成功注册后即可获取更多有关“微服务交付”的学习资源,包括视频录像、动手实验、单元小测以及项目专属答疑群。
"This blog post may reference products that are no longer available and/or no longer supported. For the most current information about available F5 NGINX products and solutions, explore our NGINX product family. NGINX is now part of F5. All previous NGINX.com links will redirect to similar NGINX content on F5.com."