利用Docker技术实现微服务架构
摘要
微服务架构并非炒作,近年来开始受到组织的关注,这些组织希望通过在整个产品生命周期中最大化自动化来提高生产效率,从而缩短软件产品的上市时间。然而,微服务架构方法也引入了许多新的复杂性,要求应用程序开发者具备一定的成熟度,才能自信地应用这种架构风格。Docker 是一项颠覆性技术,改变了应用程序的开发和分发方式。凭借诸多优势,Docker 非常适合用于实现微服务架构。在本论文中,我们将通过一个实际运行模型的案例研究,探讨 Docker 如何有效帮助利用微服务架构。
关键词 —微服务;Docker;DevOps;自动化
一。引言
迄今为止,构建软件应用程序的常见方式是单体架构,即一个部署单元承担多种职责,在某些情况下几乎负责所有功能。单体架构对于小规模团队和项目仍然适用,但当可扩展性、灵活性以及快速开发、快速上市、更广泛的团队协作等要求日益成为提升企业竞争力的关键因素时,单体架构便逐渐成为一大障碍。
当代码库变得越来越大、越来越复杂,并且有越来越多的人对其进行修改时,由于单体架构的紧耦合模型,响应用户或商业模式频繁提出的重大变更需求而对应用程序进行修改将变得更加困难。这种模式自然需要投入越来越多的协调工作来完成必要的更新,从而减慢了应用程序的发布周期,并进一步加剧了其脆弱性。
微服务架构方法被提出作为解决单体式架构问题的方案。尽管从理论上讲,它应能解决单体式架构中的大多数问题,但微服务也存在诸多缺点,这凸显了开发者必须具备一定程度的自动化和敏捷性成熟度,才能充分利用其优势。在容器化技术中,Docker处于领先地位,极大地推动了微服务架构在众多应用场景中的应用。
II. 微服务架构
微服务是协同工作以满足业务需求的小型自治服务。本节将讨论微服务架构中的一些基本概念和特性。
A. 小而专注
尽管“小”并不是描述微服务的一个很好的衡量标准,但我们仍可以借此强调微服务最重要的特性之一,即每个服务都是细粒度的、高内聚的,专注于完成一个具体的职责。
在企业环境中,微服务的设计应以业务为导向的驱动因素为核心。这意味着最终形成的微服务不应模仿组织、技术或通信边界,而应围绕特定的业务领域进行建模。
从开发角度来看,每个服务都应被视为具有独立源代码仓库和交付管道的独立应用程序。
B. 松散耦合
松耦合是微服务的一个重要特征。每个微服务都需要被部署为在无需与其他服务所有者协调的情况下即可完成。如果你有两个服务,并且总是将这两者一起作为一个大型部署发布,这可能意味着它们实际上应该合二为一,当前的服务拆分还有进一步优化的空间。松耦合使得频繁且快速的部署成为可能,最终提升应用程序对其用户需求的响应能力。
C. 语言中立
微服务需要使用开发者最熟悉的技术来构建。开发团队不应受限于任何特定的编程语言,这意味着微服务架构能够充分利用最适合任务本身以及执行任务人员的技术,从而发挥使用技术的自由度。这使得团队能够更充分地利用自身掌握的最优技术和技能优势。
由于微服务具有语言中立性,它们之间的通信也通过语言中立的应用程序编程接口(API)进行,通常是基于 HTTP 的资源 API,例如 REST。图1 描述了一个示例,展示了如何使用多种语言和技术通过微服务方法构建典型的在线购物系统。这些服务使用不同的编程语言和开发框架(如 Java、PHP 或 Node.js)进行开发。每个服务甚至拥有自己类型的数据存储,例如目录服务使用 Cloudant,订单服务使用 SQL 数据库,依此类推。
D. 限界上下文
限界上下文封装了单个领域内的细节,如数据模型、领域模型等。它还定义了与其他限界上下文的集成点。在微服务架构中,明确定义的限界上下文至关重要。这意味着领域之间的边界越清晰明确,我们就越能更好地进行服务设计和高效划分规模。有时,某些模型会在这些边界之间共享,而另一些模型则只需存在于每个边界区域内。
E. 构建微服务架构的挑战
除了众多优势之外,微服务架构风格另一方面也带来了一些挑战,在能够产生效益之前需要解决这些挑战。
1) 故障隔离
故障在所难免,只是时间问题。当特定服务发生故障时,最好能够快速失败。快速失败有助于更好地理解和解决问题。同时,我们需要采用分而治之模型,将系统划分为更小的部分,并利用或创建快速工具,以支持持续交付大量微小变更,使开发者能够一次只更改一个内容;如果出现问题,我们就能明确只有这一部分发生了故障。
为失败而设计是在成功构建基于微服务的系统中的一个重要要求。
2) 可观测性
微服务架构需要一种方法来可视化系统中每个服务的健康状态,以便快速定位和响应出现的任何问题。这还包括一个综合日志机制,用于记录、存储日志并使其可搜索,以更好地分析日志。这比仅仅增加大量监控项目要复杂得多。面对所有快速变化的组件,观测设计需要能够合理地呈现被可视化数据,从而为分析提供有价值的输入信息。
3) 自动化需求
利用自动化的文化至关重要,也是列表中最受挑战的项目。服务数量及其之间关系的激增将在某个时间点发生,可能很快就会超出无法通过自动化手段处理的程度。
4) 高独立性
基于微服务的系统的一个主要原则是使服务高度解耦。这意味着必须保持服务之间的独立性,以便每个服务都可以独立开发和部署,且互不影响。
5) 测试
测试在构建微服务架构时属于最具挑战性的任务之一。更多的移动部件意味着发生故障的可能性更高。如何确保测试足够全面以覆盖所有方面并不容易。随着时间的推移,自动化测试已显著进步,新的工具和技术不断涌现。然而,挑战依然存在,尤其是在分布式模型中,如何有效且高效地测试系统的功能性和非功能性方面。由于存在更多独立组件及其之间的协作模式,微服务架构甚至为测试增加了新的复杂性 [1]。
6) 可扩展性
尽管构建微服务架构的一个重要动机是解决可扩展性问题,但可扩展性本身也是微服务架构面临的一项严峻挑战。在某个阶段,系统中创建的微服务数量可能会急剧增加,以至于无法控制。
提及每个服务的不同版本,导致它们之间的连接数量激增,增加了基于微服务的系统的复杂性,因此需要实施特殊解决方案,例如服务发现以确定各个服务的运行位置、路由机制以通过服务的API路由流量、更优的配置管理以动态进行配置并对系统应用变更等。
III. Docker
Docker 是一个用于快速开发、发布和运行软件应用程序的开放平台。它旨在通过使用轻量级容器虚拟化平台以及一系列工具和工作流程,帮助开发者更轻松地部署和管理应用 [2]。
我们可以通过将 Docker 容器与集装箱船进行类比,快速理解其概念:就像集装箱被装载到船上,运送到不同地点后再卸下一样。Docker 容器本质上是一个可以创建应用程序的环境,您可将应用程序及其运行所需依赖组件一并放入一个加固的盒子中,然后根据质量保证需求进行各种验证或严格测试。该盒子的创建几乎可以在任何操作系统和基础设施上完成,包括云环境,并且由于采用了统一系统及其他后续将讨论的技术,其创建速度特别快。
以下是有关 Docker 技术的一些详细信息。
A. Docker 架构
Docker 采用客户端‐服务器架构。下图 2 展示了 Docker 的架构概述,包括主要组件及其相互之间的交互方式。
Docker 用户使用客户端组件中的一组 Docker 命令,通过在主机上运行的 Docker 守护进程与 Docker 主机进行交互。Docker 守护进程随后负责构建、运行和分发 Docker 容器,以及将 Docker 镜像发布到特定的 Docker 仓库。Docker 客户端可以与 Docker 守护进程在同一系统上运行,也可以在不同的系统上远程与守护进程交互。Docker 客户端组件通过套接字或一组 RESTful API 与 Docker 守护进程通信。有关每个组件的详细信息,请参见以下章节。
B. Docker 主要组件和概念
1) Docker 镜像
镜像是一个只读模板,是 Docker 的构建组件,用于启动 Docker 容器。每个镜像都从一个基础镜像开始,然后根据需要在其上添加其他部分,以满足镜像的业务职责。例如,一个镜像可以包含最小化的 CentOS 操作系统基础镜像,然后添加 Node.js 引擎等中间件,最后在之上安装您的 Web 应用程序。
使用 Docker,镜像可以在本地新建,或从其他用户创建的现有远程源仓库中下载和更新。深入来看,每个镜像由多个层组成,Docker 使用联合文件系统将这些层合并为单个镜像。联合文件系统(UFS)是一种适用于 Linux、FreeBSD 和 NetBSD 操作系统的文件系统服务,它实现了对其他文件系统的联合挂载。它允许被称为分支的独立文件系统中的文件和目录进行透明叠加,形成一个单一的统一文件系统 [2]。
在 Docker 中使用 UFS 有助于加快容器化技术的可移植性和轻量级特性。例如,当发生中间件或应用程序更新为新版本等事件导致镜像发生变化时,在构建新镜像的过程中,无需替换整个镜像或从头开始重新构建,而只需添加或更新相关的新增层。一旦构建完成,您只需要分发特定的更新层,从而使 Docker 镜像的分发更加轻量,进而更快速、更简单。
Docker 镜像的构建是通过一组简单、描述性的步骤完成的,这些步骤称为指令。它从一个名为 Dockerfile 的 Docker 专用文件开始,指令被声明式地存储在该文件中。当触发构建请求时,Docker 会读取 Dockerfile 中的指令并执行,然后生成最终镜像。每条指令都会在生成的镜像中创建一个新的层。图3 如下所示,描述了一个典型 Dockerfile 中指令的示例。
2) Docker 仓库
Docker 镜像通常存储在称为 Docker 注册表的共享仓库中。这些仓库是您可以使用 Docker 下载镜像或上传镜像的地方。客户端命令集,使镜像的分发变得简单,并结合 Docker 技术的其他部分,共同为开发者创造了一种全新的应用程序分发方式,就像使用源代码管理一样。
Docker 拥有一个名为 Docker Hub 的公共仓库,其中包含大量现成可用的镜像。人们可以自由创建新的镜像并将其添加到该仓库中,或根据需要将它们共享到企业防火墙内部私有的仓库中。
3) Docker 容器
Docker 容器是一种隔离且安全的环境,其中包含运行应用程序所需的一切内容,通常包括共享的操作系统(Docker 容器不包含客户操作系统,而是与其他容器共享主机操作系统)、必要的中间件、应用程序特定的用户添加文件以及其他元数据。Docker 容器由 Docker 镜像创建,之后可以轻松地运行、启动、停止或删除。该镜像指示 Docker 在容器启动时应运行的流程以及各种其他必要的配置元数据。Docker 镜像是只读的,但当 Docker 从镜像运行容器时,会使用 UFS 在镜像之上添加一个可读写层,应用程序便在此层中运行。
IV. Docker 是微服务的理想选择
如之前关于微服务架构的部分所述,这种方法确实带来了一系列需要解决的挑战,例如从开发到上线过程中更高的复杂性、各方面对自动化的关键需求、故障隔离、测试挑战等。幸运的是,Docker 的引入提供了关键特性和相关工具,有助于应对这些挑战。让我们讨论其中一些重点内容。
A. 加速自动化
Docker 容器天生非常适合微服务架构,因为每个容器都可以作为部署单元,精细地包含一个服务。由于每个容器的创建和启动在设计上都是可脚本化的,并且随着时间推移已有大量工具可用,Docker 容器正在加速软件开发生命周期各个阶段的自动化文化。
B. 加快独立性
每个 Docker 容器都是一个隔离的环境,可包含特定服务的运行时环境。由于 Docker 支持并采用了广泛的平台,服务的开发团队可以独立地使用他们最熟悉的任何技术、语言、流程和工具来实现该服务。
C. 加速可移植性
Docker 将应用程序及其所有依赖项放入一个容器中,该容器可在不同平台之间移植,包括 Linux 发行版和云平台。应用程序的不同利益相关者(如开发者、测试人员、管理员等)可以随意在虚拟机、本地笔记本电脑、裸金属服务器或云平台上快速运行相同的应用程序。这尤其有助于在微服务架构中对特定服务进行独立隔离的测试。
D. 加速资源利用
尽管没有明确将其列为原则,但轻量级和可移植性是构建对微服务架构友好的环境的隐含要求。
在 Docker 中,每个容器仅由应用程序及其运行所需的依赖项构成,理想情况下不多不少。然后,容器作为隔离的流程在宿主操作系统上运行,并与其他容器共享内核。因此,如果将容器置于虚拟机环境中,除了利用虚拟机带来的资源利用优势外,容器化技术还使其更加便携和高效。
在裸机环境中,Docker 容器的轻量级特性有助于创建和运行比虚拟机更多的实例,从而实现更高的资源利用。
E. 安全
Docker 提供的许多功能使开发者能够在不同层面灵活地最大化代码安全性。在构建代码时,开发者可以自由使用渗透测试工具对构建周期的任何部分进行压力测试。由于构建 Docker 镜像的源代码在 Docker 构建、分发组件(例如 Dockerfile、docker-compose 文件)中被明确且声明式地描述,开发者能够更轻松地管理镜像供应链,并根据需要强制实施安全策略。此外,通过将不可变服务放入 Docker 容器中,可以轻松地加固这些服务,从而为服务提供强有力的安全保障。
V. 案例研究 ‐ 一个可运行的模型
作为一个示例用例,我们的团队长期以来一直使用传统的单体模型来构建应用程序。我们清楚在开发、部署以及每次应用程序发布时所需的增量投入,包括开发和运维团队之间需要进行大量会议和协调所产生的开销。
我们希望在每个项目之后都能不断改进,因此决定在最近的应用程序发布中采用渐进式方法来实践微服务架构原则。Docker 在我们采用微服务架构的步骤中起到了关键作用。让我们讨论一下到目前为止在我们的路线图中是如何实现的。
A. 解决方案架构概述
我们将讨论的案例研究基本上是一个包含更新后的工作流程、流程和应用程序的解决方案,该方案有助于创新部门之间内部费用分摊活动的方式,这本质上是企业环境中典型的内部成本覆盖。
图4 下面描述了演进系统的架构概述,其中基于微服务的方法通过最大限度地利用 Docker 技术(包括 Docker 生态系统的工具)来实现。
B. 工作原理
本案例研究中讨论的解决方案不仅利用了 Docker 技术,还在软件开发中严格遵循敏捷方法,并受益于 Waffle、Github、Slack 等周边工具带来的优势。
该系统设置为:每当开发者向某个特定服务专用的共享源代码仓库推送一组提交时,系统会向该系统的主要利益相关者(包括系统负责人、其他开发者、测试人员等)以及订阅了该组通知的人员发送通知。这种可视化机制有助于促进不同利益相关者之间的参与和协作,并增强开发者对每一行代码的个人责任意识,同时在一定程度上隔离潜在缺陷。
我们利用 Github 中的 Webhook 原则来设置警报,以便在特定事件发生时发出通知。因此,一旦更改经过审查(包括同行评审、通过不同渠道的讨论)、验证并合并到主代码流后,就会触发一整套自动化测试来验证这些更改。这是通过使用 Travis 作为测试框架实现的,每当仓库的主分支收到推送时,Travis 就会运行关联 Git 项目中包含的所有测试,并报告测试是通过还是失败。我们使用社区公认的测试工具(如 JSLint、Istanbul、Mocha)来自动化测试活动。为了进一步确保代码质量,我们设置了高覆盖率测试,以确保开发的几乎所有代码行都会被扫描和测试。
一旦所有测试通过,将触发对仓库的构建。我们构建了一个名为
chageback-orchestrate
的特殊组件,它是一种集成式的基于事件的工具,用于监听来自 Github 的已配置 Webhook,然后执行一系列脚本化操作,例如请求构建 Docker 镜像、将镜像推送到注册表等。
随后将为该特定仓库的服务创建一个 Docker 镜像,并包含适当的版本控制机制,以便我们能够跟踪镜像中的代码级别以及后续 Docker 容器的状态。然后,该镜像将被推送到项目的专用私有 Docker 注册中心,以准备响应任何 Docker 拉取请求,按需启动 Docker 容器。因此,
chageback-orchestrate
组件所做的事情超出了其名称所暗示的范围,但主要专注于构建并将 Docker 镜像交付到适当的镜像仓库。
特殊的
chageback-orchestrate
项目用于存储针对不同环境的部署脚本。我们使用 Docker 生态系统中的 Docker Compose 工具以声明式的方式管理容器,以便能够根据需要快速复制或设置新的运行环境。该部分仍涉及一些手动操作:每当需要将应用程序的新版本部署到特定服务器时,我们必须手动更新 Docker Compose 文件中相应容器的版本,然后将其推送到专用的 Github 仓库。此次推送将触发一个 Webhook 负载,进而通过
chageback-orchestrate
组件启动一次新的部署。
根据当前模型,我们还可以通过在 Docker Compose 文件中映射特定代码级别下构建的相应版本的 Docker 容器,并将其推送回主流专用 chageback-orchestrate GitHub 仓库,从而按需回滚到应用程序的任何版本。
C. 改进需求
尽管案例研究中的当前模型运行良好,并且项目各方利益相关者满意度较高,但它仍在向更加自动化、可扩展的设计演进,特别是自动扩展和可观测性方面(具体指日志记录、监控),这些是我们待办事项列表中需要优先完成的重要内容,以应对可扩展性挑战。然而,对于任何意图应用微服务架构的情况而言,通过持续演进来实现改进也是非常典型的。
VI. 结论
本文讨论了关于微服务架构的一些概念,以及 Docker 如何通过一个运行良好的案例研究来帮助成功应用这种有益的架构风格。尽管 Docker 本身并非能解决构建微服务架构所有挑战的灵丹妙药,但结合周边工具,它在提高效率、自动化以及其他实现构建微服务架构最重要原则所必需的基础方面提供了巨大帮助。
171万+

被折叠的 条评论
为什么被折叠?



