Docker生态系统:服务发现和分布式配置存储
介绍
容器为那些希望大规模设计和部署应用程序的人提供了一个优雅的解决方案。 虽然 Docker 提供了实际的容器化技术,但许多其他项目协助开发在部署环境中进行适当引导和通信所需的工具。
许多 Docker 环境所依赖的核心技术之一是服务发现。 服务发现允许应用程序或组件发现有关其环境和邻居的信息。 这通常实现为分布式键值存储,它也可以作为更通用的位置来指示配置细节。 配置服务发现工具允许您将运行时配置与实际容器分开,这允许您在多个环境中重用相同的图像。
在本指南中,我们将讨论集群 Docker 环境中服务发现的好处。 我们将主要关注一般概念,但在适当的情况下提供更具体的示例。
服务发现和全球可访问的配置存储
服务发现背后的基本思想是应用程序的任何新实例都应该能够以编程方式识别其当前环境的细节。 这是为了让新实例能够“插入”到现有应用程序环境而无需人工干预。 服务发现工具通常被实现为一个全局可访问的注册表,它存储有关当前正在运行的实例或服务的信息。 大多数时候,为了使这种配置具有容错性和可扩展性,注册表分布在基础架构中的可用主机之间。
虽然服务发现平台的主要目的是提供连接细节以将组件链接在一起,但它们可以更普遍地用于存储任何类型的配置。 许多部署通过将配置数据写入发现工具来利用此功能。 如果容器配置为知道要查找这些详细信息,则它们可以根据找到的内容修改其行为。
服务发现如何工作?
每个服务发现工具都提供了一个 API,组件可以使用该 API 来设置或检索数据。 因此,对于每个组件,服务发现地址必须要么硬编码到应用程序/容器本身中,要么在运行时作为选项提供。 通常,发现服务被实现为使用标准 http 方法可访问的键值存储。
服务发现门户的工作方式是,每个服务在上线时都会向发现工具注册自己。 它记录相关组件可能需要的任何信息,以便使用它提供的服务。 例如,MySQL 数据库可能会注册运行守护程序的 IP 地址和端口,以及登录所需的用户名和凭据(可选)。
当该服务的消费者上线时,它能够在预定义的端点查询服务发现注册表以获取信息。 然后它可以根据它找到的信息与它需要的组件进行交互。 负载均衡器就是一个很好的例子。 它可以通过查询服务发现门户并相应地调整其配置来找到需要向其提供流量的每个后端服务器。
这会将配置细节从容器本身中取出。 这样做的好处之一是它使组件容器更加灵活,并且更少地绑定到特定配置。 另一个好处是它可以让您的组件对相关服务的新实例做出反应变得简单,从而允许动态重新配置。
配置存储如何关联?
全球分布式服务发现系统的一个关键优势是它可以存储组件在运行时可能需要的任何其他类型的配置数据。 这意味着您可以从容器中提取更多配置并进入更大的执行环境。
通常,为了使这项工作最有效,您的应用程序应该设计有合理的默认值,这些默认值可以在运行时通过查询配置存储来覆盖。 这允许您使用类似于使用命令行标志的方式的配置存储。 不同之处在于,通过使用全球可访问的商店,您可以为组件的每个实例提供相同的选项,而无需额外的工作。
配置存储如何帮助集群管理?
Docker 部署中分布式键值存储的一项功能最初可能并不明显,即集群成员的存储和管理。 为了管理工具,配置存储是跟踪主机成员的完美环境。
分布式键值存储中可能存储的有关各个主机的一些信息是:
- 主机 IP 地址
- 主机本身的连接信息
- 可以针对调度决策的任意元数据和标签
- 集群中的角色(如果使用领导者/跟随者模型)
这些细节在正常情况下使用服务发现平台时可能不需要关心,但它们为管理工具提供了查询或修改集群本身信息的位置。
故障检测呢?
故障检测可以通过多种方式实现。 问题是,如果组件发生故障,发现服务是否会更新以反映它不再可用的事实。 此类信息对于最大程度地减少应用程序或服务故障至关重要。
许多服务发现平台允许使用可配置的超时设置值。 该组件可以设置一个超时值,并定期 ping 发现服务以重置超时。 如果组件失败并且达到超时,则从存储中删除该实例的连接信息。 超时的长度很大程度上取决于应用程序需要多快响应组件故障。
这也可以通过将准系统“帮助器”容器与每个组件相关联来实现,其唯一职责是定期检查组件的健康状况并在组件出现故障时更新注册表。 这种架构的问题是辅助容器可能会关闭,从而导致存储中的信息不正确。 一些系统通过在服务发现工具中定义健康检查来解决这个问题。 这样,发现平台本身可以定期检查注册的组件是否仍然可用。
当细节发生变化时重新配置服务怎么办?
对基本服务发现模型的一项关键改进是动态重新配置。 虽然正常的服务发现允许您通过在启动时检查发现信息来影响组件的初始配置,但动态重新配置涉及配置您的组件以对配置存储中的新信息做出反应。 例如,如果您实施负载均衡器,后端服务器上的健康检查可能表明池中的一个成员已关闭。 负载均衡器的运行实例需要得到通知,并且需要能够调整其配置并重新加载以解决此问题。
这可以通过多种方式实现。 由于负载平衡示例是此功能的主要用例之一,因此存在许多项目,它们专门专注于在检测到配置更改时重新配置负载平衡器。 HAProxy 配置调整很常见,因为它在负载均衡空间中无处不在。
某些项目更灵活,因为它们可用于触发任何类型软件的更改。 这些工具定期查询发现服务,当检测到更改时,使用模板系统生成包含在发现端点找到的值的配置文件。 生成新的配置文件后,会重新加载受影响的服务。
这种类型的动态重新配置需要在构建过程中进行更多的规划和配置,因为所有这些机制都必须存在于组件的容器中。 这使得组件容器本身负责调整其配置。 找出写入发现服务的必要值并设计适当的数据结构以便于使用是该系统所需的另一个挑战,但好处和灵活性可能是巨大的。
安全呢?
许多人在第一次了解可全局访问的配置存储时担心的一个问题是安全性。 将连接信息存储到全球可访问的位置真的可以吗?
该问题的答案在很大程度上取决于您选择在商店中放置什么以及您认为保护数据所需的安全层数。 几乎每个服务发现平台都允许使用 SSL/TLS 加密连接。 对于某些服务,隐私可能不是非常重要,将发现服务放在专用网络上可能会令人满意。 但是,大多数应用程序可能会受益于额外的安全性。
有许多不同的方法可以解决这个问题,并且各种项目都提供了自己的解决方案。 一个项目的解决方案是继续允许对发现平台本身的开放访问,但对写入其中的数据进行加密。 应用程序使用者必须具有关联的密钥才能解密它在存储中找到的数据。 其他方将无法访问未加密的数据。
对于不同的方法,一些服务发现工具实施访问控制列表,以便将密钥空间划分为单独的区域。 然后,他们可以根据特定密钥空间定义的访问要求指定对区域的所有权或访问权。 这建立了一种简单的方法,可以为某些方提供信息,同时对其他人保密。 每个组件都可以配置为只能访问它明确需要的信息。
有哪些常见的服务发现工具?
现在我们已经讨论了服务发现工具和全球分布式键值存储的一些一般特性,我们可以提及一些与这些概念相关的项目。
一些最常见的服务发现工具是:
- etcd:这个工具是由 CoreOS 的制造商创建的,用于为容器和主机系统本身提供服务发现和全局分布式配置。 它实现了一个 http API,并在每台主机上都有一个命令行客户端。
- consul:该服务发现平台具有许多使其脱颖而出的高级功能,包括可配置的健康检查、ACL 功能、HAProxy 配置等。
- zookeeper:这个例子比前两个老了一点,提供了一个更成熟的平台,但牺牲了一些更新的特性。
其他一些扩展基本服务发现的项目是:
- crypt:Crypt 允许组件使用公钥加密来保护它们写入的信息。 可以为要读取数据的组件提供解密密钥。 所有其他方将无法读取数据。
- confd:Confd 是一个旨在允许基于服务发现门户中的更改动态重新配置任意应用程序的项目。 该系统包括一个监视相关端点变化的工具,一个基于收集到的信息构建新配置文件的模板系统,以及重新加载受影响应用程序的能力。
- vulcand:Vulcand 用作组件组的负载平衡器。 它是 etcd 感知的,并根据在存储中检测到的更改修改其配置。
- marathon:虽然 marathon 主要是一个调度程序(稍后会介绍),但它还实现了一种基本功能,即在对应该平衡的可用服务进行更改时重新加载 HAProxy。
- frontrunner:该项目挂钩马拉松,为更新 HAProxy 提供更强大的解决方案。
- synapse:这个项目引入了一个嵌入式 HAProxy 实例,可以将流量路由到组件。
- nerve:Nerve 与突触结合使用,为各个组件实例提供健康检查。 如果组件变得不可用,神经会更新突触以使组件停止旋转。
结论
服务发现和全局配置存储允许 Docker 容器适应其当前环境并插入现有组件。 这是通过允许组件跟踪和响应其环境中的变化来提供简单、免提的可扩展性和部署的必要先决条件。
在 下一篇指南 中,我们将讨论 Docker 容器和主机可以与自定义网络配置进行通信的方式。