Azure-Kubernetes-服务器和微服务教程-全-
Azure Kubernetes 服务器和微服务教程(全)
一、微服务和 AKS 简介
介绍
恭喜你,你向更好的理解微服务迈进了一步。这本书将帮助你决定何时使用微服务,以及如何使用微服务解决业务问题。如果你正在读这本书,你一定对设计和开发微服务感兴趣。也许您有兴趣通过为第三方构建面向外部的 API 来将您的业务暴露给新的市场,或者也许您希望敏捷地、更频繁地增量开发和部署软件。也许你不知道什么是微服务,但是你想了解这个大家都在谈论的新的架构风格。
无论你来这里的原因是什么,本章都将探讨什么是微服务,以及为什么在讨论现代化时微服务变得如此重要和常用。微服务是分布式和面向服务计算的重要一步,它们有可能彻底改变企业级大规模软件解决方案的开发方式,无论是现在还是将来。
本章涵盖:
-
软件开发向分布式计算的演变,以及它如何演变成“软件即服务”模型。
-
什么是微服务,什么时候用,为什么有用。
-
微服务架构风格带来的好处。
-
构建微服务的原则。
-
微服务如何与现有企业架构集成。
-
微服务的未来。
如果不了解软件开发世界向分布式计算的演变,你就无法欣赏微服务。因此,下一节回顾一下分布式计算是如何开始的,从哪里开始的。
分布式计算的历史
回顾一下分布式计算的历史,我们可以看到微服务是一种自然进化的结果。随着时间的推移,应用变得越来越松散,并被分割成多个组件。这使得应用可以分布在许多不同的机器上。这样,多个计算机资源可以用来为应用提供尽可能多的资源。
基本分布式计算的第一次商业应用涉及大型主机系统。这些昂贵的计算机可以处理许多通过哑终端登录的用户,哑终端本身没有处理能力。他们只是允许用户访问大型机系统上的可用资源。唯一的好处是这些哑终端可以位于大楼的任何地方,并且可以访问处理能力和资源所在的中央主机系统。
随着计算机变得越来越便宜,功能越来越强大,将它们放在员工的桌面上成为一种可行的选择。这改变了计算机的使用方式,因为人们可以使用相对强大的机器。使用一些本地处理能力是有意义的,而不是依赖大型机服务器来处理每个请求。
架构的进一步发展带来了下面几节中描述的改进。
客户
该模型包括一个中央服务器,其中包含一个数据库或另一个所有客户端都可以访问的中央数据存储(见图 1-1 )。在将数据发送到服务器之前,客户端处理用户界面屏幕和部分或全部业务逻辑。这释放了服务器资源,使他们可以专注于处理数据存储。客户端机器利用全部资源来处理所有其他事情,并将应用的工作负载分布在多台机器上,从而减少了对单台机器的依赖。
图 1-1
客户
-
这种方法存在重大问题,因为维护时间和新的升级需要将新的应用版本发送到成百上千个桌面。他们被称为胖客户端应用,并且有 DLL 版本控制的问题,因为管理这些成为另一个噩梦。随着用户数量的增加,扩展这些应用变得成本高昂。由于多个连接导致的资源消耗增加,并且在不增加服务器处理能力的情况下,很难增加客户端机器的数量。
-
在万维网被广泛接受后,这个问题的解决方案是一种新的建筑风格。Web 应用导致了可以通过互联网浏览器访问的应用的构建。这些应用被称为瘦客户机,因为它们在客户机上使用的资源要少得多。Web 应用部署在 web 服务器上,业务逻辑嵌入在单独的服务器上。这是互联网和网络时代的开始,它解决了之前描述的大部分问题。
组件技术
随着客户机-服务器革命的加速,面向对象编程也在加速,朝着组件化设计的方向发展。一个类是最小的单元,围绕它的面向对象编程的原则导致了组件的设计和重用。这导致了微软世界中组件对象模型(COM)和分布式组件对象模型(DCOM)的出现。在 Java 世界中,企业 Java Beans 就是答案。接口契约是二元契约。web 应用的服务器端开始使用组件设计模式。
网络服务
现在,大多数 web 应用都是使用用户界面、组件和数据库的分层模型构建的。这些组件封装了业务规则和其他特定功能,并访问数据库。这催生了被称为 web 服务的技术转变/进步。Web 服务从根本上来说是一种分布式解决方案,它们的设计依赖于 HTTP 和 XML 等互联网标准。
这种架构风格提供了在幕后使用组件对象模型来开发核心业务逻辑的灵活性。消费者不知道幕后发生了什么,带来了抽象。这种风格还使开发人员和架构师能够通过利用技术和编程语言的选择来交付业务功能。这个概念很简单——一部分功能通过 web 界面公开,并通过标准的互联网协议(如 HTTP)访问。这意味着任何客户端都可以使用互联网对互联网上的任何服务器进行类似 RPC(远程过程调用)的调用,并接收 XML 形式的响应。来回发送的消息用一种特殊的 XML 方言编码,称为简单对象访问协议(SOAP)。外部客户端可以使用名为 DISCO 的发现协议来发现 web 服务,然后创建一个名为统一描述发现和集成(UDDI)的服务中央存储库。
面向服务的架构
接下来是向面向服务架构的演进,它定义了一种通过服务接口使软件组件可重用和可互操作的方法。服务使用单一的通用接口标准,因此可以在新的应用中快速合并和重用。这导致了重用和更多的可组合模式。这种架构模式利用了 web 服务设计模式,而这些 web 服务可以向外部世界公开以使用业务功能。在内部,业务功能可以由多个内部 web 服务组成,这些服务一起工作来交付业务服务。每个 SOA 服务都包含执行一个完整的、离散的业务功能所需的代码和数据(例如,它可以处理一个购物车,执行购物旅行的支付,等等)。).
这样,web 服务就被用来创建面向服务的架构。为了将一个应用连接到另一个系统中的数据或功能,开发人员需要复杂的点对点集成—开发人员必须为每个新的开发项目部分或全部重新创建集成。通过 SOA 服务公开这些功能允许开发人员简单地重用现有功能,并通过 SOA ESB 架构进行连接。因此,企业服务总线成为编排这些服务的单点。
使用 SOA 的架构风格提供了许多好处。随着使用 SOAP 的服务的发展,出现了一个新的思维过程,当基于 XML 的 SOAP 在复杂的实体或消息开始被交换的场景中变得沉重时,架构需要交换轻量级负载的服务。那时引入了表述性状态转移架构(REST ),因此服务可以交换主要基于 JSON 的消息和有效负载。与肥皂相比,这些很轻。REST 是专门为处理媒体组件、文件甚至硬件设备上的对象等组件而设计的。任何基于 REST 原则定义的 web 服务都可以称为 RESTful web 服务。RESTful 服务使用普通的 HTTP 动词 GET、POST、PUT 和 DELETE 来处理所需的组件。在当今世界,RESTFul web 服务非常流行。
然后出现了一种新的架构风格,叫做微服务,它最终变得非常流行。每个人都在谈论微服务,因为它们似乎是所有软件问题的解决方案,如新开发、遗留系统现代化等等。
这将带您进入下一个主题——什么是微服务,为什么需要微服务?它们是唯一的解决方案吗,其他的都应该扔掉吗?下一节将回答这些问题。
什么是微服务?
微服务无非是将软件应用设计成一组相互独立的服务的一种方式;它们可以相互部署,遵循自己独立的生命周期和版本。找不到完美的定义,但是这种架构风格是基于某些特征的,基于它们是如何围绕业务能力组织的,被称为领域驱动设计。它们的部署是端到端自动化的,遵循智能端点和哑管道的原则。这种架构风格还提供了分散的控制和治理,以及使用任何编程语言和任何类型的数据库存储的自由。
该领域的先驱詹姆斯·刘易斯和马丁·福勒对微服务有这样的评价:
微服务架构风格 是一种将单个应用开发为一套小服务的方法,每个小服务都在自己的进程中运行,并通过轻量级机制(通常是 HTTP 资源 API)进行通信。这些服务是围绕业务功能构建的,可由全自动部署机器独立部署。这些服务可以用不同的编程语言编写,并使用不同的数据存储技术,只有最低限度的集中管理。
——詹姆斯·刘易斯和马丁·福勒(2014)
图 1-2 中的图表显示了微服务架构。
图 1-2
微服务架构
问题是,为什么需要微服务架构?为什么不能利用现有的服务来满足各种客户和外部消费者的需求呢?当通过互联网公开时,他们仍然可以在内部和外部使用业务功能,并且您知道使用 SOAP 或 RESTFul 服务的 web 服务已经提供了这种利用。那么为什么选择微服务呢?
为了更好地回答这个问题,您需要理解为什么在某些场景中,现有的服务驱动或面向服务的架构不够好。它对企业级客户没有帮助,这些客户是通过利用软件解决方案来推动其业务的大型企业。
单片与微服务
为了欣赏和理解微服务风格,最好理解应用的架构风格存在什么问题。一个 monolith 应用被构建为一个单一的单元,所有的组件被打包在一个单一的可部署单元中。企业应用通常由三个主要部分组成:客户端用户界面(由用户机器上的浏览器中运行的 HTML 页面和 JavaScript 组成),以及服务器端应用。服务器端应用处理 HTTP 请求,执行域逻辑,从数据库中检索和更新数据,并选择和填充要发送到浏览器和数据库(由插入到一个公共的、通常是关系型的数据库管理系统中的许多表组成)的 HTML 视图。
这种服务器端应用通常是一个整体——单个逻辑可执行文件或二进制 DLL 或相关可执行文件或服务的组合。随着功能的增强,对系统的任何更改都意味着构建和部署新版本的服务器端应用。因此,基本上整个服务器端应用或其独立组件必须完全重建和部署。
单片服务器是构建这样一个系统的自然方法。处理请求的所有逻辑都在单个进程中运行,这允许您使用语言的基本特性将应用划分为类、函数和名称空间。小心地,您可以在开发人员的机器上运行和测试应用,并使用某种类型的部署自动化来确保更改被正确地测试并部署到生产中。您可以通过在负载平衡器后面的多个服务器上运行多个实例来水平扩展 monolith。
单片应用可能会取得成功,但人们对它们越来越感到失望——尤其是当更多的应用以高频率部署时。企业越来越频繁地引入新想法,他们希望将这些想法快速构建并部署到生产中,以获得客户的反馈。他们不能等待几个月的时间来将单个服务变更作为一个整体进行部署。
变更周期是联系在一起的——对应用的一小部分进行变更需要重新构建和部署整个应用。随着时间的推移,通常很难保持一个良好的模块化结构,这使得保持应该只影响该模块中一个模块的更改变得更加困难。扩展需要扩展整个应用,而不是部分应用。
面临的挑战是确定如何在不部署整个软件系统的情况下更频繁地部署软件变更,并在不干扰其余功能的情况下灵活地仅部署增强的服务。这导致了微服务架构风格,即将应用构建为一组服务。服务是可独立部署和扩展的,每个服务都提供了一个稳固的模块边界,甚至允许用不同的编程语言编写不同的服务。他们也可以由不同的团队管理。
monolith 应用将其所有的功能都放在一个单独的进程中,如图 1-3 所示。
图 1-3
一个整体服务器端应用
如图 1-4 所示,monolith 通过在多个服务器上自我复制来扩展。
图 1-4
攀登巨石
另一方面,微服务架构将每个功能元素放入一个单独的服务中,并拥有独立于其他服务的生命周期和版本。参见图 1-5 。
图 1-5
自给自足、隔离的微服务
微服务风格支持独立地扩展、部署和版本化服务,并在多个服务器上单独扩展它们。如果一个服务被快速消费,那么只有该服务被扩展,而其他服务不被扩展。
微服务架构可以立即按需供应和部署。它还可以在需求高时进行水平和垂直扩展,然后在需求恢复正常时收缩到标准操作。
当在数据中心使用标准的内部硬件部署时,这些特征会导致成本过高。这些挑战可以通过迁移到云平台来克服,如 Microsoft Azure、AWS、Google Cloud 以及类似的云平台和服务提供商,它们提供基础设施即服务(IaaS)、平台即服务(PaaS)和软件即服务(SaaS)功能。这为利用现代方法大规模按需开发和部署微服务创造了便利条件。这被称为 DevOps (开发和运营作为一个团队工作),并导致产品开发方法而不是项目开发方法。这介绍了原生云开发的新领域,下一节将介绍原生云的含义。
云原生架构简介
回想一下,monolith 应用看起来有点像图 1-6 。这是一个典型的业务应用,你可以在任何企业中看到。
图 1-6
整体商业应用
您构建了一个包含所有领域逻辑的大型核心应用。它包括身份、目录、订购等模块。核心应用与大型关系数据库通信。核心通过 HTML 接口公开功能。
独石提供了一些独特的优势。它们很容易
-
建设
-
试验
-
部署
-
充当故障检修员
-
规模
今天存在的许多成功的应用都是作为整体开发的。这款应用很受欢迎,并在不断发展,一次又一次,增加了更多的功能。
随着应用功能的增加,它变得难以管理。开发人员发现他们失去了对应用的控制。随着时间的推移,这种感觉变得越来越强烈,他们最终会进入一种状态,即当引入新功能时,他们不确定应用将如何表现,因为它已经变得难以管理和控制。这个应用已经变得极其复杂,以至于没有人能够理解它。开发人员害怕做出改变,因为每个改变都可能有意想不到的和昂贵的副作用。实施新功能/修复变得棘手、耗时且昂贵。每个版本都尽可能小,并且需要完整部署整个应用。一个不稳定的组件会使整个系统崩溃。新技术和框架不是一个选项。实施敏捷交付方法是很困难的。随着代码库随着永无止境的“特例”而恶化,架构侵蚀开始了许多组织通过采用云原生架构来解决这种庞大的问题。当在云上构建和部署应用时,现在看起来如图 1-7 所示。
图 1-7
整体的云原生应用版本
该应用已经被分解到一组小型、孤立的微服务中。每个服务都是独立的,封装了自己的代码、数据和依赖关系。每一个都部署在一个软件容器中,由一个容器编制器管理。每个服务拥有自己的数据存储,而不是大型关系数据库,数据存储的类型根据数据需求而变化。请注意一些服务依赖于关系数据库,而另一些服务依赖于 NoSQL 数据库。一个服务将其状态存储在分布式缓存中。请注意,所有流量是如何通过 API 网关服务路由的,该服务负责将流量定向到核心后端服务,并实施许多横切关注点。最重要的是,该应用充分利用了现代云平台中的可伸缩性、可用性和弹性特性。
因此,云原生就是使用微服务等现代架构风格来设计应用,并利用原本可用于构建、测试和部署的云服务。它还利用了像 Azure DevOps 这样的 DevOps 工具。
原生云完全改变了开发者构建关键业务系统的思维方式。它旨在支持快速开发和部署。更大规模的频繁和更快的变化,建立了弹性和高可用性。
云原生计算基金会(CNCF)对云原生的定义如下:
-
云原生技术使组织能够在现代动态环境(如公共云、私有云和混合云)中构建和运行可扩展的应用。容器、服务网格、微服务、不可变基础设施和声明式 API 就是这种方法的例子。
-
这些技术使得松散耦合的系统具有弹性、可管理性和可观察性。与强大的自动化相结合,它们允许工程师以最少的劳动频繁地、可预测地做出高影响力的改变。
随着用户要求越来越多的功能,应用变得越来越复杂。企业用户期望在几乎零停机的情况下部署快速响应和创新功能。他们希望在维护期间最少停机或不停机,并希望应用具有按需性能和可扩展性。云原生提供了开发一系列业务应用所需的速度和敏捷性,这些业务应用正从单纯的业务功能演变为更具战略性的转变。它们让企业保持领先地位,并继续加速业务增长。
云原生平台上的现代应用开发基于一种被广泛接受的方法,称为十二要素应用。它描述了开发人员在构建针对现代云环境优化的应用时遵循的一系列原则和实践。特别关注跨环境的可移植性。
虽然适用于任何基于 web 的应用,但许多从业者认为 12 因素是构建云原生应用的坚实基础。基于这些原则构建的系统可以快速部署和扩展,并添加功能以快速应对市场变化。以下几点强调了十二因素方法:
-
代码库:每个微服务的单一代码库,存储在自己的存储库中。通过版本控制跟踪,它可以部署到多个环境(QA、试运行和生产)。
-
依赖关系:每个微服务隔离并打包自己的依赖关系,拥抱变化而不影响整个系统。
-
配置:配置信息被移出微服务,并通过代码外的配置管理工具具体化。通过应用正确的配置,相同的部署可以跨环境传播。
-
后台服务:辅助资源(数据存储、缓存和消息代理)应该通过一个可寻址的 URL 公开。这样做可以将资源从应用中分离出来,使其可以互换。
-
构建发布运行:每个发布都必须在构建、发布和运行阶段进行严格的分离。每个都应该用唯一的 ID 标记,并支持回滚的能力。现代 CI/CD 系统有助于实现这一原则。
-
进程:每个微服务应该在自己的进程中执行,与其他正在运行的服务隔离。将所需状态外部化到后台服务,如分布式缓存或数据存储。
-
端口绑定:每个微服务应该是自包含的,其接口和功能在自己的端口上公开。这样做可以提供与其他微服务的隔离。
-
并发性:服务跨大量相同的小进程(副本)扩展,而不是在最强大的机器上纵向扩展单个大型实例。
-
可处置性:服务实例应该是可处置的,有利于快速启动以增加可伸缩性机会,有利于正常关闭以使系统处于正确状态。Docker 容器和 orchestrator 天生就能满足这一需求。
-
开发/生产对等:在应用生命周期中保持环境尽可能相似,避免代价高昂的捷径。在这里,容器的采用可以通过促进相同的执行环境而做出巨大贡献。
-
日志:将微服务生成的日志视为事件流。使用事件聚合器处理它们,并将数据传播到数据挖掘/日志管理工具,如 Azure Monitor 或 Splunk,并最终进行长期归档。
-
管理进程:作为一次性进程运行行政/管理任务。任务可以包括数据清理和为报告提取分析。执行这些任务的工具应该从生产环境中调用,但与应用分开。
现代应用还引入了其他三个因素——API 优先设计、遥测技术以及身份验证和授权。
这些应用还需要考虑以下关键设计因素:
-
通信:前端和后端如何相互通信,微服务如何在不引入依赖性的情况下相互通信,可能通过松散耦合的消息传递模式,如队列或服务总线。
-
弹性:微服务架构将您的系统从进程内网络通信转移到进程外网络通信。在分布式架构中,当服务 B 不响应来自服务 A 的网络调用时会发生什么?或者,当服务 C 暂时不可用,而调用它的其他服务被阻塞时,会发生什么?
-
分布式数据:按照设计,每个微服务封装自己的数据,通过其公共接口公开操作。如果是,如何跨多个服务查询数据或实现事务?
-
身份:你的服务如何识别谁在访问它,他们有什么权限?
企业如何从云原生应用中获益
在当今的现代软件开发时代,企业正在利用技术推动业务发展,并努力实现数字化转型。企业需要快速引入创新的新想法,并在竞争之前部署它们。
考虑以下您将使用云原生应用和基于微服务的架构的原因。
-
战略性企业系统需要不断发展业务能力/特性。
-
一个应用需要高发布速度和高可信度。
-
一种系统,在这种系统中,必须在不完全重新部署整个系统的情况下发布单个功能。
-
由具有不同技术堆栈专业知识的团队开发的应用。
-
具有组件的应用必须能够独立地按需伸缩。
-
围绕现有应用的性能、可伸缩性和用户体验的非功能性需求应该被基线化,并相应地。
-
需要考虑外部和内部集成的依赖性,以重新设计应用并在云平台上创建云原生架构。
-
整体式应用对业务至关重要,并且通常受益于云优化的提升和转移迁移。
-
对部署进行优化,支持关键云服务,而不改变应用的核心架构。例如,您可以将应用容器化,并将其部署到容器编排器,如 Azure Kubernetes Services 等。一旦进入云中,应用就可以使用其他云服务,比如数据库、消息队列、监控和分布式缓存。
-
最后,执行战略性企业功能的单一应用可能会从云原生方法中获益最多。这种方法提供了敏捷性和速度。但是这是以重新搭建平台、重新架构和重写代码为代价的。
如果您专注于回答这些问题,这种云原生方法是合适的—云原生方法将解决的业务问题到底是什么?它如何与业务需求保持一致?
在业务驱动要求不高的场景中,一个整体仍然可以满足业务需求。微服务架构需要易于部署、按需扩展和可用性,以及应用监控、日志记录和遥测。这些非功能性需求由云平台提供,但一个更重要的特性是按需扩展。这就把我们带到了容器和容器化的世界。微服务可以很容易地部署在容器上。但是这些容器需要一种机制来编排、管理和治理。这就是像 Kubernetes 这样的服务出现的原因。否则,将不得不开发容器管理和编排,这是一个在企业范围内开发的复杂领域。下一节将介绍 Azure Kubernetes 服务(AKS)并描述其组件。
AKS 及其组件介绍
现在,您已经了解了什么是微服务,并且知道云平台为开发和部署微服务提供了本机支持,您可以看看如何利用容器来部署微服务。本节介绍了 Azure Kubernetes 服务。
Kubernetes 是一个用于部署容器化应用的开源 orchestrator。它最初是由 Google 开发的,灵感来自于十年来通过面向应用的 API 在容器中部署可伸缩的、可靠的系统的经验。
自 2014 年推出以来,Kubernetes 已经发展成为世界上最大、最受欢迎的开源项目之一。它已经成为构建云原生应用的标准 API,几乎存在于每个公共云中。
Kubernetes 是分布式系统的成熟基础设施,适合各种规模的云原生开发人员,从一群 Raspberry Pi 计算机到装满最新机器的仓库。它提供了成功构建和部署可靠的、可伸缩的分布式系统所必需的软件。
您可能想知道“可靠的、可伸缩的分布式系统”是什么意思越来越多的服务可以通过 API 在网络上交付。这些 API 通常由分布式系统交付,实现 API 的各个部分运行在不同的机器上,通过网络连接,并通过网络通信协调它们的动作。因为人们在日常生活的各个方面越来越依赖这些 API(例如,找到去最近医院的方向),所以这些系统必须高度可靠。即使系统的一部分崩溃或停止工作,它们也不会失败。同样,即使在软件发布或其他维护事件期间,他们也必须保持可用性。最后,由于越来越多的人在网上使用这样的服务,它们必须是高度可伸缩的,这样它们就可以增加容量并跟上不断增长的使用,而无需对实现服务的分布式系统进行彻底的重新设计。
公司使用像 Kubernetes 这样的容器和容器 API 有许多原因,但它们都可以追溯到以下好处之一:
-
速度
-
(软件和团队的)扩展
-
抽象基础设施
-
效率
容器是 Azure Kubernetes 服务中部署的基本单元。
Kubernetes 是一个创建、部署和管理分布式应用的平台。
这些应用有许多不同的形状和大小,但最终,它们都是由一个或多个运行在单独机器上的程序组成的。
这些程序接受输入,处理数据,然后返回结果。在您考虑构建分布式系统之前,您必须首先考虑如何构建包含这些程序的应用容器映像,并组成分布式系统的各个部分。
应用通常由语言运行时、库和源代码组成。在许多情况下,您的应用依赖于外部共享库。这些外部库通常作为安装在特定机器上的操作系统中的共享组件提供。
当在程序员的机器上开发的应用对共享库有依赖性时,这种对共享库的依赖性会导致问题,而当程序被部署到生产操作系统时,共享库是不可用的。即使开发和生产环境共享相同版本的操作系统,当开发人员忘记将相关资产文件包含在他们部署到生产环境的包中时,也会出现问题。
在一台机器上运行多个程序的传统方法要求所有这些程序在系统上共享相同版本的共享库。如果不同的程序是由不同的团队或组织开发的,这些共享的依赖增加了这些团队之间不必要的复杂性和耦合。
一个程序只有被可靠地部署到它应该运行的机器上才能成功执行。太多时候,最新的部署技术涉及到运行命令式脚本,这不可避免地会有曲折和复杂的失败案例。
这使得推出分布式系统的全部或部分新版本的任务变得困难。
使用应用时,以一种易于与他人共享的方式对它们进行打包通常会很有帮助。Docker 是默认的容器运行时引擎,它使得打包一个可执行文件并将其推送到远程注册表变得很容易,在那里它可以被其他人提取。在撰写本文时,容器注册中心在所有主要的公共云中都可用,在云中构建映像的服务也在其中的许多云中可用。您也可以使用开源或商业系统运行自己的注册表。这些注册表使用户能够轻松管理和部署私有映像,而映像构建器服务则提供了与持续交付系统的轻松集成。
容器映像将程序及其依赖项捆绑到根文件系统下的单个工件中。最流行的容器图像格式是 Docker 图像格式,它已经由开放容器倡议组织标准化为 OCI 图像格式。Kubernetes 通过 Docker 和其他运行时支持 Docker 和 OCI 兼容的映像。Docker 映像还包括容器运行时使用的附加元数据,以基于容器映像的内容启动正在运行的应用实例。
容器图像
容器映像是一个二进制包,它封装了在 OS 容器中运行程序所需的所有文件。根据您第一次使用容器的方式,您可以从本地文件系统构建一个容器映像,也可以从容器注册中心下载一个预先存在的映像。在这两种情况下,一旦容器映像出现在您的计算机上,您就可以运行该映像以在 OS 容器中生成一个正在运行的应用。
最流行和广泛使用的容器图像格式是 Docker 图像格式,它是由 Docker 开源项目开发的,用于使用docker
命令打包、分发和运行容器。随后,Docker 公司和其他公司开始通过开放容器倡议(OCI)项目对容器图像格式进行标准化。虽然 OCI 标准在 2017 年年中实现了 1.0 版本的里程碑,但这些标准的采用进展缓慢。Docker 映像格式仍然是事实上的标准,由一系列文件系统层组成。每一层都从文件系统中的前一层添加、删除或修改文件。这是一个覆盖文件系统的例子。在打包图像和使用图像时都会用到覆盖系统。
在运行时,这种文件系统有各种具体的实现,包括 aufs、overlay 和 overlay2。
接下来的小节将介绍驱动 Kubernetes 集群的各种组件。
集群
在最高级别,Kubernetes 被组织为一个虚拟或本地机器集群。这些被称为节点的机器共享计算、网络和存储资源。每个集群都有一个连接到一个或多个工作节点的主节点。工作节点负责运行多组容器化的应用和工作负载,称为,主节点管理哪些容器在哪些工作节点上运行。
**#### 控制平面
为了让主节点与工作节点通信,也为了让一个人与主节点通信,Kubernetes 包含了许多对象,它们共同构成了控制平面。开发人员和操作员主要通过主节点使用kubectl
与集群交互,这是一个安装在他们本地操作系统上的命令行界面。通过kubectl
发布到集群的命令由驻留在主节点上的 Kubernetes APIkube-apiserver
接收。然后,kube-apiserver
将请求传递给主节点中的kube-controller-manager
,后者负责处理工作节点操作。来自主节点的命令由工作节点上的 kubelet 接收。
部署应用和工作负载
Kubernetes 的下一步是部署应用和工作负载。主节点始终维护 Kubernetes 集群的当前状态和etcd
中的配置,这是一个键值存储数据库。要使用容器化的应用和工作负载运行 pods,您需要以 YAML 文件的形式向集群描述一个新的期望状态。kube-controller-manager
获取 YAML 文件,并让kube-scheduler
根据预先确定的约束决定应用或工作负载应该运行哪些工作节点。kube-scheduler
与每个工作者节点的 kubelet 协同工作,启动 pod,监视机器的状态,并全面负责资源管理。
图 1-8 显示了一个典型的 Azure Kubernetes 参考实现的样子。
图 1-8
Azure Kubernetes 服务参考架构(由微软 AKS 文档提供)
图 1-8 中的部件定义如下:
-
Azure Kubernetes 服务是一个托管的 Kubernetes 集群,托管在 Azure 云平台上。使用 AKS 时,Azure 管理 Kubernetes API 服务,你只需要管理代理节点。
-
部署 AKS 集群需要虚拟网络。默认情况下,AKS 会创建一个代理节点连接到的虚拟网络。通过在部署 AKS 集群之前创建自定义虚拟网络,可以处理更高级的场景。
-
入口服务器将 HTTP(S)路由暴露给集群内的服务。您将在后续章节中通过更多示例了解这一点。
-
Azure 负载均衡器在创建 AKS 集群后创建。负载平衡器将配置一个新的公共 IP 地址,它将作为入口控制器的前端。这样,负载平衡器将流量路由到入口。
-
外部数据存储用于驱动来自 Azure SQL 数据库、Cosmos DB 等服务的微服务数据。
-
Azure Active Directory 是通过创建身份和管理其他 Azure 资源来为集群提供安全性的关键元素。它还用于从客户端应用对用户进行身份验证和授权。
-
Azure Container Registry 存储私有 Docker 映像,这些映像被部署到集群中。AKS 可以使用其 Azure AD 身份向容器注册表进行身份验证。注意,AKS 不需要 Azure 容器注册表。您可以使用其他容器注册中心,比如 Docker Hub。
-
Helm 是 Kubernetes 的一个包管理器,这是一种将 Kubernetes 对象捆绑和概括成一个可以发布、部署、版本化和更新的单元的方法。
您看到了微服务如何使业务驱动因素受益,以及像 Microsoft Azure 这样的云平台如何支持微服务的部署。Azure Kubernetes 服务是在 Azure 平台上部署微服务的方式之一。
摘要
本章描述了软件开发世界的演变,并解释了大型机系统是如何演变成客户机-服务器和面向服务的体系结构的。
您还了解了架构风格的各种挑战,微服务架构是如何引入的,以及它给现代业务环境带来的好处。
本章还介绍了云原生应用以及它们如何为企业业务带来好处。您了解了当今时代的企业如何希望领先于竞争对手,以及云原生和微服务架构如何通过使软件开发更加快速、可扩展和敏捷来帮助他们实现这一目标。
还向您介绍了容器和 Azure Kubernetes 服务,并了解了微服务如何利用它们来简化部署和扩展。
您在本章中没有看到任何代码,这是故意的,以便您可以首先理解微服务为什么重要以及在什么场景中重要。
下一章将举例说明微服务并解释重要的设计注意事项。
附录
https://martinfowler.com/microservices/
二、微服务:架构和设计考虑
介绍
现在,您已经了解了分布式计算的发展,并了解了现代模式,这些模式提供了更健壮、更可伸缩、更快速的服务,本章将介绍架构和设计的微服务考虑事项。
然后,您将深入了解什么是容器,以及为什么需要像 Kubernetes 这样的框架和工具。
微服务架构优势
为什么组织要采用微服务?动机和挑战是什么?这些组织的领导者如何判断接受管理一组小型、松散耦合、可独立部署的服务的挑战对公司来说是有回报的?他们如何衡量成功?微服务早期采用者对这些问题的回答差异很大。然而,出现了一些共同的主题,并与“在规模上平衡速度和安全”的口号联系在一起
Amazon 对其架构的优势描述如下:
我们可以独立扩展我们的运营,保持无与伦比的系统可用性,并快速引入新服务,而无需大规模重新配置。
通过关注可伸缩性和组件独立性,Amazon 已经能够提高他们的交付速度,同时也提高了他们环境的安全性——以可伸缩性和可用性的形式。
-
减少团队之间的依赖性,从而更快地将代码投入生产
-
允许大量计划并行运行
-
支持多种技术/语言/框架
-
支持服务的适度降级
-
通过一次性代码促进创新——很容易失败并继续前进
前三点有助于加快软件开发,通过组织的联合和独立部署的能力,以及多语言。最后两点说明了有利于服务可替换性的安全环境。
社交媒体先驱 Hootsuite 根据系统的可调性观察到了他们采用微服务的效率优势:
有些服务要求高可用性,但数量很少,其他服务则相反。微服务方法允许我们针对这两种情况进行调整,而在 monolith 中,要么全有,要么全无。
这里的主要驱动因素是速度,这是企业直接要求的。然而,还强调了安全性——通过独立部署的能力和可测试性——以及通过可组合性的未来发展。
通过采用微服务,他们能够克服这个问题,并提高软件系统的可理解性。
从这些实现故事中可以看到一些共同的目标和好处。
随着功能范围的扩大,提高软件交付速度的目标是通过更大的敏捷性、更高的可组合性、更好的可理解性、独立部署服务的能力、组织一致性和多语言性来实现的。通过更高的可用性和弹性、更高的效率、组件的独立可管理性和可替换性、更高的运行时可伸缩性以及更简化的可测试性,实现了随着规模的增加而维护软件系统安全性的目标。
现在,您已经了解了这些目标和优势,让我们探索这些目标和优势如何为利用微服务架构的组织带来商业价值。
衍生商业价值
成功的公司专注于提高软件交付速度,因为他们被业务的速度所驱使。类似地,在组织的软件系统中实现的安全级别应该与特定的业务目标相关联。相反,安全措施不得不必要地妨碍速度。需要平衡。
对于每个组织来说,这种平衡是其交付速度、系统安全性以及组织功能范围和规模增长的函数。每个组织都有自己的平衡。与零售银行相比,一家旨在让尽可能多的受众了解其内容的媒体公司可能更看重交付速度,而零售银行的合规性要求要求采取特定的安全措施。尽管如此,在日益数字化的经济中,越来越多的公司认识到软件开发需要成为他们的核心竞争力之一。
在这个新的商业环境中,破坏性的竞争对手可以跨越行业边界或似乎一夜之间从零开始,快速的软件交付对于保持竞争优势和实现可持续增长至关重要。事实上,微服务架构的每一项优势都有助于提高交付速度并创造真正的商业价值:
-
敏捷性允许组织更快地交付新产品、功能和特性,并在需要时更容易地进行调整。
-
可组合性减少了开发时间,并随着时间的推移通过可重用性提供了复合优势。
-
软件系统的可理解性简化了开发计划,提高了准确性,并允许新的资源更快地投入使用。
-
组件的独立可部署性将新功能更快地投入生产,并为试点和原型制作提供更灵活的选项。
-
团队服务的组织一致性减少了加速时间,并鼓励团队迭代地构建更复杂的产品和功能。
-
通晓多种语言允许使用合适的工具完成合适的任务,从而加快技术引进并增加解决方案选择。同样,数字原生消费者期望永远在线的服务,并且不羞于改变企业忠诚度。停机或信息丢失会导致他们将业务转移到其他地方。一个安全的软件系统是必不可少的。前面讨论的与安全相关的好处也提供了商业价值。
-
软件系统中更高的效率降低了基础设施成本,并降低了与容量相关的服务中断风险。
-
独立的可管理性有助于提高效率,减少计划停机的需求。
-
组件的可替换性减少了可能导致老化、不可靠环境的技术债务。
-
更强的弹性和更高的可用性确保了良好的客户体验。
-
更好的运行时可伸缩性允许软件系统随着业务增长或收缩。
-
改进的可测试性允许企业降低实施风险。显然,微服务架构有潜力提供众多业务优势。然而,并不是每个组织都需要所有优势,也不是每个微服务架构都能提供所有优势。
定义面向目标的分层方法
虽然微服务架构最初是对单片应用局限性的反应,但业内有许多人认为新的应用仍然应该首先构建为单片。这种想法是,只有通过创建和拥有一个整体,才能确定正确的服务边界。考虑到早期的微服务采用者通常都经历了拆分他们自己的单片应用的过程,这条路肯定是走得很好的。
然而,单一的应用架构是唯一简单的系统起点吗?有可能从简单的微服务开始吗?事实上,软件系统的复杂性是由其规模决定的。规模以功能范围、运营规模和变更频率的形式出现。第一批使用微服务架构的公司一旦超过一定的规模阈值,就会从单片应用转向微服务架构。事后来看,通过分析微服务架构的共同目标和优势,您可以规划出一组采用微服务架构时要考虑的分层特征。
模块性
在最基本的层面上,微服务架构是将应用或系统分成更小的部分。一个任意模块化的软件系统,显然会有一定的局限性,但还是有潜在的好处。网络可访问的模块化促进了自动化,并提供了一种具体的抽象方法。除此之外,之前讨论的一些微服务架构优势已经应用于这个基础层。
为了提高软件交付速度,模块化服务可以独立部署。
无论服务边界是什么,也可以采用多语言方法为单个服务选择工具和平台。此外,抽象的服务接口允许更细粒度的测试。
这是最注重技术的微服务架构层。为了解决这一层的问题并实现其相关优势,您必须为您的微服务架构奠定基础。
粘结性
在您的微服务架构中,接下来要考虑的是服务的内聚性。
为了拥有一个内聚的微服务架构,它必须已经模块化。实现服务内聚来自于定义正确的服务边界和分析系统的语义。领域的概念在这一层很有用,不管它们是面向业务的还是由其他轴心定义的。
一个内聚的微服务架构可以通过将系统服务与支持组织的结构相结合来提高软件速度。它还可以产生可组合的服务,这些服务被允许按照业务指示的速度进行更改,而不是通过不必要的依赖关系进行更改。减少具有内聚服务的系统的依赖性也有助于服务的可替换性。此外,服务内聚减少了组件之间高度协调的消息交换的需要,从而创建了一个更高效的系统。
构建一个内聚的系统需要综合考虑业务、技术和组织因素。
相互关系
微服务架构中要考虑的最后也是最高级的一层是其系统元素。在通过模块化将系统分成几个部分,并通过内聚处理服务的内容之后,是时候检查服务之间的相互关系了。这是系统中最大程度的复杂性需要解决的地方,也是可以实现最大和最持久的好处的地方。
尽管即使在模块化的微服务架构中,单个服务也是可以理解的,但是只有当服务之间的连接已知时,整个软件系统才是可以理解的。此外,只有当变更对整个系统的影响能够被快速识别和评估时,敏捷性才是可能的。这也适用于涉及运行时可伸缩性的安全方面。最后,尽管在模块化或内聚的微服务架构中,单个组件可能被隔离并具有弹性,但除非了解组件的相互依赖性,否则无法保证系统的可用性。
微服务架构目标和优势的成熟度模型
这些分层的特征——模块化、内聚性和确定的相互关系——有助于定义满足多种目的的成熟度模型。首先,如前所述,它根据阶段和目标(速度或安全)对收益进行分类。其次,它说明了随着规模和复杂性的增加,收益的相对影响和优先级。
最后,它显示了处理每个架构阶段所需的活动。这个成熟度模型如图 2-1 所示。请注意,组织的微服务架构可以处于不同目标的不同阶段。许多公司已经通过自动化和其他操作考虑,将他们的安全方法系统化,而不寻求与速度一致的系统级效益。这个模型的要点不是让每个组织都通过他们的微服务架构来实现系统化的实现。
图 2-1
微服务架构目标和优势的成熟度模型
相反,该模型旨在阐明目标和优势,以帮助组织专注于他们的微服务战略,并为接下来可能发生的事情做好准备。
应用面向目标的分层方法
现在,您已经很好地理解了微服务架构如何为组织带来价值,以及理解在采用的哪个阶段什么特征可以带来什么目标和好处的模型。但是你的组织呢?你的商业目标是什么?需要解决哪些问题?为了微服务而开始微服务是一个常见的错误,没有考虑到您的目标是什么。在其他情况下,一些组织瞄准一个高层次的目标,然后只实现微服务的一个方面,而忽略了它的创建条件。例如,一个在开发和运营之间存在高度分歧的组织——一个组织的危险信号——可能对他们现有的应用执行容器化策略,然后想知道为什么他们没有充分地加速他们的软件开发。需要广阔的视角。
首先,定义您想要完成的高级业务目标,然后将这些目标与速度和安全的双重目标进行权衡。在这种情况下,考虑你的目标是独特的好处。然后,您可以使用成熟度模型来确定目标的复杂性,并确定实现目标的最佳方法。
一家数字媒体巨头在他们的单片服务平台上初步尝试了微服务架构,该平台包括用户管理和许可证管理等功能。第一次尝试明确地将重点放在从整体架构到支持服务的软件系统的转变上。结果并不乐观。然而,当他们评估应用的主要问题时——特别是围绕它的操作效率低下——他们改变了他们的方法,从重构现有的架构到自动化有问题的部署过程。通过少量投资,他们能够将其服务平台部署停机时间从一周缩短到 20 分钟。他们的下一次迭代将专注于通过自动化和从白盒测试到黑盒测试的方法转换来减少 QA 时间。在这些方法上的改变之后,他们将确定他们的整体应用中需要最大创新速度的领域,并首先分解这些领域。通过采取与明确目标相关的迭代方法,他们可以快速衡量成功,并在需要时改变过程。
微服务设计
到目前为止,您已经了解到以微服务方式构建应用的公司不仅仅是实现小组件。您现在知道了,微服务架构的构成并没有严格的定义。相反,重点是通过可替换性来构建平衡速度和安全性的应用。
但是考虑到你到目前为止对微服务系统的了解,有一点应该是清楚的——有很多移动部件需要考虑。微服务架构的标志可能是更小的服务,但是遵循微服务的方式将需要你有大的想法。您需要以正确的方式调整您的文化、组织、架构、界面和服务,以获得大规模速度和安全性的平衡。
引入的概念根植于一些大的领域:设计、复杂性和系统思维。但是,要成为一名优秀的微服务设计师,你不需要成为任何一个领域的专家。相反,本章强调了一种模型驱动的思考应用的方式,它封装了复杂性和系统思考的基本部分。
微服务的系统方法
许多首次采用微服务的人倾向于关注需要构建的服务。但是为了以微服务的方式开发应用,您需要将设计概念化,而不仅仅是孤立的、单独的服务设计。这并不意味着可以忽略服务的设计——就像汽车和行人对于交通系统来说是必不可少的一样,服务是微服务系统的关键组成部分。但是仅仅从服务的角度考虑是不够的;相反,你需要考虑系统的所有方面如何一起工作来形成一个紧急行为。紧急行为是大于其部分总和的行为,对于微服务应用,这包括当您将单个服务连接在一起时出现的运行时行为,以及实现这一点的组织行为。
微服务系统包含了您的组织中与它所生产的应用相关的所有东西。这意味着你的组织结构,在那里工作的人,他们的工作方式,以及他们的产出都是重要的系统因素。同样重要的是运行时架构元素,如服务协调、错误处理和操作实践。除了您需要考虑的广泛主题之外,还有一个额外的挑战,即所有这些元素都是相互关联的——对系统一部分的更改可能会对另一部分产生不可预见的影响。
例如,实现团队规模的变化会对实现团队的工作产生深远的影响。
如果你在正确的时间实施正确的决策,你就可以影响系统的行为,产生你想要的行为。但这往往说起来容易做起来难。同时处理所有这些系统元素是很困难的。事实上,你可能会发现在你的头脑中概念化微服务系统的所有移动部分特别具有挑战性。
复杂性科学家在研究复杂系统时面临类似的挑战。
由于所有相互关联的部分和由此产生的复杂涌现,很难理解这些部分是如何协同工作的。很难预测系统变化可能产生的结果。所以,他们做了科学家们一直在做的事情——开发一个模型。
基于模型的方法可以帮助我们所有人概念化我们的学习系统,并使我们更容易谈论系统的各个部分。
考虑到这一点,图 2-2 描绘了一个由五个部分组成的微服务设计模型:服务、解决方案、过程和工具、组织和文化。
图 2-2
微服务系统设计模型
该模型的目标是突出关注的主要领域和您需要影响的系统部分,以便成功地使用这种架构风格。
服务
实现设计良好的微服务和 API 对于微服务系统至关重要。在微服务系统中,服务形成了构建整个有机体的原子构件。如果您能够正确地获得服务的设计、范围和粒度,您将能够从一组看似简单的组件中归纳出复杂的行为。
解决办法
解决方案架构不同于单独的服务设计元素,因为它代表了解决方案的宏观视图。当设计一个特定的微服务时,您的决策受到产生单一输出(服务本身)的需求的限制。相反,在设计解决方案架构时,您的决策受到协调多个服务的所有输入和输出的需求的限制。
这种系统的宏观视图允许设计者归纳出更理想的系统行为。例如,提供发现、安全和路由功能的解决方案体系结构可以降低单个服务的复杂性。
流程和工具
您的微服务系统不仅仅是运行时处理消息的服务组件的副产品。系统行为也是系统中的工作人员用来完成工作的过程和工具的结果。在微服务的系统中,这通常包括与软件开发、代码部署、维护和产品管理相关的工具和过程。
选择正确的流程和工具是产生良好微服务系统行为的重要因素。例如,采用像 DevOps 和 Agile 这样的标准化流程或像 Docker containers 这样的工具可以增加系统的可变性。
组织
我们如何工作通常是我们与谁一起工作以及我们如何沟通的结果。
从微服务系统的角度来看,组织设计包括团队的结构、权力方向、粒度和组成。许多在微服务架构方面取得成功的公司指出,他们的组织设计是一个关键因素。但是,组织设计对环境极其敏感,如果你试图在一个 15 人的初创企业之后,为你的 1000 多名员工的企业结构建模,你可能会发现自己处于一个可怕的境地(反之亦然)。
一个好的微服务系统设计师了解改变这些组织属性的含义,并且知道好的服务设计是好的组织设计的副产品。
文化
在所有微服务系统领域中,文化可能是最无形的,但也可能是最重要的。你可以广义地将文化定义为一个组织内所有员工共享的一套价值观、信仰或理想。你的组织的文化很重要,因为它塑造了系统中的人们将要做出的所有基本决策。这种大范围的影响使得它成为您系统设计工作中的一个强大工具。
与组织设计非常相似,文化是系统的一个上下文相关的特性。
在日本行得通的方法在美国可能行不通,在大型保险公司行得通的方法在电子商务公司可能行不通。所以,当你试图效仿一家你欣赏其文化的公司的做法时,你需要小心谨慎。没有配方或剧本能保证你得到同样的结果。
一个组织的文化虽然重要,但却难以衡量。
正式的调查和建模方法是存在的,但是许多商业和技术领导者以一种更本能的方式评估他们团队的文化。通过与团队成员、团队产品以及他们所服务的客户的日常互动,你可以感受到组织的文化。
文化通常是你的系统的其他部分的影响的指示。共同的理想塑造了人们的工作方式,而他们的工作方式又反过来塑造了他们的组织观。这就是系统的互联性。
拥抱变化
时间是微服务系统的基本要素,不考虑时间是一个严重的错误。你对组织、文化、流程、服务和解决方案做出的所有决定都应该植根于变革不可避免的理念。
你不能在你的系统设计中完全确定性;相反,您应该将适应性作为一个特性设计到系统中。
采取这种观点有很好的理由:首先,试图确定您的组织和解决方案设计的最终状态应该是什么样子是一项几乎不可能完成的任务。第二,你做出设计决策的背景不可能保持不变。需求、市场和技术的变化都会让今天的好决策很快过时。
一个好的微服务设计师了解适应性的需要,并努力不断改进系统,而不是简单地生产一个解决方案。
标准化和协调
几乎我们所有人都在有约束的组织中工作。这些约束的出现是因为错误类型的系统行为可能对组织有害,甚至导致组织由于特别糟糕的行为而失败。比如,一个让窃取他人钱财变得轻而易举的银行技术系统,或者一个无法保护用户私人信息的税收系统,都是不可接受的。
由于不想要的系统行为的成本如此之高,难怪如此多的架构师和设计者尽最大努力来控制系统行为。在实践中,系统设计者决定有一些行为或期望必须普遍适用于系统中的参与者。策略、治理和审计都是作为监管系统行为并确保参与者遵守的方式引入的。换句话说,系统的某些部分是标准化的。
但是对这种复杂系统的真正控制是一种幻想。你保证你的银行系统绝对安全的机会,就像一个农民保证他的庄稼永远生长一样多。无论您应用多少规则、检查和治理方法,您总是受到系统中可能做出糟糕决策的参与者的支配。
相反,所有这些控制机制都充当着系统影响者的角色,极大地增加了您想要的结果的可能性。掌握你正在设计的系统并让它做你想做的事情,需要你制定正确的标准,确保标准得到应用,并衡量你所做的改变的结果。
然而,控制系统的代价很高。标准化是适应性的敌人,如果你对系统的太多部分进行标准化,你就有可能创造出昂贵且难以改变的东西。
标准化过程
你已经读到过关于过程和工具对于从你的系统中出现的行为是多么重要。通过标准化人们的工作方式和他们使用的工具,您可以以一种更可预测的方式影响行为。例如,随着新部署成本的降低,标准化减少组件部署时间的部署过程可以提高系统的整体可变更性。
标准化你的工作方式对你的工作类型、你雇佣的员工类型以及你的组织文化有着深远的影响。敏捷方法是过程标准化的一个很好的例子。敏捷使这样一个概念制度化,即变化应该以小的可测量的增量引入,使组织更容易处理变化。敏捷团队的一个可观察到的系统影响是他们产生的输出开始改变。软件版本变得越来越小,可测量性成为他们输出的产品的一个特征。通常会对文化和组织设计产生后续影响。
除了过程标准化之外,大多数公司还采用某种形式的工具标准化。事实上,许多大型组织都有部门,他们的唯一目的是定义员工可以使用的工具类型。例如,一些公司禁止使用开源软件,并限制他们的团队使用由专家团队采购的集中批准的软件。
标准化输出
您可以将团队定义为一组工人,他们接受一组输入并将它们转换成一个或多个输出。输出标准化是一种为输出内容设定通用标准的方式。例如,在装配线上,生产线工人的产出是标准化的——生产线上的每个人都必须生产相同的产品。任何偏离标准输出的情况都被视为失败。
在微服务系统中,一个团队获取一组需求,并将这些需求转化为微服务。因此,服务是输出,而输出的表面是接口(或 API ),它提供对微服务所提供的特性和数据的访问。事实上,从微服务消费者的角度来看,API 就是输出,因为他们看不到它背后的实现。
在微服务环境中,输出标准化通常意味着为公开服务的 API 开发一些标准。例如,您可能决定组织的所有服务都应该有一个 HTTP 接口,或者所有服务都应该能够订阅和发出事件。一些组织甚至标准化了界面的设计,以提高可用性、可变性和使用服务的整体体验。
规范人
您还可以决定标准化在您的组织中工作的人员类型。例如,您可以为任何想要在微服务团队中工作的人引入一个最低技能要求。事实上,许多分享微服务故事的公司都指出,员工的技能水平是他们成功的主要特征。
标准化技能或人才可以有效地为您的微服务系统引入更多自主权。当实现服务的人更加熟练时,他们就有更好的机会做出决策,创建您想要的系统行为。
所有的组织都为他们的员工设置了一定程度的最低技能和经验水平,但是优先考虑技能标准化的组织通常会设置非常高的专业要求,以便获得系统的好处。如果只有最优秀、最聪明的人才能够在你的系统内工作,那么准备好付出高昂的代价来维持这个标准。
标准化权衡
标准化有助于您对系统施加影响,但是您不必只选择其中一个标准来利用。但是请记住,虽然它们并不相互排斥,但是引入不同的标准化模式可能会在系统的其他部分产生意想不到的后果。
例如,您可能会决定对所有微服务公开的 API 进行标准化,因为您希望降低解决方案架构中的连接成本。要做到这一点,您可以为开发人员可以创建的 API 类型指定一组规则,并建立一个审查过程来监督这种标准化。例如,许多组织标准化了记录所创建的接口的方式。现在,Swagger(也称为 OpenAPI)是一个流行的接口描述语言的例子,但还有许多其他的(WADL,蓝图,RAML 等。).
但是您可能会发现,约束您的人员可以生成的 API 的类型会限制他们可以用来创建它们的工具的类型。您希望每个人都使用的开发工具可能不支持您已经选择的接口描述语言。换句话说,标准化团队产出的决定对团队的工作过程产生了意想不到的后果。这是因为标准化是试图从系统中消除不确定性,但这是以减少创新和可变性为代价的。
标准化的好处是减少了所有可能结果的集合。它通过为系统中的人可以采取的行动设置约束和边界,为您提供了一种塑造系统的方式。但是这种好处是有代价的。标准化也限制了个人决策者的自主权。设计师面临的挑战是引入足够的标准化来实现最佳的紧急系统结果,同时还采用互补的标准和约束。
微服务设计流程
专业设计师知道伟大设计的秘密是使用正确的设计过程。当其他人采纳专家的建议或对他们的设计决策的影响做出错误的假设时,一个好的设计师会采用一个过程来帮助他们不断接近最好的产品。这并不意味着你永远不必做出假设,或者专家的指导一定是错误的。相反,这意味着在设计您想要的微服务系统时,您最好的机会是使用一个流程,该流程可以帮助您了解您的假设的影响以及在您更改系统时建议的适用性。图 2-3 展示了一个设计流程框架,您可以在自己的微服务系统设计中使用。在实践中,您可能需要定制流程,以适应您自己独特的约束和环境。您最终可能会以不同于这里给出的顺序使用这些设计活动。你也可能决定有些活动不适合你的目标,或者需要增加其他步骤。
图 2-3
微服务系统设计流程
设定优化目标
你的微服务系统的行为在帮助你实现目标的时候是“正确的”。没有一套完美适用于所有组织的优化目标,因此您的首要任务之一将是确定对您的特定情况有意义的目标。您在这里做出的选择非常重要——此后设计过程中的每个决定都是有利于优化目标的权衡。
请注意,优化并不意味着其他系统质量不受欢迎。事实上,很有可能你最初会为你创建的系统列出许多期望的结果。但是当你经历系统设计过程时,你会发现很难同时将你的系统推向多个方向。
例如,金融服务信息系统的可靠性和安全性可能比所有其他因素都重要。这并不意味着可变性、可用性和其他系统质量不重要——这只是意味着设计者总是会做出更倾向于安全性和可靠性的决定。
在应用生命周期的某个时刻,您可能需要更改您的优化目标。这只是表明您需要遵循设计过程并实现小的更改来引导您的系统朝着新的目标前进。如果目标变更与您最初的设计目标大相径庭,这可能需要一些时间。如果优化目标与您最初的目标完全不同,您甚至可以创建一个全新的系统设计。
发展原则
支撑系统优化目标的是一组原则。原则概述了一般的政策、约束和理念,这些政策、约束和理念应该普遍适用于系统内的参与者,以指导决策和行为。最好的设计原则简单明了,易于理解,并且对它们所作用的系统有深远的影响。
概述系统设计
如果您发现自己在一个全新的环境中构建应用,没有现成的组织或解决方案体系结构,那么为系统设计建立一个良好的起点是非常重要的。你不可能在第一次尝试时就创造出完美的系统,而且你也不太可能有时间或信息去做这件事。相反,为了评估和迭代的目的,一个好的方法是勾画出系统设计的重要部分。
如何做到这一点完全取决于你自己。有大量的建模和交流工具可以用来概念化组织和解决方案架构;选择最适合你的。但是这一步在设计过程中的价值是将你头脑中的一些抽象概念序列化为可以评估的有形形式。草图练习的目标是不断地改进设计,直到你能自如地前进。
目标是勾画出你的系统的核心部分,包括组织结构(团队有多大?权威的方向是什么?团队中有谁?)、解决方案架构(服务是如何组织的?什么样的基础设施必须到位?),服务设计(什么输出?多大?),以及流程和工具(如何部署服务?需要哪些工具?).你应该根据你之前概述的目标和原则来评估这些决定。你的系统会促进这些目标吗?这些原则有意义吗?原则需要改变吗?系统设计需要改变吗?当重新开始的风险很小的时候,速写是很强大的。好的草图很容易制作,也很容易销毁,所以避免用一种需要投入大量时间和精力的方式来建模你的系统。你花越多的精力来勾画你的系统,你就越不可能扔掉它。在系统设计的早期阶段,改变应该是廉价的。
最重要的是,记住迭代草图阶段的目的是参与设计的过程。目标是形成新的想法,考虑提议设计的影响,并以安全的方式进行实验。
实施、观察和调整
糟糕的设计者对系统如何工作做出假设,应用变化,希望它会产生期望的行为,然后就到此为止。优秀的设计师会对系统进行小的改动,评估这些改动的影响,并不断地促使系统行为朝着预期的结果发展。但是一个好的设计过程是基于你从你正在设计的系统中获得反馈的能力。这实际上比听起来要困难得多——对系统的一个小部分进行更改的影响可能会导致连锁反应,从而影响系统的其他低可见性部分。
完美的微服务系统提供关于跨文化、组织、解决方案架构、服务和过程的所有领域的系统的所有方面的完美信息。当然,这是不现实的。更现实的做法是,通过识别一些关键的度量来获得我们系统的基本可见性,这些度量为我们提供了关于系统行为的最有价值的信息。在组织设计中,这种类型的指标被称为关键绩效指标 (KPI)。微服务设计师面临的挑战是确定正确的服务。
通过识别 KPI 来收集关于您的系统的信息是有用的,但是能够利用这些指标来预测未来的行为是非常有价值的。所有系统设计者面临的挑战之一是未来的不确定性。有了关于系统可能需要如何改变的完美信息,您可以在完全正确的地方建立边界,并对您的服务和团队的规模做出完美的决策。
没有完美的信息,你被迫做出假设。在现有应用上工作的设计人员可以观察系统的现有和过去的行为,以识别模式——经常变化的组件、总是在变化的需求,以及可能预期高使用率的服务。但是,开发新应用的设计师通常从很少的信息开始——识别应用弱点的唯一方法是交付产品,然后看看会发生什么。
做出糟糕决策的风险在于,你将系统引向了增加“技术债务”(即解决技术缺陷的未来成本)的方向。如果你在错误的道路上走得太远,你可能会产生一个变得过于昂贵而无法改变的系统,所以你放弃了。
这方面的经典微服务示例是“monolith”的警示故事当功能集很小并且组件复杂性很低时,团队创建应用的初始版本。随着时间的推移,功能集不断增加,部署的应用也越来越复杂,这使得更改变得更加困难。在这一点上,团队同意应用需要重新设计和模块化,以提高其可变性。但是重新设计工作不断被推迟,因为这项工作的成本太高,难以证明。
在天平的另一端,是一个为了未来的灵活性而过度设计和过度工程化的系统,它变得不切实际。一个难以置信的复杂,适应性强的系统,是为大量似乎永远不会发生的变化而构建的。
一个好的微服务设计师不是试图预测未来,而是检查当前状态,并对系统做出微小的、可测量的改变。这有点像在长途旅行中走错了路——如果你不知道自己犯了一个错误,你可能不会发现自己走错了路,直到回头为时已晚。
一个被设计成具有高度可见性的系统可能会给你很多关于正在发生的事情的信息,但是如果改变系统的成本太高,你将无法做出任何方向的修正。当你需要特别的许可、额外的资金、更多的人或更多的时间来对系统进行你想要的改变时,这种高成本改变的问题就出现了。
因此,为了设计动态的微服务系统,您需要确定正确的 KPI,能够解释数据,并对系统进行小而廉价的更改,以引导您回到正确的道路上。只有当正确的组织、文化、过程和系统架构到位,使之变得便宜和容易时,这才是可能的。
微服务系统设计师
但是你还没有确定这个系统设计者是谁,或者他们在你现有组织中的位置。
为了最有效,微服务系统设计者应该能够对广泛的系统问题进行修改。我们已经认识到,组织、文化、过程、解决方案架构和服务是系统设计师的重要关注点。但是这个系统的边界还没有被正确地确定。
您可以决定系统边界应该反映公司的边界。这意味着你所实施的变革将会产生深远的影响。或者,你可以专注于公司内的一个部门或服务线,建立一个与母公司战略目标一致的系统。事实上,这种类型的嵌套系统是常见的,我们在物理世界(例如,人类和整个人类社区)中看到它在我们周围。
微服务系统设计师或者实际上是软件系统设计师负责有界系统的所有元素。系统设计者的任务是在系统中引入小的变化,以产生与预期目标一致的行为。解决方案架构师关注服务的协调,团队经理关注人员,服务开发人员关注服务设计。为了微服务系统的成功,应该有一个人或一个团队负责整个系统的整体视图。
目标和原则
无论您采用哪种软件架构风格,重要的是要有一些总体目标和原则来帮助您了解设计选择并指导实现工作。在为开发团队提供高度自治的公司中尤其如此。您允许的自主权越多,您需要向这些团队提供的指导和背景就越多。
这一部分着眼于微服务架构的一些一般目标和一些示例原则。在此过程中,我们将列出我们自己建议的原则供您考虑。
微服务方式的目标
在决定做什么和如何做时,有一套高层次的目标作为指导是一个好主意。我们已经介绍了以微服务的方式构建应用的目标:在规模上找到速度和安全性的恰当平衡。这个总体目标给了你一个目标,如果有足够的时间、迭代和坚持,将允许你建立一个适合你自己组织的系统。
当然,这种策略有一个明显的问题——如果你从零开始,你可能需要很长时间才能找到速度和安全的完美和谐。但由于一代又一代技术专家的努力,我们已经获得了提高速度和安全性的行之有效的方法。因此,您不需要重新发明已建立的软件开发实践。相反,您可以试验这些实践的参数。
从我们的研究中,我们已经能够提炼出四个具体的目标,这些目标导致有助于安全和变化速度的实践。这些目标并不是微服务架构所独有的,但它们对塑造您的旅程非常有用。以下是需要考虑的四个目标:
-
降低成本:这是否会降低设计、实施和维护 IT 服务的总体成本?
-
提高发布速度:这会提高你的团队从想法到部署服务的速度吗?
-
提高弹性:这会提高你的服务网络的弹性吗?
-
启用可见性:这是否有助于您更好地了解服务网络中的情况?
让我们更深入地看看这些。
降低成本
降低设计、实现和部署服务的成本的能力允许您在决定是否创建服务时有更大的灵活性。例如,如果创建一个新的服务组件的工作包括三个月的设计和审查,六个月的编码和测试,以及两个多星期的投入生产,那么这是一个非常高的成本—在开始之前您可能会非常仔细地考虑这个成本。然而,如果创建一个新的服务组件只需要几个星期的时间,您可能更愿意构建这个组件,看看它是否能帮助解决一个重要的问题。降低成本可以增加你的灵活性,因为它使你更有可能尝试新的想法。
在运营领域,降低成本是通过虚拟化硬件实现的。通过使“服务器”的成本变得几乎微不足道,它使您更有可能旋转一堆服务器,以便进行负载测试、组件在与其他组件交互时的行为等等。对于微服务来说,这意味着想办法降低编码和连接服务的成本。模板化的组件存根、标准化的数据传递格式和通用接口都是降低编码和连接服务组件成本的例子。
提高释放速度
提高“从设计到部署”周期的速度是另一个共同的目标。看待这个目标的一个更有用的方法是,您希望缩短构思和部署之间的时间。有时候,你不需要“走得更快”,你只需要走捷径。当你能够快速地从想法到运行实例,你就有机会在早期获得反馈,从错误中学习,并且在最终产品发布之前更频繁地迭代设计。与降低成本的目标一样,提高速度的能力也可以降低尝试新产品想法的风险,甚至是像新的、更有效的数据处理例程这样简单的事情。
可以提高速度的一个地方是部署过程。通过自动化部署周期的重要元素,您可以加快将服务投入生产的整个过程。我们为这本书采访的一些公司花了大量的时间为他们的组织建立高效的部署管道。他们中的许多人都有这样一个设计良好的部署模型,以至于他们一天多次发布到产品中。自动化发布对于提高微服务实现的速度以及带来标准化和可预测性大有帮助。
提高弹性
无论解决方案的速度或成本如何,构建能够“抵御”意外故障的系统也很重要。换句话说,即使出现错误,系统也不会崩溃。当你有一个整体的系统方法时(不仅仅关注一个单一的组件或解决方案),你可以致力于创建弹性系统。这个目标通常比试图创建一个完全没有错误的组件更合理。事实上,创建一个零 bug 的组件通常是不可能的,有时甚至不值得花费时间和金钱去尝试。
DevOps 实践集中于提高弹性的方法之一是通过使用自动化测试。通过将测试作为构建过程的一部分,测试会不断地针对签入的代码运行,这增加了在代码中发现错误的机会。这包括代码,但不包括运行时可能发生的错误。
有些公司在发布到产品之前运行他们所谓的端到端测试,但许多公司依赖于 Jez Humble 称之为蓝绿色部署的实践。在这种情况下,一个新的版本被放入生产环境中,只有一小部分用户,如果在监控阶段一切顺利,更多的用户将被路由到新的版本,直到新的版本上有了完整的用户群。如果在这个分阶段的推广过程中遇到任何问题,用户都可以返回到以前的版本,直到问题得到解决,过程重新开始。
启用可见性
另一个关键目标应该是支持运行时可见性。换句话说,提高涉众看到和理解系统中正在发生的事情的能力。有一套很好的工具可以在编码过程中实现可见性。您经常会得到关于代码积压、创建了多少构建、系统中的 bug 数量与已完成的 bug 数量等等的报告。但是您还需要对运行时系统的可见性。
日志和监控的 DevOps 实践是这种级别的运行时可见性的很好的例子。迄今为止,大多数工作都是记录和监控操作级指标(内存、存储、吞吐量等)。).然而,有一些监控工具可以在情况变糟时采取行动(例如,重新路由流量)。
权衡取舍
这些都是重要的目标,有时它们是相互竞争的目标。需要考虑权衡。您也许能够降低总体成本,但是它可能会对运行时弹性产生负面影响。或者,您可能能够加快部署,但这可能意味着您无法跟踪生产中正在运行的服务,并降低了对更大服务网络的可见性。最后,您需要平衡各种目标,并为您的组织找到合适的组合。
您的组织可能有一些您想要考虑和记录的其他高级目标。不管这些结果是什么,接下来你需要做的事情之一就是将这些目标转化为一套可操作的原则。
操作原则
除了微服务方法的一组目标之外,拥有一组原则也很重要。与一般的目标不同,原则为如何实现这些目标提供了更具体的指导。原则不是规则——它们没有列出必需的元素。相反,他们提供了如何在可识别的情况下采取行动的例子。
原则也可以用来指导最佳实践。我们在做研究时观察的许多组织都有自己的一套原则。
网飞
一家公司已经公开了他们自己创建成功微服务架构的历程,这就是网飞。在这里,我们只提出了网飞的几个原则。
抗脆性
网飞努力加强他们的内部系统,使他们能够承受意外的问题。“抗脆弱性的要点是,你总是希望你的系统中有一点压力,让它变得更强大。”网飞做了几件事情来促进这一点,包括他们的“猿人军队”工具集,该工具集“执行架构原则,引发各种各样的失败,并测试我们在失败中生存的能力”。软件有 bug,操作人员有失误,硬件有故障。通过在受控条件下制造生产中的故障,开发人员被激励去学习构建更健壮的系统。定期测试错误报告和恢复系统,并以最小的戏剧性和客户影响处理真正的故障。
不变
网飞使用不变性来断言自动伸缩的服务实例组是无状态的和相同的,这使得网飞的系统能够“水平伸缩”混沌猴是猿猴部队的一员,它定期删除实例以执行不变的无状态服务原则。另一种相关技术是使用“红/黑推送”。尽管每个发布的组件都是不可变的,但是在新的实例上,新版本的服务会与旧版本一起引入,然后流量会从旧版本重定向到新版本。在等待确定一切正常后,旧实例被终止。
关注点分离
网飞微服务架构的出现是因为工程团队组织中的关注点分离(SoC)。每个团队拥有一组服务。
他们拥有这些服务的构建、操作和发展,并向这些服务的消费者提供稳定的一致同意的接口和服务级别协议。
援引康威定律,一个由独立自足的工程师组成的组织自然会构建现在所谓的微服务架构。
三个关键原则:抗脆弱性、不变性和关注点分离。道格拉斯·麦克洛伊在描述 UNIX 操作系统时,对其中一些观点的表述略有不同。
一种多用户的计算机操作系统
以下四点是作为一套“在 UNIX 系统的构建者和用户中流行的准则”提出的
这是道格拉斯·麦克罗伊和他的同事们列出的清单:
-
让每个程序做好一件事。要做一项新工作,就要重新构建,而不是通过添加新功能来使旧程序变得复杂。
-
期望每个程序的输出成为另一个未知程序的输入。不要用无关的信息混淆输出。避免严格的列或二进制输入格式。不要坚持交互输入。
-
设计和构建软件,甚至是操作系统,尽早试用,最好在几周内。不要犹豫,扔掉笨拙的部分,重建它们。
-
优先使用工具,而不是不熟练的帮助来减轻编程任务,即使您必须绕道去构建工具,并期望在使用完它们后扔掉一些。
关于这四个原则的一个有趣的事情是,它们提供了关于如何考虑编写软件的一般指导。像“做好一件事”和“构建软件…尽早试用”这样的短语会导致开发人员在编写代码时采用在 UNIX 世界中被称为“吝啬法则”的东西(“只有在没有其他东西可以做的时候才编写大程序”)。这与其他 UNIX 规则一起,为开发人员提供了一套使用哪种编程语言或库的指导原则。
这些原则也意味着塑造开发者的思维。
建议的原则
拥有一套指导软件开发人员和架构师的原则是非常有意义的。没有一套原则适合每家公司。每个组织都需要创建一个适合其公司的集合。
考虑到这一点,我们提供了一组原则,这些原则反映了到目前为止您所看到的其他示例的各个方面。你可以用这些作为开始材料,为你的公司组合出你自己独特的一套,或者调整这些直到它们适合为止。
做好一件事
许多微服务实现采用了基本的信息——“做好一件事”,这导致了在您的实现中决定什么构成“一件事”的挑战。
重新建造
麦克洛伊第一原则的第二部分(“重建”)也很重要。UNIX 哲学的一部分是创建一个强大工具的集合,这些工具是可预测的,并且在很长一段时间内是一致的。在实现微服务时,这是一个值得考虑的附加原则。构建一个新的微服务组件可能比尝试使用已投入生产的现有组件并对其进行更改以完成额外工作更好。这也映射到网飞的不变性原理。
期望输出成为输入
UNIX 开发人员的另一个重要原则是,一个程序的输出是另一个程序的输入。对于 UNIX 系统,这导致依赖文本字符串作为主要的数据传递媒介。在 Web 上,数据传递的媒介是媒体类型(HTML、HAL、Siren、Collection+JSON 等。).在某些情况下,您甚至可以使用 HTTP 的内容协商特性来允许 API 提供者和消费者在运行时自己决定使用哪种格式来传递数据。
不要坚持交互式输入
在 UNIX 世界中,人们希望创建将许多命令行工具捆绑在一起的脚本,以创建一个“解决方案”这意味着人类不需要参与每一步——脚本自己处理输入和输出。减少对人工交互的需求增加了组件以意想不到的方式使用的可能性。
微服务组件在运行时不需要处理人机交互。但是当你把你的关注范围扩大到微服务系统时,你很容易发现无数的人类互动可以受益于这个原则。在软件开发过程中减少对人类交互的依赖,可以大大提高变化发生的速度。
尽早尝试
接受您的微服务组件应该“尽早尝试”的观点,非常符合持续交付的概念以及将速度作为您的实现目标的愿望。这个“尽早尝试”原则的另一个好处是,你会很早就知道你的错误。事实证明“尽早尝试”也是鼓励团队养成尽早和经常发布的习惯的一种方式。越早发布(即使是在测试环境中),越早得到反馈,就能越快改进。
不要犹豫扔掉它
这对于一些开发者来说是一个难题。当你花了大量的时间和精力来构建一个组件时,想要扔掉一些东西是很难的。然而,当你采用“尽早尝试”的原则时,抛弃早期的尝试会更容易。
对于已经在生产中运行了很长时间的组件,考虑这种“扔掉它”的原则也很重要。随着时间的推移,曾经发挥重要作用的组件可能不再需要。您可能已经应用了“重新构建”原则,用一个更好的组件替换了这个组件。可能的情况是,组件所做的“一件事”已经不再需要了。重要的是,当一个组件不再满足其预期目的时,要愿意扔掉它。
工具制造
“使用工具”原则涵盖了这样一个概念,即在构建解决方案时,您有时需要为工作构建“正确的工具”。人类发展史上的一个重要因素是创造工具的能力。创造这些工具是为了达到一个目标。换句话说,工具是手段,不是目的。这也是微服务架构的一个重要原则。
在为这本书做研究时,我们发现了几个公司创建自己的开发人员和部署工具链的例子,以改善他们的整体开发人员体验。有时这些工具是从现有的开源软件项目中构建的。有时,这些工具本身被传递到开源中,以便其他人可以使用它们,并为改进和维护它们做出贡献。这里重要的一点是要认识到,在某些情况下,您可能需要从构建解决方案中转移出来,花一些时间构建工具来帮助您构建解决方案。
平台
除了一组总体目标和具体原则,您还需要有形的工具来使它们成为真正的平台,从而使您的微服务环境成为现实。从微服务架构的角度来看,好的平台可以提高大规模变化的速度和安全性之间的和谐平衡。我们通常认为速度和安全是对立的属性,需要做出权衡,但正确的工具和自动化给了你一个欺骗权衡的机会。
例如,不变性原则主要提高了对系统所做更改的安全性。不变性还有一个固有的发布成本,因为每个可部署单元都需要它自己的相关发布机制、基础设施和管理。就其本身而言,增加的成本会降低变革的速度。然而,像 Docker 这样的容器化工具的引入使得独立部署变得容易,并且大大降低了相关的成本。当不变性与容器化相结合时,更改的速度和安全性都得到了优化,这可能解释了 Docker 在大型组织中的快速采用。
好消息是,有许多公司建立——甚至共享——他们的微服务平台的例子。挑战在于,似乎每家公司都在以自己的方式做这件事,这为任何想要构建自己的微服务环境的人提供了一些选择。你只是选择一个现有的 OSS 平台吗?你想买一个吗?从头开始造一个?如果只是选择一家受欢迎的公司的平台,而不经过仔细考虑就采用它,那将是一个错误。这家公司提供的服务类型和我的一样吗?这家公司的优化目标和我的一样吗?我们有相似的员工和培训环境吗?我们的目标客户相似吗(优先顺序、技能、期望结果等)。)?不要只关注一家现有公司的平台,而应该关注微服务平台的通用模型。
共享功能
大型企业通常会创建一组共享服务供所有人使用。
这些通常以组织的公共基础设施为中心。例如,任何与硬件(实际的或虚拟的)相关的东西都属于这一类。常见的数据库技术(MySQL、Cassandra 等。)和其他软件实现的基础设施是共享服务的另一个例子。
这些是标准化的东西,如容器技术、策略执行、服务编排/互操作和数据存储服务。即使在大型组织中,为了限制复杂性和获得成本效益,缩小这些元素的选择范围也是有意义的。本质上,这些都是提供给组织中每个团队的服务。
需要注意的是,共享服务并不意味着共享实例或共享数据。仅仅因为所有团队都使用单一类型的数据存储技术(例如,Mongo、Cassandra 等。)并不意味着它们都使用相同的数据存储运行实例,并且都从相同的表中读取和写入。
虽然共享功能提供了潜在的成本节约,但它们最终植根于变更安全的微服务目标。高度重视变更安全性的组织更有可能部署能够提供一致、可预测结果的集中式共享功能。另一方面,那些不惜一切代价追求速度的组织可能会尽可能避免共享组件,因为它有可能抑制分散化变革的速度。在这些以速度为中心的公司中,能力重用没有交付速度重要。与微服务方式中的所有事情一样,您需要尝试不同形式的共享功能,以了解什么最适合您的独特环境。
以下部分概述了共享服务平台通常提供的内容。
硬件服务
所有组织都处理部署操作系统级和协议级软件基础设施的工作。在一些公司中,有一个团队负责接收硬件(例如,1-U 服务器),在这些机器上安装基准操作系统和用于监控、运行状况检查等的通用软件,然后将完成的单元放入“服务器机房”的机架中,以备应用团队使用。
另一种方法是将操作系统和基准软件包虚拟化为虚拟机(VM)。虚拟机使大部分填充“新机器”并将其投入生产的工作自动化成为可能。
最近的趋势是使用容器来解决这个问题。Docker 是这个领域最受欢迎的选手。
源代码管理、测试和部署
一旦将正在运行的服务器作为目标,就可以向它们部署应用代码。这就是代码管理(例如,源代码控制和审查)、测试和(最终)部署的切入点。所有这些服务都有相当多的选项,其中一些与开发环境相关,尤其是测试。
大多数微服务商店都不遗余力地实现这部分流程的自动化。例如,云平台提供了测试和部署的自动化,开发人员一签入他们的代码,测试和部署就开始了。自动化的过程可能是复杂的,发布到产品中可能是有风险的,因此将它视为所有团队都学习使用的共享服务是一个好主意。
数据存储
现在有许多可用的数据存储平台,从经典的基于 SQL 的系统到 JSON 文档存储,一直到图形风格的数据库,比如 Neo4J。
对于大型组织来说,支持所有可能的存储技术通常是无效的。对于您的组织来说,将重点放在选定的几个存储平台上,并向所有开发团队提供这些平台是有意义的。
服务编排
服务编排或服务互操作性背后的技术是所有团队共享的另一项技术。这里有各种各样的选择。许多旗舰微服务公司都编写了自己的编排平台。
安全性和身份
平台级安全性是另一种共享服务。这通常通过网关和代理在外围发生。共享身份服务有时实际上在公司外部。
建筑政策
最后,除了共享安全性,有时还会共享额外的策略服务。这些服务用于实施特定于公司的模式或模型——通常在运行时通过一种检查甚至侵入式测试来实施。
运行时策略执行的一个例子是网飞的“猿猴部队”——一组旨在故意在网络上造成问题的服务(模拟丢失数据包、无响应的服务等)。)来测试系统的弹性。
另一种策略工具是标准化停机或其他事故的事后处理方式。这种事后回顾有时被称为事后分析。无论是以运行时监视器还是事后分析的形式,策略服务都确保不同的团队在如何处理实现中的弹性和安全性方面遵循相同的指导。
本地化功能
本地化的能力是在团队或组级别选择和维护的。本地能力集的主要目标之一是帮助团队变得更加自给自足。这允许他们按照自己的节奏工作,并减少团队在实现目标时遇到的阻碍因素。此外,通常允许团队自己决定哪些开发工具、框架、支持库、配置工具等等最适合他们的工作。有时,这些工具是从一组“批准的”产品中挑选出来的。
大多数本地能力服务访问和/或操纵共享服务。以下是微服务环境的常见本地功能列表:
-
通用工具—一项关键的本地功能是自动化部署、监控和管理虚拟机和部署包的流程。网飞为此创造了阿斯加德和阿米娜特。一个流行的开源工具是 Jenkins 和 Azure DevOps。
-
运行时配置—在许多使用微服务的组织中发现的一种模式是在一系列受控阶段推出新功能的能力。这允许团队评估一个新的发布对系统其余部分的影响(我们是否运行得更慢了,发布中是否有意外的 bug,等等)。).Twitter 的 Decider 配置工具被许多公司使用,包括 Pinterest、Gilt 和 Twitter。脸书创造了他们自己的工具,叫做看门人,做同样的事情。同样,将这种权力交给编写和发布代码的团队是一种重要的本地能力。
-
服务发现(Service discovery)—有一些流行的服务发现工具,包括 Apache Zookeeper、CoreOS 的 etcd 和 HashiCorp 的 Consul。这些工具使得构建和发布服务成为可能,这些服务在安装后向中央源注册,然后允许其他服务在运行时“发现”彼此的确切地址/位置。这种抽象服务确切位置的能力允许不同的团队对他们自己的服务部署位置进行更改,而不用担心破坏其他团队现有的运行代码。
-
请求路由—一旦机器和部署启动、运行并发现服务,处理请求的实际过程就开始了。所有系统都使用某种请求路由技术来转换外部调用(通常通过 HTTP、WebSockets 等)。)转换成内部代码执行(例如,代码库中某处的函数)。最简单的请求路由形式就是从 Apache、Microsoft IIS、NodeJS 等 web 服务器中公开 HTTP 端点。然而,随着服务请求的增加,通常会在 web 服务器的“前端”安装专门的路由代理或网关。网飞创造了祖尔来处理他们的路由。
有流行的开源服务,如 Netty(由 JBoss 创建)和 Twitter 的 Finagle。
- 系统可观察性—快速变化的分布式环境中的一大挑战是获得运行实例的视图——看到它们的失败/成功率,发现系统中的瓶颈,等等。这方面的工具相当多。Twitter 为此任务创建了(并开源了)Zipkin,还有其他类似的框架提供了对运行系统状态的可见性。
还有另一类可观察性工具——它们不仅仅是报告系统状态。这些工具实际上在事情似乎变得糟糕时采取行动,通过重新路由流量、警告关键团队成员等等。网飞的 Hystrix 就是这些工具之一。它实现了一种称为断路器的模式,以提高运行系统的弹性。
文化
除了建立目标和原则,用管理平台、代码和运行时环境的正确工具武装您的组织之外,还有另一个需要考虑的重要基础元素——您的公司文化。文化很重要,因为它不仅为人们在一个组织中的行为方式定下基调,而且还会影响团队的产出。你的团队产生的代码是文化的结果。
但是什么是文化呢?已经有很多关于文化的文章——从很多角度,包括人类学和组织学的角度。
那么,文化是如何影响团队产出的呢?如果是的话,什么样的团队文化可以提高团队绩效和工作质量?我们将着眼于文化的三个方面,您应该考虑将它们作为您微服务工作的基础:
-
团队之间的交流:研究表明你的团队交流的方式(相互之间以及与其他团队的交流)对你的软件质量有直接的可测量的影响。
-
团队协调:团队的规模也会影响产出。团队中更多的人意味着更多的开销。
-
促进创新:创新对组织来说可能是破坏性的,但对成长和长期成功却是必不可少的。
调整你的团队
团队合作很重要——它会影响代码的质量。如何利用这些信息呢?使用本章开头的信息,您可以使用哪些“可调”元素来改进您的团队结构的一致性,以实现您的微服务工作的提高速度、弹性和可见性的目标?
随着群体规模的增长,独特的沟通渠道的数量以非线性方式增长。这种组合爆炸的例子是一个常见的问题,在你设计你的团队时需要牢记在心。
例如,瑞典音乐流媒体公司 Spotify 依靠大约 7 人的团队规模(他们称之为团队)。他们还依赖于几个团队的集合,他们称之为部落,并提到在建立你的团队时还有几个其他因素——包括责任、可交付成果和技能组合——需要在团队中存在。
促进创新
管理公司文化的第三个重要因素是在你的组织内培养创新。许多公司表示,他们希望让创新思维在公司内部变得普遍。利用创造性和创新性想法的能力有时被认为是采用微服务方法开发软件的一个原因。因此,花点时间探索创新是什么样子以及它如何影响你的组织是有意义的。
在韦氏词典的字典中,创新的简单定义是“以新的方式做某事;对如何做某事有新的想法。”值得注意的是,创新通常专注于改变已经确立的东西。这不同于创造新事物。创新通常被认为是一个改善团队或公司已经拥有或正在做的事情的机会。
一个常见的挑战是,创新过程对组织来说具有很大的破坏性。有时“改变我们做事的方式”是不必要的,甚至是威胁性的练习——特别是如果改变会扰乱组织的某些部分(例如,导致取消任务、减少工作量,甚至替换整个团队)。出于这个原因,创新的行为可能会很困难。创新的另一个问题是,从外表上看,过程往往是混乱的。创新可能意味着想出一些可能行不通的想法,这些想法需要时间才能正常运行,甚至开始时比当前的实践更加昂贵和耗时。
然而,许多组织确实希望鼓励团队内部的创新工作。
我们采访的公司通过采用一些关键原则来实现创新。首先,他们为他们的团队提供了一定程度的自主权。它们允许团队决定处理团队内部细节的最佳方式。网飞称之为“背景,而不是控制”的原则团队领导被教导为团队的工作提供背景,并为实现目标提供指导,但不控制团队做什么。
第二,鼓励创新的公司能够容忍一定程度的混乱。他们的理解是,如果有些东西看起来有点杂乱无章也没关系。当然,这是有限度的。《哈佛商业评论》的《管理创新:受控混乱》指出,“有效的创新管理者……主要通过设定目标、选择关键人物、建立一些关键限制和干预决策点来进行管理。”促进创新意味着设定界限,防止团队采取威胁公司健康和福利的行动,并允许团队在这些安全界限内独立行动。
管理沟通渠道,协调团队,建立安全的创新场所,这些都是创造成功文化的关键,这种文化可以利用微服务风格的方法来设计、实现和维护软件。
摘要
在本章中,您学习了微服务的各种设计原则。你也看到了这些不同的模式。
您还了解了 AWS 和网飞等其他公司如何创建强大的模式,您可以在微服务的设计和架构中加以利用。
下一章着眼于微服务设计模式,并展示它们如何应用于一个示例应用。
附录
https://netflixtechblog.com/the-netflix-simian-army-16e57fbab116
https://www.thoughtworks.com/insights/blog/demystifying-conways-law
https://homepage.cs.uri.edu/~thenry/resources/unix_art/ch01s06.html
https://www.atlassian.com/agile/agile-at-scale/spotify
三、微服务设计模式
介绍
现在,您已经了解了评估微服务成熟度和就绪性的架构和组织考虑事项,本章将介绍微服务使用的设计模式。
一个示例解释了这些设计模式,并展示了它们如何应用于微服务设计。
服务设计
其中一个关键要素是实际微服务组件本身的设计,这也是大多数人在谈论微服务架构时都会想到的。正是这些自主服务构成了微服务系统的结构,并执行实施您的解决方案策略的实际工作。实现包含许多小型服务组件的系统是一个挑战,所以我用了整整一章来介绍一组工具和过程,它们可以帮助您和您的团队完成这项任务。
在我们与各种组织合作和采访其他人的经验中,采用微服务架构的团队面临的一些更具挑战性的问题是如何正确地确定微服务的规模(“微有多微?”)以及如何正确处理数据持久性以避免跨服务共享数据。这两个问题实际上是密切相关的。最佳规模的错误通常会导致无关的数据共享问题,但后者在操作上尤其成问题,因为它会创建紧密的跨服务耦合,并阻碍独立的可部署性,而独立的可部署性是架构风格的核心价值。当我们与设计和实现微服务的人交谈时,经常出现的其他话题是支持异步消息传递、事务建模以及处理微服务环境中的依赖关系。掌握这些元素将有助于您抑制蔓延到整个系统中的额外的(不必要的)复杂性。这样做可以帮助你在任何 IT 系统中平衡两个关键因素:速度和安全。
这一章涵盖了微服务的边界,看看一个服务应该有多“微”以及为什么。它将探索微服务接口(API),讨论可演化的、面向消息的 API 对于微服务的重要性,以及它们如何减少组件间的耦合。它将研究微服务的有效数据存储方法,探索从以数据为中心和状态捕获模型向能力驱动和面向事件源的模型转变的力量。
本章还展示了命令查询责任分离(CQRS)模式如何提高数据服务的粒度,同时保持足够的速度和安全性。
当您阅读完这些材料时,您应该已经很好地理解了在设计和构建微服务组件时所面临的挑战以及可用的模式和实践。
先说大的:“微服务的最优规模是多少?”
微服务边界
那么微服务应该有多微呢?这个问题没有简单的答案。首先想到的事情,如微服务中的代码行或从事某项服务的团队规模,是引人注目的,因为它们提供了关注可量化价值的机会(例如,“答案是 40”)。然而,这些方法的问题是它们忽略了你所实现的业务环境。它们没有解决谁在实现服务的组织环境,更重要的是,服务在您的系统中是如何使用的。
大多数公司不是试图找到一些数量来衡量,而是关注每个微服务的质量——组件将被使用的用例或上下文。许多微服务采用者已经转向 Eric Evans 的“领域驱动设计”(DDD)方法,以获得一套完善的流程和实践,促进大型复杂系统的有效、业务环境友好的模块化。
微服务边界和领域驱动设计
本质上,我们看到人们在将微服务引入公司时所做的事情是,他们开始将现有组件分解为更小的部分,以便在不牺牲可靠性的情况下,提高他们更快提高服务质量的能力。
有许多方法可以将一个大系统分解成更小的子系统。在一种情况下,您可能会尝试基于实现技术来分解系统。
例如,您可以说所有计算量大的服务都需要用 C 或 Rust 或 Go(选择您自己的毒药)编写,因此它们是一个独立的子系统,而 I/O 量大的功能肯定会受益于 Node.js 等技术的非阻塞 I/O,因此它们是自己的子系统。或者,您可以根据团队地理划分一个大型系统:一个子系统可能在美国编写,而其他子系统可能由非洲、亚洲、澳大利亚、欧洲或南美洲的软件团队开发和维护。直观上,给一个在一个地方的团队一个用于开发的自包含子系统是很好的优化。
您可能决定根据地理位置划分系统的另一个原因是,在特定市场运营的特定法律、商业和文化要求可能会被本地团队更好地理解。一个来自纽约的软件开发团队能准确地捕捉到一个将在开罗使用的会计软件的所有必要细节吗?
一种在大系统中确定子系统边界的新方法。该过程提供了软件系统设计的以模型为中心的视图。正如所指出的,模型是观察一个系统的好方法。它们提供了一种看待事物的抽象方式——一种突出你感兴趣的事物的方式。模型是一种观点。
这只是一个模型
为了理解 DDD 方法,重要的是要记住任何软件系统都是现实的模型——它不是现实本身。例如,当你登录网上银行并查看你的支票账户时,你看到的并不是真正的支票账户。您只是在查看一个表示——一个模型——它为您提供了关于支票账户的信息,比如余额和过去的交易。很可能你的银行出纳员在查看你的账户时看到的屏幕有不同的信息,因为它是你账户的另一个模型。
大多数大型系统实际上没有单一的模型。一个大系统的整体模型是由许多混合在一起的小模型组成的。这些较小的模型是相关业务环境的有机表示——它们在它们的环境中是有意义的,并且当在环境中使用时,对于环境的主题专家来说是直观的。
限界上下文
当使用模型时,团队在组合上下文模型以形成更大的软件系统时需要非常小心。在任何大型项目中,都有多个模型在起作用。然而,当基于不同模型的代码组合在一起时,软件就会变得错误百出、不可靠且难以理解。团队成员之间的交流变得混乱。通常不清楚在什么情况下不应该应用模型。早在微服务一词出现之前,人们就已经想到了这个概念。
然而,前面的引用是关于建模本质的一个重要观察——如果你试图依赖一个单一的模型(例如,一个规范的模型),事情会变得难以理解。微服务方法试图将大型组件(模型)分解成较小的组件,以减少混乱,并使系统的每个元素更加清晰。因此,微服务架构是一种与 DDD 建模方式高度兼容的架构风格。为了帮助创建更小、更一致的组件,引入了有界上下文的概念。系统中的每个组件都存在于它自己的有界上下文中,这意味着每个组件的模型和这些上下文模型只在它们的有界范围内使用,而不在有界上下文之间共享。
众所周知,使用 DDD 技术正确识别系统中的有界环境,并沿着这些有界环境的接缝分解大型系统是设计微服务边界的有效方法。如果您使用 DDD 和有界上下文方法,那么两个微服务需要共享一个模型和相应的数据空间,或者最终具有紧密耦合的可能性会低得多。避免数据共享提高了将每个微服务视为独立可部署单元的能力。
使用 DDD 和有界上下文是设计组件的一个很好的过程。然而,故事还没完。你实际上可以使用 DDD,最终仍然可以创建相当大的组件。但是在微服务架构中,大并不是你想要的。相反,你的目标是小的,甚至是微型的。这就引出了微服务组件设计的一个重要方面——越小越好。
越小越好
工作单元粒度的概念在现代软件开发的许多上下文中是一个关键的概念。无论是明确定义还是隐含定义,你都可以清楚地看到这种趋势出现在诸如敏捷开发、精益启动和持续交付等基础方法论中。这些方法分别革新了项目管理、产品开发和开发运维。
有趣的是,它们中的每一个都有其核心的规模缩减原则:减少问题的规模或范围,减少完成任务所需的时间,减少获得反馈所需的时间,以及减少部署单元的规模。这些都属于我们称之为“批量缩减”的概念
例如,下面是敏捷宣言的摘录:
频繁地交付工作软件,从几个星期到几个月,优先考虑较短的时间尺度。
—敏捷宣言,肯特·贝克等人。
基本上,从瀑布模型转移到敏捷模型可以被看作是开发周期“批量大小”的减少——如果在瀑布模型中周期需要几个月,现在你努力在更短的周期(几周而不是几个月)内完成类似的一批任务:定义、架构、设计、开发和部署。诚然,敏捷宣言也列出了其他重要的原则,但它们只是加强和补充了“更短的周期”(即,减少批量)的核心原则。
连续交付的主要优势,Martin Fowler 对小批量的作用毫不含糊,称之为该方法核心优势的先决条件。
一旦您从代码、项目和部署级别的敏捷、精益和连续交付中接受了有限批量的概念,那么考虑在架构级别应用它也是有意义的。我们采访的许多公司都这样做了。毕竟,建筑学是其他三个学科的直接对应。所以,用最简单的话来说,这个“有限批量”就是微服务中的“微”。
就像敏捷中一样,等等。,没有简单、通用的方法来确定微服务应该“多小”(例如,数量)。
人们告诉我们的是,他们使用“小”这个词作为“可靠”和“连贯”等品质。
普遍存在的语言
仅仅通过陈述“越小越好”的简单偏好,如果有界上下文是您调整微服务的唯一工具,您将立即遇到问题,因为有界上下文实际上不可能任意小。以下是 DDD 领域的一位杰出权威沃恩·弗农对有界环境的最佳规模的看法:
在 DDD,我们需要共同的理解和表达领域细节的方式。这种共同的理解应该为业务和技术团队提供一种共同的语言,他们可以使用这种语言在模型的定义和实现上进行协作。正如 DDD 告诉我们在一个组件中使用一个模型(有界环境),在这个有界环境中使用的语言应该是连贯的和普遍的——我们在 DDD 称之为 无处不在的语言 。
从纯技术的角度来看,微服务越小,就越容易开发得更快(敏捷),迭代得更快(精益),部署得更频繁(持续交付)。但是在建模方面,重要的是避免创建“太小”的服务根据 Vernon 的说法,我们不能任意减少有界上下文的大小,因为它的最佳大小是由业务上下文(模型)决定的。对服务规模的技术需求有时可能不同于(小于)DDD 建模所能提供的。这可能就是为什么 Sam Newman 非常谨慎地称有界上下文分析是一个“良好的开端”,但不是如何确定微服务规模的唯一方法。我们完全同意。有界上下文是一个很好的开始,但是如果您想要有效地调整微服务的规模,您的工具箱中需要更多的工具。
微服务的 API 设计
当考虑微服务组件边界时,源代码本身只是关注的一部分。微服务组件只有在能够与系统中的其他组件通信时才变得有价值。它们都有一个接口或 API。正如您需要实现代码的高度分离、独立和模块化一样,您需要确保您的 API(组件接口)也是松散耦合的。否则无法独立部署两个微服务,为了兼顾速度和安全,这是首要目标之一。
这里有两个为微服务制作 API 的实践值得一提:
-
面向消息
-
超媒体驱动
面向消息
正如您致力于编写可以随时间安全重构的组件代码一样,您需要将同样的努力应用于组件之间的共享接口。最有效的方法是对微服务 API 采用面向消息的实现。消息传递作为组件间共享信息的一种方式的概念可以追溯到关于面向对象编程如何工作的最初想法。
我们谈过微服务组件设计的所有公司都提到消息传递是一个关键的设计实践。例如,网飞依赖 Avro、Protobuf 和 Thrift over TCP/IP 等消息格式进行内部通信,依赖 JSON over HTTP 与外部消费者(如手机、浏览器等)通信。).通过采用面向消息的方法,开发人员可以公开组件的一般入口点(例如,IP 地址和端口号),同时接收特定于任务的消息。这允许消息内容的改变,作为一种安全地重构组件的方式。这里学到的关键经验是,长久以来,开发人员一直将 API 和 web 服务视为通过网络传输序列化“对象”的工具。然而,更有效的方法是将一个复杂的系统看作是通过网络交换消息的服务的集合。
超媒体驱动
我们采访过的一些公司正在将面向消息的概念推向下一个层次。他们依赖超媒体驱动的实现。在这些情况下,组件之间传递的消息不仅仅包含数据。这些消息还包含可能的动作的描述(例如,链接和表单)。现在,不仅数据是松散耦合的,动作也是如此。例如,Amazon 的 API Gateway 和 App-Stream API 都支持超文本应用语言(HAL)格式的响应。
超媒体风格的 API 将可进化性和松散耦合作为设计风格的核心价值。您可能也知道这种风格是以超媒体作为应用状态引擎的 API(hate OAS API)。不管使用什么名称,如果你要在微服务架构中设计合适的 API,熟悉超媒体风格是有帮助的。
超媒体风格本质上是 HTML 为浏览器工作的方式。HTTP 消息被发送到一个 IP 地址(您的服务器或客户端在互联网上的位置)和一个端口号(通常是“80”或“443”)。这些消息包含以 HTML 格式编码的数据和动作。例如,包含即将到达您办公室的未处理货物信息的邮件可能如下所示:
<html>
<head>
<title>Shipment #123</title>
</head>
<body>
<h1>Shipment #123</h1>
<div id="data">
<span>ID: 123</span><br />
<span>Description: Widget Covers</span><br />
<span>Quantity: 1 Gross</span><br />
<span>Estimated Arrival: 2017-01-09</span><br />
</div>
<div id="actions">
<a href="...">Refresh</a>
<a href="...">Exit</a>
<form method="get" action="...">
<input name="id" value="" />
<input type="submit" value="Search" />
</form>
</div>
</html>
超媒体 API 风格对于 API 空间的变革就像面向对象设计对于代码设计一样。很久以前,我们习惯于编写无穷无尽的代码行(可能只是简单地将它们组织在函数中),但随后面向对象的设计带来了一个革命性的想法:“如果我们将状态和对该状态进行操作的方法分组到一个称为对象的自治单元中,从而封装数据和行为,会怎么样?”本质上,除了 API 设计,超媒体风格有非常相似的方法。这是一种 API 风格,其中 API 消息包含数据和控件(例如,元数据、链接、表单),从而通过不仅用静态数据而且用描述 API 启示的控件元数据(即,“我可以用这个 API 做什么?”).
公开启示对于通过 Web 通信的服务是有意义的。如果你把网络看作是以人为中心的网络(由人类消费的网站)和机器网络(API),你可以看到机器网络落后多少的明显差异。当你在以人为中心的网络上加载一个网页时,它不只是给你内容(文本、照片、视频等)。)—大多数网页还包含相关内容或搜索菜单的链接:一些你可以与之互动的东西。基本上,网页在回复中告诉你,你还能做什么。传统的 Web APIs 不会这样做。
大多数当代的 RESTful(CRUD)API 只响应数据,然后你不得不去阅读一些文档,看看还能做些什么。大多数人都会同意,这将是一次相当可笑的经历。如果回答不包含行为启示,人类网络就不会很有功能。但是这正是大多数现代 RESTful APIs 的情况。事实上,对于机器网络来说,只有数据的方法就像以人为中心的网络一样脆弱和不正常,除非我们已经习惯了这种不幸的状况。
超媒体 API 更像人类网络:可进化、适应性强、版本自由——你最后一次关心你正在看的网站的“版本”是什么时候?因此,超媒体风格的 API 不太脆弱,更容易被发现,并且适合高度分布式的协作架构风格,如微服务。
数据和微服务
作为软件工程师,我们被训练首先从数据的角度思考问题。
举一个最简单的例子,它已经深深植根于我们的“肌肉记忆”中,或者不管它在精神上的等同物是什么,通过首先设计相关的数据模型来开始系统设计。当被要求构建一个应用时,大多数软件工程师将完成的第一个任务是识别实体和设计用于数据存储的数据库表。这是一种设计集中式系统的有效方式,整代程序员都被训练以这种方式思考。但是以数据为中心的设计并不是实现分布式系统的好方法——尤其是依赖于可独立部署的微服务的系统。最大的原因是在分布式系统的情况下,缺乏对整个系统的强有力的、集中的、统一的控制,这使得以前高效的过程变得低效。
打破以数据为中心的习惯的第一步是重新思考我们的系统设计。事实证明,以能力为中心的设计比更传统的以数据为中心的设计更适合微服务。
运输公司示例
假设您正在为一家羽翼未丰的运输公司设计一个微服务架构,这个公司的名字恰如其分。作为一家包裹递送公司,他们需要接受包裹,通过各种分拣仓库(路线上的跳跃点)发送包裹,并最终递送到目的地。因为现在是 2021 年,该公司非常精通技术,所以航运公司正在为各种平台开发本地移动应用,让客户从取件到最终交付全程跟踪他们的包裹。这些移动应用将从一组微服务中获得所需的数据和功能。
让我们想象一下,航运公司的会计和销售子系统(微服务)需要访问每日货币汇率来执行操作。以数据为中心的设计会在数据库中创建一个或一组包含汇率的表。然后,我们会让各种子系统查询我们的数据库来检索数据。
这个解决方案有很大的问题——两个微服务依赖于共享表的设计和其中的数据,导致紧密耦合并阻碍独立部署。
相反,如果我们将“货币汇率”视为一种能力,并构建一个独立的微服务(货币汇率)来服务于销售和会计微服务,我们将拥有三个独立的服务,所有这些服务都是松散耦合且可独立部署的。此外,由于服务中的 API 本质上隐藏了实现细节,我们可以完全改变支持货币汇率服务的数据持久性(例如,如果可伸缩性成为问题,从 MySQL 到 Cassandra ),而服务的任何消费者都不会注意到这种改变或需要进行调整。最后但同样重要的是,由于服务(API)能够向其各种消费者提供替代接口,我们可以轻松地改变货币汇率微服务向销售微服务提供的接口,而不会影响会计微服务,从而实现独立发展的承诺,这是独立部署的必要条件。
一般来说,从能力而不是数据的角度来考虑是 API 设计的一种非常强大的技术。它通常会产生一个更加面向用例的接口(而不是类似 SQL 的数据对象接口)。以功能为中心的 API 设计通常是一种好的方法,但是在微服务的情况下,它不仅仅是一种聪明的设计技术,还是避免紧密耦合的一种强有力的方法。你刚刚看到了证据。
与有限的上下文分析非常相似,面向能力的设计是一项关键技术,但不足以确保所有用例的独立部署。并不是每个例子都像汇率这样简单。你不能总是将共享数据封装在微服务中,然后就此收工。例如,不能用封装的功能解决的一个常见用例是报告。任何业务应用都需要一定级别的报告。并且报告通常跨越多个模型、有限的上下文和功能。是否应该允许面向报告的微服务与其他微服务共享表?显而易见的答案是否定的,因为这将立即在整个系统中产生严重的服务紧耦合,并且至少会破坏(如果不是完全扼杀)独立部署。
让我们看看在复杂的用例中,您可以使用什么技术来避免数据共享。第一个是 event sourcing,这是一种强大的数据建模方法,可以帮助您避免微服务中的数据共享,即使是在非常复杂的情况下。第二,相关的方法是 CQRS——命令查询责任分离。
活动采购
回想一下,有一些根深蒂固的软件工程习惯极大地影响了人们通常对待系统工程的方式。这些习惯中最普遍的一个是结构化数据建模。对于开发人员来说,将模型描述为交互逻辑实体的集合,然后将这些逻辑实体映射到存储数据的物理表已经变得非常自然。最近,人们开始使用 NoSQL 和对象存储,这使他们稍微远离了关系世界,但本质上这种方法仍然是相同的:你设计结构化的实体来模拟你周围的对象,然后将对象的状态“保存”在某种数据库存储中。无论存储发生在表的行和列中,序列化为 JSON 字符串,还是对象图,您仍然在执行基于 CRUD 的建模。但这不是模拟世界的唯一方式。您可以存储导致世界当前状态的事件,而不是存储模拟世界状态的结构。这种建模方法被称为事件源。
公平地说,对于大多数习惯于结构化数据建模的软件开发人员来说,事件源最初听起来会很陌生,甚至可能有些怪异。
但真的不是。首先,事件源不是一些尖端的、未经测试的理论,这些理论是为了解决微服务中的问题而虚构出来的。独立于任何微服务架构协会,事件源已经在金融行业获得了巨大的成功。
此外,事件来源的根源和灵感远远超出了微服务、互联网本身,甚至计算机,一直追溯到财务会计和包含交易列表的纸和笔分类账,而不仅仅是余额的最终值(“状态”)。想想你的银行账户:你的支票账户和储蓄账户都有余额,但这些都不是银行存储在数据库中的头等值。账户余额总是一个导数值;这是一个函数。
更确切地说,余额是从你开户那天起所有交易的总和。
要质疑你当前的余额,你的银行不会去错误,这是非常具体和原始的系统。相反,他们会为您打印出所有相关的交易(或指引您到网上银行,在那里您可以自己操作),并让您验证交易的结果确实应该等于显示的余额值。如果您发现任何交易有错误,银行将发布“补偿交易”来修复错误。这是事件采购的另一个重要属性:就像生活中一样,我们永远无法回到过去并改变过去。我们只能在当下做一些事情来弥补过去的错误。在事件源中,数据是不可变的——我们总是发出新的命令/事件来补偿,而不是像在 CRUD 风格中那样更新实体的状态。
当向开发人员介绍事件源时,最关心的通常是性能。如果任何状态值是事件的函数,我们可以假设每次访问该值都需要从源事件重新计算当前状态。显然,这将是非常缓慢的,通常是不可接受的。幸运的是,在事件源中,我们可以通过使用所谓的滚动快照(在给定时间点实体状态的投影)来避免这种昂贵的操作。根据事件源实现的不同,通常会在不同的时间点对中间值进行快照。例如,您可以预先计算每个月最后一天的银行账户余额,这样,如果您在 2021 年 1 月 15 日需要余额,您在 2020 年 12 月 31 日就已经有了,并且只需要计算两周的预测,而不是银行账户的整个寿命。如何实现滚动快照和预测的细节可能取决于应用的上下文。
尽管有其会计根源,事件源不仅仅与财务用例相关。本章的其余部分使用了一个你能想象到的远离银行和会计的业务场景——货物的装运和交付。
作为一家包裹递送公司,运输公司需要接受包裹,通过各种分拣仓库(路线上的跳跃点)发送包裹,并最终将它们递送到目的地。
图 3-1 显示了以结构化方式执行的该系统的代表性数据模型。
图 3-1
使用“当前状态”方法的航运公司的数据模型
相应的基于事件的模型如图 3-2 所示。
图 3-2
基于事件源的航运公司数据模型流程
正如您所看到的,结构化模型努力只保存系统的当前状态,而事件源方法保存单个的“事实”在事件源中,状态是发生的所有相关事实的函数。这不仅为您提供了完全的可审计性(正如您打电话给银行对余额提出异议时所展示的那样),您还可以构建对过去任何时间的状态预测,而不仅仅是“现在”。你想知道星期三所有的包裹在哪里吗?活动采购没有问题!用结构化模型回答这个问题会更加困难,因为它需要特殊的编码。
如果你喜欢像我们一样注意看似不相关的事物中的模式,我们建议你再看一看这两个图表。您可能会注意到,结构模型中的每个实体都是一片“雪花”(即,它在属性和关系方面具有独特的“形状”,并且被精心制作以表示不同的现实生活概念)。
相比之下,事件存储中的事件从外部看起来都是一样的。这和另一个与微服务密切相关的技术:容器是非常相似的观点。实际上,对于容器主机(例如,Docker 主机),所有容器看起来都相似——主机不“关心”容器内是什么,它知道如何独立于容器的内容来管理容器的生命周期。相比之下,定制安装的企业应用具有主机必须确保存在的各种特殊的“形状”和环境依赖性(例如,应用期望的共享库)。
“对形状和内容漠不关心”的方法似乎是现代技术的一种趋势,我们可以在 SQL 和 NoSQL 存储中看到相同的模式。它很容易让人想起,在多种环境下出现的趋势,是我们之前在多学科(例如,项目管理、产品开发、运营和架构)中查看不同的现代方法时注意到的“批量缩减”趋势。我们喜欢这一点——当相同的模式在多个地方出现时,我们可以利用我们对该模式的理解来识别或预测“下一件大事”
但是让我们回到微服务。您尝试了一种称为事件源的数据建模技术,并注意到了它相对于传统的结构化建模的一些优势,但是它如何帮助您解决微服务架构的数据隔离和封装挑战呢?事实证明,您还需要一个设计模式,CQRS,来补充事件源,并且您将朝着能够使用数据持久性模型为微服务设计有效的数据存储的方向前进,该模型可以避免甚至非常小的微服务规模的数据共享。
航运公司系统模型
如前所述,微服务系统设计的良好开端是识别系统中的有界上下文。图 3-3 显示了这个问题空间中关键有界上下文的上下文图。
图 3-3
航运公司微服务架构的高级上下文图
图中箭头和数字所示的三种上下文以及上下文之间的一些数据流的功能是什么?它们如下:
-
客户管理创建、编辑和启用/禁用客户帐户,并可以向任何感兴趣的上下文提供客户的表示。
-
货件管理负责包裹的整个生命周期,从卸货到最终交付。当包裹沿着递送路线通过分拣和转发设施时,它发出事件。
-
货件跟踪是一个报告应用,允许最终用户在他们的移动设备上跟踪他们的货件。
如果您要使用传统的、结构化的、面向 CRUD 的模型来实现这个应用的数据模型,您会立即遇到数据共享和紧耦合的问题。实际上,请注意,装运管理和装运跟踪上下文必须查询相同的表,至少是包含沿途中转的表。然而,利用事件源,装运管理有界上下文(及其相应的微服务)可以改为记录事件/命令,并为其他上下文发出事件通知,这些其他上下文将建立它们自己的数据索引(投影),而从不需要直接访问装运管理微服务拥有和管理的任何数据。
这个过程的正式方法用一个叫做 CQRS 的模式来描述。
CQRS(消歧义)
命令查询责任分离是一种设计模式,它规定您可以(有时应该)将数据更新和数据查询功能分离到不同的模型中。它的祖先可以追溯到一个叫做命令-查询分离的原则,CQRS 将这个概念向前推进了一大步,指导你使用完全不同的模型进行更新和查询。这一看似简单的陈述往往足以扭转乾坤,尤其是在本章前面提到的以报告为中心的微服务的复杂情况下。
由于报告通常需要汇总和对比大型系统不同部分生成的数据,因此它们通常需要跨越多个子系统和有限的上下文,并且几乎总是需要访问来自多个上下文的数据。但是,只有当您假设任何实体都有一个模型时,才会出现这种情况,在这个模型中,您既可以查询实体,也可以更新实体。如果使用 CQRS,就不需要跨多个上下文访问数据(以及相关的问题)。通过 CQRS,运输管理微服务可以“拥有”和封装任何与包裹交付相关的更新,只需通知其他上下文有关事件的发生。通过订阅这些事件的通知,运输跟踪等报告服务可以构建完全独立的查询优化模型,而不需要与任何其他服务共享。
正如您在图 3-4 中看到的,由于 CQRS,您能够分离装运管理和跟踪微服务的数据模型。事实上,航运管理甚至不需要知道跟踪微服务的存在,跟踪微服务唯一依赖的是一个事件流来构建其查询索引。在运行时,跟踪微服务只查询自己的索引。此外,跟踪微服务可以包括来自使用相同流的其他微服务的事件和命令数据,保持其独立性和松散耦合。
图 3-4
基于命令-查询责任分离(CQRS)的航运公司数据流程模型
使用事件源和 CQRS 的最大好处是,它们允许你设计非常细粒度的、松散耦合的组件。对于有界上下文,边界必须与业务能力和子域边界保持一致。借助事件源,您可以创建非常小的微服务,它们只管理一种类型的事件或运行一个报告。有针对性地使用事件源和 CQRS 可以将您带到微服务架构中自治粒度的下一个级别。因此,它们在建筑风格中起着至关重要的作用。
不要过度使用事件源和 CQRS。您应该只在必要时使用事件源和 CQRS,因为它们会使您的实现变得复杂。事件源和 CQRS 并不是你整个系统的“架构”,而是一个强大的工具集,可以少用。在许多用例中,传统的、基于 CRUD 的模型要简单得多,应该是首选的。
分布式事务和传奇
共享数据模型并不是唯一可以在微服务之间引入紧密耦合的用例。另一个重要的威胁是工作流。许多现实生活中的过程不能用单一的原子操作来表示,因为它们是一系列的步骤。当您处理这样的工作流时,只有当所有步骤都可以执行时,结果才有意义。换句话说,如果序列中的任何一步失败,相关系统的结果状态将变得无效。您可能在 RDBMS 系统中发现了这个问题,在 RDBMS 系统中,这样的过程被称为“事务”然而,数据库事务是本地的,包含在单个数据库的范围内,其中它们的实现主要依赖于共享状态的使用(即,您将锁放在参与事务的行和表上,以保证数据一致性)。一旦事务完全执行,您就可以移除锁,或者如果事务步骤中的任何一步失败,您可以回滚已经尝试过的步骤。
对于分布式工作流和无共享环境(微服务架构也是如此),您不能使用具有数据锁和 ACID 合规性的传统事务实现,因为此类事务需要共享数据和本地执行。相反,许多团队使用的有效方法被称为“sagas”。Sagas 是由埃克托·加西亚-莫利纳和肯尼斯·塞勒姆为长期分布式事务设计的,并于 1987 年在他们在普林斯顿大学工作期间推出(是的,远在微服务甚至网络之前)。
Sagas 非常强大,因为它们允许在分布式、松散耦合的环境中运行类似事务的可逆工作流,而无需对复杂系统的每个组件或整个系统本身的可靠性做出任何假设。这里的折衷是,sagas 不能总是回滚到事务尝试之前系统的确切初始状态。但是你可以尽最大努力通过补偿使系统达到与初始状态一致的状态。
在 sagas 中,工作流中的每一步都执行其工作部分,在名为“路由单”的消息中注册对“补偿事务”的回调,并将更新后的消息传递到活动链。如果下游的任何步骤失败,该步骤会查看传送名单,并调用最近步骤的补偿事务,传回传送名单。前面的步骤做同样的事情,调用它的前一个补偿事务,以此类推,直到所有已经执行的事务都得到补偿。例如:假设一位客户通过运输公司的保险递送邮寄了一张 100 美元的预付银行本票。当快递员出现在目的地时,他们发现地址是错误的,居民不会接受包裹。
因此,运输公司无法完成交易。由于包裹已经投保,因此运输公司有责任“回滚”交易,并将款项退还给寄件人。对于符合 ACID 的事务,运输公司应该将正好 100 美元的支票返还给原始发送者,将系统状态恢复到它的初始值。不幸的是,在回来的路上,包裹丢失了。自从船运公司。无法再“回滚”交易,他们决定通过将 100 美元存入客户的账户来补偿保险价值。因为这是一家长期活跃的船运公司。顾客和一个理性的人,他们不在乎哪 100 美元被退回给他们。系统没有返回到它确切的初始状态,但是补偿事务将环境带回到一致的状态。这就是传奇故事的基本运作方式。
由于其高度容错的分布式特性,当微服务架构中需要跨微服务边界的事务时,sagas 非常适合于取代传统事务。如果你想了解更多关于传奇的知识,并看到实现一个非常有表现力的例子的工作代码,请参考链接 https://docs.microsoft.com/en-us/azure/architecture/reference-architectures/saga/saga
异步消息传递和微服务
异步消息传递在保持微服务架构中的松散耦合方面起着重要的作用。您可能已经注意到,在本章前面的一个例子中,我们使用了一个消息代理,以异步方式将事件通知从我们的装运管理微服务传递到装运跟踪微服务。也就是说,让微服务直接与消息代理(如 RabbitMQ 等)交互。)很少是个好主意。如果两个微服务通过消息队列通道直接通信,那么它们共享一个数据空间(通道),您已经知道这不是一个好主意。相反,您可以做的是将消息传递封装在一个独立的微服务之后,该微服务可以以松散耦合的方式向所有感兴趣的微服务提供消息传递功能。
在微服务架构的上下文中,您最感兴趣的消息传递工作流是一个简单的发布/订阅工作流。如何用标准的方式表达成 HTTP API/微服务?我们建议将这样的工作流建立在现有标准的基础上,比如 PubSubHubbub。公平地说,PubSubHubbub 不是为 API 或超媒体 API 创建的,而是为博客环境中的 RSS 和 Atom 提要创建的。也就是说,您可以相对较好地调整它,以服务于支持超媒体 API 的工作流。为此,您需要实现如图 3-5 所示的流程。
图 3-5
用发布-子-中心-Bub 启发的流实现异步消息传递
您还需要标准化一些超媒体启示:
这是指启用注册以通知上下文更新的中心:
rel="hub"
这给出了链接上下文的 pingback 资源的地址:
rel="pingback"
当被包括在事件的资源表示中时,"sub"
(订阅)链接关系可以标识表示订阅链接上下文中的发布/订阅事件类型资源的能力的目标资源:
rel="sub"
当被包括在事件的资源表示中时,"unsub"
(预订取消)链接关系可以标识目标资源,该目标资源表示从链接上下文中的发布/订阅事件类型资源取消预订的能力。
rel="unsub"
这是可订阅事件的资源表示:
rel="event"
这是表示订阅事件列表的集合资源的链接:
rel="events"
处理依赖性
与独立部署能力相关的另一个重要主题是嵌入依赖关系。想象一下,航运公司的货币汇率微服务正受到来自其他微服务的用户查询和请求的打击。如果您将微服务托管在公共云中,而不是贵公司数据中心的昂贵服务器上,成本会低得多。但是,如果它将数据存储在与所有其他微服务相同的 SQL 或 NoSQL 数据库系统中,那么将微服务移动到另一台主机似乎是不可能的。
注意,数据表不是共享的,只是数据库管理系统的安装。似乎合乎逻辑的结论是,即使安装了数据存储系统,也不能共享任何微服务。有些人可能会认为,微服务需要“嵌入”它可能需要的每一个依赖项,这样微服务就可以随时随地部署,而无需与系统的其他部分进行任何协调。
完全依赖嵌入的严格要求可能是一个很大的问题,因为几十年来,我们已经设计了具有集中数据存储的架构,如图 3-6 所示。
图 3-6
使用集中依赖池的组件
集中式数据存储在操作上很方便:它允许专门的团队(DBA、sysadmins)维护和微调这些复杂的系统,使开发人员看不到复杂性。
相比之下,微服务倾向于嵌入所有依赖关系,以实现独立部署。在这样的场景中,每个微服务管理并嵌入它的数据库、键值存储、搜索索引、队列等等。那么移动这个微服务到任何地方就变得微不足道了。这种部署将如图 3-7 所示。
图 3-7
使用完全嵌入、隔离依赖关系的组件
大规模嵌入(数据存储)依赖关系的假设表面上看起来很美,但实际上,除了最简单的用例之外,这对其他所有用例来说都是极其浪费的。很明显,你将很难在你开发的每一个微服务中嵌入整个 Cassandra、Oracle 或 Elasticsearch 集群。尤其是如果你已经在微服务之旅中走得很远,并且可能有数百个微服务。这是不可行的。也没有必要。
微服务不必携带每一个依赖项(如数据存储系统),就可以在数据中心之间自由移动。
在他以前的工作中,我们中的一个(伊拉克利)经常出差。他已经获得了有效完成任务的重要技巧——这些技巧在他以前作为一个随意旅行者的生活中是完全不重要的。正如任何经常旅行的人会告诉你的那样,对于流动性来说,最重要的规则是保持你的行李轻便。你不必把你可能需要的所有东西都打包。例如,没有人会在出差时带上淋浴喷头和毛巾:你知道你会在酒店里找到它们。如果你知道目的地酒店有便利店,而且你的雇主会支付杂费,你甚至不用打包大多数洗漱用品。伊拉克利知道他可以指望什么是“现场”可用的,以及他需要总是带着什么。而且,为了轻装上阵,他学会了限制自己对许多东西的“依赖”,这些东西并不是他日常打包工作的一部分。
同样,微服务移动性的诀窍不是打包所有东西,而是确保部署目的地在每个可能部署微服务的目的地以可用和可自动发现的形式提供重资产,如数据库集群。应该编写微服务,以便他们可以在部署时快速发现这些资产,并开始使用它们。
要明确的是:微服务之间的数据共享仍然是终极大忌。共享数据会在微服务之间产生紧密耦合,这会扼杀它们的移动性。然而,共享数据库集群安装是可以的,因为每个微服务只访问它的隔离的、命名空间的部分。
语用迁移
图 3-8 展示了一个适当的、复杂的微服务部署在实践中应该是什么样子。
图 3-8
实用方法:组件使用集中的依赖关系池,不共享数据空间
如果您决定将微服务 1 迁移到另一个数据中心,它会期望新的数据中心也有一个兼容版本的正常工作的 Cassandra 集群(在前面的比喻中,酒店提供了您可以使用的毛巾),但它会找到一种方法来移动它的数据片,并且不依赖于目的地任何其他微服务的存在或状态,如图 3-9 所示。
图 3-9
实用方法:微服务 1 迁移到不同的数据中心无需数据共享
微服务不需要“旅行”时负重,打包所有可能需要的东西。在复杂的情况下,对目标环境有一些合理的期望是好的,尤其是在涉及复杂的数据存储能力时。
当决定在一个环境中嵌入依赖关系还是“期望”特征时,你需要问的最重要的问题是,这个决定会增加还是减少移动性?目标是最大化微服务的部署移动性,这在不同的上下文中可能意味着不同的事情。
本章解释了“批量缩减”技术在系统工程中的首要作用,即在规模上同时实现速度和安全是期望的结果。
它还表明,在某些粒度级别,架构师可能需要额外的模式,在领域驱动设计的模式之上,例如事件源、CQRS 和 Sagas。它展示了这些模式如何从根本上改变您对模型设计的看法,以及这如何导致更松散耦合的服务,服务被分割以提供独特的功能。
最后但并非最不重要的一点是,微服务是 API,因此除了代码、实现和部署方面的考虑之外,本章的很大一部分致力于解释构成微服务的 API 的独特接口设计需求。
系统设计和操作
采用微服务架构的好处不一定是免费的,它们可以将复杂性转化为操作。采用微服务架构的团队需要具备一定程度的基础设施自动化和运营成熟度才能取得成功。让我们看看这在实践中意味着什么。
本章回顾了微服务运营的关键概念,如独立部署、容器在经济高效的部署中的作用,特别是 Docker 在微服务、服务发现、安全、路由、转换和编排中的作用。总之,这些主题将为您理解、设计和执行微服务架构的运营需求奠定坚实的基础。
独立可部署性
微服务架构风格的核心原则之一是独立可部署性原则——也就是说,每个微服务必须完全独立于任何其他微服务进行部署。架构风格的一些最重要的好处依赖于忠实地坚持这一原则。
独立部署允许您执行选择性或按需扩展;如果系统的一部分(例如,单个微服务)经历高负载,您可以将该微服务重新部署或移动到具有更多资源的环境中,而不必为整个(通常是大型)企业系统扩展硬件容量。对于许多组织来说,选择性扩展的运营能力可以节省大量资金并提供必要的灵活性。
作为一家包裹递送公司,运输公司需要接受包裹,通过各种分拣仓库(路线上的跳跃点)发送包裹,并最终将它们递送到目的地。
让我们考虑一个航运公司选择性扩展的例子。该公司存储和操作敏感的客户信息,包括其客户的人口统计和财务数据。运输公司收集信用卡信息,因此受到政府严格监管的审计要求。
出于安全原因,运输公司将实施的敏感部分部署在内部数据中心,但出于成本和可扩展性原因,其 CTO 仍希望尽可能利用“云计算”。
在内部扩展硬件资源的成本非常高,您必须根据预期的使用情况而不是实际使用情况来购买昂贵的硬件。与此同时,应用中承受负载并需要扩展的部分可能不包含任何敏感的客户或财务数据。它可以是像一个返回美国各州列表的 API 或一个能够转换各种货币汇率的 API 这样琐碎的事情。运输公司的首席架构师相信,他们的安全团队将轻松地允许将这种安全的微服务部署到公共/私有云中,在那里扩展资源要便宜得多。问题是,在这种情况下,他们能否将应用的一部分部署到单独的数据中心,即基于云的数据中心?大多数企业系统(通常是整体式的)的架构方式是,独立地部署应用的选择性部分要么非常困难,要么实际上不可能。相比之下,微服务强调独立部署到核心原则级别的要求,从而为您提供急需的操作灵活性。
除了节省运营成本和灵活性之外,独立部署的另一个重要优势是组织优势。两个不同的团队将负责开发独立的微服务(例如,客户管理和运输管理)。如果负责客户管理微服务的第一个团队需要进行更改并重新发布,但是客户管理不能独立于装运管理微服务发布,那么您现在需要与拥有装运管理的团队协调客户管理的发布。这种协调可能是昂贵和复杂的,因为后一个团队可能与负责客户管理的团队有完全不同的优先级。通常这种协调的必要性会延迟发布。现在想象一下,你可能拥有由几十个团队维护的数百个微服务,而不是少数几个。对于这样的组织来说,发布协调的开销可能是毁灭性的,会导致产品延迟发货,或者有时在发货时就过时了。
您需要更多服务器吗?
为了确保独立部署,您需要使用一个自治的、隔离的环境单元来开发、打包和发布每个微服务。但是“自主的、孤立的环境单元”在这个上下文中是什么意思呢?这种环境单位的例子有哪些?让我们假设您正在开发一个服务应用。乍一看,类似于服务应用文件的东西似乎是封装和隔离的合适单元。
毕竟,这就是这些打包格式的设计目的——在应用服务器的上下文中,分发可执行代码和相关资源的集合,共同形成一个独立的应用。
轻量级打包解决方案,如 NPM 模块(用于节点)或 PIP 包(用于 Python),不能提供微服务所需的足够的模块化和隔离级别。服务部署文件仍然共享系统资源,如磁盘、内存、共享库、操作系统等等。他们可能还希望环境中有特定版本的操作系统库。任何有经验的 sysadmin 或 DevOps 工程师都知道,一个应用的环境预期可能与另一个截然不同,如果您需要在同一台服务器上安装这两个应用,就会导致版本和依赖性冲突。采用微服务架构的核心动机之一是避免复杂的协调和冲突解决的需要,因此不能避免这种相互依赖的打包解决方案不适合微服务。您需要更高级别的组件隔离来保证独立部署。
如果您在每台物理服务器或每台虚拟机上部署一个微服务会怎么样?这当然符合微服务对隔离的高要求,但这种解决方案的财务成本是多少?对于已经使用微服务架构好几年的公司来说,开发和维护数百个微服务并不罕见。假设你在一家成熟的微服务公司工作,大约有 500 个微服务。为了以可靠、冗余的方式部署这些微服务,每个微服务至少需要三台服务器/虚拟机,因此仅生产系统就需要 1,500 台服务器。通常,大多数公司运行不止一个环境(QA、stage、integration 等。),这迅速增加了所需服务器的数量。
坏消息来了:成千上万的服务器成本很高。即使您使用虚拟机而不是物理服务器,即使在“最便宜”的云托管环境中,利用数千台服务器进行设置的预算也会非常高,可能高于大多数公司能够负担或愿意花费的费用。然后是开发环境的重要问题。大多数开发人员喜欢在他们的工作站上有一个工作的、完整的(如果是按比例缩小的)生产环境模型。
在一台笔记本电脑或台式机上,您实际上可以启动多少个虚拟机?最多五个或十个?不是几百或几千。那么,这种快速、简单的微服务托管成本计算意味着什么呢?从运营的角度来看,微服务架构是不是根本不现实、不可实现?对大多数公司来说,这可能是几年前的事了。这就是为什么你会看到更大的公司,如亚马逊和网飞,成为这种建筑风格的先驱——他们是少数几个能够证明其成本的公司。
然而,近年来情况发生了显著变化。
微服务架构是其时代的产物
我们经常被问到——微服务架构和面向服务架构之间的根本区别是什么,尤其是考虑到这么多的底层原则看起来都很相似?我们认为这两种建筑风格是各自时代的产物,大约相差十年。在这 10 年中,该行业在自动化基础设施运营的有效方式方面已经变得更加熟练。微服务架构正在利用 DevOps 和连续交付方面最先进的成就,使架构风格的优势可以为更广泛的受众所用,并且具有成本效益,而不仅仅是像亚马逊或网飞这样的少数大型早期采用者。
微服务架构在财务和运营上可行的原因与容器有很大关系。
发布和运输微服务通常使用的部署单元是容器。如果您以前从未使用过容器,您可以将容器想象成一个极其轻量级的“虚拟机”该技术与传统虚拟机的技术有很大不同。它基于 Linux 内核扩展(LXC ),允许在共享操作系统内核的单个 Linux 主机上运行许多隔离的 Linux 环境(容器),这意味着您可以在单个服务器或虚拟机上运行数百个容器,同时仍然可以实现与运行独立服务器相当的环境隔离和自治,因此完全可以满足我们的微服务需求。
容器将不仅限于 Linux 现在有来自 Microsoft Windows 的容器要部署。容器提供了一种几乎零开销的现代隔离解决方案。虽然您不能在一台主机上运行多个传统虚拟机,但在一台主机上运行数百个容器是完全可能的。目前部署最广泛的容器工具集是 Docker,所以实际上 Docker 和容器已经有点同义了。实际上,还有其他新兴的容器解决方案,它们在未来可能会更加突出。
坞站和微服务
本节讨论 Docker,因为它是当今生产中部署最广泛的容器工具集。然而,如上所述,替代容器解决方案存在于生产准备的不同阶段。因此,本节中的大多数内容应该被理解为与容器相关,而不仅仅是 Docker。
在 2016 年初,如果不利用 Docker 容器,大多数微服务部署几乎是不可想象的。我们已经讨论了其中的一些实际原因。也就是说,你不应该认为 Docker 或 containers 是专为微服务架构设计的工具。
一般来说,容器,尤其是 Docker,肯定存在于微服务架构之外。事实上,如果你看一下当前的系统运营情况,你会发现使用容器的个人和公司的数量比实施微服务架构的多很多倍。Docker 本身比微服务架构更常见。
容器不是为微服务创建的。它们是对一个实际需求的有力回应:技术团队需要一个强大的工具集,用于复杂应用的通用和可预测的部署。事实上,通过将应用打包为 Docker 容器(假定以正确的版本号预捆绑所有必需的依赖项),您可以让其他人可靠地将其部署到任何云或本地托管设施,而无需担心目标环境和兼容性。
剩下的惟一部署需求是,在大多数情况下,服务器应该支持 Docker。相比之下,如果您只是将您的应用作为可执行文件提供给某人,而没有预捆绑的环境依赖,您将会让他们承受大量的依赖痛苦。或者,如果您想将相同的软件打包成一个虚拟机映像,您将不得不为几个主要平台创建多个虚拟机映像,因为目前没有一个单一的主流虚拟机标准被主要参与者采用。
但是兼容性不是唯一的胜利;当您考虑容器与虚拟机映像时,还有另一个同样重要(如果不是更重要的话)的好处。Linux 容器使用分层的文件系统架构,称为联合挂载 。这提供了传统虚拟机架构所不具备的强大可扩展性和可重用性。有了容器,从“基本映像”扩展您的映像就变得很简单了如果基础映像更新,您的容器将在下次重新构建时继承这些更改。这种分层的、可继承的构建过程促进了协作开发,增加了许多团队的努力。集中式注册表、发现服务和面向社区的平台(如 Docker Hub 和 GitHub)进一步促进了该领域的快速采用和教育。
事实上,我们可以很容易地扭转局面,声称是 Docker 将推动微服务的采用,而不是相反。这种说法的原因之一是,Docker 非常强调运输容器的“UNIX 哲学”,即“做一件事,并把它做好。”事实上,这个核心原则在 Docker 文档本身中有突出的描述:
每个容器只运行一个过程。几乎在所有情况下,您都应该只在一个容器中运行一个进程。将应用解耦到多个容器中使得水平伸缩和重用容器变得更加容易。
—Docker 文档
以这些原则为核心,Docker 哲学比传统的大型整体架构更接近微服务架构。当你追求“做一件事”时,将你整个庞大的企业应用封装成一个 Docker 容器是没有意义的。您肯定希望首先将应用模块化为松散耦合的组件,这些组件通过标准网络协议进行通信,这就是微服务架构所提供的。因此,如果您的目标是将大型复杂的应用容器化,那么您可能需要在复杂的应用中进行一定程度的微服务设计。
从我们的角度来看,Docker 容器和微服务架构是通向持续交付和运营效率这一共同目标的两端。如果达到了预期的目标,你可以从任何一端开始。
服务发现的作用
如果您使用 Docker 容器来打包和部署您的微服务,您可以使用一个简单的 Docker Compose 配置来将多个微服务(及其容器)编排到一个一致的应用中。只要您在单个主机(服务器)上,这种配置将允许多个微服务“发现”并相互通信。这种方法通常用于本地开发和快速原型开发。
但是在生产环境中,事情会变得非常复杂。出于可靠性和冗余性的需要,在生产中只使用一台 Docker 主机是不太可能的。相反,您可能会部署至少三个或更多 Docker 主机,每个主机上有几个容器。
此外,如果您的服务获得显著不同的负载级别,您可能会决定不在所有主机上部署所有服务,而是最终在选定数量的主机上部署高负载服务(假设十台),而低负载服务可能只部署在三台服务器上,而且不一定是同一台服务器。此外,出于安全和业务方面的原因,您可能需要在某些主机上部署某些服务,而在其他主机上部署其他服务。
一般来说,如何在可用的主机上分发服务将取决于您的业务和技术需求,并且很可能会随着时间的推移而改变。主机只是服务器,不能保证永远存在。
微服务容器的每个实例都有不同的编号。在本例中,所有四台主机上都部署了微服务 1,但微服务 2 仅部署在主机 1–3 上。请记住,部署拓扑可能会根据负载、业务规则、哪个主机可用以及您的微服务实例是否突然崩溃而随时发生变化。
请注意,由于许多服务通常部署在同一台主机上,因此您不能仅通过 IP 地址来寻址微服务。通常有太多的微服务,这些微服务的实例可以随时上升和下降。如果您为每个微服务分配一个 IP,那么 IP 地址的分配将变得过于复杂。相反,您可以为每台主机(服务器)分配一个 IP,微服务将通过以下组合得到充分解决:
-
(主机的)IP 地址
-
服务在主机上可用的端口号
我们已经注意到微服务可用的 IPs 是不断变化的,但是端口呢?您可能会假设您可以为单个微服务分配固定端口,比如说,“我们的帐户管理微服务总是在端口 5555 上启动。”但这不是一个好主意。许多不同的团队将需要在共享的主机池中独立启动微服务。如果您假设特定的微服务总是在主机的特定端口上启动,您将需要高级别的跨团队协调,以确保多个团队不会意外地占用同一个端口。但是使用微服务架构的主要动机之一是消除昂贵的跨团队协作的需要。总的来说,这种协调是站不住脚的。这也是不必要的,因为有更好的方法来实现同样的目标。
这就是服务发现进入微服务场景的地方。您需要某种系统,该系统将始终关注所有服务,并跟踪在任何给定时间在哪个 IP/端口组合上部署了哪个服务,以便可以相应地无缝路由微服务的客户端。
如前几章所述,在服务发现的开源领域有几个成熟的解决方案。一方面是 CoreOs 的 etcd 和 HashiCorp 的 Consul 等工具。它们是为架构师提供高度控制和可见性的“低级”工具。另一方面是提供“容器调度”功能以及服务发现的工具。
谷歌的 Kubernetes 可能是这一类别中最知名的,Docker Swarm 是另一个更新的玩家。使用容器调度解决方案,您可以获得高度的自动化和抽象化。在这种情况下,不需要决定在哪些服务器上启动哪个容器,您只需告诉系统有多少主机池的资源应该专用于某项服务,Kubernetes 或 Swarm 会根据这些标准负责平衡/重新平衡主机上的容器。利用容器的另一项重要技术是中间层。
Mesosphere 甚至比 Kubernetes 或 Swarm 更抽象,目前作为“数据中心操作系统”销售,允许更高程度的自动化,而不必担心部署的许多节点,并操作整个服务器集群。
在考虑服务发现时,没有“更好”的工具。作为一名架构师,您需要决定您想要从这些工具中获得多少自动化“魔力”,以及您需要为自己保留多少控制权。即使在同一个企业应用中,您很可能会发现 Kubernetes 非常适合某一批微服务,而架构师可能会认为,如果使用类似 Consul 的东西直接管理,另一类微服务可能会部署得更好。
对 API 网关的需求
在几乎所有微服务实现中观察到的一个常见模式是团队使用 API 网关保护由微服务提供的 API 端点。现代 API 网关提供了微服务所需的一个额外的关键特性:转换和编排。在大多数成熟的实现中,API 网关与服务发现工具合作来路由来自微服务客户端的请求。
安全
微服务架构是一种自由度非常高的架构。或者换句话说,与单片应用相比,移动部件要多得多。如前所述,在为复杂的企业应用实现架构的成熟微服务组织中,部署数百个微服务是很常见的。当有许多移动部件时,事情可能会变得非常糟糕。你当然需要一些法律和秩序来维持一切的控制和安全。这就是为什么在几乎所有的微服务实现中,您会看到由各种微服务提供的 API 端点使用一个有能力的 API 网关来保护。
微服务提供的 API 可以相互调用,可以由“前端”调用,即面向公众的 API,或者可以由 API 客户端(如移动应用、web 应用和合作伙伴系统)直接调用。根据微服务本身、组织的业务需求以及行业、市场或应用环境,所有场景都是公平的。为了确保您永远不会危及整个系统的安全性,广泛推荐的方法是使用有能力的 API 网关来保护启用微服务的系统的“面向公众”的 API 端点的调用。
基于我们构建微服务系统和帮助各种组织做同样事情的经验,我们推荐一种更激进的方法,而不仅仅是保护“公共 API 端点”
“公共”和“私有”API 之间的区别最终往往是任意的。您有多确定您认为“仅限内部”的 API 永远不会被任何外部系统所需要?只要您尝试通过公共 web、从您自己的 Web 应用或从移动应用使用 API,就安全性而言,该端点就是“公共”的,需要受到保护。对于 Amazon 来说,最重要的是 Amazon Web Services:它们暴露了可能的最低级别的技术堆栈——硬件资源,如磁盘、CPU、网络等。,由他们的电子商务网站使用——供世界上任何人使用,他们从中赚取了数十亿美元。
那么,为什么你会认为你有一些 API 永远是“内部专用”的呢?有时,某些微服务被认为是“内部”的,并被排除在 API 网关提供的安全性之外,因为您认为外部客户端永远无法访问它们。这是危险的,因为随着时间的推移,假设可能会变得无效。
最好始终使用 API 网关来保护任何 API/微服务访问。在大多数情况下,在服务调用之间引入 API 网关的可忽略的开销是值得的。
转型和流程编排
如前所述,微服务通常被设计为提供单一功能。它们是拥抱 UNIX 哲学“做一件事,并把它做好”的网络版本。然而,任何 UNIX 开发人员都会告诉您,单一责任方法之所以有效,是因为 UNIX 通过通用的输入和输出管道,促进了其高度专门化的实用程序的高级编排。使用管道,您可以轻松地组合和链接 UNIX 实用程序,以解决涉及复杂流程工作流的重要问题。API 和微服务领域也迫切需要类似的解决方案。基本上,要使微服务有用,您需要一个像 UNIX 管道这样的编排框架,但是要适合 web APIs。
微服务由于其狭窄的专门化和典型的小规模,对于生产它们的团队来说是非常有用的部署单元。也就是说,它们可能不太方便消费,这取决于客户。网络是一个分布式系统。由于它的分布式本质,在网络上,所谓的“聊天”界面是被避免的。在这些接口中,您需要进行多次调用来获取单个任务所需的数据。这种对聊天式界面的厌恶在移动开发人员中尤其明显,因为他们经常必须处理不可靠、断断续续和缓慢的连接。比起 API 接口,移动开发人员更讨厌一些东西,API 接口迫使他们进行多次调用来检索他们认为是一条信息的东西。
让我们想象一下,在成功完成移动应用所需的 API 之后,Shipping Company 微服务架构背后的技术团队决定踏上开发“智能”库存管理系统的新征程。新系统的目的是正确分析通过运输公司的数百万次运输的匿名数据,将这种洞察力与运输货物的所有元数据相结合,确定消费者的行为模式,并利用人工和机器算法设计一个“推荐引擎”,能够向运输公司的“白金”客户建议最佳库存水平。如果一切正常,这些建议将能够帮助客户在管理产品库存方面实现无与伦比的效率,解决任何在线零售商的主要问题之一。
如果团队使用微服务架构构建这个系统,他们可能最终会为主要功能创建两个微服务:
-
建议微服务,它接收用户信息,并以包含建议的列表进行响应,即该客户通常运送的各种产品的建议库存水平。
-
产品元数据微服务,它接受一个产品类型的 ID,并检索关于它的各种有用的元数据。
从 API 发布者的角度来看,将关注点分离成专门的微服务是完全有意义的,或者你可以称之为服务器端团队。然而,对于正在实现最终用户界面的团队来说,调用前面的微服务只不过是一件令人头疼的事情。更有可能的是,移动团队正在用户屏幕上工作,他们试图显示几个即将到来的建议。假设页面大小是 20,那么一次 20 条建议。对于当前微服务的逐字设计,用户界面团队必须进行 21 次 HTTP 调用:一次检索推荐列表,然后一次检索每个推荐的细节,如产品名称、尺寸、大小、价格等等。
在这一点上,用户界面团队并不满意。他们想要一个单一的列表;而是被迫进行多次调用(臭名昭著的“N+1 查询”问题,在 API 中再次出现)。此外,对产品元数据微服务的调用返回了太多的信息(大负载问题),这对于慢速连接的移动设备来说是一个问题。其结果是非常重要的移动屏幕的渲染速度缓慢,导致用户体验不佳。
像刚才描述的这种情况太普遍了。事实上,它们甚至在微服务架构出现之前就已经存在了。例如,REST API 风格因“喋喋不休的接口”而饱受批评您不必以 RESTful 风格构建您的微服务 API,但是类似的问题仍然存在,因为我们决定微服务需要做“一件事”,这可能导致聊天。
幸运的是,由于 API 中的“聊天”问题并不新鲜,成熟的 API 网关完全可以处理这个问题。一个强大的 API 网关将允许您通过配置以声明方式创建 API 接口,这些接口可以编排后端微服务,并将它们的粒度“隐藏”在一个对开发人员更加友好的接口后面,并消除闲聊。在示例场景中,您可以快速地将 N+1 个调用聚合成一个 API 调用,并优化响应负载。这给了移动开发者他们所需要的:通过一个查询得到的推荐列表,以及他们所需要的元数据。API 网关将调用后端微服务。好的 API 网关还可以将对产品元数据微服务的 20 个调用并行化,使得聚合调用非常快速高效。
选择途径
本章已经提到,为了正确地发现微服务,您需要使用服务发现系统。Consul 和 etcd 等服务发现系统将监控您的微服务实例,并跟踪元数据,了解您的每个微服务在任何给定时间可用的 IP 和端口。然而,直接提供 IP/端口组合的元组来路由 API 客户端并不是一个合适的解决方案。一个合适的解决方案需要从客户端抽象出实现细节。API 客户端仍然期望以特定的 URI 检索 API,而不管其背后是否有微服务架构,也不管有多少服务器、Docker 容器或任何其他东西在为请求提供服务。
一些服务发现解决方案(例如 Consul 和使用 SkyDNS 的 etcd)提供了基于 DNS 的发现接口。这对于调试非常有用,但仍然不能满足生产需求,因为普通的 DNS 查询只查找域/IP 映射,而对于微服务,您需要具有 IP+端口组合的域映射。在 Consul 和 SkyDNS 中,您都可以使用 DNS 通过 RFC 2782 SRV 查询来查找 IP 和端口号,但是实际上没有 API 客户端期望或愿意在调用 API 之前发出 SRV 请求。
这不是常态。相反,你应该做的是让 API 网关隐藏从客户端应用路由到微服务的复杂性。API 网关可以与服务发现系统的 HTTP 或 DNS 接口对接,并且当请求与微服务相关联的外部 URI 时,将 API 客户端路由到正确的服务。您也可以使用负载均衡器或智能反向代理来实现相同的目标,但是由于您已经使用 API 网关来保护到微服务的路由,因此在网关上实现路由需求是很有意义的。
监控和警报
如前所述,虽然微服务架构带来了显著的优势,但它也是一个比整体式架构有更多移动部件的系统。因此,在实施微服务架构时,进行广泛的系统范围监控并避免级联故障变得非常重要。
提到的用于服务发现的工具也可以提供强大的监控和故障转移功能。我们以领事为例。Consul 不仅知道某个特定服务有多少活动容器,如果该数目为零,则标记该服务已损坏,而且它还允许您为任何服务部署定制的健康检查监视器。这可能非常有用。事实上,仅仅因为微服务的容器实例启动并运行并不总是意味着微服务本身是健康的。您可能希望检查微服务是否在特定端口或特定 URL 上响应,甚至可能检查健康 ping 是否返回预定的响应数据。
除了 Consul 代理查询服务的“拉”工作流之外,您还可以配置面向“推”的健康检查,其中微服务本身负责定期检查,即将预定的有效负载推送到 Consul。如果 Consul 没有收到这样的“签入”,服务的实例将被标记为“损坏”这种替代工作流对于必须按预定计划运行的预定服务非常有价值。通常很难验证计划的作业是否按预期运行,但是基于“推送”的运行状况检查工作流可以准确地满足您的需求。
这些功能强大的服务允许您建立复杂的事件通知电话树和/或通过电子邮件、短信通知您的技术团队,并通过他们的移动应用推送通知。
摘要
本章介绍了用于衍生微服务的各种设计原则。您还看到了正在使用的各种模式,并了解了 AWS 和网飞等其他公司如何创建强大的模式,您可以在微服务设计和架构中利用这些模式。
您还了解了一个用船运公司示例实现模式的实际例子。
下一章着眼于 Docker 和 Kubernetes 等技术组件,并解释如何构建这样的服务和处理健康监控。
附录
https://docs.microsoft.com/en-us/azure/architecture/reference-architectures/saga/saga
https://pubsubhubbub.appspot.com/
四、容器和 Azure Kubernetes 服务
介绍
到目前为止,您已经了解了评估微服务的成熟度和就绪性时的架构和组织考虑事项。您还了解了微服务使用的设计模式。本章解释了容器和 Azure Kubernetes 服务,它们构成了微服务的基础构件。
容器
容器构成了构建可伸缩的、平台无关的、隔离的托管和处理生态系统的基础构件。
当软件从一个计算环境转移到另一个计算环境时,从开发人员的机器转移到测试环境,从试运行环境转移到生产环境,可能从物理机转移到数据中心,再转移到私有或公共云中的虚拟机,容器是如何让软件可靠运行的问题的解决方案。
当支持的软件环境不相同时,问题就出现了。也许该软件是用 Python 2.7 测试的,现在它将在 Python 3 上运行。一些奇怪的行为发生了。挑战在于,您依赖于某个版本的 SSL 库的行为,但是安装了另一个版本。您在一个版本的 Linux 上运行您的测试,而生产是在 Red Hat 上进行的,可以观察到各种各样的行为变化。从一个环境转移到另一个环境是不可预测的,并且需要花费大量的精力来调整环境,而不是专注于实际的工作。
容器如何解决这个问题
容器是一个完整的运行时环境(即应用,加上运行它所需的所有依赖项、库、其他二进制文件和配置文件,都打包在一个包中)。通过容器化应用平台及其依赖项,操作系统分布和底层基础设施的差异被抽象出来。
容器化与虚拟化有何不同
虚拟化技术只不过是作为虚拟机安装的一个包,它包括整个操作系统和应用(见图 4-1 )。一台实际的物理服务器运行三台虚拟机,并在其上运行一个虚拟机管理程序和三个独立的操作系统。
图 4-1
虚拟机架构
另一方面,使用 Docker 运行三个容器化应用的服务器运行单个操作系统,每个容器与其他容器共享操作系统内核(见图 4-2 )。操作系统的共享部分是只读的,而每个容器都有自己的挂载(即访问容器的方式)用于写入。这意味着容器比虚拟机更轻量级,使用的资源也更少。
图 4-2
容器架构礼貌: docs。微软。com/en-us/virtual ization/windows container s/about/containers-vs-VM
容器化带来了以下好处:
-
隔离
-
紧密的
-
一致的
-
快的
-
简单的
-
可攀登的
-
轻便的
容器可以在各种设备和操作系统上运行,如图 4-3 所示。
图 4-3
容器无处不在
图 4-4 中的图表显示了传统部署是如何发展到容器的。
图 4-4
部署随时间的演变。io/docs/concepts/overview/what-is kubernetes/#时光倒流
有两种类型的容器可用——Linux 和 Windows——图像层如图 4-5 所示。
图 4-5
图像中的层
容器层如图 4-6 所示。
图 4-6
多层容器
使用 Docker
Docker 是一个开发、发布和运行应用的开放平台。Docker 使您能够将应用从基础设施中分离出来,这样您就可以快速交付软件。使用 Docker,您可以像管理应用一样管理基础设施。参见图 4-7 。
图 4-7
Docker 容器互动礼遇:docs . docker . com/get-started/overview/
下面列出了构建 docker 容器的开发工具:
-
VS 代码
-
推荐 Windows 使用:
-
Windows 终端
-
如果允许,Linux 的 Windows 子系统(WSL2)
-
软件包管理器,如
winget
或scoop
,如果允许的话(使在 Windows 上安装 CLI 工具更容易) -
您选择的首选 shell:PowerShell Core(pwsh)、GitBash、WSL2 Bash/ZSH 等等
-
-
CLI 工具:用于在 Kubernetes 服务上执行运行构建和运行 Docker 容器的命令。
-
饭桶
-
蓝色 CLI
-
库布特雷
-
定制
-
舵
-
Curl 或 Httpie
-
此外,你需要 Docker 桌面,如下所述。
在您的开发环境中安装 Docker 桌面
https://www.docker.com/products/docker-desktop
见。
首先,确保 Kubernetes 已启用,如图 4-8 所示。
图 4-8
Kubernetes 启用的设置
如果你正在使用 WSL2,不要忘记启用它来设置限制,如 https://docs.microsoft.com/en-us/windows/wsl/wsl-config#configure-global-options-with-wslconfig
中所解释的。您还需要将 Docker 集成到您的wsl2
发行版中(参见参考资料选项)。
现在让我们来看一个部署在 Docker 容器上的基本级别的“Hello World”程序。如果 Docker 镜像还没有下载到本地,Docker 会从 Docker Hub 获取镜像。
从终端运行以下命令:
docker run hello-world
Note
docker run = docker create + docker start (+ also docker attach)
hello-world
形象从何而来?是官方形象吗?
Hint
https://hub.docker.com/_/hello-world
见。
观察输出日志,从从公共注册表中提取图像开始。
现在您需要运行 Ubuntu 并与其 shell 环境交互:
docker run -it ubuntu bash
or
docker run -i -t ubuntu bash
在 Docker 容器中执行以下命令:
ls
通过键入exit
退出容器外壳。
花点时间去理解当与docker run
一起使用时-it
标志的作用:
`i` - keep STDIN open even if not attached
`t` - Allocate a pseudo-tty
一个容易记忆的方法是-it
表示 i 交互 t 终端。
要查看本地缓存的图像,请使用以下命令:
docker images
结果显示了在您的环境中本地缓存的图像。下次运行该图像时,它不会从注册表中取出。
探索 docker 运行命令
再次运行同一个 Ubuntu 映像,但这次稍加改动:
- 末尾不带
bash
运行。注意到它仍然像以前一样工作吗?这是因为 Ubuntu 映像的cmd
被默认设置为运行bash
。退出容器外壳。
docker run -it ubuntu
Note
如果你只是运行docker run ubuntu
,bash
会自动退出,因为它没有stdin
可以监听。稍后您将了解如何在 Docker 中使用EntryPoint
执行流程,以及 web 应用如何使用它。
- 现在用其他命令覆盖默认的
cmd
,比如ls
。运行以下命令并注意不同的结果:
docker run -it ubuntu ls
观察结果。这是怎么回事?您正在覆盖该图像的默认cmd
。https://docs.docker.com/engine/reference/run/#cmd-default-command-or-options
见。
运行 web 服务器
按如下方式运行nginx
网络服务器:
docker run -d -p 9000:80 nginx
# -p stands for publish (publish a container's port to the host)
# You will be able to see the webpage on localhost:9000 if you are running docker locally or in a linux vm.
-d
标志表示容器将在分离模式下运行,所以它不会等待通过stdin
的输入。
# See running containers
docker ps
现在,运行nginx
容器的另一个实例。只需使用不同的端口。
docker run -d -p 9001:80 nginx
docker ps # notice the new container from same image. Much like new objects from a class.
从终端查看网页内容
您可以使用 HTTP 客户端工具(如curl
或httpie
)从浏览器或终端查看网页:
curl localhost:9000
# or via httpie (for coloured output and more helpful info)
http localhost:9001
现在停止 nginx 容器:
# run `docker ps` to list the running containers.
docker stop <container-id>
or
docker stop <container_name_1> <container_name_2> # Note: it's container name not image name.
额外收获:寻找stop
、kill
和rm
命令之间的区别。
现在您可以看到所有容器,包括created
和exited
容器:
# `docker ps` only shows containers that are of status `Running`. To see all containers, use `-a` flag
docker ps -a
您总是可以通过发出start
命令来启动一个停止的容器。
通过在docker ps -a
上查找,找到您想要启动的容器。仅仅因为容器已经停止或退出,并不意味着它已经死了。
docker start <container_id or name>
清理流程
要删除已停止的容器,请使用以下命令:
docker rm <container_id/name>
要删除图像,请使用以下命令:
docker rmi image <image_id_1> <image_id_2>
使用docker system prune
命令清理悬空资源:
docker system prune
要清理所有资源,包括映像、容器、卷等,请使用以下命令:
docker system prune --all
# `y' when prompted
Important
与任何其他系统一样,请谨慎使用这些清理命令。不要强制删除仍被容器引用的图像。
快速阅读以下链接:
要检查您的环境是否已清理,请使用以下命令:
docker ps -a
docker images -a
下一节将介绍 Docker 基础知识。
文档文件
为了开始这个例子,创建一个名为Docker Directory
的目录。创建您的第一个 docker 文件并执行一个CMD (greeter:1.0)
:
-
从
docker
目录中,创建一个名为my_first_dockerfile
的子目录,并在其中创建一个 Dockerfile。设置应该如下所示,这样您就有了一个名为docker
的基本目录。您可以从终端使用
touch Dockerfile
,或者右键单击适当的文件夹并选择新建文件:
```bash
# from my_first_dockerfile directory
touch Dockerfile
您的设置应该如下所示:
1. 在 Dockerfile 文件中键入以下内容。(除非特别说明,否则避免复制和粘贴。)
├── my_exercise
├── docker
│ └── my_first_dockerfile
│ └── Dockerfile
└── kubernetes
1. 建立你的码头工人形象。确保终端指向 Dockerfile 所在的目录。
2. 构建一个名为`greeter`的映像,并将其标记为版本`1.0`:
FROM ubuntu
Base Layer
CMD ["echo", "Hello everyone"]
1. 重要提示:花点时间去理解`-t`是做什么的。还要注意`docker build`后面的`.`(圆点)。
2. 使用`docker images`命令查看您的新 docker 图像。
3. 从新的 Docker 映像启动容器:
docker build . -t greeter:1.0
1. 观察输出,然后通过覆盖默认的`CMD`让它打印一些东西:
docker run greeter:1.0
docker run greeter:1.0 echo "hello universe"
or any command of your choice that is available in ubuntu image
docker run greeter:1.0 sleep "3"
注意,您必须指定完整的命令来覆盖现有的命令。
#### 使用 entrypoint 使 greater 更具可配置性
1. 如下所示更新 Dockerfile 文件。如果需要,注释掉以前编写的代码。
1. 用 2.0 版构建并标记欢迎映像,然后运行容器。
FROM ubuntu
ENTRYPOINT [ "echo" ]
CMD ["Hello everyone"]
1. 现在,只需运行下面的代码,让容器打印您选择的消息。
docker build . -t greeter:2.0
docker run greeter:2.0
docker run greeter:2.0 "Hello Greeter 2.0"
#### 使用复制启动一个简单的静态网站
1. 在另一个文件夹中创建一个新的 docker 文件,或者继续使用现有的 docker 文件。
2. 创建一个名为`website`的文件夹,并在里面创建一个名为`index.html`的文件。键入一些简单的标记,如下所示。注意 Linux 中的文件名是区分大小写的。
1. 现在,在 docker 文件中键入以下内容:
Hello World
FROM nginx:alpine
Notice the change in base image.
COPY ./website/ /usr/share/nginx/html
4.将网站文件夹的内容复制到 nginx 默认网站位置。Nginx 是一个强大且非常受欢迎的 web 服务器。参见 [`https://hub.docker.com/_/nginx`](https://hub.docker.com/_/nginx) 的 Nginx 基础图像。
5.现在建立你的 Docker 图像如下。请随意为图像选择您自己的名称。在构建之前,请确保您的文件夹结构如下所示:
1. 运行分离的映像并进行端口转发。如果端口已经被使用,您将得到一个异常。
.
├── Dockerfile
└── website
└── index.html
docker build . -t hello-web:1.0
docker images "hello-web" # to see your new built image.
1. 使用`docker ps`确保容器按预期运行。观察您的`my-first-website`容器的所有列。
2. 使用`docker stop <container-name>`停止容器。
docker run --name my-first-website -d -p 9000:80 hello-web:1.0
Notice the --name
argument. We give our own container name this time.
### 监控 Docker 容器和 Docker 日志
首先在分离模式下启动一个容器,每秒打印一次日期。我们在这里使用了一个`busybox`图像,并将容器称为`date-printer`:
docker run --name date-printer -d busybox sh -c "while true; do $(echo date); sleep 1; done"
现在跟随它的日志。按 Ctrl+C 退出。
docker logs -f date-printer
Retrieve logs only since last 3 seconds
docker logs date-printer --since=3s
[`https://docs.docker.com/engine/reference/commandline/logs/`见](https://docs.docker.com/engine/reference/commandline/logs/)。
### Docker Exec:在运行的容器中运行命令!
启动一个`redis`容器,并确保它正在运行。
docker run -d redis
docker ps
note down the container name
现在使用 redis 的 CLI 设置一些数据。首先连接到它的容器外壳。
docker exec -it <redis_container_name> sh
进入容器后(当提示符变为`#`时),键入以下内容:
redis-cli
提示符现在应该类似于`127.0.0.1:6379` (redis 默认运行在 6379 上):
set name "Jane"
exit
exit
Exit from redis-cli
and then from the container shell
从终端,您可以直接检索这些数据。下面的输出应该打印`Jane`,例如:
docker exec -it <redis_container_name> redis-cli get name
### 码头检查
您可以检查容器、网络、卷等 Docker 对象的所有属性和状态。
例如,要检查一个容器,发出以下命令:
docker inspect <container_id or name>
要检查 Docker 网络,请发出以下命令:
docker network ls
docker inspect <network_name>
for e.g: docker inspect bridge (default network that containers attach to when network not specified)
使用 Linux 命令行工具,如`jq`,您可以操作 JSON 输出。
以下命令将打印连接到桥接网络的容器。
docker inspect bridge | jq '[.[].Containers]'
更多关于`jq`的信息,请访问 [`https://stedolan.github.io/jq/tutorial/`](https://stedolan.github.io/jq/tutorial/) 。
### 创建 Docker Hub 帐户并与之连接
前往 [`https://hub.docker.com/`](https://hub.docker.com/) ,使用您的临时/个人帐户注册。如果你使用你的个人邮箱来注册 Docker hub,确保你使用的是你自己的个人开发机器。(完成后也可以运行`docker logout`)。
1. 创建 Docker hub 帐户后,通过终端登录,如下所示:
1. 出现提示时,输入您的用户名和密码。你应该会收到类似`login succeeded`的东西。
docker login
#### 标记您的图像并将其推送到注册表
1. 在您可以将您的图像推送到您的注册表之前,您需要标记它。
Tag your `hello-web` image as shown here.
```
docker images hello-web
# Copy the image-id
docker tag <image-id> <dockerhub-username>/hello-web:1.0
docker push <docker-hub-username>/hello-web:1.0
```
2. 转到`hub.docker.com`以确保您的图像被正确推送。稍后在 Kubernetes 实验室中,您将会看到这张图片。
3. 您可以通过如下运行来测试您的映像。
1. 从终端注销 Docker hub:
docker run -d -p 9010:80
docker ps
docker stop <hello-web_container_id>
docker logout
像以前一样清理资源,以确保您的环境得到正确整理。
docker system prune -a
# type `y` when prompted
docker ps -a
docker images
## 使用库比涅斯
既然您已经知道如何独立运行 Docker 容器,那么是时候考虑当您有多个容器要构建和运行时会发生什么。为此,您需要一个像 Kubernetes 这样的容器编排引擎。
有许多容器编排器,如下所示:
* 忽必烈忽必烈忽必烈忽必烈忽必烈忽必烈忽必烈忽必烈忽必烈忽必烈
* 码头工人群
* 月 DC/OS
* 谷歌博格
* 还有更多
这些编排引擎提供了以下特性,您不必构建这些特性:
* 自愈
* 负载平衡
* 服务发现
* 行程安排
* 安全
* 配置
* 监视
* 缩放比例
云中的 Kubernetes 架构如图 4-9 所示。
![img/517807_1_En_4_Fig9_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_4_Fig9_HTML.png)
图 4-9
Kubernetes 建筑礼貌: [` kubernetes。io/docs/concepts/overview/components/`](https://kubernetes.io/docs/concepts/overview/components/)
图 4-10 展示了对该架构的深入研究,并说明了组件之间的交互方式。
![img/517807_1_En_4_Fig10_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_4_Fig10_HTML.png)
图 4-10
库比特组件
运行 Kubernetes,您需要以下任何一项
* 迷你库比
* AK(蓝色库柏服务)
* gke(Google kuble engine)
* 内部部署
* 树莓皮
* 还有更多
Kubernetes 总体框架的关键对象部分如下:
* 节点(无)
* 命名空间(ns)
* pod(采购订单)
* 部署(部署)
* 服务(服务)
* 乔布斯
* 克朗乔布斯
* 配置贴图(厘米)
* 秘密
* 持续量声明(pvc)
* Persistentvolumes (pv)
Kubernetes 上的无状态微服务/app 如图 4-11 所示。
![img/517807_1_En_4_Fig11_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_4_Fig11_HTML.png)
图 4-11
Kubernetes 部署和副本集
### Kubernetes 工具和设置
`kubectl`,发音为 *Kube-Control* ,是针对 Kubernetes 集群运行命令的命令行界面。
在这个练习中,你将探索`kubectl`的一些有用的特性。
1. 获取集群信息:
1. 将集群信息写入名为`cluster.txt`的文件。如果输出流`>`不工作,您可能需要`bash`??:
kubectl cluster-info
1. 如果您愿意,也可以使用`cat`查看:
kubectl cluster-info > cluster.txt
1. 获取群集中所有命名空间的列表。在这里,您也可以看到其他参与者的名称空间。在现实世界中,您可能无权查看其他名称空间。
cat cluster.txt
1. 您可以按如下方式使用速记命令:
kubectl get namespaces
1. 使用`grep`过滤您的名称空间:
kubectl get ns
1. 检查当前上下文的默认名称空间:
kubectl get ns | grep '
kubectl config get-contexts
您应该在`NAMESPACE`列下看到您的名称空间。
Important
如果`NAMESPACE`列为空或者不包含您的名称空间名称,这意味着您没有正确配置您的默认名称空间。请参见 repo 的自述文件或向讲师寻求帮助。
1. 获取群集中的节点列表:
`kubectl get nodes`
您可以使用- `o wide`查看更多信息:
kubectl get nodes -o wide
`kubectl explain`将解释给定的资源,例如像 Pod 这样的顶级 API 对象或像 Pod 的容器这样的特定字段。
1. 获取 Pod 资源及其字段的文档。
1. 获取 Pod 容器规格的文档。
`# to just explain pod`
`kubectl explain pod`
`# to further explain the properties` `and nested objects`
kubectl explain node
kubectl explain pods.spec.containers
Note
`pods.spec.containers`匹配 YAML 物体结构:
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
name: nginx
spec:
containers:
- image: nginx
imagePullPolicy: IfNotPresent
name: nginx
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Never
在 Azure 门户中,你可以创建 AKS 集群,如图 4-12 所示。
![img/517807_1_En_4_Fig12_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_4_Fig12_HTML.png)
图 4-12
蓝色忽必烈服务
您单击 Create,然后根据您的要求继续填写信息。参见图 4-13 。
![img/517807_1_En_4_Fig13_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_4_Fig13_HTML.png)
图 4-13
Azure Kubernetes 服务:创建群集
以下是您可以使用的一些高级 Azure CLI 命令:
Run az --version to find the version.
要创建 Azure Kubernetes 集群,发出以下命令:
az aks create
--resource-group newResourceGroup
--name newAKSCluster
--node-count 3
--generate-ssh-keys
--attach-acr
要安装 CLI,请发出以下命令:
az aks install-cli
要连接到集群,请发出以下命令:
az aks get-credentials --resource-group aksResourceGroup --name newAKSCluster
要获取节点,发出以下命令:
kubectl get nodes
## 摘要
在本章中,你学习了什么是容器和 Kubernetes,以及如何在开发中设置和使用它们。下一章着眼于如何监控和保护 Azure Kubernetes 集群(AKC)。
## 附录
[`https://docs.microsoft.com/en-us/virtualization/windowscontainers/about/containers-vs-vm`](https://docs.microsoft.com/en-us/virtualization/windowscontainers/about/containers-vs-vm)
[`https://kubernetes.io/docs/concepts/overview/what-is-kubernetes/#going-back-in-time`](https://kubernetes.io/docs/concepts/overview/what-is-kubernetes/%2523going-back-in-time)
[`https://docs.docker.com/get-started/overview/`](https://docs.docker.com/get-started/overview/)
[`https://github.com/microsoft/terminal#installing-and-running-windows-terminal`](https://github.com/microsoft/terminal%2523installing-and-running-windows-terminal)
[`https://docs.microsoft.com/en-us/windows/wsl/about`](https://docs.microsoft.com/en-us/windows/wsl/about)
[`https://www.docker.com/products/docker-desktop`](https://www.docker.com/products/docker-desktop)
[`https://docs.microsoft.com/en-us/windows/wsl/wsl-config#configure-global-options-with-wslconfig`](https://docs.microsoft.com/en-us/windows/wsl/wsl-config%2523configure-global-options-with-wslconfig)
[`https://hub.docker.com/_/hello-world`](https://hub.docker.com/_/hello-world)
[`https://docs.docker.com/engine/reference/run/#cmd-default-command-or-options`](https://docs.docker.com/engine/reference/run/%2523cmd-default-command-or-options)
[`https://docs.docker.com/engine/reference/commandline/system_prune/`](https://docs.docker.com/engine/reference/commandline/system_prune/)
[`https://docs.docker.com/config/pruning/`](https://docs.docker.com/config/pruning/)
[`https://docs.docker.com/engine/reference/commandline/rmi/`](https://docs.docker.com/engine/reference/commandline/rmi/)
[`https://hub.docker.com/_/nginx`](https://hub.docker.com/_/nginx)
[`https://docs.docker.com/engine/reference/commandline/logs/`](https://docs.docker.com/engine/reference/commandline/logs/)
[`https://stedolan.github.io/jq/tutorial/`](https://stedolan.github.io/jq/tutorial/)
[`https://kubernetes.io/docs/concepts/overview/components/`](https://kubernetes.io/docs/concepts/overview/components/)
# 五、保护和监控 AKS 上运行的应用
## 介绍
首先,祝贺你完成了本书的 60%。在阅读完架构设计和模式之后,在本章中,你将经历另一个有趣而重要的方面——监控和保护基于 Azure Kubernetes 服务的应用。你一定很奇怪我为什么不提微服务。答案很简单——当我说应用时,它涵盖了所有内容。
数字平台计划正在促使组织拥抱云文化。云支持包括构建向客户交付更多价值的战略。其中一个策略关注应用的安全性。随着开发步伐的不断加快,规划应用的安全性以避免业务运营中的任何障碍变得非常重要。
在这里,我将向您介绍应用和集群的安全概念,并以应用在安全性方面的最佳估算者之一作为结论。
## 安全概念
Kubernetes 和 Microsoft Azure 都包含各自的安全组件。Azure Kubernetes 服务结合了这些安全组件,以:
* 确保您的 AKS 集群运行的是最新的 Kubernetes 版本
* 确保它拥有最新的操作系统安全更新
* 安全 Pod 流量
* 提供对敏感凭据的可信访问
让我们深入了解一些在 Azure Kubernetes 服务中保护应用和集群的核心概念。
### 主安全
在 AKS 中,每个集群都有一个专用的 Kubernetes 主支持 API 服务器、调度程序等等。这个 Kubernetes API 服务器使用一个 FQDN——一个完全合格的域名——以及一个公共 IP 地址。作为一项 PaaS 服务,Kubernetes 主组件包含在托管服务中,由微软维护。
您可以通过以下方式采用它们:
![img/517807_1_En_5_Fig1_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_5_Fig1_HTML.png)
图 5-1
Azure PortalImage 中的授权 IP 范围功能图片来源:Microsoft 文档
* 您可以创建一个专用集群,限制服务器对专用虚拟网络的访问。
* 使用授权的 IP 范围,您可以限制对 API 服务器端点的访问。参见图 5-1 。
此外,您可以使用 Kubernetes RBAC 和 Azure RBAC 来控制访问。详见 [`https://docs.microsoft.com/en-us/azure/aks/managed-aad`](https://docs.microsoft.com/en-us/azure/aks/managed-aad) 的实施细节。
### 节点安全性
Azure Kubernetes 服务节点只不过是您管理的虚拟机。Linux 和 Windows 服务器节点都分别运行优化的 Ubuntu 发行版和 Windows Server 2019 版本,使用 Docker 容器运行时。
无论何时创建 AKS 集群,也无论何时扩展,最新的操作系统安全更新和配置都会自动部署到节点上。
Linux 节点和 Windows server 节点的安全补丁可以通过运行简单的 azure CLI 命令来实现。为了更好地理解,以下 Azure CLI 命令将升级名为`myaksbooknodepool`的节点池:
az aks nodepool upgrade
--resource-group myAKSBookResourceGroup
--cluster-name myAKSBookCluster
--name myaksbooknodepool
--kubernetes-version KUBERNETES_VERSION
--no-wait
这只是可用于管理节点的各种简单 Azure CLI 命令中的一个示例。
节点总是部署到专用虚拟网络。甚至节点使用的存储都是由固态硬盘支持的优质 Azure 托管磁盘。在 Azure 平台中,这个磁盘上的数据在静态时总是加密的。Azure 还为隔离的虚拟机提供了选项,这是合规性和监管要求的一部分。这适用于 Linux 和 Windows 虚拟机。在撰写本书时,有几个选项可用于隔离的虚拟机:
* `Standard_E80ids_v4`
* `Standard_E80is_v4`
* `Standard_F72s_v2`
* `Standard_M128ms`
* `Standard_DC8_v2`
### 集群升级
Azure 提供了一个升级编排工具,它包括 Kubernetes 主组件和代理组件。该工具支持以下操作:
* AKS 集群及其组件的升级
* 安全维护
* 合规维护
* 访问最新功能
它所需要的只是可用的 Kubernetes 版本,剩下的就交给它了,当然,只需要更少的命令。
### 网络安全性
为了与本地网络通信,您可以将 AKS 部署到 Azure 虚拟网络子网。使用站点到站点 VPN 或快速路由,此虚拟网络连接到您的内部网络。您还可以使用私有的内部 IP 地址定义 Kubernetes 入口控制器,以限制服务对网络连接的访问。您可以利用 Azure 网络安全组甚至 Kubernetes 网络策略来控制流量。
Azure Kubernetes 服务提供对 Kubernetes 网络策略的支持,以基于名称空间、标签选择器等来限制给定集群中的 pod 之间的网络流量。
### 不可告人的秘密
使用 Kubernetes Secret,您可以将您的敏感数据(如访问凭证和密钥)添加到 Pods 中。使用机密可以最大限度地减少(Pod 或服务 YAML)清单中敏感信息的使用。您可以请求将该秘密作为您的清单的一部分,将对该信息的访问仅限于特定的 pod。
Kubernetes 的秘密存储在`Etcd`中,这是一个分布式键值存储。`Etcd`商店完全由 AKS 管理,数据在 Azure 平台内被加密。见图 5-2 。
![img/517807_1_En_5_Fig2_HTML.jpg](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_5_Fig2_HTML.jpg)
图 5-2
Azure 静态加密组件图片来源:微软文档
关于库伯内特的秘密,有几点你需要知道:
* 您可以使用 Kubernetes API 创建一个秘密。
* 你为你的 Pod 定义和请求秘密。
* 秘密不是写在磁盘上,而是存储在`tmpfs`里。
* 当需要该秘密的 Pod 被删除时,该秘密也被从`tmpfs`节点中删除。
* 机密存储在一个名称空间中,使得它们只能由同一名称空间中的 pod 访问。
除了这些与应用和集群相关的安全概念之外,最好还了解以下内容:
* Azure Kubernetes 服务的 Azure 安全基线
(见 [`https://docs.microsoft.com/en-us/security/benchmark/azure/baselines/aks-security-baseline?context=/azure/aks/context/aks-context`](https://docs.microsoft.com/en-us/security/benchmark/azure/baselines/aks-security-baseline%253Fcontext%253D/azure/aks/context/aks-context) )。)
* 针对 Azure Kubernetes 服务(AKS)的 Azure 策略法规遵从性控制
(见 [`https://docs.microsoft.com/en-us/azure/aks/security-controls-policy`](https://docs.microsoft.com/en-us/azure/aks/security-controls-policy) )。)
## 蓝色库柏服务清单
此清单包含一些在使用 AKS 时要遵循的最佳实践。它不是一种要遵循的圣经,而只是在涉及到安全性时要遵循的最佳实践
![img/517807_1_En_5_Fig3_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_5_Fig3_HTML.png)
图 5-3
*Kubernetes Secrets* *和* *Azure KeyVault 图标*
* **避免将敏感信息注入图像,使用秘密代替**。如上所述,避免将密码等敏感信息直接输入到图像或清单中。相反,总是使用秘密 Kubernetes Secrets 或 Azure Key vault——来存储这类信息。见图 5-3 。
![img/517807_1_En_5_Fig4_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_5_Fig4_HTML.png)
图 5-4
一名开发人员创建了一个 Pod,它使用托管身份来请求访问 Azure SQL 数据库图片来源:Microsoft 文档
* **执行 Pod 身份识别**。不要在 Pod 映像中存储固定的凭据。相反,您可以使用 Pod 身份,它使用 Azure 身份解决方案来访问所需的(Azure)资源。这些凭证可以是用于与其他 Azure 服务对话的任何凭证,如 Azure SQL 或 Azure Storage。您可以在 Kubernetes Secrets 中定义它们,但它需要手动管理。在这里,您可能会错过轮换正在使用的机密的最佳实践。
Azure 资源的 Pod 管理的身份可用于通过 Azure AD 进行访问请求。图 5-4 描述了请求流程。
Note
在写这本书的时候,AK 的 Pod 管理的身份是预览版。
![img/517807_1_En_5_Fig5_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_5_Fig5_HTML.png)
图 5-5
AKS 集群中的命名空间示例图像源:Microsoft 文档
* **使用 Kubernetes 名称空间**。名称空间是资源的逻辑分区。它们不仅加强了资源的分离,还限制了允许的用户范围。为了便于理解,不同的业务单位或组可以有不同的名称空间。您应该使用 Kubernetes 名称空间来隔离您的 Kubernetes 资源。见图 5-5 。
创建 AKS 集群时,可以使用以下命名空间:
* `Default`:当没有给定名称空间时,这是创建窗格的地方。
* `kube-system`:有核心资源的地方。
* 任何用户都可以查看这些资源。
Important
避免使用默认名称空间。
* **为 Pod** 指定正确的安全上下文。这是决定 Pod 访问控制设置的一个重要因素。如果没有设置上下文,Pod 将获得默认的上下文,这将为它提供更多的权限。
* **体现最佳实践**。确保清单的配置遵循最佳做法。一个好的清单代表一个好的集群。&# x1f 609;
* **对构建的图像进行静态分析**。将 DevSecOps 引入到环境中,以促进主动安全模式,开始将责任转移到左边。azure Defender for container registries 可以在这里使用。
* **执行合规** **打造形象**。您必须浏览 Azure Kubernetes 服务的 Azure 策略内置定义;见 [`https://docs.microsoft.com/en-us/azure/aks/policy-reference?ref=akschecklist`](https://docs.microsoft.com/en-us/azure/aks/policy-reference%253Fref%253Dakschecklist) 。
Note
收藏以下网址: [`https://www.the-aks-checklist.com/`](https://www.the-aks-checklist.com/) 。前面解释的七条戒律是这个论坛的一部分,它们会根据新的环境不断变化。
### 安全概念:结论
AKS 的安全方面可以在他们自己的一整本书中涵盖。然而,考虑到本章的范围,我试图总结出在使用基于 AKS 的应用时应该知道的事情。当讨论基于 AKS 的应用安全性时,请将这些答案视为您期望从面试官那里得到的答案。
下一节涵盖了另一个重要的领域,监控。
## 监控概念
您的应用是安全的,但需要一直保持运行和可用。保护不可用的应用是没有用的。因此,监控是你需要认识的一个重要领域。这一节将向您展示监控基于 AKS 的应用以及使用 Azure Monitor 监控 AKS 的细节。
### 容器洞察
可以监视生成性能指标和资源日志的资源的健康和性能。和其他 Azure 资源一样,Azure Kubernetes 服务也有日志。
Azure Monitor 有一个名为 Container Insights 的特性,它为托管在 AKS 上的托管 Kubernetes 运行这些检查。它之所以受欢迎,是因为它能够呈现来自不同监控场景的数据的交互式视图。它与 Azure Kubernetes 服务进行了本机集成,有助于收集关键日志、发送警报和可视化。图 5-6 展示了 Azure 门户中的容器洞察。
![img/517807_1_En_5_Fig6_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_5_Fig6_HTML.png)
图 5-6
Container insightsImage 的功能来源:Microsoft 文档
以下是使用 Azure Monitor 为 AKS 集群配置监控所需的步骤:
![img/517807_1_En_5_Fig7_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_5_Fig7_HTML.png)
图 5-7
使用 Container Insights 配置 Prometheus 指标的抓取图片来源:微软文档
1. 创建日志分析工作区。您必须有一个日志分析工作区,以便从 AKS 集群收集遥测数据。Container Insights 需要至少一个日志分析工作区。
2. 启用容器洞察。启用容器洞察取决于您正在使用的 AKS 集群。AKS 集群已经存在还是新创建的?启用后,将部署日志分析代理的容器化版本,它将数据发送到 Azure Monitor。
3. 配置普罗米修斯的收藏。使用 Container Insights 允许您收集 Prometheus 指标,而不需要 Prometheus 服务器。这使得该组合对于 E2E 监测是成功的。参见图 5-7 ,该图描绘了 Container Insights 和 Prometheus 的工作情况。
![img/517807_1_En_5_Fig8_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_5_Fig8_HTML.png)
图 5-8
用于在 Azure 门户中配置诊断设置的屏幕
1. 收集资源日志。这些是 Azure 中实现的 AKS 控制平面组件的日志。您需要有一个诊断设置来收集这些日志。你可以把它放在日志分析工作区或者 Azure 存储中。图 5-8 显示了配置诊断设置的屏幕。
### Azure 监视器功能
有两种方式可以查看 AKS 集群的 Azure Monitor 功能:
![img/517807_1_En_5_Fig9_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_5_Fig9_HTML.png)
图 5-9
Azure 门户中 Kubernetes 服务屏幕的洞察选项
* 转到 Azure 门户➤ Kubernetes 服务,并从左侧窗格中选择监视器部分。这主要是针对单个 AKS 集群的。参见图 5-9 。
![img/517807_1_En_5_Fig10_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_5_Fig10_HTML.png)
图 5-10
Azure Portal 监视器屏幕中的容器细节窗格
* 转到 Azure 门户网站。在搜索框中键入 **Monitor** ,然后选择 Insights Section ➤容器。
图 5-10 显示了订阅中的所有 AKS 集群。
图 5-11 是 Azure Portal 中 Monitor 的新屏幕视图。它是监控集群、创建警报和许多更酷的实现的入口点。
![img/517807_1_En_5_Fig11_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_5_Fig11_HTML.png)
图 5-11
在 Azure Portal 的监控下*容器* *新鲜画面*
*Azure Kubernetes 服务监控具有不同的实现和独特的需求。这种方法依赖于这些要求。它处理从基础设施到应用的不同层,并根据层提出不同的监控要求。
考虑自下而上的方法,这些层可以如图 5-12 所示列出。
![img/517807_1_En_5_Fig12_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_5_Fig12_HTML.png)
图 5-12
AKSImage 源的层:微软文档
为了保持本章的范围和简洁,我将讨论第 4 级,即监控应用层,它包括在 AKS 集群中运行的应用工作负载。
这一层主要关注监控微服务应用和识别应用故障,以及请求率、响应时间、遇到的任何异常等信息。对于在 AKS 上运行的应用的完整监控,您可以使用应用洞察,如图 5-13 所示。
![img/517807_1_En_5_Fig13_HTML.jpg](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_5_Fig13_HTML.jpg)
图 5-13
应用洞察图标
根据您的应用堆栈,您需要配置基于代码的监控来收集所需的数据。它可以是任何东西——Java、Python、.Net 或任何其他平台。在这个例子中,我对 ASP.NET 核心应用更感兴趣。
您需要一个有效的 Application Insights 工具密钥,并创建 Application Insight 资源。
若要创建一个,请转到 Azure 订阅。在搜索中键入 **Application Insights** ,然后单击新建。您将看到一个屏幕,添加创建服务所需的基本强制细节。输入所有详细信息,然后单击“查看+创建”。参见图 5-14 。
![img/517807_1_En_5_Fig14_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_5_Fig14_HTML.png)
图 5-14
在 Azure 门户中创建应用洞察的屏幕
验证完成后,单击 Create 完成服务创建。
转到新创建的服务屏幕,在 Overview 部分下找到检测密钥、连接字符串和其他详细信息。参见图 5-15 中突出显示的部分。
![img/517807_1_En_5_Fig15_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_5_Fig15_HTML.png)
图 5-15
Azure 门户中应用洞察的工具键
Tip
强烈建议使用连接字符串而不是检测密钥,因为新的 Azure 区域需要连接字符串。无论哪种情况,您都需要创建服务。
接下来,您需要在您的 IDE 中启用应用洞察。我最喜欢的 IDE 是 Visual Studio,但是你也可以使用其他 IDE,比如可视化代码。使用 ide 启用 Application Insights 服务器端遥测后,选择 nu get packages➤Microsoft . application insights . aspnetcore 下载 SDK 的最新稳定版本。参见图 15-16 。
![img/517807_1_En_5_Fig16_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_5_Fig16_HTML.png)
图 15-16
NuGet 包中的 SDK 图片来源:Microsoft 文档
通过向应用添加几行代码,它将从遥测数据开始,并可以在 Azure Portal 的 Applications Insights 屏幕中呈现。可以对这些数据进行分析,并根据应用的状态创建警报。
代码和其他选项请参考 [`https://docs.microsoft.com/en-us/azure/azure-monitor/app/asp-net-core`](https://docs.microsoft.com/en-us/azure/azure-monitor/app/asp-net-core) 。
## 摘要
本章介绍了关于保护和监控基于 AKS 的应用您应该知道的事情。通过提供的链接,确保您对这些问题有适当的实践经验。这一章结束了这本书的理论部分。下一章使用一个实用的分步方法来实现 Azure Kubernetes 基于服务的应用的 CICD。直到那时,快乐的蔚蓝学习。*
# 六、AK 的 CI/CD
## 介绍
你现在在这本书的最后一章。到目前为止,您已经了解了微服务和 Azure Kubernetes 服务的设计考虑事项。您几乎已经准备好监控和保护一个基于 Azure Kubernetes 服务的应用。在这最后一章中,您将了解应用交付的一个重要方面,持续集成和持续部署,重点是基于 Azure Kubernetes 服务的应用。
## 快速浏览 DevOps
我假设您对这个主题并不陌生,但是在开始这一章之前,我先简单介绍一下 DevOps。
DevOps 将人员、流程和技术结合在一起,自动化软件交付,为您的用户提供持续的价值。DevOps 自动化并加速软件交付。它使您的过程和产品更加可靠。
DevOps 是一个过程,一种实践,一套工具或所有工具的总和。它共同致力于一个组织所采用的更快的软件/产品交付。它在很大程度上放大了团队的统一性,有助于使开发阶段无缝衔接。它受欢迎的主要原因是交付速度更快。您在存储库中编码和添加,CI 用最新的更改构建应用,并向它提供一个可部署的工件。这个工件现在被获取并实时推送,所有这些都是 CD 流程的一部分。这可以在您工作的所有环境中进行。同样的工件可以被提升到更高的环境,比如从开发到 QA 到 UAT 到生产。
Note
如果你是 DevOps 概念的初学者,最好浏览一下在 [`https://docs.microsoft.com/en-us/learn/modules/get-started-with-devops/2-what-is-devops`](https://docs.microsoft.com/en-us/learn/modules/get-started-with-devops/2-what-is-devops) 找到的文档。
为了让这最后一章更有趣,我用一步一步的方法来介绍这个练习。理论少,实际应用多。我相信这不仅会使你的学习变得有趣,而且会帮助你更容易理解这个话题。& # x1F60A
作为以下练习的先决条件的一部分,您需要在您的计算机上安装有效的 Microsoft Azure 订阅、Visual Studio 作为 IDE、Azure DevOps 项目和 Docker Desktop for Windows。该练习使用 GitHub 作为源代码库。
## 本次练习的目标
以下是本次练习的日程安排:
* 使用 Azure Portal 创建 Azure Kubernetes 服务。
* 使用 Azure Portal 创建 Azure 容器实例。
* 使用 Visual Studio 构建示例应用。
您可以使用各种工具实现 CI/CD,但如果您是微软云爱好者,以下工具是最佳选择:
* Azure DevOps
* GitHub 动作
本章向您介绍了使用 Azure DevOps 的步骤。对于 GitHub 动作,你会得到一个参考链接,你可以把它作为本章的第一个练习。本章中的大多数详细步骤都是不言自明的,但是我会在需要的地方包含更多的细节。
所以做好准备,按照这些步骤来做吧!& # x1F60A
## 使用 Azure 门户创建 Azure Kubernetes 服务
![img/517807_1_En_6_Fig1_HTML.jpg](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig1_HTML.jpg)
图 6-1
图像细节步骤 1
1. 从 [`http://portal.azure.com/`](http://portal.azure.com/) 打开微软 Azure 门户,点击创建资源链接,如图 6-1 所示。
![img/517807_1_En_6_Fig2_HTML.jpg](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig2_HTML.jpg)
图 6-2
图像细节步骤 2
1. 在搜索框中搜索 Kubernetes 服务,或者导航到计算➤ Kubernetes 服务,点击列出的服务,如图 6-2 所示。
![img/517807_1_En_6_Fig3_HTML.jpg](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig3_HTML.jpg)
图 6-3
图像细节步骤 3
1. 您将看到输入基本细节的屏幕。详细信息,如选择您的订阅、资源组、集群名称、区域等。这个例子使用的是 Kubernetes 版本 1.19.11。输入所有必需的详细信息,然后单击节点池的下一步。见图 6-3 。
![img/517807_1_En_6_Fig4_HTML.jpg](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig4_HTML.jpg)
图 6-4
图像细节步骤 04
1. 现在,您将添加一个节点池。单击+添加节点池按钮。您会看到多个选项,如图 6-4 所示。
![img/517807_1_En_6_Fig5_HTML.jpg](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig5_HTML.jpg)
图 6-5
图像细节步骤 5
1. 给出节点池名称,然后选择虚拟机大小,如图 6-5 所示。您不必选择与图中所示相同的虚拟机大小。
![img/517807_1_En_6_Fig6_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig6_HTML.png)
图 6-6
图像细节步骤 6
1. 将列出新创建的节点。单击“下一步”转到身份验证。见图 6-6 。
![img/517807_1_En_6_Fig7_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig7_HTML.png)
图 6-7
图像细节步骤 7
1. 选择认证方式和 RBAC 角色,如图 6-7 所示。单击下一步。
![img/517807_1_En_6_Fig8_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig8_HTML.png)
图 6-8
图像细节步骤 8
1. 选择网络配置为 Azure CNI 等必填字段,如图 6-8 所示。
![img/517807_1_En_6_Fig9_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig9_HTML.png)
图 6-9
图像细节步骤 9
1. 确保选择 Azure 作为网络策略,如图 6-9 所示。
![img/517807_1_En_6_Fig10_HTML.jpg](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig10_HTML.jpg)
图 6-10
图像细节步骤 10
1. 单击“下一步”并显示集成细节。我会照原样去。点击'审核+创建',如图 6-10 所示。
![img/517807_1_En_6_Fig11_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig11_HTML.png)
图 6-11
图像细节步骤 11
1. 验证通过后,点击【创建】,如图 6-11 所示。
![img/517807_1_En_6_Fig12_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig12_HTML.png)
图 6-12
图像细节步骤 12
1. 这将导致显示部署进度的屏幕。部署成功后,点击【转到资源】,如图 6-12 所示。
![img/517807_1_En_6_Fig13_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig13_HTML.png)
图 6-13
图像细节步骤 13
1. 您将看到新创建的 Kubernetes 集群,如图 6-13 所示。
## 使用 Azure 门户创建 Azure 容器实例
![img/517807_1_En_6_Fig14_HTML.jpg](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig14_HTML.jpg)
图 6-14
图像细节步骤 14
1. 遵循图 6-14 所示的步骤。
![img/517807_1_En_6_Fig15_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig15_HTML.png)
图 6-15
图像细节步骤 15
1. 遵循图 6-15 所示的步骤。
![img/517807_1_En_6_Fig16_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig16_HTML.png)
图 6-16
图像细节步骤 16
1. 在基本屏幕上输入必需的详细信息,其余的设置为默认值。点击审核+创建,如图 6-16 所示。
![img/517807_1_En_6_Fig17_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig17_HTML.png)
图 6-17
图像细节步骤 17
1. 看到验证通过后,单击创建。见图 6-17
![img/517807_1_En_6_Fig18_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig18_HTML.png)
图 6-18
图像细节步骤 18
1. 等待部署完成。点击进入资源,如图 6-18 所示。
![img/517807_1_En_6_Fig19_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig19_HTML.png)
图 6-19
图像细节步骤 19
1. 从左侧刀片中选择门禁,如图 6-19 所示。
![img/517807_1_En_6_Fig20_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig20_HTML.png)
图 6-20
图像细节步骤 20
1. 点击添加新的角色分配,如图 6-20 所示。
![img/517807_1_En_6_Fig21_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig21_HTML.png)
图 6-21
图像细节步骤 21
1. 选择呈现用户管理身份的Á远程角色,然后选择新创建的池,如图 6-21 所示。
![img/517807_1_En_6_Fig22_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig22_HTML.png)
图 6-22
图像细节步骤 22
1. 遵循图 6-22 所示的步骤。
![img/517807_1_En_6_Fig23_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig23_HTML.png)
图 6-23
图像细节步骤 23
1. 从左侧刀片,进入设置部分下的访问键,如图 6-23 所示。
![img/517807_1_En_6_Fig24_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig24_HTML.png)
图 6-24
图像细节步骤 24
1. 点击 Toggle 以管理员用户身份启用按键,如图 6-24 所示。
## 使用 Visual Studio 构建示例应用
![img/517807_1_En_6_Fig25_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig25_HTML.png)
图 6-25
图像细节步骤 25
1. 在打开 IDE 之前,先去下面的链接下载 Docker 桌面,用默认设置安装: [`https://www.docker.com/products/docker-desktop`](https://www.docker.com/products/docker-desktop) (见图 6-25 )。
![img/517807_1_En_6_Fig26_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig26_HTML.png)
图 6-26
图像细节步骤 26
1. 图 6-26 显示 Docker 已启动并运行。
![img/517807_1_En_6_Fig27_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig27_HTML.png)
图 6-27
图像细节步骤 27
1. 现在打开 Visual Studio,选择新建一个项目,如图 6-27 所示。
![img/517807_1_En_6_Fig28_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig28_HTML.png)
图 6-28
图像细节步骤 28
1. 遵循图 6-28 所示的步骤。
![img/517807_1_En_6_Fig29_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig29_HTML.png)
图 6-29
图像细节步骤 29
1. 选择应用的名称,如图 6-29 所示。
![img/517807_1_En_6_Fig30_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig30_HTML.png)
图 6-30
图像细节步骤 30
1. 确保启用 Docker 并选择 Windows 作为 Docker OS,如图 6-30 所示。
![img/517807_1_En_6_Fig31_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig31_HTML.png)
图 6-31
图像细节步骤 31
1. 您可以看到创建的应用,如图 6-31 所示。
![img/517807_1_En_6_Fig32_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig32_HTML.png)
图 6-32
图像细节步骤 32
1. 选择运行➤ Kubernetes 应用,如图 6-32 所示。
![img/517807_1_En_6_Fig33_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig33_HTML.png)
图 6-33
图像细节步骤 33
1. 点击运行应用,如图 6-33 所示。
![img/517807_1_En_6_Fig34_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig34_HTML.png)
图 6-34
图像细节步骤 34
1. 确保应用运行良好,没有错误。见图 6-34 。
![img/517807_1_En_6_Fig35_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig35_HTML.png)
图 6-35
图像细节步骤 35
1. 现在,通过右键单击并选择“添加➤新文件”来添加一个新文件。见图 6-35 。
![img/517807_1_En_6_Fig36_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig36_HTML.png)
图 6-36
图像细节步骤 36
1. 您必须添加这个 YAML 文件,因为它定义了 Kubernetes 中容器的部署细节。见图 6-36
![img/517807_1_En_6_Fig37_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig37_HTML.png)
图 6-37
图像细节步骤 37
1. 您可以删除这个默认代码,并在下一步添加脚本。见图 6-37 。
![img/517807_1_En_6_Fig38_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig38_HTML.png)
图 6-38
图像细节步骤 38
1. 以下脚本定义了容器映像的详细信息、它必须创建的副本数量、要公开的端口、缩放指标和更新策略。见图 6-38
![img/517807_1_En_6_Fig39_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig39_HTML.png)
图 6-39
图像细节步骤 39
1. 遵循图 6-39 所示的步骤。
![img/517807_1_En_6_Fig40_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig40_HTML.png)
图 6-40
图像细节步骤 40
1. 这个完整的脚本有助于构建容器应用。这是默认脚本,您可以根据需要更改它。见图 6-40
![img/517807_1_En_6_Fig41_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig41_HTML.png)
图 6-41
图像细节步骤 41
1. 用图 6-41 中的脚本替换默认脚本。该脚本以 dotnet 核心容器映像为基础,构建容器应用。
您已经完成了对应用的必要更改。现在,您将构建用于设置 CI/CD 的管道。
## 使用 Azure DevOps 的 CI/CD
![img/517807_1_En_6_Fig42_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig42_HTML.png)
图 6-42
图像细节步骤 42
1. 打开团队资源管理器,并遵循图 6-42 中所示的步骤。
![img/517807_1_En_6_Fig43_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig43_HTML.png)
图 6-43
图像细节步骤 43
1. 按照图 6-43 所示的步骤连接到 GitHub 存储库。
![img/517807_1_En_6_Fig44_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig44_HTML.png)
图 6-44
图像细节步骤 44
1. 认证你的 GitHub 凭证,如图 6-44 所示。
![img/517807_1_En_6_Fig45_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig45_HTML.png)
图 6-45
图像细节步骤 45
1. 一旦授权成功,您将看到如图 6-45 所示的信息。
![img/517807_1_En_6_Fig46_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig46_HTML.png)
图 6-46
图像细节步骤 46
1. 遵循图 6-46 所示的步骤。
![img/517807_1_En_6_Fig47_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig47_HTML.png)
图 6-47
图像细节步骤 47
1. 遵循图 6-47 所示的步骤。
![img/517807_1_En_6_Fig48_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig48_HTML.png)
图 6-48
图像细节步骤 48
1. 遵循图 6-48 所示的步骤。
![img/517807_1_En_6_Fig49_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig49_HTML.png)
图 6-49
图像细节步骤 49
1. 您创建的应用现在是您 repo 的一部分,并且可以看到文件,如图 6-49 所示。
![img/517807_1_En_6_Fig50_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig50_HTML.png)
图 6-50
图像细节步骤 50
1. 进入 [`https://devops.azure.com/`](https://devops.azure.com/) ,如图 6-50 。
![img/517807_1_En_6_Fig51_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig51_HTML.png)
图 6-51
图像细节步骤 51
1. 按照图 6-51 所示的步骤创建一个新项目。
![img/517807_1_En_6_Fig52_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig52_HTML.png)
图 6-52
图像细节步骤 52
1. 遵循图 6-52 所示的步骤。
![img/517807_1_En_6_Fig53_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig53_HTML.png)
图 6-53
图像细节步骤 53
1. 按照图 6-53 所示步骤启动管道。
![img/517807_1_En_6_Fig54_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig54_HTML.png)
图 6-54
图像细节步骤 54
1. 点击【创建管道】,如图 6-54 所示。
![img/517807_1_En_6_Fig55_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig55_HTML.png)
图 6-55
图像细节步骤 55
1. 挑选你的代码;本例使用经典编辑器,如图 6-55 所示。
![img/517807_1_En_6_Fig56_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig56_HTML.png)
图 6-56
图像细节步骤 56
1. 选择 GitHub,用你的 GitHub 凭证授权,如图 6-56 所示。
![img/517807_1_En_6_Fig57_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig57_HTML.png)
图 6-57
图像细节步骤 57
1. 选择存放您的应用文件的仓库,如图 6-57 所示。
![img/517807_1_En_6_Fig58_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig58_HTML.png)
图 6-58
图像细节步骤 58
1. 遵循图 6-58 所示的步骤。
![img/517807_1_En_6_Fig59_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig59_HTML.png)
图 6-59
图像细节步骤 59
1. 点击继续,如图 6-59 所示。
![img/517807_1_En_6_Fig60_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig60_HTML.png)
图 6-60
图像细节步骤 60
1. 添加新任务。这是一个 DevOps 管道任务,可以帮助您构建和推送容器映像。您需要使用此任务或任何其他此类任务来构建容器应用。见图 6-60
![img/517807_1_En_6_Fig61_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig61_HTML.png)
图 6-61
图像细节步骤 61
1. 遵循图 6-61 所示的步骤。
![img/517807_1_En_6_Fig62_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig62_HTML.png)
图 6-62
图像细节步骤 62
1. 遵循图 6-62 所示的步骤。
![img/517807_1_En_6_Fig63_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig63_HTML.png)
图 6-63
图像细节步骤 63
1. 遵循图 6-63 中的步骤。
![img/517807_1_En_6_Fig64_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig64_HTML.png)
图 6-64
图像细节步骤 64
1. 授权您的订阅,如图 6-64 所示。
![img/517807_1_En_6_Fig65_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig65_HTML.png)
图 6-65
图像细节步骤 65
1. 遵循图 6-65 所示的步骤。
![img/517807_1_En_6_Fig66_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig66_HTML.png)
图 6-66
图像细节步骤 66
1. 选择路径,如图 6-66 所示。
![img/517807_1_En_6_Fig67_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig67_HTML.png)
图 6-67
图像细节步骤 67
1. 最好为每个构建创建一个新版本的容器,因为代码中的每个新变化都会构建一个容器。因此,为了保持映像版本的唯一性,请使用管道的构建 ID,该 ID 是管道每次运行构建操作时唯一生成的。图 6-67 中显示的前面带有$的值是 DevOps 管道中的一个变量。
![img/517807_1_En_6_Fig68_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig68_HTML.png)
图 6-68
图像细节步骤 68
1. 遵循图 6-68 所示的步骤。
![img/517807_1_En_6_Fig69_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig69_HTML.png)
图 6-69
图像细节步骤 69
1. 这与前面提到的 Docker 映像的构建任务相同。您需要为将要推入 ACR 的 Docker 映像提供一个唯一的版本。因此,使用图 6-69 所示的变量。
![img/517807_1_En_6_Fig70_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig70_HTML.png)
图 6-70
图像细节步骤 70
1. 我们可以使用替换令牌任务来替换 Azure 容器注册表的 URL,它将用于存储容器图像。您不需要在源代码中对注册中心的 URL 进行硬编码,而是在 YAML 文件中创建一个变量,这个变量最初是为了定义部署到 Kubernetes 中的容器配置而添加的。每次运行时,您可以在管道中提供一个变量,以便在管道运行时,您可以定义容器注册表的详细信息。见图 6-70
![img/517807_1_En_6_Fig71_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig71_HTML.png)
图 6-71
图像细节步骤 71
1. 遵循图 6-71 所示的步骤。
![img/517807_1_En_6_Fig72_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig72_HTML.png)
图 6-72
图像细节步骤 72
1. 选择路径,如图 6-72 所示。
![img/517807_1_En_6_Fig73_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig73_HTML.png)
图 6-73
图像细节步骤 73
1. 在这里,您列出了要替换变量的文件的详细信息,该变量是容器注册表名称。见图 6-73 。
![img/517807_1_En_6_Fig74_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig74_HTML.png)
图 6-74
图像细节步骤 74
1. 转到变量,点击添加按钮,如图 6-74 所示。
![img/517807_1_En_6_Fig75_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig75_HTML.png)
图 6-75
图像细节步骤 75
1. 添加ÁCR 作为新的变量名,添加来自 Azure 门户的 ACR 登录服务器 URL 作为值,如图 6-75 所示。
![img/517807_1_En_6_Fig76_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig76_HTML.png)
图 6-76
图像细节步骤 76
1. 在 Azure Portal 中,获取需要的 URL,如图 6-76 。
![img/517807_1_En_6_Fig77_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig77_HTML.png)
图 6-77
图像细节步骤 77
1. 粘贴变量名 ACR 的值,如图 6-77 所示。
![img/517807_1_En_6_Fig79_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig79_HTML.png)
图 6-79
图像细节步骤 79
![img/517807_1_En_6_Fig78_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig78_HTML.png)
图 6-78
图像细节步骤 78
1. 添加名为复制文件的新任务名称。遵循图 6-78 所示的步骤。
1. 这是一个构建管道,用于构建您的代码,构建的工件将被提供给发布管道以发布代码。使用复制文件任务复制构建的工件。但是在这里,您没有构建任何工件,因为您在构建管道中将图像发送到容器注册表。您需要 YAML,因此您使用这个任务复制它,并将其作为工件发布,以便在发布管道中使用。参见图 7-79 。
![img/517807_1_En_6_Fig80_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig80_HTML.png)
图 6-80
图像细节步骤 80
1. 添加另一个名为发布构建工件的任务名称。遵循图 6-80 所示的步骤。
![img/517807_1_En_6_Fig81_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig81_HTML.png)
图 6-81
图像细节步骤 81
1. 按照图 6-81 所示的步骤进行发布任务。
![img/517807_1_En_6_Fig82_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig82_HTML.png)
图 6-82
图像细节步骤 82
1. 进入触发器部分,通过勾选选项启用持续集成,如图 6-82 所示。
![img/517807_1_En_6_Fig83_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig83_HTML.png)
图 6-83
图像细节步骤 83
1. 遵循图 6-83 所示的步骤。
![img/517807_1_En_6_Fig84_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig84_HTML.png)
图 6-84
图像细节步骤 84
1. 现在你将创建释放管道,如图 6-84 所示。
![img/517807_1_En_6_Fig85_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig85_HTML.png)
图 6-85
图像细节步骤 85
1. 部署到一个 Kubernetes 集群任务,如图 6-85 所示。
![img/517807_1_En_6_Fig86_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig86_HTML.png)
图 6-86
图像细节步骤 86
1. 给它起个名字,如图 6-86 所示。
![img/517807_1_En_6_Fig87_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig87_HTML.png)
图 6-87
图像细节步骤 87
1. 遵循图 6-87 所示的步骤。
![img/517807_1_En_6_Fig88_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig88_HTML.png)
图 6-88
图像细节步骤 88
1. 选择构建,并以您在前面步骤中创建的构建管道作为源来呈现它。参见图 6-88 。
![img/517807_1_En_6_Fig89_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig89_HTML.png)
图 6-89
图像细节步骤 89
1. 点击高亮图标,启用持续部署触发器,如图 6-89 所示。
![img/517807_1_En_6_Fig90_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig90_HTML.png)
图 6-90
图像细节步骤 90
1. 使用开关将其激活,如图 6-90 所示。
![img/517807_1_En_6_Fig91_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig91_HTML.png)
图 6-91
图像细节步骤 91
1. 在“阶段”下,单击任务链接继续。见图 6-91 。
![img/517807_1_En_6_Fig92_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig92_HTML.png)
图 6-92
图像细节步骤 92
1. 针对该任务,单击 New 创建新的服务连接。见图 6-92 。
![img/517807_1_En_6_Fig93_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig93_HTML.png)
图 6-93
图像细节步骤 93
1. 选择 Azure 订阅作为身份验证方法,并选择订阅、资源组和命名空间作为默认值。输入服务连接的名称,然后单击保存。见图 6-93 。
![img/517807_1_En_6_Fig94_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig94_HTML.png)
图 6-94
图像细节步骤 94
1. 继续细节,如图 6-94 所示。
![img/517807_1_En_6_Fig95_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig95_HTML.png)
图 6-95
图像细节步骤 95
1. 这项任务将把容器部署到 Kubernetes 中,这可以使用您在构建管道中发布的 YAML 文件中编写的指令来完成。提供您在构建任务中复制的 YAML 文件的路径,而不是文件路径。见图 6-95 。
![img/517807_1_En_6_Fig96_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig96_HTML.png)
图 6-96
图像细节步骤 96
1. 输入秘密详情,如图 6-96 所示。
![img/517807_1_En_6_Fig97_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig97_HTML.png)
图 6-97
图像细节步骤 97
1. 选择最新版本以确保部署工作正常。见图 6-97 。
![img/517807_1_En_6_Fig98_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig98_HTML.png)
图 6-98
图像细节步骤 98
1. 当通过更改应用的源代码将容器应用的下一个版本部署到 Kubernetes 中时,您应该获得最新的容器应用。要做到这一点,可以使用 Kubectl `set`命令来设置容器的版本;见图 6-98 。
![img/517807_1_En_6_Fig99_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig99_HTML.png)
图 6-99
图像细节步骤 99
1. 增加如图 6-99 所示的强制细节。
![img/517807_1_En_6_Fig100_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig100_HTML.png)
图 6-100
图像细节步骤 100
1. 因为每次构建都会创建一个新版本的容器,所以使用带有 Kubectl `set`命令的构建 ID 变量来设置构建的镜像的相同版本,作为要在 Kubernetes 中部署的镜像的最新版本。参见图 6-100 。
![img/517807_1_En_6_Fig101_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig101_HTML.png)
图 6-101
图像细节步骤 101
1. 转到变量部分,添加名为 ACR 的变量名。使用相同的 ACR 服务器 DNS。参见图 6-101 。
![img/517807_1_En_6_Fig102_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig102_HTML.png)
图 6-102
图像细节步骤 102
1. 遵循图 6-102 所示的步骤。
![img/517807_1_En_6_Fig103_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig103_HTML.png)
图 6-103
图像细节步骤 103
1. 现在你将对应用做一个小小的改动,如图 6-103 所示。
![img/517807_1_En_6_Fig104_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig104_HTML.png)
图 6-104
图像细节步骤 104
1. 对`Index.chtml`文件进行更改;参见图 6-104 。
![img/517807_1_En_6_Fig105_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig105_HTML.png)
图 6-105
图像细节步骤 105
1. 添加相关注释,然后提交并推送更改,如图 6-105 所示。
![img/517807_1_En_6_Fig106_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig106_HTML.png)
图 6-106
图像细节步骤 106
1. 您可以在 Pipelines 部分下查看添加的注释和更改,如图 6-106 所示。
![img/517807_1_En_6_Fig107_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig107_HTML.png)
图 6-107
图像细节步骤 107
1. 验证更改。参见图 6-107 。
![img/517807_1_En_6_Fig108_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig108_HTML.png)
图 6-108
图像细节步骤 108
1. 单击并检查状态。参见图 6-108 。
![img/517807_1_En_6_Fig109_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig109_HTML.png)
图 6-109
图像细节步骤 109
1. 您可以查看所有任务的执行情况;参见图 6-109 。
![img/517807_1_En_6_Fig110_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig110_HTML.png)
图 6-110
图像细节步骤 110
1. 转到 Azure Portal 并验证用标签推送的更改。它们可以通过选择容器注册➤服务➤仓库看到。参见图 6-110 。
![img/517807_1_En_6_Fig111_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig111_HTML.png)
图 6-111
图像细节步骤 111
1. 现在在 Azure DevOps 门户中,在 Release 下,可以看到需要部署的相关变更的细节。参见图 6-111 。
![img/517807_1_En_6_Fig112_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig112_HTML.png)
图 6-112
图像细节步骤 112
1. 可以查看部署进度。参见图 6-112 。
![img/517807_1_En_6_Fig113_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig113_HTML.png)
图 6-113
图像细节步骤 113
1. 通过点击日志,您可以看到正在执行的步骤。参见图 6-113 。
![img/517807_1_En_6_Fig114_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig114_HTML.png)
图 6-114
图像细节步骤 114
1. 从 Azure 门户中,选择 Kubernetes 服务。在 Kubernetes 资源部分下,选择工作负载。在“部署”下,将列出最新的部署。参见图 6-114 。
![img/517807_1_En_6_Fig115_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig115_HTML.png)
图 6-115
图像细节步骤 115
1. 单击列出的部署以查看更多详细信息。参见图 6-115 。
![img/517807_1_En_6_Fig117_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig117_HTML.png)
图 6-117
图像细节步骤 117
![img/517807_1_En_6_Fig116_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig116_HTML.png)
图 6-116
图像细节步骤 116
1. 单击概述,然后单击连接,查看使用 Azure CLI 和示例命令连接群集的方式。按照图 6-116 所示步骤,使用云壳连接 AKS。
1. 复制并输入如图 6-117 所示的命令。您可以托管外部 IP。
![img/517807_1_En_6_Fig118_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig118_HTML.png)
图 6-118
图像细节步骤 118
1. 在浏览器中输入 IP 并查看托管的应用。参见图 6-118 。
![img/517807_1_En_6_Fig119_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig119_HTML.png)
图 6-119
图像细节步骤 119
1. 现在,一旦验证了 CI/CD 实施。参见图 6-119 。
![img/517807_1_En_6_Fig120_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig120_HTML.png)
图 6-120
图像细节步骤 120
1. 对`index`文件做小改动,如图 6-120 所示。
![img/517807_1_En_6_Fig121_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig121_HTML.png)
图 6-121
图像细节步骤 121
1. 提交并推动新的变革。参见图 6-121 。
![img/517807_1_En_6_Fig122_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig122_HTML.png)
图 6-122
图像细节步骤 122
1. 在 GitHub 上也可以看到变化,如图 6-122 。
![img/517807_1_En_6_Fig123_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig123_HTML.png)
图 6-123
图像细节步骤 123
1. 当然,你可以在 Azure DevOps Portal 中的 Pipelines 下查看这些变化,如图 6-123 所示。
![img/517807_1_En_6_Fig124_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig124_HTML.png)
图 6-124
图像细节步骤 124
1. 在 Releases 下,您可以看到部署已经成功。这是因为我启用了持续部署触发器。参见图 6-124 。
![img/517807_1_En_6_Fig125_HTML.png](https://gitee.com/OpenDocCN/vkdoc-devops-zh/raw/master/docs/azure-k8s-svc-microsvc/img/517807_1_En_6_Fig125_HTML.png)
图 6-125
图像细节步骤 125
1. 在浏览器中,刷新页面以验证更改。参见图 6-125 。
您可以看到,应用已经启动并运行良好,只是做了一些更改。& # x1F60A
## 摘要
如果您遵循了本章中的步骤,CI/CD 将在您的 web 应用中成功实现。这是一个好主意,密切遵循这些步骤两到三次。现在,作为练习的一部分,尝试部署一个 web API,而不是 Web 应用。在构建过程中,您只需更改很少的几个步骤。让我知道你是如何通过本章和其他章节的循序渐进的方法来学习的。我希望这本书加快了你对 Azure Kubernetes 服务的学习之旅。感谢您在学习过程中阅读本书。祝你好运,祝你 Azure 学习愉快。