架构师的-Azure-指南第三版-全-
架构师的 Azure 指南第三版(全)
原文:
annas-archive.org/md5/0b3cfce43ce7ffb62c4f01cafdc66996
译者:飞龙
序言
关于本书
本节简要介绍了作者、书籍的覆盖内容、开始时所需的技术技能以及使用 Azure 架构解决方案所需的硬件和软件要求。
关于《Azure for Architects》第三版
由于其对高可用性、可扩展性、安全性、性能和灾难恢复的支持,Azure 已广泛应用于轻松创建和部署各种类型的应用程序。更新了最新发展的《Azure for Architects》第三版帮助你掌握设计无服务器架构的核心概念,包括容器、Kubernetes 部署和大数据解决方案。你将学习如何架构诸如无服务器功能等解决方案,发现容器和 Kubernetes 的部署模式,并探索使用 Spark 和 Databricks 进行大规模大数据处理。随着深入,你将使用 Azure DevOps 实现 DevOps,利用 Azure Cognitive Services 工作智能解决方案,并将安全性、高可用性和可扩展性集成到每个解决方案中。最后,你将深入了解 Azure 安全概念,如 OAuth、OpenConnect 和托管身份。
到本书结束时,你将有信心基于容器和无服务器功能设计智能的 Azure 解决方案。
作者简介
Ritesh Modi 是微软前高级技术布道者。他因对微软产品、服务和社区的贡献被认定为微软区域总监。他是一位云架构师、出版作者、演讲者和领导者,因其在数据中心、Azure、Kubernetes、区块链、认知服务、DevOps、人工智能和自动化方面的贡献而广受欢迎。他是八本书的作者。
Ritesh 曾在众多国内外会议上发表演讲,并且是 MSDN 杂志的出版作者。他在为客户构建和部署企业解决方案方面有超过十年的经验,并且拥有超过 25 项技术认证。他的爱好包括写书、和女儿玩耍、看电影以及学习新技术。他目前居住在印度海得拉巴。你可以在 Twitter 上关注他,账号是 @automationnext。
Jack Lee 是一位高级 Azure 认证顾问和 Azure 实践负责人,对软件开发、云计算和 DevOps 创新充满热情。Jack 因其对技术社区的贡献而被评为微软 MVP。他曾在多个用户组和会议上发表演讲,包括微软加拿大的全球 Azure 启动营。Jack 是一位经验丰富的导师和黑客松评审员,同时也是一个专注于 Azure、DevOps 和软件开发的用户组的主席。他是《Cloud Analytics with Microsoft Azure》一书的合著者,出版方为 Packt Publishing。你可以在 Twitter 上关注 Jack,账号是 @jlee_consulting。
Rithin Skaria 是一名开源倡导者,拥有超过 7 年的在 Azure、AWS 和 OpenStack 上管理开源工作负载的经验。他目前在微软工作,并参与了微软内多项开源社区活动。他是微软认证培训师、Linux 基金会认证工程师和管理员、Kubernetes 应用开发者和管理员,以及认证 OpenStack 管理员。在 Azure 方面,他拥有四项认证(解决方案架构、Azure 管理、DevOps 和安全),同时他也获得了 Office 365 管理认证。他在多个开源部署中扮演了重要角色,并负责这些工作负载向云平台的管理和迁移。他还是Linux Administration on Azure一书的合著者,书籍由 Packt 出版。通过 LinkedIn 可以联系他,账号为@rithin-skaria。
审稿人简介
Melony Qin 是一位从事 STEM 领域的女性。目前,她在微软担任项目经理,并且是计算机协会(ACM)和项目管理协会(PMI)的成员。她曾在微软 Azure 平台上贡献于无服务器计算、大数据处理、DevOps、人工智能、机器学习和物联网(IoT)等领域。她拥有所有 Azure 认证(包括应用与基础设施轨道和数据与 AI 轨道),以及认证 Kubernetes 管理员(CKA)和认证 Kubernetes 应用开发者(CKAD)证书,目前主要专注于在社区中为开源软件(OSS)、DevOps、Kubernetes、无服务器、大数据分析和物联网等领域做出贡献。她是两本书的作者和合著者,分别是Microsoft Azure Infrastructure和The Kubernetes Workshop,这两本书均由 Packt 出版。她可以通过 Twitter 与人联系,账号为@MelonyQ。
Sanjeev Kumar 是微软 Azure 上 SAP 云解决方案架构师。他目前居住在瑞士苏黎世,拥有超过 19 年的 SAP 技术经验。在过去的 8 年里,他一直在公共云技术领域工作,其中最近 2 年专注于微软 Azure。
在担任 SAP on Azure 云架构顾问的角色时,Sanjeev Kumar 与许多世界顶级的金融服务和制造公司合作。他的关注领域包括云架构和设计,帮助客户将 SAP 系统迁移到 Azure,并采用 Azure 最佳实践进行 SAP 部署,特别是在实施基础设施即代码(Infrastructure as Code)和 DevOps 方面。他还在使用 Docker 和 Azure Kubernetes Service 进行容器化和微服务、使用 Apache Kafka 进行流数据处理以及使用 Node.js 进行全栈应用开发等方面有丰富经验。他参与了涉及 IaaS、PaaS 和 SaaS 的各种产品开发工作。他还对人工智能、机器学习以及大规模数据处理和分析等新兴领域感兴趣。他在 LinkedIn 上撰写有关 SAP on Azure、DevOps 和基础设施即代码的文章,你可以在@sanjeevkumarprofile找到他。
学习目标
在本书结束时,你将能够:
-
了解 Azure 云平台的组件
-
使用云设计模式
-
使用企业安全指南进行 Azure 部署
-
设计并实现无服务器和集成解决方案
-
在 Azure 上构建高效的数据解决方案
-
了解 Azure 上的容器服务
目标读者
如果你是云架构师、DevOps 工程师或开发人员,想要了解 Azure 云平台的关键架构方面,本书适合你。对 Azure 云平台的基本理解将帮助你更有效地掌握本书中的概念。
方法
本书通过逐步讲解关键概念、实际示例和自我评估问题,涵盖了每个主题。通过理论和实际操作经验的平衡,本书将帮助你理解架构师在现实世界中的工作方式。
硬件要求
为了获得最佳体验,我们建议以下配置:
-
最少 4GB RAM
-
最少 32GB 的空闲内存
软件要求
-
Visual Studio 2019
-
Docker for Windows 最新版本
-
AZ PowerShell 模块 1.7 及以上版本
-
Azure CLI 最新版本
-
Azure 订阅
-
Windows Server 2016/2019
-
Windows 10 最新版本 - 64 位
约定
文本中的代码字、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL 和用户输入如下所示:
DSC 配置仍未被 Azure Automation 识别。它在某些本地机器上可用,应该上传到 Azure Automation DSC 配置中。Azure Automation 提供了Import-AzureRMAutomationDscConfiguration
cmdlet 用于将配置导入到 Azure Automation:
Import-AzureRmAutomationDscConfiguration -SourcePath "C:\DSC\AA\DSCfiles\ConfigureSiteOnIIS.ps1" -ResourceGroupName "omsauto" -AutomationAccountName "datacenterautomation" -Published -Verbose
下载资源
本书的代码包也托管在 GitHub 上,地址为:github.com/PacktPublishing/Azure-for-Architects-Third-Edition
。
我们还有其他代码包,来自我们丰富的书籍和视频目录,您可以在github.com/PacktPublishing
找到。快去看看吧!
第一章:1. 开始使用 Azure
每隔几年,就会出现一种技术创新,它会永久性地改变整个周围的格局和生态系统。如果我们追溯历史,1970 年代和 1980 年代是大型主机的时代。这些大型主机体积庞大,通常占据整间房间,几乎承担了所有计算工作。由于技术难以采购且使用繁琐,许多企业曾经需要提前一个月下订单,才能确保安装好可用的大型主机。
然后,1990 年代初期见证了个人计算和互联网需求的激增。因此,计算机变得更小,且相对容易为大众采购。个人计算和互联网领域的不断创新最终改变了整个计算机行业。许多人拥有能够运行多个程序并连接互联网的台式计算机。互联网的崛起也推动了客户端-服务器部署模式的兴起。现在可以有集中式服务器托管应用程序,任何有互联网连接的人都可以访问这些服务,世界任何地方的人都可以实现这一点。这也是服务器技术获得重要地位的时期;Windows NT 就是在这个时期发布的,随后是 Windows 2000 和 Windows 2003,它们分别出现在世纪之交。
2000 年代最显著的创新是便携设备的崛起和普及,尤其是智能手机,随之而来的是大量的应用程序。应用程序可以连接到互联网上的集中式服务器,并照常开展业务。用户不再依赖浏览器来完成这项工作;所有的服务器要么是自托管的,要么是通过服务提供商托管的,例如互联网服务提供商(ISP)。
用户对其服务器的控制权有限。多个客户及其部署共用同一台服务器,甚至客户并不知情。
然而,在 2000 年代初期和中期发生了另一件事,那就是云计算的崛起,它再次重塑了整个 IT 行业的格局。最初,云计算的采用速度较慢,人们对其持谨慎态度,原因要么是云计算处于初期阶段,还需要成熟,要么是人们对其存在各种负面看法。
为了更好地理解这种颠覆性技术,我们将在本章中介绍以下主题:
-
云计算
-
基础设施即服务(IaaS)、平台即服务(PaaS)和软件即服务(SaaS)
-
理解 Azure
-
Azure 资源管理器(ARM)
-
虚拟化、容器与 Docker
-
与智能云互动
云计算
今天,云计算是最有前景的技术之一,无论大小企业都在将其作为其 IT 战略的一部分。如今,很难进行任何有意义的 IT 战略讨论而不将云计算纳入整体解决方案讨论。
云计算,通俗来说就是“云”,指的是互联网资源的可用性。这些资源作为服务通过互联网提供给用户。例如,存储可以通过互联网按需提供,供用户存储文件、文档等。在这里,存储是由云服务提供商提供的一种服务。
云服务提供商是提供云服务给其他企业和消费者的公司或公司联盟。它们代表用户托管和管理这些服务,负责启用和维护服务的健康运行。全球各地的多个大型数据中心已经由云服务提供商开设,以满足用户的 IT 需求。
云资源包括按需基础设施的托管服务,如计算基础设施、网络和存储设施。这种云类型被称为 IaaS。
云计算的优势
云计算的采用率达到了历史最高水平,并且因以下几个优势而不断增长:
-
按需付费模式:客户无需购买硬件和软件来使用云资源。使用云资源不需要资本支出;客户只需为使用或预留资源的时间付费。
-
全球访问:云资源通过互联网在全球范围内可用。客户可以随时随地按需访问他们的资源。
-
无限资源:云技术的扩展能力是无限的;客户可以根据需要配置任何数量的资源,且没有任何限制。这也被称为无限扩展性。
-
托管服务:云服务提供商提供许多由他们为客户管理的服务。这可以减轻客户的技术和财务负担。
为什么选择云计算?
为了理解云计算的必要性,我们必须理解行业的视角。
灵活性和敏捷性
今天,应用程序并不是采用“大爆炸”式的部署方法创建的庞大单体应用,而是通过微服务范式由较小的服务组成。微服务帮助以独立和自主的方式创建服务,可以在隔离的状态下演化,而不会导致整个应用程序崩溃。它们在将变更快速而更好的带入生产过程中提供了极大的灵活性和敏捷性。许多微服务共同构成一个应用程序,并为客户提供集成的解决方案。这些微服务应当是可发现的,并具有明确的集成端点。与传统单体应用程序相比,微服务方法的集成数量非常高。这些集成在应用程序的开发和部署中增加了复杂性。
速度、标准化和一致性
因此,部署的方法论也应当进行调整,以适应这些服务的需求,也就是说,频繁的变更和频繁的部署。对于频繁的变更和部署,使用有助于以可预测且一致的方式进行这些变更的流程非常重要。应当使用自动化的敏捷流程,使得较小的变更可以被隔离地部署和测试。
保持相关性
最后,部署目标应当重新定义。部署目标不仅应当能够在几秒钟内轻松创建,而且构建的环境应该在各个版本间保持一致,具备适当的二进制文件、运行时、框架和配置。单体应用使用虚拟机,但微服务需要比虚拟机更具敏捷性、灵活性和更轻量化的选项。容器技术是这些服务的首选部署目标机制,我们将在本章稍后讨论更多相关内容。
可扩展性
使用微服务的一些重要原则是它们在隔离状态下具有无限的扩展能力、全球高可用性、近乎零恢复点的灾难恢复能力和时间目标。微服务的这些特性需要可以无限扩展的基础设施。不应有任何资源限制。虽然如此,组织在未使用资源时,也不应提前支付资源费用。
成本效益
按照使用的资源付费,并通过自动增加或减少资源数量和容量来优化使用,是云计算的基本原则。这些新兴的应用需求要求云作为首选平台,能够轻松扩展,具有高可用性,抗灾能力强,能够轻松引入变更,并以成本效益高的方式实现可预测和一致的自动化部署。
Azure 中的部署范式
在 Azure 中有三种不同的部署模式,具体如下:
-
IaaS
-
PaaS
-
SaaS
这三种部署模式之间的区别在于客户通过 Azure 行使控制的级别。图 1.1 显示了每种部署模式中不同的控制级别:
图 1.1:云服务——IaaS、PaaS 和 SaaS
从图 1.1可以明显看出,使用 IaaS 部署时,客户拥有更多的控制权,而随着从 PaaS 到 SaaS 部署的推进,控制级别逐渐降低。
IaaS
IaaS 是一种部署模型,允许客户在 Azure 上配置自己的基础设施。Azure 提供了多种基础设施资源,客户可以按需配置它们。客户负责维护和管理自己的基础设施。Azure 会确保托管这些虚拟基础设施资源的物理基础设施得到维护。在这种模式下,客户需要在 Azure 环境中进行积极的管理和操作。
PaaS
PaaS 将基础设施部署和控制权从客户手中移除。相较于 IaaS,这是一种更高级的抽象模式。在这种方式中,客户将自己的应用、代码和数据引入并部署到 Azure 提供的平台上。这些平台由 Azure 管理和治理,客户仅对其应用程序负责。客户只需进行与应用部署相关的活动。相比于 IaaS,这种模式为应用的部署提供了更快速、更便捷的选项。
SaaS
SaaS 是一种相较于 PaaS 更高级的抽象模式。在这种方式中,软件及其服务可以供客户使用。客户只需将数据引入这些服务中——他们无法控制这些服务。现在我们已经对 Azure 中的服务类型有了基本了解,接下来让我们深入了解 Azure,从基础开始理解它。
理解 Azure
Azure 提供了云的所有好处,同时保持开放和灵活。Azure 支持多种操作系统、编程语言、工具、平台、实用程序和框架。例如,它支持 Linux 和 Windows、SQL Server、MySQL 和 PostgreSQL。它支持大多数编程语言,包括 C#、Python、Java、Node.js 和 Bash。它支持 NoSQL 数据库,如 MongoDB 和 Cosmos DB,并且还支持持续集成工具,如 Jenkins 和 Azure DevOps Services(前身是Visual Studio Team Services(VSTS))。这个生态系统的核心思想是使客户能够自由选择自己的语言、平台、操作系统、数据库、存储以及工具和实用程序。客户不应该受到技术方面的限制;相反,他们应该能够构建并专注于他们的业务解决方案,而 Azure 为他们提供了一个世界级的技术栈供其使用。
Azure 与客户选择的技术栈高度兼容。例如,Azure 支持所有流行的(开源和商业)数据库环境。Azure 提供 Azure SQL、MySQL 和 Postgres 的 PaaS 服务。它提供了 Hadoop 生态系统,并提供基于 100% Apache Hadoop 的 PaaS 服务 HDInsight。它还为那些更倾向于 IaaS 方法的客户提供了基于 Linux 的 Hadoop 虚拟机(VM)实现。Azure 还提供 Redis 缓存服务,并支持其他流行的数据库环境,如 Cassandra、Couchbase 和 Oracle,作为 IaaS 实现。
Azure 上的服务数量日益增加,最新的服务列表可以在 azure.microsoft.com/services
找到。
Azure 还提供了一种独特的云计算范式——混合云。混合云指的是一种部署策略,其中一部分服务部署在公共云上,而其他服务则部署在本地私有云或数据中心。公共云和私有云之间通过虚拟专用网络(VPN)连接。Azure 为客户提供了将工作负载划分并同时部署在公共云和本地数据中心的灵活性。
Azure 在全球范围内拥有数据中心,并将这些数据中心组合成区域。每个区域都有多个数据中心,以确保灾难恢复迅速高效。到目前为止,全球已有 58 个区域。这为客户提供了在选择的位置部署服务的灵活性。客户还可以结合这些区域,部署灾难恢复能力强且靠近客户群的解决方案。
注意
在中国和德国,Azure 云服务在普通使用和政府使用方面是分开的。这意味着云服务在不同的数据中心进行维护。
Azure 作为智能云
Azure 提供基础设施和服务,利用超大规模处理技术处理数十亿的事务。它为数据提供了 PB 级的存储,并提供了大量互联的服务,可以在它们之间传递数据。凭借这样的能力,数据可以被处理以生成有意义的知识和见解。通过数据分析可以生成多种类型的见解,具体如下:
-
描述性:这种类型的分析提供关于正在发生或过去发生的事情的详细信息。
-
预测性:这种类型的分析提供有关未来将要发生的事情的详细信息。
-
规范性:这种类型的分析提供有关应采取什么措施来增强或防止当前或未来事件的详细信息。
-
认知性:这种类型的分析实际上执行由规范性分析确定的自动化操作。
尽管从数据中提取见解非常重要,但同样重要的是根据这些见解采取行动。Azure 提供了一个强大的平台,用于摄取大量数据、处理和转换数据、存储并生成见解,并将其显示在实时仪表板上。还可以根据这些见解自动采取行动。这些服务面向所有 Azure 客户提供,形成了一个丰富的生态系统,客户可以在其中创建解决方案。由于 Azure 提供的智能服务的易得性,企业正在创建大量的应用程序和服务,完全颠覆了行业,这些服务结合起来为最终客户创造了有意义的价值。Azure 确保那些对中小型公司来说商业上不可行的服务,现在可以轻松消费并在几分钟内部署。
Azure 资源管理器
Azure 资源管理器 (ARM) 是微软的技术平台和编排服务,将之前讨论的所有组件结合起来。它将 Azure 的资源提供者、资源和资源组结合起来,形成一个统一的云平台。它使 Azure 服务以订阅的形式提供,资源类型以资源组的形式提供,并使资源和资源 API 可供门户和其他客户端访问,同时进行身份验证以访问这些资源。它还启用了如标签、身份验证、基于角色的访问控制 (RBAC)、资源锁定和策略执行等功能,用于订阅及其资源组的管理。它还通过 Azure 门户、Azure PowerShell 和 命令行接口 (CLI) 工具提供部署和管理功能。
ARM 架构
ARM 架构及其组件如图 1.2所示。如我们所见,Azure 订阅由多个资源组组成。每个资源组包含从资源提供者中可用的资源类型创建的资源实例:
图 1.2:ARM 架构
为什么选择 ARM?
在 ARM 之前,Azure 使用的框架被称为Azure 服务管理器(ASM)。了解 ASM 的一些基本情况非常重要,这样我们才能清楚地理解 ARM 的出现,以及 ASM 的逐步弃用过程。
ASM 的限制
ASM 存在固有的限制。例如,ASM 部署较慢且会被阻塞——如果前一个操作正在进行,后续操作将会被阻塞。ASM 的一些限制如下:
-
并行性:并行性在 ASM 中是一个挑战。无法成功地并行执行多个事务。ASM 中的操作是线性的,依次执行。如果同时执行多个事务,将会出现并行操作错误或事务被阻塞。
-
资源:ASM 中的资源是相互独立地进行配置和管理的;ASM 资源之间没有关系。无法将服务和资源进行分组或一起配置。
-
云服务:云服务是 ASM 中的部署单元。它们依赖于亲和性组,并且由于设计和架构的原因,无法进行扩展。
无法为 ASM 中的资源分配细粒度和独立的角色和权限。客户要么是服务管理员,要么是订阅中的共同管理员。客户要么对资源拥有完全控制权限,要么根本无法访问这些资源。ASM 不提供部署支持。要么需要手动进行部署,要么需要编写.NET 或 PowerShell 脚本进行自动化。ASM 的 API 在不同资源之间并不一致。
ARM 的优势
ARM 相比于 ASM 提供了明显的优势,具体如下:
-
分组:ARM 允许将资源逻辑上分组到一个容器中。这些资源可以一起管理,并作为一个整体经历共同的生命周期。这样更容易识别相关和依赖的资源。
-
共同生命周期:分组中的资源具有相同的生命周期。这些资源可以一起发展并作为一个单位进行管理。
-
RBAC:可以为资源分配细粒度的角色和权限,从而为客户提供独立的访问权限。客户也只能拥有分配给他们的那些权限。
-
部署支持:ARM 通过模板提供部署支持,支持 DevOps 和基础设施即代码(IaC)。这些部署速度更快、一致且可预测。
-
更优的技术:资源的成本和计费可以作为一个单位进行管理。每个资源组可以提供其使用情况和成本信息。
-
可管理性:ARM 提供了高级功能,如安全性、监控、审计和标记,以便更好地管理资源。可以根据标签查询资源。标签还提供了类似标签资源的成本和计费信息。
-
迁移:在资源组内部和跨资源组迁移和更新资源变得更容易。
ARM 概念
使用 ARM,Azure 中的一切都是资源。资源的例子包括虚拟机(VM)、网络接口、公有 IP 地址、存储帐户和虚拟网络。ARM 基于与资源提供者和资源消费者相关的概念。Azure 通过多个资源提供者提供资源和服务,这些资源和服务在组内被消费和部署。
资源提供者
这些是通过 ARM 提供资源类型的服务。ARM 中的顶级概念是资源提供者。资源提供者是资源类型的容器。资源类型被分组到资源提供者中。它们负责部署和管理资源。例如,虚拟机资源类型由名为 Microsoft.Compute/virtualMachines 的资源提供者提供。表述性状态传输(REST)API 操作已版本化,以便区分它们。版本命名基于它们由 Microsoft 发布的日期。为部署资源,相关的资源提供者必须在订阅中可用。并非所有资源提供者在默认情况下都可用。如果某个资源在订阅中不可用,我们需要检查所需的资源提供者是否在每个区域中可用。如果可用,客户可以明确地为该订阅注册。
资源类型
资源类型是定义资源公共 API 接口和实现的实际资源规范。它们实现资源所支持的工作和操作。与资源提供者类似,资源类型在其内部实现方面也会随着时间的推移而发展,并且有多个版本的架构和公共 API 接口。版本名称基于它们由 Microsoft 作为预览或正式发布(GA)的日期。资源类型在资源提供者注册之后作为订阅可用。此外,并非每个资源类型都在每个 Azure 区域中可用。资源的可用性取决于资源提供者在 Azure 区域的可用性和注册情况,并且必须支持为其提供所需的 API 版本。
资源组
资源组是 ARM 中的部署单元。它们是将多个资源实例组合在一起的容器,并具有安全性和管理边界。资源组在一个订阅中具有唯一名称。资源可以部署在不同的 Azure 区域,但仍然属于同一个资源组。资源组为其中的所有资源提供附加服务。资源组提供元数据服务,例如标签功能,用于对资源进行分类;基于策略的资源管理;RBAC(基于角色的访问控制);保护资源免受意外删除或更新等。如前所述,资源组具有安全边界,无法访问资源组的用户也无法访问其中包含的资源。每个资源实例都需要属于一个资源组,否则无法进行部署。
资源和资源实例
资源是由资源类型创建的,是资源类型的实例。一个实例可以在全球范围内唯一,或者在资源组级别唯一。唯一性由资源的名称和类型共同定义。如果将其与面向对象编程结构进行比较,资源实例可以视为对象,而资源类型则可以视为类。服务通过资源实例所支持和实现的操作进行消费。资源类型定义了属性,每个实例在实例配置时应配置强制性的属性。有些是强制性的属性,而其他则是可选的。资源实例继承其父资源组的安全性和访问配置。这些继承的权限和角色分配可以被覆盖到每个资源。可以以某种方式锁定资源,从而阻止某些操作,使其即使对角色、用户和组具有访问权限,也无法使用。资源可以被标记,以便于发现和管理。
ARM 特性
下面是 ARM 提供的一些主要功能:
-
RBAC:Azure Active Directory(Azure AD)认证用户以提供对订阅、资源组和资源的访问。ARM 在平台中实现 OAuth 和 RBAC,基于分配给用户或组的角色,启用对资源、资源组和订阅的授权和访问控制。权限定义了对资源操作的访问。这些权限可以允许或拒绝对资源的访问。角色定义是这些权限的集合。角色将 Azure AD 用户和组映射到特定权限。角色随后被分配到某个范围;这个范围可以是单个用户、一组资源、资源组或订阅。添加到角色中的 Azure AD 身份(用户、组和服务主体)根据角色中定义的权限访问资源。ARM 提供多个开箱即用的角色,包括系统角色,如所有者、贡献者和阅读者。它还提供基于资源的角色,如 SQL 数据库贡献者和虚拟机贡献者。ARM 还允许创建自定义角色。
-
标签:标签是名称-值对,向资源添加额外的信息和元数据。资源和资源组都可以使用多个标签。标签有助于资源的分类,从而提升可发现性和可管理性。资源可以快速搜索并轻松识别。还可以获取具有相同标签的资源的计费和成本信息。尽管此功能由 ARM 提供,但 IT 管理员会根据资源和资源组定义其使用和分类。分类和标签可以与部门、资源使用、位置、项目或从成本、使用、计费或搜索角度来看被认为合适的其他标准相关。这些标签随后可以应用于资源。在资源组级别定义的标签不会被其资源继承。
-
策略:ARM 提供的另一项安全功能是自定义策略。可以创建自定义策略来控制对资源的访问。策略被定义为约定和规则,在与资源和资源组交互时必须遵守这些规则。策略定义明确禁止对资源的操作或访问。默认情况下,所有未在策略定义中提及的访问都会被允许。这些策略定义被分配到资源、资源组和订阅范围内。需要注意的是,这些策略并不是 RBAC 的替代品或替换品。实际上,它们与 RBAC 互补并协同工作。策略会在用户通过 Azure AD 进行身份验证并通过 RBAC 服务授权后进行评估。ARM 提供了一种基于 JSON 的策略定义语言来定义策略。一些策略定义的示例包括:必须对每个已配置的资源进行标签,并且资源只能在特定的 Azure 区域进行配置。
-
锁定:可以对订阅、资源组和资源进行锁定,以防止经过身份验证的用户意外删除或更新。应用于更高层级的锁定会向下流向子资源。或者,应用于订阅级别的锁定会锁定每个资源组及其中的资源。
-
多区域:Azure 提供多个区域来配置和托管资源。ARM 允许在不同位置配置资源,同时仍然位于同一个资源组内。一个资源组可以包含来自不同区域的资源。
-
幂等:此功能通过确保每次部署都能导致资源和配置处于相同的状态,无论执行多少次,从而确保资源部署的可预测性、标准化和一致性。
-
可扩展:ARM 提供了一个可扩展的架构,允许在平台上创建和插入新的资源提供程序和资源类型。
虚拟化
虚拟化是一项突破性的创新,它彻底改变了对物理服务器的看法。它是将物理对象抽象为逻辑对象的过程。
物理服务器的虚拟化导致了被称为虚拟机(VM)的虚拟服务器。这些虚拟机共享并使用托管它们的物理服务器的 CPU、内存、存储和其他硬件。这使得按需提供应用环境变得更快、更容易,提供了高可用性和可扩展性,并且降低了成本。一个物理服务器就足以托管多个虚拟机,每个虚拟机都有自己的操作系统并在其上托管服务。
不再需要购买额外的物理服务器来部署新的应用程序和服务。现有的物理服务器足以托管更多的虚拟机。此外,通过虚拟化的帮助,许多物理服务器被整合为少数几台,以实现合理化。
每个虚拟机都包含整个操作系统,并且每个虚拟机与其他虚拟机完全隔离,包括物理主机。虽然虚拟机使用宿主物理服务器提供的硬件,但它对其分配的资源和环境拥有完全控制权。这些虚拟机可以托管在如物理服务器等网络上,并拥有自己的身份。
Azure 可以在几分钟内创建 Linux 和 Windows 虚拟机。微软提供了自己的镜像,以及来自其合作伙伴和社区的镜像;用户也可以提供自己的镜像。虚拟机使用这些镜像进行创建。
容器
容器也是一种虚拟化技术;然而,它们并不虚拟化服务器。相反,容器是操作系统级别的虚拟化。这意味着容器共享宿主操作系统内核(由宿主提供)以及宿主之间的内核。运行在宿主(物理或虚拟)上的多个容器共享宿主操作系统内核。容器确保它们复用宿主内核,而不是每个容器都有自己的独立内核。
容器与其宿主或运行在宿主上的其他容器完全隔离。Windows 容器使用 Windows 存储过滤驱动程序和会话隔离来隔离操作系统服务,如文件系统、注册表、进程和网络。即使在 Linux 宿主上运行的 Linux 容器也是如此。Linux 容器使用 Linux 命名空间、控制组和联合文件系统来虚拟化宿主操作系统。
容器看起来仿佛拥有一个全新且未被触及的操作系统和资源。这种安排带来了许多好处,诸如以下几点:
-
容器的快速配置时间远远少于虚拟机。容器中的大多数操作系统服务由宿主操作系统提供。
-
容器比虚拟机更轻量,所需的计算资源也更少。使用容器时,不再需要操作系统资源开销。
-
容器比虚拟机小得多。
-
容器能够以直观、自动化和简便的方式帮助解决与管理多个应用程序依赖关系相关的问题。
-
容器提供了基础设施,用于在一个地方定义所有应用程序的依赖关系。
容器是 Windows Server 2016 和 Windows 10 的固有特性;然而,它们是通过 Docker 客户端和 Docker 守护进程进行管理和访问的。可以在 Azure 上使用 Windows Server 2016 SKU 作为镜像来创建容器。每个容器都有一个必须保持运行的主进程,以确保容器的存在。当该进程结束时,容器将停止。此外,容器可以在交互模式下运行,也可以像服务一样在分离模式下运行:
图 1.3:容器架构
图 1.3 展示了启用容器的所有技术层。最底层提供了核心基础设施,包括网络、存储、负载均衡器和网络卡。在基础设施的顶部是计算层,由物理服务器或物理服务器上方的虚拟和物理服务器组成。此层包含能够托管容器的操作系统。操作系统提供了执行驱动程序,上层使用该驱动程序调用内核代码和对象来执行容器。微软为管理和创建容器而创建了 Host Container System Shim(HCSShim),并使用 Windows 存储过滤驱动程序进行镜像和文件管理。
容器环境隔离已在 Windows 会话中启用。Windows Server 2016 和 Nano Server 提供操作系统,启用容器功能,并执行用户级的 Docker 客户端和 Docker 引擎。Docker 引擎使用 HCSShim、存储过滤驱动程序和会话服务,在服务器上生成多个容器,每个容器中包含一个服务、应用程序或数据库。
Docker
Docker 为 Windows 容器提供管理功能。它包括以下两个可执行文件:
-
Docker 守护进程
-
Docker 客户端
Docker 守护进程是管理容器的核心工具。它是一个 Windows 服务,负责管理主机上与容器相关的所有活动。Docker 客户端与 Docker 守护进程进行交互,负责捕获输入并将其发送到 Docker 守护进程。Docker 守护进程提供运行时、库、图形驱动程序和引擎,用于创建、管理和监控主机服务器上的容器和镜像。它还能够创建用于构建和交付应用程序到多个环境的自定义镜像。
与智能云交互
Azure 提供多种连接、自动化和与智能云交互的方式。所有这些方法都需要用户在使用前通过有效凭据进行身份验证。连接 Azure 的不同方式如下:
-
Azure 门户
-
PowerShell
-
Azure CLI
-
Azure REST API
Azure 门户
Azure 门户是一个很好的入门平台。通过 Azure 门户,用户可以登录并开始手动创建和管理 Azure 资源。该门户通过浏览器提供直观、易于使用的用户界面。Azure 门户提供了一种便捷的方式,通过 blade 来导航资源。Blade 显示资源的所有属性,包括日志、费用、与其他资源的关系、标签、安全选项等。整个云部署都可以通过门户进行管理。
PowerShell
PowerShell 是一个基于对象的命令行外壳和脚本语言,用于基础设施和环境的管理、配置和控制。它建立在 .NET 框架之上,提供自动化功能。PowerShell 已真正成为 IT 管理员和自动化开发人员在管理和控制 Windows 环境中的第一选择。如今,几乎每个 Windows 环境和许多 Linux 环境都可以通过 PowerShell 进行管理。事实上,几乎每个 Azure 的方面也可以通过 PowerShell 管理。Azure 提供了对 PowerShell 的丰富支持,针对每个资源提供商都提供了 PowerShell 模块,其中包含数百个 cmdlet。用户可以在脚本中使用这些 cmdlet 来自动化与 Azure 的交互。Azure PowerShell 模块可以通过 Web 平台安装程序以及通过 PowerShellGet
模块快速、轻松地从 PowerShell Gallery 下载和安装 PowerShell 模块。PowerShellGet
模块提供了 Install-Module
cmdlet 用于在系统上下载和安装模块。
安装模块是一个简单的复制模块文件到定义好的模块位置的过程,具体操作如下:
Import-module PowerShellGet
Install-Module -Name az -verbose
Import-module
命令将模块及其相关功能导入当前执行范围,Install-Module
帮助安装模块。
Azure CLI
Azure 还提供了 Azure CLI 2.0,可以在 Linux、Windows 和 macOS 操作系统上部署。Azure CLI 2.0 是 Azure 的新命令行工具,用于管理 Azure 资源。Azure CLI 2.0 针对通过命令行管理和管理 Azure 资源进行了优化,适用于构建与 ARM 交互的自动化脚本。CLI 可以使用 Bash shell 或 Windows 命令行执行命令。Azure CLI 在非 Windows 用户中非常受欢迎,因为它允许在 Linux 和 macOS 上与 Azure 进行交互。Azure CLI 2.0 的安装步骤可以参考 docs.microsoft.com/cli/azure/install-azure-cli?view=azure-cli-latest
。
Azure REST API
所有 Azure 资源都通过 REST 端点暴露给用户。REST API 是服务端点,通过提供 创建、检索、更新 或 删除(CRUD)访问来实现 HTTP 操作(或方法)。用户可以使用这些 API 来创建和管理资源。实际上,CLI 和 PowerShell 机制内部使用这些 REST API 与 Azure 上的资源进行交互。
ARM 模板
在前面的部分中,我们讨论了 ARM 提供的部署特性,例如多服务、多区域、可扩展和幂等性等。ARM 模板是 ARM 中资源配置的主要方式,ARM 模板为 ARM 的部署特性提供了实现支持。
ARM 模板通过声明性模型来指定资源、其配置、脚本和扩展。ARM 模板基于 JavaScript 对象表示法(JSON)格式。它们使用 JSON 语法和约定来声明和配置资源。JSON 文件是基于文本的,用户友好且易于阅读的文件。
它们可以存储在源代码库中,并进行版本控制。它们也是表示基础设施即代码(IaC)的一种方式,可以反复、可预测且一致地用于在 Azure 资源组中配置资源。模板需要一个资源组来进行部署。它只能部署到资源组,并且资源组应在执行模板部署之前存在。模板无法创建资源组。
模板提供了在设计和实现中保持通用性和模块化的灵活性。模板允许接受用户输入的参数,声明内部变量,定义资源之间的依赖关系,链接同一资源组或不同资源组中的资源,并执行其他模板。它们还提供脚本语言类型的表达式和函数,使得模板在运行时具有动态性和可定制性。
部署
PowerShell 支持以下两种模板部署模式:
-
增量:增量部署会将模板中声明但在资源组中不存在的资源添加到资源组,将资源组中不属于模板定义的资源保持不变,并保持模板和资源组中都存在的资源(且配置状态相同)不变。
-
完整:完整部署模式则将模板中声明的资源添加到资源组中,从资源组中删除模板中不存在的资源,并保持在资源组和模板中都存在的资源(且配置状态相同)不变。
摘要
云计算是一个相对较新的范式,仍处于初期阶段。随着时间的推移,很多创新和功能将会加入其中。Azure 是目前领先的云服务提供商之一,它通过 IaaS、PaaS、SaaS 和混合部署提供了丰富的功能。事实上,Azure Stack 是微软推出的私有云实现,预计很快就会发布。这将具备与公有云相同的功能,实际上它们会无缝且透明地连接并协同工作。
开始使用 Azure 非常简单,但如果开发人员和架构师没有适当设计和架构他们的解决方案,也很容易陷入困境。本书尝试为架构解决方案提供指导和方向,帮助以正确的方式使用合适的服务和资源。Azure 上的每个服务都是一种资源。理解这些资源如何在 Azure 中组织和管理是非常重要的。本章介绍了 ARM 和资源组——这两个核心框架为资源提供了基础构件。ARM 为资源提供了一套服务,帮助在管理它们时实现统一性、标准化和一致性。诸如 RBAC、标签、策略和锁等服务,适用于每个资源提供者和资源。Azure 还提供了丰富的自动化功能,可以自动化并与资源交互。工具如 PowerShell、ARM 模板和 Azure CLI 可以作为发布流水线、持续部署和交付的一部分进行集成。用户可以通过这些自动化工具从异构环境连接到 Azure。
下一章将讨论一些重要的架构问题,这些问题有助于解决常见的基于云的部署问题,并确保应用程序在长期内是安全的、可用的、可扩展的和可维护的。
第二章:2. Azure 解决方案的可用性、可扩展性和监控
架构上的关注点,如高可用性和可扩展性,是任何架构师最高优先级的任务之一。这在许多项目和解决方案中都很常见。然而,在将应用程序部署到云端时,这些问题变得尤为重要,因为云端的复杂性。在大多数情况下,复杂性并不是来自应用程序本身,而是来自云中类似资源的多样性。云端带来的另一个复杂问题是新功能的不断涌现。这些新功能几乎使得架构师的决策在回顾时完全显得多余。
在本章中,我们将从架构师的角度,探讨如何在 Azure 上部署高度可用和可扩展的应用程序。
Azure 是一个成熟的平台,提供了多个级别的高可用性和可扩展性的实现选项。架构师必须了解这些选项,包括它们之间的差异、所涉及的成本,并最终能够选择一个符合最佳需求的解决方案。没有一个适合所有场景的解决方案,但每个项目都有一个合适的方案。
对于组织来说,能够随时向用户提供可用的应用程序和系统,是最重要的优先事项之一。它们希望自己的应用程序能够持续运行且具备功能,即使在发生一些不利事件时,仍能继续为客户提供服务。高可用性是本章的主要主题。保持系统运行 是高可用性的常用比喻。实现应用程序的高可用性并非易事,组织必须投入大量的时间、精力、资源和金钱。此外,仍然存在组织的实施方案无法达到预期结果的风险。Azure 为虚拟机(VMs)和平台即服务(PaaS)服务提供了许多高可用性功能。本章将介绍 Azure 提供的架构和设计功能,以确保正在运行的应用程序和服务的高可用性。
在本章中,我们将涵盖以下主题:
-
高可用性
-
Azure 高可用性
-
高可用性的架构考虑因素
-
可扩展性
-
升级和维护
高可用性
高可用性是任何业务关键服务及其部署的核心非功能性技术要求之一。高可用性是指一个服务或应用程序保持持续运行的特性;它通过满足或超越其承诺的服务级别协议(SLA)来实现这一点。用户根据服务类型会被承诺一定的 SLA。服务应该根据其 SLA 可供用户使用。例如,SLA 可以定义一个应用程序在一年内的可用性为 99%。这意味着它应该可以供用户使用 361.35 天。如果它未能在此期间保持可用,则构成违反 SLA。大多数关键任务应用程序将它们的高可用性 SLA 定义为 99.999%(每年)。这意味着该应用程序应该全年都能保持运行并可供使用,但它的停机时间不能超过 5.2 小时。如果停机时间超过这一限度,您将有资格获得信用,信用金额将根据总的正常运行时间百分比来计算。
需要注意的是,高可用性是根据时间来定义的(可以是按年、按月、按周,或这些的组合)。
一个服务或应用程序由多个组件组成,这些组件部署在不同的层级和层次上。此外,服务或应用程序部署在操作系统(OS)上,并托管在物理机器或虚拟机(VM)上。它消耗网络和存储服务来满足各种需求,甚至可能依赖于外部系统。为了确保这些服务或应用程序具备高可用性,网络、存储、操作系统、虚拟机或物理机器以及应用程序的每个组件都必须考虑 SLA 和高可用性。为了确保高可用性,从应用程序规划开始直到投入运营,都需要采用明确的应用程序生命周期流程。这也涉及到冗余的引入。冗余资源应该包括在整个应用程序和部署架构中,以确保如果一个资源出现故障,另一个资源能够接管并继续为客户提供服务。
影响应用程序高可用性的一些主要因素如下:
-
计划性维护
-
非计划性维护
-
应用程序部署架构
我们将在接下来的章节中详细探讨这些因素。让我们仔细看看 Azure 如何确保部署的高可用性。
Azure 高可用性
实现高可用性并满足高 SLA 要求是非常困难的。Azure 提供了许多功能,能够为应用程序实现高可用性,从主机和来宾操作系统到使用其 PaaS 的应用程序。架构师可以通过这些功能,通过配置来实现应用程序的高可用性,而不必从头开始构建这些功能或依赖第三方工具。
在本节中,我们将探讨 Azure 提供的使应用程序高可用的功能和能力。在深入架构和配置细节之前,理解与 Azure 高可用性相关的概念非常重要。
概念
Azure 提供的实现高可用性的基本概念如下:
-
可用性集
-
故障域
-
更新域
-
可用性区域
如你所知,设计高可用性解决方案非常重要。工作负载可能是关键任务,并且需要高可用架构。我们现在将仔细查看 Azure 中高可用性的每个概念。我们从可用性集开始。
可用性集
Azure 中的高可用性主要通过冗余来实现。冗余意味着有多个相同类型的资源实例,在主资源发生故障时接管控制。然而,仅仅拥有更多相似的资源并不能使它们具备高可用性。例如,在一个订阅中可能会配置多个虚拟机,但仅仅有多个虚拟机并不意味着它们具备高可用性。Azure 提供了一个名为可用性集的资源,将多个虚拟机与其关联可以使它们具备高可用性。为了实现高可用性,至少应将两台虚拟机托管在可用性集中。由于所有虚拟机都被放置在 Azure 数据中心的不同物理机架上,它们都会具备高可用性。在更新时,这些虚拟机会逐一更新,而不是同时更新。可用性集提供了故障域和更新域来实现这一点,我们将在下一部分详细讨论。简而言之,可用性集在数据中心级别提供冗余,类似于本地冗余存储。
需要注意的是,可用性集仅在数据中心内部提供高可用性。如果整个数据中心发生故障,应用程序的可用性将受到影响。为了确保在数据中心故障时应用程序仍然可用,Azure 引入了一个名为可用性区域的新特性,我们将在稍后学习。
如果你回顾基本概念列表,接下来是故障域。故障域通常用缩写 FD 表示。在下一部分中,我们将讨论故障域是什么,以及它在设计高可用性解决方案时的相关性。
故障域
故障域(FDs)表示一组共享相同电源和网络交换机的虚拟机(VM)。当一台 VM 被配置并分配到可用性集时,它将被托管在一个故障域中。每个可用性集默认有两个或三个故障域,这取决于 Azure 区域。有些区域提供两个故障域,而其他区域则提供三个故障域。故障域无法由用户配置。
当多个虚拟机被创建时,它们会被放置在不同的 FDs 上。如果虚拟机的数量超过了 FDs 的数量,多余的虚拟机会被放置在现有的 FDs 上。例如,如果有五个虚拟机,则这些虚拟机会托管在多个虚拟机上。
FDs 与 Azure 数据中心中的物理机架相关。FDs 在由于硬件、电力和网络故障导致的计划外停机情况下提供高可用性。由于每个虚拟机(VM)都被放置在不同的机架上,具有不同的硬件、不同的电源和不同的网络,因此如果某个机架出现故障,其他虚拟机将继续运行。
列表中的下一个是更新域。
更新域
FD 处理计划外停机,而更新域(update domain)则处理来自计划维护的停机。每个虚拟机也会被分配一个更新域,该更新域中的所有虚拟机将一起重启。一个可用性集最多可以有 20 个更新域。更新域是用户无法配置的。当多个虚拟机被创建时,它们会被放置在不同的更新域中。如果在一个可用性集中配置了超过 20 个虚拟机,它们将以轮询方式分布到这些更新域中。更新域处理计划维护。通过 Azure 门户中的服务健康,你可以查看计划维护的详细信息并设置警报。
在接下来的部分中,我们将介绍可用性区域(availability zones)。
可用性区域
这是 Azure 引入的一个相对较新的概念,与存储帐户的区域冗余非常相似。可用性区域通过将虚拟机实例放置在区域内不同的数据中心中,提供区域内的高可用性。可用性区域适用于 Azure 中的许多资源,包括虚拟机、托管磁盘、虚拟机规模集和负载均衡器。支持可用性区域的资源的完整列表可以在 docs.microsoft.com/azure/availability-zones/az-overview#services-that-support-availability-zones
中找到。长时间以来,无法跨区域配置可用性是 Azure 的一个缺口,直到引入可用性区域后才得以解决。
每个 Azure 区域由多个配备独立电力、冷却和网络设施的数据中心组成。一些区域的数据中心较多,而另一些区域的数据中心较少。该区域内的数据中心被称为区域。在所有启用的区域中,至少有三个独立的区域以确保弹性。将虚拟机部署在可用性区域中,确保这些虚拟机位于不同的数据中心,并且位于不同的机架和网络上。这些区域内的数据中心之间具有高速网络,这些虚拟机之间的通信不会出现延迟。图 2.1 显示了在区域中如何设置可用性区域:
图 2.1:区域中的可用性区域
您可以在docs.microsoft.com/azure/availability-zones/az-overview
找到有关可用性区域的更多信息。
区域冗余服务将您的应用程序和数据复制到可用性区域,以防止单点故障。
如果应用程序需要更高的可用性,并且您希望确保即使整个 Azure 区域宕机,也可用,可用性的下一个层次是 Traffic Manager 功能,这将在本章后面讨论。现在让我们继续了解 Azure VM 负载平衡的工作原理。
负载均衡
负载均衡,顾名思义,是指在 VM 和应用程序之间平衡负载的过程。如果只有一个 VM,则无需负载均衡器,因为整个负载位于单个 VM 上,没有其他 VM 可以共享负载。然而,通过包含相同应用程序和服务的多个 VM,可以通过负载均衡器在它们之间分发负载。Azure 提供了几种资源来实现负载均衡:
-
负载均衡器:Azure 负载均衡器有助于设计具有高可用性的解决方案。在传输控制协议(TCP)堆栈内,它是第 4 层传输级别的负载均衡器。这是一个第 4 层负载均衡器,将传入的流量分发到负载平衡集中定义的健康服务实例之间。第 4 层负载均衡器在传输级别工作,并具有网络级别的信息,如 IP 地址和端口,以决定传入请求的目标。负载均衡器将在本章后面详细讨论。
-
应用程序网关:Azure 应用程序网关为您的应用程序提供高可用性。它们是第 7 层负载均衡器,将传入的流量分发到服务的健康实例之间。第 7 层负载均衡器可以在应用程序级别工作,并具有应用程序级别的信息,如 cookie、HTTP、HTTPS 和会话等。应用程序网关将在本章后面详细讨论。在部署 Azure Kubernetes 服务时,特别是需要将来自互联网的入口流量路由到集群中的 Kubernetes 服务的场景中,也会使用应用程序网关。
-
Azure Front Door:Azure Front Door 与应用程序网关非常相似;但是,它不在区域或数据中心级别工作。相反,它在全球范围内帮助路由请求。它具有与应用程序网关相同的功能集,但是在全局级别提供。它还提供网页应用程序防火墙以过滤请求并提供其他安全相关的保护。它提供会话亲和性、TLS 终止和基于 URL 的路由作为其部分功能。
-
流量管理器:流量管理器帮助根据区域端点的健康状况和可用性,在多个区域之间对请求进行全局路由。它支持通过 DNS 重定向条目来实现这一点。它具有高度的弹性,并且在区域故障期间不会影响服务。
由于我们已经探讨了可以用于实现负载均衡的方法和服务,接下来我们将讨论如何使虚拟机具备高可用性。
虚拟机高可用性
虚拟机提供计算能力。它们为应用程序和服务提供处理能力和托管支持。如果应用程序部署在单个虚拟机上,而该虚拟机出现故障,则应用程序将无法使用。如果应用程序由多个层组成,并且每个层都部署在各自的单个虚拟机实例上,那么即使是单个虚拟机实例的停机也可能导致整个应用程序不可用。Azure 尝试使单个虚拟机实例的可用性达到 99.9%,特别是当这些单实例虚拟机使用高级存储作为磁盘时。对于那些在可用性集中分组在一起的虚拟机,Azure 提供了更高的服务级别协议(SLA)。对于包含两个或更多虚拟机的可用性集,提供 99.95% 的 SLA。如果虚拟机部署在可用性区域中,SLA 可达 99.99%。在下一节中,我们将讨论计算资源的高可用性。
计算高可用性
需要高可用性的应用程序应部署在同一可用性集中的多个虚拟机(VM)上。如果应用程序由多个层组成,那么每个层应有一组虚拟机,部署在其专用的可用性集中。简而言之,如果一个应用程序有三个层,那么应有三个可用性集,并且至少需要六个虚拟机(每个可用性集两个虚拟机),以确保整个应用程序具有高可用性。
那么,Azure 是如何通过在每个可用性集中部署多个虚拟机来提供服务级别协议(SLA)和高可用性的呢?这个问题可能会浮现在你的脑海中。
在这里,我们之前考虑的概念起到了关键作用——即故障域(FD)和更新域。当 Azure 发现可用性集中有多个虚拟机时,它会将这些虚拟机放置在不同的故障域中。换句话说,这些虚拟机会被放置在不同的物理机架上,而不是同一个机架上。这确保了即使发生电源、硬件或机架故障,至少有一台虚拟机可以继续使用。一个可用性集中有两个或三个故障域,并且根据可用性集中的虚拟机数量,这些虚拟机会被放置在不同的故障域中,或者以循环方式重复放置。这确保了即使机架发生故障,高可用性也不会受到影响。
Azure 还将这些虚拟机放置在不同的更新域中。换句话说,Azure 内部为这些虚拟机打上标签,使得这些虚拟机按照顺序进行修补和更新,以确保在某个更新域中的任何重启都不会影响应用程序的可用性。这确保了虚拟机和主机维护不会影响高可用性。需要注意的是,Azure 不负责操作系统级别和应用程序的维护。
通过将虚拟机放置在不同的故障域和更新域中,Azure 确保所有虚拟机不会同时宕机,并且即使它们正在进行维护或面临物理停机问题,也能保持在线并能够处理请求:
图 2.2:虚拟机在故障域和更新域中的分布
图 2.2 显示了四个虚拟机(其中两个安装了Internet 信息服务(IIS),另两个安装了 SQL Server)。IIS 和 SQL 虚拟机都属于可用性集的一部分。IIS 和 SQL 虚拟机位于数据中心的不同故障域(FD)和机架中,并且它们也处于不同的更新域中。
图 2.3 显示了故障域和更新域之间的关系:
图 2.3:可用性集中更新域和故障域的布局
到目前为止,我们讨论了如何实现计算资源的高可用性。在接下来的章节中,您将学习如何为 PaaS 实现高可用性。
高可用性平台
Azure 提供了许多新功能,以确保 PaaS 的高可用性。以下是其中的一些功能:
-
应用服务中的容器
-
Azure 容器实例组
-
Azure Kubernetes 服务
-
其他容器协调器,如 DC/OS 和 Swarm
另一个提供高可用性的重要平台是Service Fabric。Service Fabric 和包含 Kubernetes 的容器协调器都能确保在环境中始终有所需数量的应用实例在运行。这意味着即使环境中的某个实例宕机,协调器也能通过主动监控得知,并会在另一个节点上启动新的实例,从而保持理想的应用实例数量。它这样做不需要管理员的手动或自动干预。
虽然 Service Fabric 允许任何类型的应用程序实现高可用性,但 Kubernetes、DC/OS 和 Swarm 等协调器特定于容器。同时,需要理解的是,这些平台提供的功能有助于进行滚动更新,而不是可能影响应用程序可用性的整体更新。
当我们讨论虚拟机的高可用性时,我们简要介绍了负载均衡的概念。让我们进一步深入了解,以便更好地理解它在 Azure 中是如何工作的。
Azure 中的负载均衡器
Azure 提供了两种具有负载均衡器功能的资源。它提供了一个 4 层负载均衡器,在 TCP OSI 协议栈的传输层工作;以及一个 7 层负载均衡器(应用程序网关),它在应用层和会话层工作。
虽然应用程序网关和负载均衡器都提供负载均衡的基本功能,但它们的用途不同。在许多使用场景中,部署应用程序网关比负载均衡器更合适。
应用程序网关提供以下 Azure 负载均衡器所不具备的功能:
-
Web 应用防火墙:这是操作系统防火墙之上的一个附加防火墙,它能深入查看传入的消息。这有助于识别和防止常见的基于 Web 的攻击,如 SQL 注入、跨站脚本攻击和会话劫持。
-
基于 Cookie 的会话保持:负载均衡器将传入流量分配给健康且相对空闲的服务实例。一个请求可以由任何服务实例处理。然而,一些应用程序需要更高级的功能,要求所有后续请求都由同一服务实例处理。这被称为基于 Cookie 的会话保持。应用程序网关通过使用 Cookie 提供基于 Cookie 的会话保持,从而将用户会话保持在同一服务实例上。
-
安全套接字层(SSL)卸载:请求和响应数据的加密与解密由 SSL 执行,这通常是一个昂贵的操作。Web 服务器理应将其资源用于处理和响应请求,而不是加密和解密流量。SSL 卸载有助于将这一加密过程从 Web 服务器转移到负载均衡器,从而为处理用户请求的 Web 服务器提供更多资源。用户的请求经过加密后,在应用程序网关处解密,而不是在 Web 服务器处解密。来自应用程序网关到 Web 服务器的请求则保持未加密。
-
端到端 SSL:虽然 SSL 卸载是某些应用程序的一个不错功能,但有些关键任务的安全应用程序仍然需要完全的 SSL 加密和解密,即使流量经过负载均衡器。应用程序网关也可以配置为进行端到端 SSL 加密。
-
基于 URL 的内容路由:应用程序网关对于根据传入请求的 URL 内容将流量重定向到不同的服务器也很有用。这有助于在托管多个服务和其他应用程序时进行流量管理。
Azure 负载均衡器
Azure 负载均衡器根据可用的传输层信息分配传入的流量。它依赖于以下特性:
-
源 IP 地址
-
目标 IP 地址
-
源端口号
-
目标端口号
-
一种协议类型——TCP 或 HTTP
Azure 负载均衡器可以是私有负载均衡器或公共负载均衡器。私有负载均衡器可用于在内部网络中分配流量。由于这是内部使用,因此不会分配公共 IP 地址,并且不能通过互联网访问。公共负载均衡器具有附加的外部公共 IP 地址,可以通过互联网访问。在图 2.4中,您可以看到如何将内部(私有)和公共负载均衡器集成到一个解决方案中,分别处理内部和外部流量:
图 2.4:使用 Azure 负载均衡器分配流量
在图 2.4中,您可以看到外部用户通过公共负载均衡器访问虚拟机(VM),然后来自虚拟机的流量通过内部负载均衡器分配到另一组虚拟机。
我们已经对 Azure 负载均衡器与应用程序网关的区别进行了比较。在下一节中,我们将更详细地讨论应用程序网关。
Azure 应用程序网关
Azure 负载均衡器帮助我们在基础设施层面启用解决方案。然而,有时使用负载均衡器需要高级服务和功能。这些高级服务包括 SSL 终止、粘性会话、高级安全性等。Azure 应用程序网关提供了这些附加功能;Azure 应用程序网关是一个第七层负载均衡器,能够处理应用程序和会话负载,在 TCP OSI 堆栈中运行。
与 Azure 负载均衡器相比,应用程序网关拥有更多的信息,用于在服务器之间做出请求路由和负载均衡的决策。应用程序网关由 Azure 管理,并具有高可用性。
如图 2.5所示,应用程序网关位于用户和虚拟机之间:
图 2.5:Azure 应用程序网关
应用程序网关是一种托管服务。它们使用应用程序请求路由(ARR)将请求路由到不同的服务和端点。创建应用程序网关需要一个私有或公共 IP 地址。然后,应用程序网关将 HTTP/HTTPS 流量路由到配置的端点。
从配置的角度来看,应用程序网关与 Azure 负载均衡器相似,但具有额外的结构和功能。应用程序网关可以配置前端 IP 地址、证书、端口配置、后端池、会话亲和性和协议信息。
我们在讨论虚拟机高可用性时提到了另一个服务——Azure 流量管理器。让我们在下一节中进一步了解该服务。
Azure 流量管理器
在充分了解 Azure 负载均衡器和应用程序网关之后,是时候深入了解 Traffic Manager 了。Azure 负载均衡器和应用程序网关是数据中心或区域内高可用性所需的资源;然而,要实现跨区域和跨数据中心的高可用性,还需要另一种资源,而 Traffic Manager 就在这方面为我们提供了帮助。
Traffic Manager 帮助我们创建跨多个地理位置、区域和数据中心的高可用解决方案。Traffic Manager 不同于负载均衡器。它使用域名服务(DNS)将请求重定向到由端点的健康状况和配置决定的适当端点。Traffic Manager 不是代理或网关,它无法看到客户端与服务之间传递的流量。它仅根据最合适的端点重定向请求。
Azure Traffic Manager 有助于控制分配到应用程序端点的流量。端点可以被定义为任何面向互联网的服务,无论是在 Azure 内部还是外部托管。
端点是面向互联网的、可访问的公共 URL。应用程序被部署在多个地理位置和 Azure 区域。部署到每个区域的应用程序有一个唯一的端点,通过.trafficmanager.net
的 URL 扩展来引用。
当请求到达 Traffic Manager 的 URL 时,它会在列表中找到最合适的端点,并将请求重定向到该端点。简而言之,Azure Traffic Manager 充当全球 DNS 来识别将处理请求的区域。
然而,Traffic Manager 如何知道使用哪些端点并将客户端请求重定向到它们呢?Traffic Manager 考虑两个方面来确定最合适的端点和区域。
首先,Traffic Manager 会积极监控所有端点的健康状况。它可以监控虚拟机、云服务和应用服务的健康状况。如果它确定部署在某个区域的应用程序健康状况不适合重定向流量,它会将请求重定向到健康的端点。
其次,Traffic Manager 可以配置路由信息。Traffic Manager 提供了六种流量路由方法,具体如下:
-
优先级:当所有流量应发送到默认端点,并且当主端点不可用时需要备份端点时,应使用此选项。
-
加权:当需要在端点之间均匀分配流量,或根据定义的权重分配流量时,应使用此选项。
-
性能:当端点位于不同区域时,应使用此选项,并根据用户的位置将其重定向到最接近的端点。这直接影响网络延迟。
-
地理:这应当用于根据最近的地理位置将用户重定向到一个端点(Azure、外部或嵌套)。这有助于遵守与数据保护、地域化和基于区域的流量收集相关的合规要求。
-
子网:这是一种新的路由方法,帮助根据客户端的 IP 地址提供不同的端点。在此方法中,每个端点会分配一系列 IP 地址。这些 IP 地址范围与客户端的 IP 地址映射,以确定合适的返回端点。通过这种路由方法,可以根据用户的源 IP 地址向不同的人提供不同的内容。
-
多值:这也是 Azure 中新增的一种方法。在这种方法中,多个端点会返回给客户端,客户端可以使用其中任何一个端点。这确保了如果一个端点不可用,其他端点可以作为替代使用,从而提升了解决方案的整体可用性。
需要注意的是,在流量管理器确定有效且健康的端点后,客户端将直接连接到应用程序。接下来,让我们继续了解 Azure 在全球范围内路由用户请求的能力。
在接下来的部分,我们将讨论另一项服务,叫做 Azure Front Door。该服务类似于 Azure 应用程序网关;然而,它有一个小的区别,使得该服务与众不同。让我们继续深入了解 Azure Front Door。
Azure Front Door
Azure Front Door 是 Azure 提供的最新服务,它帮助将请求路由到全球服务,而不是像 Azure 应用程序网关和负载均衡器那样将请求路由到本地区域或数据中心级别。Azure Front Door 类似于应用程序网关,不同之处在于它的范围。它是一个第七层负载均衡器,帮助将请求路由到在多个区域中部署的最近的、性能最优的服务端点。它提供诸如 TLS 终止、会话亲和性、基于 URL 的路由和多站点托管等功能,并带有 Web 应用防火墙。它与流量管理器相似,默认情况下对整个区域的故障具有弹性,并提供路由能力。它还定期进行端点健康探测,确保请求仅路由到健康的端点。
它提供了四种不同的路由方法:
-
延迟:请求将路由到具有最小端到端延迟的端点。
-
优先级:请求将路由到主端点,如果主端点失败,则路由到备用端点。
-
加权:请求将根据分配给端点的权重进行路由。
-
会话亲和性:会话中的请求将始终指向相同的端点,以便利用先前请求的会话数据。原始请求可以指向任何可用的端点。
寻求全球级别弹性的部署应在其架构中包括 Azure Front Door,并结合应用程序网关和负载均衡器。在接下来的章节中,你将看到在设计高可用解决方案时应考虑的一些架构要点。
高可用性的架构考虑因素
Azure 通过多种方式和不同级别提供高可用性。高可用性可以在数据中心级别、区域级别,甚至跨 Azure 实现。在本节中,我们将介绍一些高可用性的架构。
Azure 区域内的高可用性
如图 2.6所示,该架构展示了在单一 Azure 区域内的高可用性部署。高可用性在单个资源级别进行设计。在该架构中,每一层都有多个虚拟机(VM),这些虚拟机通过应用程序网关或负载均衡器连接,并且它们都属于一个可用性集。每一层都与一个可用性集关联。这些虚拟机被放置在不同的故障和更新域上。虽然 Web 服务器连接到应用程序网关,但其他层次(如应用程序层和数据库层)使用内部负载均衡器:
图 2.6:在一个区域内设计高可用性
现在你已经知道如何在同一区域内设计高度可用的解决方案,接下来我们来讨论如何设计一个类似的架构,且跨多个 Azure 区域进行部署。
跨 Azure 区域的高可用性
该架构展示了在两个不同 Azure 区域中的类似部署。如图 2.7所示,两个区域都部署了相同的资源。高可用性在这些区域内的单个资源级别进行设计。每一层都有多个虚拟机,虚拟机通过负载均衡器连接,并且它们属于一个可用性集。这些虚拟机被放置在不同的故障和更新域上。Web 服务器连接到外部负载均衡器,而其他层次(如应用程序层和数据库层)则使用内部负载均衡器。需要注意的是,如果需要高级服务(如会话保持、SSL 终止、使用Web 应用防火墙(WAF)的高级安全性以及基于路径的路由),则可以使用应用程序负载均衡器来替代 Azure 负载均衡器,部署在 Web 服务器和应用程序层。两个区域中的数据库通过虚拟网络对等连接和网关互相连接。这对于配置日志传输、SQL Server Always On 和其他数据同步技术非常有用。
来自两个区域的负载均衡器端点用于配置流量管理器端点,流量根据优先级负载均衡方法进行路由。流量管理器帮助将所有请求路由到东美国区域,在故障转移的情况下,如果第一个区域不可用,则路由到西欧区域:
图 2.7:跨 Azure 区域设计高可用性
在接下来的部分中,我们将探讨可扩展性,这是云计算的另一个优势。
可扩展性
运行对用户开放的应用程序和系统对于任何业务关键应用程序的架构师来说都非常重要。然而,另一个同样重要的应用程序特性,也是架构师的首要任务之一,就是应用程序的可扩展性。
想象一种情况,应用程序已经部署,并且在少量用户下能够获得良好的性能和可用性,但随着用户数量的增加,可用性和性能都会下降。应用程序在正常负载下表现良好,但在用户数量增加时性能下降。这可能发生在用户数量突然增加且环境未针对如此大量用户进行构建时。
为了应对用户数量的激增,您可能会为应对高峰期配置硬件和带宽。问题在于,额外的容量在大部分年份都未被使用,因此无法提供投资回报。它仅为假期或促销期间使用。我希望到现在为止,您已经开始熟悉架构师正在努力解决的问题。所有这些问题都与容量配置和应用程序的可扩展性相关。本章的重点是将可扩展性视为架构上的一个问题,并了解 Azure 提供的用于实现可扩展性的服务。
容量规划和资源配置是架构师及其应用程序和服务的几个首要任务。架构师必须在购买和配置过多资源与购买和配置过少资源之间找到平衡。资源过少会导致无法满足所有用户需求,从而导致他们转向竞争对手。另一方面,资源过多则会损害预算和投资回报率,因为大多数资源大部分时间处于未使用状态。此外,问题会因需求水平在不同时间的波动而加剧。几乎不可能预测一天内的应用用户数,更别说一年的用户数了。然而,通过过去的信息和持续的监控,找到一个大致的数字是可能的。
可扩展性指的是处理日益增长的用户数量,并为他们提供与较少用户时相同水平的性能,即使在应用程序部署、进程和技术使用资源时。可扩展性可能意味着在性能不下降的情况下处理更多请求,或者意味着处理更大、更耗时的工作而不损失性能,在这两种情况下都是如此。
容量规划和大小调整练习应由架构师在项目初期和规划阶段进行,以便为应用程序提供可扩展性。
一些应用程序具有稳定的需求模式,而另一些应用程序则难以预测需求。对于稳定需求的应用程序,可扩展性要求是已知的,而对于需求变化较大的应用程序,识别其需求可能是一个更复杂的过程。自动扩展是我们在下一节将要讨论的概念,应该应用于那些无法预测需求的应用程序。
人们常常把可扩展性和性能混为一谈。在接下来的章节中,你将看到这两个术语的简要对比。
可扩展性与性能
在架构问题上,很多人容易将可扩展性与性能混淆,因为可扩展性完全是为了确保无论有多少用户使用应用程序,所有用户都能获得预定的性能水平。
性能与确保应用程序满足预定义的响应时间和吞吐量相关。可扩展性指的是在需要时提供更多资源,以容纳更多用户而不牺牲性能。
通过类比来理解这一点会更好:火车的速度与铁路网络的性能直接相关。然而,增加更多的火车以平行运行在相同或更高的速度下,代表着铁路网络的可扩展性。
现在你已经知道了可扩展性与性能之间的区别,接下来我们来讨论 Azure 如何提供可扩展性。
Azure 可扩展性
在这一节中,我们将探讨 Azure 提供的功能和能力,以使应用程序具备高可用性。在深入了解架构和配置细节之前,理解 Azure 的高可用性概念,即可扩展性,是非常重要的。
扩展指的是增加或减少用于处理用户请求的资源量。扩展可以是自动的,也可以是手动的。手动扩展需要管理员手动启动扩展过程,而自动扩展指的是根据环境和生态系统中可用的事件(如内存和 CPU 可用性)自动增加或减少资源。资源可以向上或向下扩展,也可以向外或向内扩展,这将在本节后面解释。
除了滚动更新,Azure 提供的实现高可用性的基本构造如下:
-
扩展上下调节
-
向外扩展与向内收缩
-
自动伸缩
向上扩展
对虚拟机或服务进行向上扩展意味着向现有服务器添加更多资源,如 CPU、内存和磁盘。其目的是增加现有物理硬件和资源的容量。
向下扩展
对虚拟机或服务进行向下扩展意味着从现有服务器中移除资源,如 CPU、内存和磁盘。其目的是减少现有物理和虚拟硬件及资源的容量。
向外扩展
向外扩展意味着添加更多硬件,如额外的服务器和容量。这通常包括新增服务器、分配 IP 地址、在其上部署应用程序,并将其纳入现有的负载均衡器,以便流量可以路由到这些服务器。向外扩展既可以是自动的,也可以是手动的。然而,为了获得更好的效果,应该使用自动化:
图 2.8:向外扩展
向内扩展
向内扩展指的是移除现有硬件的过程,具体来说就是现有的服务器和容量。这通常包括移除现有服务器,取消分配它们的 IP 地址,并将它们从现有的负载均衡器配置中移除,以确保流量不能路由到它们。像向外扩展一样,向内扩展也可以是自动的或手动的。
自动伸缩
自动伸缩指的是根据应用程序需求动态地进行向上/向下或向外/向内扩展的过程,并且这一过程是通过自动化实现的。自动伸缩非常有用,因为它确保部署始终由理想数量的服务器实例组成。自动伸缩有助于构建具有容错性的应用程序。它不仅支持可伸缩性,还使应用程序具有高可用性。最后,它提供了最佳的成本管理。自动伸缩使得根据需求配置服务器实例的最优配置成为可能。它帮助避免过度配置服务器,以免服务器最终被闲置,并且能够在向外扩展后移除不再需要的服务器。
到目前为止,我们已经讨论了 Azure 中的可伸缩性。Azure 为其大多数服务提供了可伸缩性选项。接下来,我们将探索 Azure 中 PaaS 的可伸缩性。
PaaS 可伸缩性
Azure 提供了 App Service 来托管托管应用程序。App Service 是 Azure 的 PaaS 服务。它为 Web 和移动平台提供服务。在这些 Web 和移动平台背后,有一套由 Azure 代表用户管理的托管基础设施。用户无需查看或管理任何基础设施;然而,他们可以扩展平台并在其上部署应用程序。通过这种方式,架构师和开发人员可以专注于他们的业务问题,而无需担心基础平台和基础设施的配置、部署和故障排除。开发人员可以灵活选择任何语言、操作系统和框架来开发应用程序。App Service 提供了多个计划,用户可以根据选择的计划享受不同程度的可扩展性。App Service 提供以下五种计划:
-
免费:此计划使用共享基础设施。这意味着多个应用程序将部署在相同的基础设施上,可以是来自同一租户或多个租户。它提供 1 GB 的免费存储。然而,此计划不支持扩展功能。
-
共享:此计划也使用共享基础设施,并提供 1 GB 的免费存储。此外,还提供定制域名作为额外功能。然而,此计划不支持扩展功能。
-
基础:该计划有三个不同的库存单位(SKU):B1、B2 和 B3。它们在 CPU 和内存方面有逐渐增加的资源配置。简而言之,它们提供了更好的虚拟机配置,以支持这些服务。此外,还提供存储、定制域名和 SSL 支持。基础计划提供了手动扩展的基本功能。此计划不支持自动扩展。最多可以使用三个实例来扩展应用程序。
-
标准:该计划也有三个不同的 SKU:S1、S2 和 S3。它们在 CPU 和内存方面有逐渐增加的资源配置。简而言之,它们提供了更好的虚拟机配置,以支持这些服务。此外,它们还提供类似基础计划的存储、定制域名和 SSL 支持。该计划还提供一个 Traffic Manager 实例、预发布插槽和每天一次的备份,作为基础计划的额外功能。标准计划提供了自动扩展功能。最多可以使用 10 个实例来扩展应用程序。
-
高级:这也有三个不同的 SKU:P1、P2 和 P3。它们分别提供更多的 CPU 和内存资源。简而言之,它们提供了更好的虚拟机配置,支撑这些服务。此外,它们还提供与基础计划类似的存储、自定义域和 SSL 支持。该计划还提供了一个流量管理器实例、暂存槽和 50 个每日备份,作为基础计划的附加功能。标准计划提供自动扩展功能。最多可以使用 20 个实例来扩展应用。
我们已经探讨了 PaaS 服务的可扩展性层级。现在,让我们来看一下如何在应用服务计划中进行扩展。
PaaS – 扩展和缩减
托管在应用服务中的服务的扩展和缩减是非常简单的。Azure 应用服务的“扩展”菜单会打开一个新面板,列出所有计划和它们的 SKU。选择一个计划和 SKU 将会扩展或缩减服务,如图 2.9所示:
图 2.9:不同计划及其 SKU
PaaS – 扩展和缩减
在应用服务中扩展和缩减服务也非常简单。Azure 应用服务的“扩展”菜单项会打开一个新面板,提供扩展配置选项。
默认情况下,自动扩展对高级和标准计划是禁用的。可以通过扩展菜单项并点击启用自动扩展按钮来启用,如图 2.10所示:
图 2.10:启用自动扩展选项
手动扩展不需要配置,但自动扩展有助于通过以下属性进行配置:
-
扩展模式:基于性能指标,如 CPU 或内存使用情况,或者用户可以简单指定要扩展的实例数量。
-
何时扩展:可以添加多个规则来确定何时扩展和缩减。每个规则可以确定诸如 CPU 或内存消耗、是否增加或减少实例数量,以及每次增加或减少多少实例等标准。至少应该配置一个扩展规则和一个缩减规则。阈值定义有助于定义触发自动扩展的上限和下限——通过增加或减少实例数量来实现。
-
如何扩展:这指定了在每次扩展或缩减操作中要创建或移除多少个实例:
图 2.11:设置实例限制
这是在任何部署中都非常好的功能。然而,您应该同时启用扩展和缩减,以确保在扩展后环境能够恢复到正常容量。
由于我们已经覆盖了 PaaS 的可扩展性,现在让我们继续讨论 IaaS 的可扩展性。
IaaS 可扩展性
有些用户希望对其基础架构、平台和应用程序拥有完全的控制权。他们更倾向于使用 IaaS 解决方案,而非 PaaS 解决方案。当这类客户创建虚拟机时,他们还需要负责容量规划和扩展。对于虚拟机的手动扩展或自动扩展,Azure 并没有现成的配置。这些客户需要编写自己的自动化脚本、触发器和规则来实现自动扩展。使用虚拟机也意味着需要负责维护它们。虚拟机的补丁管理、更新和升级由所有者负责。架构师应考虑计划内和计划外的维护。必须考虑虚拟机如何打补丁、顺序、分组以及其他因素,以确保不会影响应用程序的可扩展性和可用性。为了解决这些问题,Azure 提供了 虚拟机规模集(VMSS)作为解决方案,我们接下来会讨论这一点。
虚拟机规模集
VMSS 是 Azure 计算资源,您可以用它来部署和管理一组相同的虚拟机。所有虚拟机都以相同的方式配置,规模集旨在支持真正的自动扩展,并且不需要预先配置虚拟机。它有助于配置多个通过虚拟网络和子网互联的相同虚拟机。
VMSS(虚拟机规模集)由多个虚拟机组成,但它们是在 VMSS 层级上进行管理的。所有虚拟机都是该单元的一部分,任何所做的更改都会应用于该单元,从而通过预定算法应用于正在使用这些虚拟机的 VM:
图 2.12:一个虚拟机规模集
这使得这些虚拟机能够使用 Azure 负载均衡器或应用程序网关进行负载均衡。虚拟机可以是 Windows 或 Linux 虚拟机。它们可以使用 PowerShell 扩展运行自动化脚本,并可以通过状态配置进行集中管理。它们可以作为一个单元进行监控,或通过日志分析分别进行监控。
VMSS 可以通过 Azure 门户、Azure CLI、Azure 资源管理器模板、REST API 和 PowerShell cmdlet 进行配置。可以从任何平台、环境或操作系统以及任何语言中调用 REST API 和 Azure CLI。
许多 Azure 服务已经将 VMSS 用作其底层架构。包括 Azure Batch、Azure Service Fabric 和 Azure 容器服务。Azure 容器服务又在这些 VMSS 上部署 Kubernetes 和 DC/OS。
VMSS 架构
当使用平台镜像时,VMSS 最多允许在一个规模集内创建 1,000 个虚拟机,使用自定义镜像时则为 100 个虚拟机。如果规模集中的虚拟机数量少于 100 个,它们将被放置在一个可用性集中;如果虚拟机数量大于 100 个,则会创建多个可用性集(称为放置组),并将虚拟机分布在这些可用性集中。我们从第一章,开始使用 Azure中了解到,可用性集中的虚拟机会被放置在不同的故障域和更新域中。与 VMSS 相关的可用性集默认有五个故障域和更新域。VMSS 提供了一个模型,用于保存整个集的元数据。更改此模型并应用更改会影响所有虚拟机实例。此信息包括虚拟机实例的最大和最小数量、操作系统 SKU 和版本、当前虚拟机数量、故障域和更新域等。这在图 2.13中有演示:
图 2.13:可用性集中的虚拟机
VMSS 缩放
缩放是指增加或减少计算和存储资源。VMSS 是一个功能丰富的资源,使缩放变得简单高效。它提供自动缩放功能,帮助基于外部事件和数据(如 CPU 和内存使用率)进行向上或向下的缩放。以下是 VMSS 缩放的一些功能。
横向与纵向缩放
缩放可以是横向或纵向的,或者两者兼有。横向缩放是扩展和收缩的另一种说法,而纵向缩放则指的是向上或向下缩放。
容量
VMSS 具有一个capacity
属性,用于确定规模集中的虚拟机数量。可以将capacity
属性设置为零来部署 VMSS,这样不会创建任何虚拟机;然而,如果为capacity
属性提供一个数字,则会创建相应数量的虚拟机。
自动缩放
VMSS 中的虚拟机自动缩放是指根据配置的环境增加或移除虚拟机实例,以满足应用程序的性能和可扩展性需求。通常,在没有 VMSS 的情况下,这通过自动化脚本和运行手册来实现。
VMSS 通过支持配置帮助实现这一自动化过程。与其编写脚本,不如配置 VMSS 进行自动向上或向下缩放。
自动缩放使用多个集成组件来实现其最终目标。自动缩放涉及持续监控虚拟机并收集其遥测数据。这些数据被存储、合并,然后根据一组规则进行评估,以确定是否触发自动缩放。触发条件可能是扩展或收缩,也可能是向上或向下缩放。
自动缩放机制使用诊断日志收集来自虚拟机的遥测数据。这些日志作为诊断指标存储在存储帐户中。自动缩放机制还使用应用程序洞察监控服务,读取这些指标,将它们组合在一起并存储在存储帐户中。
背景自动缩放任务会持续运行,读取应用程序洞察存储数据,基于配置的所有自动缩放规则进行评估,并且,如果满足任何规则或规则组合,执行自动缩放过程。规则可以考虑来自来宾虚拟机和主机服务器的指标。
使用属性描述定义的规则可以在 docs.microsoft.com/azure/virtual-machine-scale-sets/virtual-machine-scale-sets-autoscale-overview
获取。
VMSS 自动缩放架构如 图 2.14 所示:
图 2.14:VMSS 自动缩放架构
自动缩放可以为比环境中一般可用指标更复杂的场景进行配置。例如,缩放可以基于以下任一项:
-
特定日期
-
循环的时间表,例如周末
-
工作日与周末的对比
-
假期和一次性事件
-
多个资源指标
这些可以使用应用程序洞察资源的 schedule
属性进行配置,帮助注册规则。
建筑师应确保至少配置两种操作——扩展和缩减。仅仅扩展或缩减配置无法实现 VMSS 提供的扩展优势。
总结来说,我们已经涵盖了 Azure 中的可扩展性选项,以及 IaaS 和 PaaS 的详细缩放功能,以满足您的业务需求。如果您记得共享责任模型,您会记得平台升级和维护应由云提供商负责。在这种情况下,微软负责平台相关的升级和维护。让我们在下一部分中看看这是如何实现的。
升级和维护
在部署 VMSS 和应用程序后,它们需要进行积极的维护。应定期进行计划性维护,确保从安全性和韧性角度来看,环境和应用程序都能更新到最新功能。
升级可以与应用程序、来宾虚拟机实例或镜像本身关联。升级可能相当复杂,因为它们应该在不影响环境和应用程序的可用性、可扩展性和性能的情况下进行。为了确保更新可以通过滚动升级方法逐个实例进行,VMSS 必须支持并提供这些高级场景所需的功能。
Azure 团队提供了一个用于管理 VMSS 更新的工具。这是一个基于 Python 的工具,可以从 github.com/gbowerman/vmssdashboard
下载。它通过 REST API 调用 Azure 来管理扩展集。这个工具可以用来启动、停止、升级和重新镜像在故障域(FD)或虚拟机组中的虚拟机,如 图 2.15 所示:
图 2.15:用于管理 VMSS 更新的工具
既然你已经对升级和维护有了基本的了解,那么我们来看看应用程序更新是如何在 VMSS 中进行的。
应用程序更新
VMSS 中的应用程序更新不应手动执行。它们必须作为发布管理和自动化管道的一部分运行。此外,更新应该一次处理一个应用程序实例,且不应影响应用程序的整体可用性和可扩展性。应部署配置管理工具,如 期望状态配置 (DSC),来管理应用程序更新。DSC 拉取服务器可以配置为包含最新版本的应用程序配置,并应以滚动方式应用到每个实例。
在下一节中,我们将重点介绍如何在客户操作系统上进行更新。
客户更新
虚拟机的更新由管理员负责。Azure 不负责修补客户虚拟机。客户更新目前处于预览模式,用户应手动控制修补或使用自定义自动化方法,如运行簿和脚本。然而,滚动补丁升级也处于预览模式,并且可以通过升级策略在 Azure 资源管理器模板中进行配置,如下所示:
"upgradePolicy": {"mode": "Rolling","automaticOSUpgrade": "true" or "false", "rollingUpgradePolicy": { "batchInstancePercent": 20, "maxUnhealthyUpgradedInstanceCount": 0, "pauseTimeBetweenBatches": "PT0S" }}
现在我们已经了解了 Azure 如何管理客户更新,接下来看看镜像更新是如何完成的。
镜像更新
VMSS 可以在没有任何停机的情况下更新操作系统版本。操作系统更新涉及更改操作系统的版本或 SKU,或更改自定义镜像的 URI。无停机更新意味着一次更新一个虚拟机或一组虚拟机(例如,一次更新一个故障域),而不是一次性更新所有虚拟机。通过这种方式,未被升级的虚拟机可以继续运行。
到目前为止,我们讨论了更新和维护。现在让我们来看看 VMSS 的扩展最佳实践是什么。
VMSS 扩展的最佳实践
在本节中,我们将介绍一些应用程序应当实施的最佳实践,以便充分利用 VMSS 提供的扩展能力。
偏好扩展操作
扩展横向(Scaling out)是比纵向扩展(Scaling up)更好的扩展方案。纵向扩展或缩减意味着调整虚拟机实例的大小。当虚拟机调整大小时,通常需要重新启动,这有其自身的缺点。首先,机器会有停机时间。其次,如果有活动用户连接到该实例上的应用程序,他们可能会面临应用程序不可用,甚至可能丧失事务。扩展横向不会影响现有虚拟机,而是配置新的机器并将其添加到组中。
新实例与休眠实例
扩展新实例可以采取两种广泛的方法:从头开始创建新实例,这需要安装应用程序、配置和测试它们;或者在由于其他服务器的可扩展性压力而需要时启动休眠的实例。
适当配置最大和最小实例数量
如果将最小实例数和最大实例数都设置为 2,且当前实例数为 2,则无法进行扩展操作。最大实例数和最小实例数之间应有足够的差距,这两个值是包含在内的。自动扩展总是在这些限制之间进行。
并发
应用程序应该设计为专注于并发以实现可扩展性。应用程序应使用异步模式,确保当资源忙于处理其他请求时,客户端请求不会无限期等待获取资源。在代码中实现异步模式可以确保线程不会因等待资源而阻塞,从而避免系统耗尽所有可用线程。如果预期有间歇性的故障,应用程序应该实现超时概念。
设计无状态应用程序
应用程序和服务应该设计为无状态的。具有状态的服务可能会导致可扩展性成为挑战,而无状态服务则容易扩展。有状态就意味着需要额外的组件和实现,例如复制、集中式或分布式存储库、维护和粘性会话。所有这些都是可扩展性道路上的障碍。试想一个服务在本地服务器上维护一个活动状态。无论整体应用程序或单个服务器上的请求数量如何,后续请求必须由相同的服务器处理,其他服务器无法处理这些请求。这使得可扩展性的实现变得具有挑战性。
缓存和内容分发网络(CDN)
应用程序和服务应利用缓存技术。缓存有助于消除多次对数据库或文件系统的后续调用。这有助于使资源可用并为空间腾出更多请求。CDN 是另一种用于缓存静态文件(如图片和 JavaScript 库)的机制。这些文件在全球范围内的服务器上可用,也使资源可用并为空间腾出更多客户端请求——这使得应用程序具有高度可扩展性。
N+1 设计
N+1 设计 指的是在每个组件的整体部署中构建冗余。这意味着即使在没有要求的情况下,也要规划一定的冗余。这可能意味着额外的虚拟机、存储和网络接口。
在设计使用 VMSS 的工作负载时,考虑上述最佳实践将提高应用程序的可扩展性。在下一部分中,我们将探讨监控。
监控
监控是一个重要的架构问题,应该是任何解决方案的一部分,无论是大型还是小型、关键任务还是非关键任务、基于云的还是非基于云的——它不应被忽视。
监控指的是跟踪解决方案并捕获各种遥测信息的过程,处理这些信息,基于规则识别符合警报条件的信息,并触发警报。通常,环境中会部署一个代理进行监控,收集遥测信息并发送到集中服务器,在那里进行警报生成和通知相关人员的处理。
监控采取了主动和被动的措施来应对解决方案的挑战。它也是审计解决方案的第一步。如果没有监控日志记录的能力,从多个角度(如安全性、性能和可用性)审计系统是困难的。
监控有助于我们在问题发生之前识别可用性、性能和可扩展性问题。硬件故障、软件配置错误和补丁更新问题可以在影响用户之前通过监控发现,性能下降也可以在发生前得到修复。
被动监控通过日志记录标出导致问题的特定区域和位置,识别问题并加速修复过程。
团队可以通过监控遥测信息识别问题的模式,并通过创新新的解决方案和功能来消除它们。
Azure 是一个丰富的云环境,提供了多种丰富的监控功能和资源,不仅可以监控基于云的部署,还可以监控本地部署。
Azure 监控
首要问题是,“我们必须监控什么?” 对于部署在云上的解决方案来说,这个问题变得更加重要,因为我们对其控制有限。
有一些重要的组件需要被监控。它们包括以下内容:
-
自定义应用程序
-
Azure 资源
-
客户操作系统(虚拟机)
-
主机操作系统(Azure 物理服务器)
-
Azure 基础设施
针对这些组件,Azure 提供了不同的日志记录和监控服务,以下章节将讨论这些服务。
Azure 活动日志
以前被称为审计日志和操作日志,活动日志是 Azure 平台上的控制平面事件。它们提供了在订阅级别而非单个资源级别的信息和遥测数据。活动日志跟踪在订阅级别发生的所有更改的信息,例如使用Azure 资源管理器(ARM)创建、删除和更新资源。活动日志帮助我们发现资源的身份(如服务主体、用户或组),以及执行对资源的操作(如写入或更新)(例如,存储、虚拟机或 SQL 数据库)。它们提供有关资源的配置信息变更,而不是资源的内部工作和执行。例如,您可以查看启动虚拟机、调整虚拟机大小或停止虚拟机的日志。
接下来我们要讨论的主题是诊断日志。
Azure 诊断日志
来源于 Azure 资源内部工作的信息被记录在所谓的诊断日志中。它们提供关于资源操作的遥测信息,这些操作是资源固有的。并不是所有资源都提供诊断日志,而且提供自己内容日志的资源与其他资源完全不同。诊断日志是为每个资源单独配置的。诊断日志的示例包括在存储帐户中的容器中存储文件。
接下来我们将讨论的日志类型是应用程序日志。
Azure 应用程序日志
应用程序日志可以通过应用程序洞察资源捕获,并且可以集中管理。它们获取自定义应用程序的内部工作信息,如性能指标和可用性,用户可以从中获得见解,以便更好地管理它们。
最后,我们将讨论来宾操作系统和主机操作系统日志。让我们理解一下它们是什么。
来宾操作系统和主机操作系统日志
使用 Azure Monitor,用户可以获得来宾操作系统和主机操作系统的日志。这些日志提供了主机和来宾操作系统的状态信息:
图 2.16:Azure 中的日志记录
重要的 Azure 监控相关资源包括 Azure Monitor、Azure Application Insights 和 Log Analytics,后者以前称为操作洞察。
还有一些工具,如系统中心操作管理器(SCOM),它们不是云功能的一部分,但可以部署在基于 IaaS 的虚拟机上,监控 Azure 或本地数据中心中的任何工作负载。让我们在接下来的章节中讨论三种监控资源。
Azure Monitor
Azure Monitor 是一个核心工具和资源,提供完整的管理功能,使你能够监控 Azure 订阅。它为活动日志、诊断日志、指标、Application Insights 和 Log Analytics 提供管理功能。应将其视为所有其他监控功能的仪表板和管理资源。
我们的下一个主题是 Azure Application Insights。
Azure Application Insights
Azure Application Insights 提供集中式的 Azure 规模监控、日志和指标功能,供自定义应用程序使用。自定义应用程序可以将指标、日志和其他遥测信息发送到 Azure Application Insights。它还提供丰富的报告、仪表板和分析功能,帮助从传入数据中获取洞察并采取行动。
现在我们已经讨论了 Application Insights,让我们来看看另一个类似的服务——Azure Log Analytics。
Azure Log Analytics
Azure Log Analytics 使日志的集中处理成为可能,并从中生成洞察和警报。活动日志、诊断日志、应用程序日志、事件日志,甚至自定义日志都可以将信息发送到 Log Analytics,后者可以进一步提供丰富的报告、仪表板和分析功能,帮助从传入数据中获取洞察并采取行动。
现在我们已经了解了 Log Analytics 的目的,让我们讨论一下日志是如何存储在 Log Analytics 工作区中的,以及如何查询这些日志。
日志
Log Analytics 工作区提供搜索功能,可以搜索特定的日志条目,将所有遥测数据导出到 Excel 和/或 Power BI,并搜索一种名为 Kusto 查询语言(KQL)的查询语言,该语言与 SQL 类似。
日志搜索 屏幕如下所示:
图 2.17:Log Analytics 工作区中的日志搜索
在下一节中,我们将讨论 Log Analytics 解决方案,它们就像是 Log Analytics 工作区中的附加功能。
解决方案
Log Analytics 中的解决方案是可以添加到工作区的附加功能,用于捕获默认情况下未捕获的其他遥测数据。当这些解决方案添加到工作区时,适当的管理包会发送到连接到该工作区的所有代理,以便它们可以自我配置,从虚拟机和容器捕获特定于解决方案的数据,并将其发送到 Log Analytics 工作区。来自 Microsoft 和合作伙伴的监控解决方案可以通过 Azure Marketplace 获取。
Azure 提供了许多 Log Analytics 解决方案,用于跟踪和监控环境和应用程序的不同方面。至少应该向工作区添加一组通用的解决方案,适用于几乎所有环境:
-
容量与性能
-
代理健康
-
变更跟踪
-
容器
-
安全与审计
-
更新管理
-
网络性能监控
监控的另一个关键方面是警报。警报有助于在任何监控事件发生时通知相关人员。接下来的部分,我们将介绍警报的相关内容。
警报
Log Analytics 允许我们生成与摄取数据相关的警报。它通过运行一个预定义的查询来做到这一点,查询由对输入数据的条件组成。如果查询结果中有任何记录符合条件,它就会生成一个警报。Log Analytics 提供了一个高度可配置的环境,用于确定生成警报的条件、查询应返回记录的时间窗口、查询应执行的时间窗口以及当查询返回警报时采取的行动:
图 2.18:通过 Log Analytics 配置警报
让我们逐步了解如何通过 Log Analytics 配置警报:
-
配置警报的第一步是通过 Azure 门户或从 Log Analytics 资源的警报菜单中使用自动化添加新的警报规则。
-
配置警报的第一步是通过 Azure 门户或从 Log Analytics 资源的警报菜单中使用自动化添加新的警报规则。
-
从结果面板中,选择警报规则的范围。范围决定了应监控哪个资源以触发警报——它可以是资源实例,如 Azure 存储账户,也可以是资源类型,如 Azure 虚拟机,资源组或订阅:
图 2.19:为警报选择资源
-
在选择资源之后,必须为警报设置条件。条件决定了评估所选资源上的日志和指标的规则,只有在条件为真时,警报才会被触发。有许多可用的指标和日志可以用来生成条件。在以下示例中,创建了一个静态阈值为 80% 的CPU 使用率百分比(平均值)的警报,并且数据每五分钟收集一次,每分钟评估一次:
图 2.20:为 CPU 使用率百分比(平均值)创建警报
警报还支持动态阈值,它使用机器学习来学习指标的历史行为,并检测可能表示服务问题的不正常现象。
-
最后,创建一个操作组或重用现有的组,该组确定向利益相关者发送与警报相关的通知。操作组部分允许你配置警报后需要执行的内容。通常,应该有一个补救和/或通知动作。Log Analytics 提供了八种不同的方式来创建一个新操作。这些操作可以按任何你喜欢的方式组合。一个警报会执行以下任何或所有配置的操作:
-
电子邮件/SMS/推送/语音通知:这将向配置的收件人发送电子邮件/SMS/推送/语音通知。
-
Webhook:Webhook 使用 HTTP POST 机制运行任意外部进程。例如,可以执行 REST API,或调用 Service Manager/ServiceNow API 来创建工单。
-
Azure 函数:此操作运行一个 Azure 函数,传递必要的负载并运行负载中包含的逻辑。
-
逻辑应用程序:此操作执行自定义逻辑应用程序工作流。
-
电子邮件 Azure 资源管理器角色:此操作向 Azure 资源管理器角色的持有者发送电子邮件,例如所有者、贡献者或读取者。
-
安全 Webhook:Webhook 使用 HTTP POST 机制运行任意外部进程。Webhook 使用身份提供者进行保护,例如 Azure Active Directory。
-
自动化运行书:此操作执行 Azure 自动化运行书。
-
ITSM:在使用此选项之前,应该先配置 ITSM 解决方案。它有助于将信息连接并发送到 ITSM 系统。
-
-
完成所有配置后,你需要提供 名称、描述 和 严重性 值,以便生成警报规则。
正如本节开头提到的,警报在监控中起着至关重要的作用,它帮助授权人员根据触发的警报采取必要的行动。
摘要
高可用性和可扩展性是至关重要的架构问题。几乎每个应用程序和每个架构师都尝试实现高可用性。Azure 是一个成熟的平台,理解应用程序中这些架构需求的重要性,并提供资源以在多个层次上实现这些需求。这些架构问题不是事后考虑的,它们应该是应用程序开发生命周期的一部分,从规划阶段开始。
监控是任何解决方案的重要架构方面。它也是能够正确审计应用程序的第一步。它使运维团队能够对解决方案进行管理,既可以被动响应,也可以主动预防。它提供了处理平台和应用程序可能出现问题所需的记录。Azure 提供了许多与监控实施相关的资源,适用于 Azure、其他云和本地数据中心。Application Insights 和 Log Analytics 是其中最重要的两个资源。不用说,监控是通过基于监控数据的洞察力创新来改进解决方案和产品的必要条件。
本章纯粹讲解了解决方案的可用性、可扩展性和监控;下一章将介绍与虚拟网络、存储帐户、区域、可用性区域和可用性集相关的设计模式。在云中设计解决方案时,这些原则在构建具有成本效益、提高生产力和可用性的解决方案中至关重要。
第三章:3. 设计模式 – 网络、存储、消息传递和事件
在上一章中,你概览了 Azure 云并了解了一些相关的重要概念。本章讲解的是与虚拟网络、存储帐户、区域、可用性区域和可用性集相关的 Azure 云设计模式。这些是影响最终架构的重要构建块,直接关系到成本、效率和整体生产力。本章还简要讨论了帮助我们实现架构可扩展性和性能的云设计模式。
本章将涵盖以下主题:
-
Azure 虚拟网络设计
-
Azure 存储设计
-
Azure 可用性区域、区域和可用性集
-
与消息传递、性能和可扩展性相关的 Azure 设计模式
Azure 可用性区域和区域
Azure 由大型数据中心支持,这些数据中心通过一个庞大的网络互联。数据中心根据其物理位置的接近性,分组为 Azure 区域。例如,西欧的数据中心对西欧区域的 Azure 用户可用。用户无法选择其偏好的数据中心,他们只能选择 Azure 区域,Azure 会分配一个合适的数据中心。
选择合适的区域是一个重要的架构决策,因为它会影响:
-
资源的可用性
-
数据和隐私合规性
-
应用程序的性能
-
运行应用程序的成本
让我们详细讨论一下这些要点。
资源的可用性
并非所有资源都在每个 Azure 区域中可用。如果你的应用架构要求的资源在某个区域不可用,那么选择该区域是没有帮助的。相反,应该根据应用程序所需资源的可用性来选择区域。可能在开发应用程序架构时该资源不可用,但它可能在 Azure 的发展路线图中,后续会使其可用。
例如,Log Analytics 并非在所有区域都可用。如果你的数据源位于区域 A,而 Log Analytics 工作区位于区域 B,你需要支付带宽费用,即从区域 A 到 B 的数据出口费用。类似地,一些服务只能与位于同一区域的资源一起使用。例如,如果你希望加密部署在区域 A 的虚拟机磁盘,你需要在区域 A 部署 Azure Key Vault 来存储加密密钥。在部署任何服务之前,你需要检查你的依赖服务是否在该区域内可用。查看 Azure 产品在各个区域的可用性的一个好途径是这个产品页面:azure.microsoft.com/global-infrastructure/services
。
数据和隐私合规性
每个国家都有自己的数据和隐私合规性规定。有些国家对于将其公民的数据存储在本国领土内有非常明确的要求。因此,在设计每个应用程序的架构时,必须考虑到这些法律要求。
应用程序性能
应用程序的性能取决于请求和响应到达目标并返回时所经过的网络路由。地理上更接近的区域不一定是延迟最低的区域。我们可以按公里或英里来计算距离,但延迟是基于数据包所经过的路径。例如,部署在西欧的面向东南亚用户的应用程序,其性能可能不如部署在东亚区域面向该地区用户的应用程序。因此,确保在离您最近的区域架构解决方案至关重要,以提供最低的延迟和最佳的性能。
运行应用程序的成本
Azure 服务的费用因区域而异。应选择整体成本较低的区域。本书中有完整的一章讲解成本管理(第六章,Azure 解决方案的成本管理),可以参考其中的详细信息。
到目前为止,我们已经讨论了如何选择合适的区域来架构我们的解决方案。现在我们已经确定了适合解决方案的区域,接下来我们将讨论如何在 Azure 中设计我们的虚拟网络。
虚拟网络
虚拟网络应该像物理办公室或家庭局域网一样考虑。从概念上讲,它们是相同的,尽管Azure 虚拟网络(VNet)作为一种软件定义网络,通过庞大的物理网络基础设施实现。
VNet 是托管虚拟机所必需的。它提供了 Azure 资源之间的安全通信机制,使得它们能够相互连接。VNet 为资源提供内部 IP 地址,便于访问和连接其他资源(包括同一虚拟网络上的虚拟机),路由请求,并提供与其他网络的连接。
虚拟网络包含在一个资源组中,并托管在某个区域内,例如西欧。它不能跨多个区域,但可以跨该区域内的所有数据中心,这意味着我们可以跨区域的多个可用性区域构建虚拟网络。对于跨区域的连接,虚拟网络可以通过 VNet 对 VNet 连接实现互联。
虚拟网络还提供与本地数据中心的连接,支持混合云架构。可以使用多种 VPN 技术将本地数据中心扩展到云端,例如站点对站点 VPN 和点对站点 VPN。还可以通过使用 ExpressRoute,在 Azure VNet 与本地网络之间建立专用连接。
虚拟网络是免费的。每个订阅可以在所有区域内创建最多 50 个虚拟网络。然而,如果需要增加此数量,可以联系 Azure 支持团队。如果数据不离开部署区域,将不会收费。截止撰写本文时,来自同一地区的可用性区域之间的进出数据传输不会产生费用;但是,从 2020 年 7 月 1 日起,将开始计费。
有关网络限制的信息可以在 Microsoft 文档中找到,网址为 docs.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits
。
虚拟网络的架构考虑因素
虚拟网络与其他资源一样,可以通过 ARM 模板、REST API、PowerShell 和 CLI 进行配置。在开发生命周期的早期尽可能规划网络拓扑非常重要,以避免后续出现问题。这是因为一旦网络被配置并且资源开始使用它,就很难在没有停机的情况下进行更改。例如,将虚拟机从一个网络移动到另一个网络时,需要先关闭虚拟机。
让我们看看在设计虚拟网络时的一些关键架构考虑因素。
区域
VNet 是 Azure 的一项资源,并且在某个区域内进行配置,例如西欧。跨多个区域的应用程序需要分别为每个区域配置虚拟网络,并且还需要通过 VNet-to-VNet 连接进行连接。VNet-to-VNet 连接会产生进出流量的费用。对于传入(入口)数据没有费用,但传出数据会产生费用。
专用 DNS
VNet 默认使用 Azure 的 DNS 来解析虚拟网络中的名称,并且也支持互联网名称解析。如果应用程序需要专用的名称解析服务或希望连接到本地数据中心,它应该配置自己的 DNS 服务器,并且该服务器应在虚拟网络内配置以确保名称解析成功。此外,你可以将公共域名托管在 Azure 中,并通过 Azure 门户完全管理记录,而无需管理额外的 DNS 服务器。
虚拟网络数量
虚拟网络的数量受区域数量、服务的带宽使用、跨区域连接和安全性的影响。比起多个较小的 VNet,拥有较少但更大的 VNet 可以消除管理负担。
每个虚拟网络中的子网数量
子网提供虚拟网络内的隔离。它们还可以提供安全边界。网络安全组(NSG)可以与子网关联,从而限制或允许对 IP 地址和端口的特定访问。具有独立安全性和可访问性要求的应用组件应放置在独立的子网中。
网络和子网的 IP 范围
每个子网都有一个 IP 范围。IP 范围不应过大,以免 IP 地址未得到充分利用,但也不应过小,以免由于缺乏 IP 地址而使子网变得无法使用。部署的未来 IP 地址需求应考虑在内。
应为 Azure 网络、子网和本地数据中心的 IP 地址和范围进行规划。为了确保无缝连接性和可访问性,应该避免重叠。
监控
监控是一个重要的架构方面,必须包含在整体部署中。Azure 网络监视器提供了日志记录和诊断功能,能够洞察网络性能和健康状况。Azure 网络监视器的一些功能包括:
-
诊断虚拟机的网络流量过滤问题
-
理解用户定义路由的下一跳
-
查看虚拟网络中的资源及其关系
-
监控虚拟机与终端之间的通信
-
捕获来自虚拟机的流量
-
NSG 流量日志,用于记录与通过 NSG 的流量相关的信息。这些数据将存储在 Azure 存储中,以供进一步分析。
它还提供了资源组中所有网络资源的诊断日志。
网络性能可以通过日志分析进行监控。网络性能监视器管理解决方案提供了网络监控功能。它监控网络的健康状况、可用性和可达性。它还用于监控公共云和本地子网之间的连接性,这些子网承载多层应用的不同层。
安全性考虑事项
虚拟网络是 Azure 上任何资源访问的首要组件。安全性在允许或拒绝访问资源中起着重要作用。NSG 是启用虚拟网络安全性的主要手段。它们可以附加到虚拟网络子网上,每个进出流量都受到其约束、过滤和允许。
用户定义的路由(UDR)和 IP 转发也有助于过滤和路由请求到 Azure 上的资源。你可以在 docs.microsoft.com/azure/virtual-network/virtual-networks-udr-overview
阅读更多关于 UDR 和强制隧道的信息。
Azure 防火墙是 Azure 提供的完全托管的防火墙即服务。它可以帮助你保护虚拟网络中的资源。Azure 防火墙可以用于传入和传出的流量包过滤等操作。此外,Azure 防火墙的威胁情报功能可以用于提醒并拒绝来自或去往恶意域名或 IP 地址的流量。IP 地址和域名的数据来源是 Microsoft 的威胁情报数据流。
还可以通过部署网络设备(azure.microsoft.com/solutions/network-appliances
)来保护资源,这些设备包括 Barracuda、F5 和其他第三方组件。
部署
虚拟网络应部署在各自独立的资源组中。网络管理员应获得所有者的许可才能使用该资源组,而开发人员或团队成员应拥有贡献者权限,以便他们可以在其他资源组中创建使用虚拟网络服务的其他 Azure 资源。
将具有静态 IP 地址的资源部署在专用子网中是一个好的实践,而与动态 IP 地址相关的资源可以部署在另一个子网中。
策略不仅应创建,以确保只有网络管理员可以删除虚拟网络,还应对其进行标签标记,以便用于计费目的。
连接性
虚拟网络中同一地区的资源可以无缝地互相通信。即使是虚拟网络中其他子网的资源,也可以在没有任何明确配置的情况下相互通信。不同地区的资源无法使用相同的虚拟网络。虚拟网络的边界是在一个地区内。要实现跨区域的资源通信,我们需要在两端部署专用网关以促进通信。
话虽如此,如果你希望在不同地区的两个网络之间建立私有连接,你可以使用全球 VNet 对等互联。使用全球 VNet 对等互联时,通信通过 Microsoft 的骨干网进行,这意味着在通信过程中不需要公共互联网、网关或加密。如果你的虚拟网络位于同一区域但使用不同的地址空间,那么一个网络中的资源将无法与另一个网络中的资源通信。由于它们位于同一区域,我们可以使用虚拟网络对等互联,这类似于全球 VNet 对等互联;唯一的区别是源虚拟网络和目标虚拟网络部署在同一区域内。
由于许多组织采用了混合云,Azure 资源有时需要与本地数据中心进行通信或连接,反之亦然。Azure 虚拟网络可以使用 VPN 技术和 ExpressRoute 连接到本地数据中心。实际上,一个虚拟网络能够同时连接多个本地数据中心和其他 Azure 区域。作为最佳实践,每个连接应位于虚拟网络内的专用子网中。
现在我们已经探讨了虚拟网络的多个方面,接下来让我们讨论虚拟网络的好处。
虚拟网络的好处
虚拟网络是部署任何有意义的 IaaS 解决方案所必需的。没有虚拟网络,无法配置虚拟机。除了在 IaaS 解决方案中几乎是一个强制性组件外,它们还提供了巨大的架构优势,其中一些在此列出:
-
隔离性:大多数应用组件有独立的安全性和带宽要求,并且生命周期管理不同。虚拟网络帮助为这些组件创建隔离的区域,可以借助虚拟网络和子网独立管理这些组件,而不影响其他组件。
-
安全性:过滤和跟踪访问资源的用户是虚拟网络提供的重要功能。它们可以阻止对恶意 IP 地址和端口的访问。
-
可扩展性:虚拟网络就像云上的私人局域网。通过连接全球的其他虚拟网络,它们还可以扩展为广域网(WAN),并且可以作为本地数据中心的扩展。
我们已经探讨了虚拟网络的好处。现在的问题是我们如何利用这些好处并设计一个虚拟网络来托管我们的解决方案。在接下来的部分,我们将讨论虚拟网络的设计。
虚拟网络设计
在本节中,我们将考虑一些流行的虚拟网络设计和用例场景。
虚拟网络有多种用途。可以在每个虚拟网络端点部署网关,以启用安全性并传输完整性和保密性的数据包。在连接到本地网络时,必须使用网关;然而,在使用 Azure VNet 对等连接时,网关是可选的。此外,您还可以利用网关传输功能,简化扩展本地数据中心的过程,而无需部署多个网关。网关传输功能允许您与所有对等虚拟网络共享 ExpressRoute 或 VPN 网关。这将使管理变得更加容易,并减少部署多个网关的成本。
在上一节中,我们提到了对等连接,并提到我们不使用网关或公共互联网来建立对等网络之间的通信。接下来我们将进一步探讨对等连接的设计方面,以及在特定场景下需要使用哪些对等连接。
连接同一区域和订阅内的资源
同一区域和订阅内的多个虚拟网络可以相互连接。在 VNet 对等连接的帮助下,两个网络可以连接,并使用 Azure 私有网络骨干网互相传输数据包。这些网络上的虚拟机和服务可以相互通信,但受限于网络流量的约束。在下图中,VNet1 和 VNet2 都部署在美国西部区域。然而,VNet1 的地址空间是 172.16.0.0/16,而 VNet2 的地址空间是 10.0.0.0/16。默认情况下,VNet1 中的资源无法与 VNet2 中的资源通信。由于我们已经在两者之间建立了 VNet 对等连接,因此这些资源将能够通过 Microsoft 骨干网络相互通信:
图 3.1:相同订阅内资源的 VNet 对等连接
连接到另一个订阅内同一区域的资源
这个场景与前一个场景非常相似,唯一不同的是虚拟网络托管在两个不同的订阅中。这些订阅可以属于同一个租户,也可以来自多个租户。如果两个资源属于同一个订阅并且位于同一区域,则适用前一个场景。这个场景可以通过两种方式实现:使用网关或使用虚拟网络对等连接。
如果我们在这个场景中使用网关,我们需要在两端部署网关以促进通信。以下是使用网关连接两个不同订阅资源的架构表示:
图 3.2:使用网关进行不同订阅资源的 VNet 对等连接
然而,部署网关会产生一些费用。我们将讨论 VNet 对等连接,之后我们会比较这两种实现方式,看看哪种方式最适合我们的解决方案。
在使用对等连接时,我们不会部署任何网关。图 3.3 展示了如何进行对等连接:
图 3.3:跨订阅的 VNet 对等连接
VNet 对等连接提供了低延迟、高带宽的连接,如图所示,我们没有部署任何网关来实现通信。这对于数据复制或故障转移等场景非常有用。如前所述,对等连接使用 Microsoft 骨干网络,消除了对公共互联网的需求。
网关用于需要加密且带宽不是问题的场景,因为这将是一个带宽有限的连接。然而,这并不意味着带宽有约束。此方法适用于对延迟不太敏感的客户。
到目前为止,我们已经查看了跨订阅的同一区域资源。在下一节中,我们将探讨如何在两个不同区域的虚拟网络之间建立连接。
连接到另一个订阅中不同区域的资源
在这种场景中,我们有两个实现方式,一个使用网关,另一个使用全球 VNet 对等连接。
流量将通过公共网络传输,我们将在两端部署网关以便建立加密连接。图 3.4 说明了实现方法:
图 3.4:使用不同订阅连接不同区域的资源
我们将采用类似的方式使用全球 VNet 对等连接。图 3.5 显示了如何使用全球 VNet 对等连接:
图 3.5:使用全球 VNet 对等连接连接不同区域的资源
选择网关或对等连接的考虑因素已在之前讨论过,这些考虑因素在本场景中同样适用。到目前为止,我们已经讨论了跨区域和订阅连接虚拟网络;但我们还没有讨论如何将本地数据中心连接到云。接下来的部分将讨论实现这一目标的方法。
连接到本地数据中心
虚拟网络可以连接到本地数据中心,从而使 Azure 和本地数据中心成为一个单一的广域网(WAN)。需要在网络的两侧部署网关和 VPN。为此,有三种不同的技术可供选择。
站点到站点 VPN
当 Azure 网络和本地数据中心连接以形成一个广域网(WAN),且两个网络中的任何资源都可以访问网络中的任何其他资源,无论它们是部署在 Azure 还是本地数据中心时,应使用此方法。为了安全起见,需要在两端的网络上部署 VPN 网关。此外,Azure 网关应部署在与本地数据中心连接的虚拟网络的子网中。本地网关必须分配公共 IP 地址,以便 Azure 通过公共网络连接到它们:
图 3.6:站点到站点 VPN 架构
点对站点 VPN
这类似于站点到站点的 VPN 连接,但有一个单一的服务器或计算机连接到本地数据中心。当需要从远程位置安全地连接到 Azure 且只有少数用户或客户端时,应使用此方式。此外,在这种情况下,无需在本地侧配置公共 IP 和网关:
图 3.7:点对站点 VPN 架构
ExpressRoute
无论是站点到站点(site-to-site)还是点对站点(point-to-site)VPN,均使用公共互联网工作。它们通过 VPN 和证书技术对网络流量进行加密。然而,一些应用程序希望使用混合技术进行部署——一部分组件部署在 Azure,另一部分部署在本地数据中心——同时又不希望使用公共互联网连接 Azure 和本地数据中心。对于这些需求,Azure ExpressRoute 是最佳解决方案,尽管它比另外两种连接方式成本更高。它也是最安全和可靠的提供商,速度更快,延迟更低,因为流量不会经过公共互联网。Azure ExpressRoute 可以通过连接提供商通过专用私有连接将本地网络扩展到 Azure。如果你的解决方案是网络密集型的,例如事务性企业应用程序(如 SAP),强烈建议使用 ExpressRoute。
图 3.8:ExpressRoute 网络架构
图 3.9 显示了三种混合网络类型:
图 3.9:不同类型的混合网络
从安全性和隔离的角度来看,虚拟网络为每个逻辑组件创建单独的子网并进行独立部署是一种良好的实践。
我们在 Azure 部署的所有资源都需要某种方式的网络支持,因此在架构设计 Azure 解决方案时,需要深入理解网络知识。另一个关键要素是存储。在接下来的章节中,你将进一步了解存储。
存储
Azure 通过存储服务提供了一个持久、高可用且可扩展的存储解决方案。
存储用于持久化数据,以满足长期需求。Azure 存储可以通过互联网为几乎所有编程语言提供服务。
存储类别
存储有两类存储账户:
-
一种标准存储性能层,允许你存储表格、队列、文件、Blob 和 Azure 虚拟机磁盘。
-
一种支持 Azure 虚拟机磁盘的高级存储性能层,写作时,Premium 存储比标准通用存储提供更高的性能和 IOPS。Premium 存储当前作为虚拟机的数据磁盘,使用 SSD 作为支持。
根据存储的数据类型,存储可以分为不同的类型。让我们来看一下存储类型,并深入了解它们。
存储类型
Azure 提供四种常见的存储服务:
-
Azure Blob 存储: 这种存储类型最适合非结构化数据,如文档、图片和其他类型的文件。Blob 存储可以分为热存储、冷存储和归档存储。热存储适用于需要非常频繁访问的数据。冷存储适用于访问频率低于热存储的数据,并且数据的存储时间为 30 天。最后,归档存储适用于归档目的,访问频率非常低。
-
Azure 表格存储: 这是一个 NoSQL 键值数据存储,适用于结构化数据。数据以实体的形式存储。
-
Azure 队列存储: 这提供了可靠的消息存储,用于存储大量消息。这些消息可以通过 HTTP 或 HTTPS 调用从任何地方访问。队列消息的最大大小为 64 KB。
-
Azure 文件: 这是基于 SMB 协议的共享存储,通常用于存储和共享文件。它也存储非结构化数据,但其主要区别在于它可以通过 SMB 协议进行共享。
-
Azure 磁盘: 这是 Azure 虚拟机的块级存储。
这五种存储类型满足不同的架构需求,涵盖几乎所有类型的数据存储设施。
存储功能
Azure 存储是弹性的,这意味着您可以存储从几兆字节到几拍字节的数据。您无需预先设置存储容量,它会自动增长和收缩。用户只需为实际使用的存储付费。以下是使用 Azure 存储的一些主要好处:
-
Azure 存储是安全的,只能通过 SSL 协议访问。此外,访问必须经过身份验证。
-
Azure 存储提供了生成帐户级安全访问签名(SAS)令牌的功能,存储客户端可以使用该令牌进行身份验证。还可以为 Blob、队列、表格和文件生成单独的服务级 SAS 令牌。
-
存储在 Azure 存储中的数据可以被加密,这被称为静态数据加密。
-
Azure 磁盘加密用于加密 IaaS 虚拟机中的操作系统和数据磁盘。客户端加密(CSE)和存储服务加密(SSE)都用于加密 Azure 存储中的数据。SSE 是 Azure 存储的一个设置,确保在数据写入存储时加密,并在存储引擎读取数据时解密。这确保了启用 SSE 不需要任何应用程序更改。在 CSE 中,客户端应用程序可以使用存储 SDK 在数据发送并写入 Azure 存储之前对数据进行加密。客户端应用程序可以在读取数据时再解密这些数据。这为数据传输中的数据和静态数据提供了安全性。CSE 依赖于 Azure 密钥保管库中的密钥。
-
Azure 存储具有高度的可用性和持久性。这意味着 Azure 始终保持多个 Azure 账户的副本。副本的地点和数量取决于复制配置。
Azure 提供以下复制设置和数据冗余选项:
-
本地冗余存储(LRS):在主区域的单一物理位置内,将同步存储三份数据副本。从计费的角度来看,这是最便宜的选项;然而,它不推荐用于需要高可用性的解决方案。LRS 提供在给定一年内对象的 99.999999999% 的持久性级别。
-
区域冗余存储(ZRS):在 LRS 的情况下,副本存储在同一物理位置。而在 ZRS 的情况下,数据将同步复制到主区域内的可用区。由于这些可用区都是主区域内的独立物理位置,ZRS 提供比 LRS 更好的持久性和更高的可用性。
-
地理冗余存储(GRS):GRS 通过使用 LRS 在单一主区域内同步复制三份数据副本,从而提高高可用性。它还将数据复制到次要区域的单一物理位置。
-
地理区域冗余存储(GZRS):这与 GRS 非常相似,但不同之处在于,GZRS 不是在主区域内单一物理位置复制数据,而是跨三个可用区同步复制数据。正如我们在 ZRS 的案例中所讨论的,由于可用区是主区域内独立的物理位置,GZRS 提供了更好的持久性,并且可以包含在高可用设计中。
-
读取访问地理冗余存储(RA-GRS)和读取访问地理区域冗余存储:通过 GZRS 或 GRS 复制到次要区域的数据无法进行读写。这些数据将在主数据中心发生故障转移时由次要区域使用。RA-GRS 和 RA-GZRS 遵循与 GRS 和 GZRS 相同的复制模式;唯一的区别是通过 RA-GRS 或 RA-GZRS 复制到次要区域的数据可以进行读取。
现在我们已经了解了 Azure 上各种存储和连接选项,接下来让我们了解该技术的底层架构。
存储帐户的架构考虑事项
存储帐户应在与其他应用程序组件相同的区域中进行配置。这意味着使用相同的数据中心网络骨干,避免产生任何网络费用。
Azure 存储服务具有与每个服务相关的容量、事务速率和带宽的可扩展性目标。一个通用的存储帐户允许存储 500 TB 的数据。如果需要存储超过 500 TB 的数据,则应创建多个存储帐户或使用高级存储。
通用存储的最大性能为 20,000 IOPS 或每秒 60 MB 的数据。如果需要更高的 IOPS 或每秒管理的数据量,则会受到限制。如果从性能角度来看,这些不足以满足应用程序的需求,那么应使用高级存储或多个存储帐户。对于一个帐户,访问表格的可扩展性限制为最多 20,000(每个 1 KB)条目。插入、更新、删除或扫描的实体数量将计入目标。单个队列每秒可处理大约 2,000 条消息(每条 1 KB),每个 AddMessage
、GetMessage
和 DeleteMessage
的计数将被视为一条消息。如果这些值不足以满足你的应用程序需求,你应该将消息分布到多个队列中。
虚拟机的大小决定了可用数据磁盘的大小和容量。虽然较大的虚拟机具有更高 IOPS 容量的数据磁盘,但最大容量仍将限制为 20,000 IOPS 和每秒 60 MB。需要注意的是,这些是最大值,因此在最终确定存储架构时,应考虑较低的值。
截至目前,GRS 帐户在美国的入站带宽目标为 10 Gbps,如果启用了 RA-GRS/GRS,则为 20 Gbps。对于 LRS 帐户,限制相对较高,入站带宽为 20 Gbps,出站带宽为 30 Gbps。在美国以外,带宽目标较低:入站带宽为 10 Gbps,出站带宽为 5 Gbps。如果需要更高的带宽,可以联系 Azure 支持团队,他们将帮助你获取更多的选项。
存储帐户应启用使用 SAS 令牌进行身份验证。它们不应允许匿名访问。此外,对于 Blob 存储,应根据不同类型和类别的客户端创建不同的容器,并为每个容器生成独立的 SAS 令牌。这些 SAS 令牌应定期重新生成,以确保密钥不会被破解或猜测。你将会在第八章,构建 Azure 上的安全应用程序中了解更多关于 SAS 令牌和其他安全选项的内容。
通常,从 Blob 存储帐户获取的 Blob 应该进行缓存。我们可以通过将其最后修改属性与重新获取的最新 Blob 进行比较,来判断缓存是否过时。
存储帐户提供并发功能,以确保同一文件和数据不会被多个用户同时修改。它们提供以下功能:
-
乐观并发:这允许多个用户同时修改数据,但在写入时,它会检查文件或数据是否已经更改。如果有更改,它会提示用户重新获取数据并再次执行更新操作。这是表格的默认并发方式。
-
悲观并发:当一个应用尝试更新文件时,它会加锁,明确拒绝其他用户对文件的任何更新。这是通过 SMB 协议访问文件时的默认并发模式。
-
最后写者获胜:更新没有限制,最后一个用户会更新文件,而不管最初读取的内容是什么。这是队列、Blob 和文件(通过 REST 访问时)的默认并发模式。
到目前为止,你应该已经知道了不同的存储服务是什么,以及如何在你的解决方案中利用它们。在接下来的章节中,我们将讨论设计模式,并看看它们如何与架构设计相关。
云设计模式
设计模式是针对已知设计问题的成熟解决方案。它们是可重用的解决方案,可以应用于问题中。它们不是可以直接嵌入到解决方案中的可重用代码或设计,而是解决问题的文档化描述和指导。一个问题可能在不同的上下文中表现出来,设计模式可以帮助解决这些问题。Azure 提供了大量的服务,每个服务都提供特定的功能和能力。使用这些服务很简单,但将多个服务结合起来创建解决方案可能会有挑战。而且,为解决方案实现高可用性、超高可扩展性、可靠性、性能和安全性并非易事。
Azure 设计模式提供了可以根据具体问题定制的现成解决方案。它们帮助我们在 Azure 上构建高可用、可扩展、可靠、安全和以性能为中心的解决方案。尽管有许多模式,并且一些模式将在后续章节中详细讨论,但本章提到了其中的一些消息传递、性能和可扩展性模式。同时,还提供了这些模式的详细描述链接。这些设计模式本身值得一本完整的书来讨论。它们在这里被提及,旨在让你意识到它们的存在,并为进一步了解提供参考。
消息传递模式
消息传递模式有助于以松耦合的方式连接服务。这意味着服务之间从不直接通信。相反,服务会生成并将消息发送到一个代理(通常是队列),任何对该消息感兴趣的服务都可以取出并处理它。发送方和接收方服务之间没有直接通信。这种解耦不仅使服务和整个应用程序更可靠,还使其更强健和容错。接收方可以根据自己的速度接收和读取消息。
消息传递有助于创建异步模式。消息传递涉及从一个实体向另一个实体发送消息。这些消息由发送方创建并转发,存储在持久存储中,最后被接收方消费。
消息传递模式解决的主要架构问题如下:
-
耐久性:消息被存储在持久化存储中,应用程序可以在故障转移后读取已接收到的消息。
-
可靠性:消息通过持久化存储在磁盘上,确保不会丢失,从而实现可靠性。
-
消息的可用性:在恢复连接并在停机之前,消息可以供应用程序消费。
Azure 提供了服务总线队列和主题来实现应用程序内的消息传递模式。Azure 队列存储也可以用于相同的目的。
在选择 Azure 服务总线队列与队列存储时,需要考虑消息存储的时间、消息大小、延迟和成本等因素。Azure 服务总线支持 256 KB 的消息,而队列存储支持 64 KB 的消息。Azure 服务总线可以存储消息无限期,而队列存储则只能存储 7 天。服务总线队列的成本和延迟较高。
根据应用程序的需求和要求,在决定最佳队列之前,应考虑上述因素。在下一部分中,我们将讨论不同类型的消息传递模式。
竞争消费者模式
如果应用程序没有实现异步读取消息的逻辑,单一消费者将以同步方式处理消息。竞争消费者模式则提供了一种解决方案,其中多个消费者准备好处理传入的消息,并竞争处理每一条消息。这种方式可以实现高可用性和可扩展的解决方案。此模式可扩展,因为通过多个消费者,可以在较短的时间内处理更多的消息。它具有高可用性,因为即使部分消费者崩溃,仍然会有至少一个消费者可以处理消息。
当每条消息独立于其他消息时,应使用此模式。消息本身包含了消费者完成任务所需的所有信息。如果消息之间存在依赖关系,则不应使用此模式。消费者应能够在隔离的情况下完成任务。此外,如果服务需求波动,则此模式适用。可以根据需求增加或删除消费者。
实现竞争消费者模式需要一个消息队列。在这里,来自多个来源的模式通过一个单一的队列传递,队列的另一端连接着多个消费者。这些消费者在读取每条消息后应删除该消息,以防止它们被重新处理:
图 3.10:竞争消费者模式
请参阅 Microsoft 文档 docs.microsoft.com/azure/architecture/patterns/competing-consumers
以了解有关此模式的更多信息。
优先队列模式
经常需要优先处理某些消息。这个模式对那些为消费者提供不同服务级别协议(SLA)的应用程序非常重要,这些应用程序根据不同的计划和订阅提供服务。
队列遵循先进先出(FIFO)模式。消息按顺序处理。然而,在优先级队列模式的帮助下,可以根据消息的优先级加速某些消息的处理。实现这一点有多种方法。如果队列允许你分配优先级并根据优先级重新排序消息,那么即使是单一队列也足以实现这一模式:
图 3.11:单一优先级队列模式
然而,如果队列无法重新排序消息,可以为不同的优先级创建独立的队列,并且每个队列可以有与之关联的独立消费者:
图 3.12:使用独立消息队列处理不同优先级
事实上,该模式可以使用竞争消费者模式(Competing Consumer pattern)来加速使用多个消费者处理每个队列中的消息。有关优先级队列模式的更多信息,请参阅微软文档 docs.microsoft.com/azure/architecture/patterns/priority-queue
。
基于队列的负载均衡模式
基于队列的负载均衡模式减少了需求峰值对任务和服务的可用性和警觉性的影响。在任务和服务之间,队列将充当缓冲区。它可以在发生突发负载时被调用,避免服务中断或超时。该模式有助于解决性能和可靠性问题。为了防止服务超载,我们将引入一个队列,直到服务取出消息。服务将以一致的方式从队列中取出并处理消息。
图 3.13 展示了基于队列的负载均衡模式的工作原理:
图 3.13:基于队列的负载均衡模式
尽管该模式有助于处理意外需求的激增,但在构建低延迟服务时,它不是最佳选择。说到延迟,它是一个性能指标,下一节我们将专注于性能和可扩展性模式。
性能和可扩展性模式
性能和可扩展性是相辅相成的。性能是衡量系统在给定时间间隔内如何快速、有效地执行操作的指标。另一方面,可扩展性是指系统在不影响性能的情况下处理意外负载的能力,或者系统如何利用现有资源迅速扩展。在本节中,将介绍与性能和可扩展性相关的几个设计模式。
命令与查询职责分离(CQRS)模式
CQRS 不是一个特定于 Azure 的模式,而是一个可以应用于任何应用程序的一般模式。它可以提高应用程序的整体性能和响应能力。
CQRS 是一种将读取数据(查询)操作与更新数据(命令)操作隔离开来的模式,通过使用不同的接口。这意味着用于查询和更新的数据模型是不同的。然后,这些模型可以像图 3.14中所示那样隔离,尽管这不是强制要求。
当在更新和检索数据时,涉及大量复杂的业务规则时,应该使用该模式。此外,这种模式在某些情况下非常适用,其中一个开发团队可以专注于写模型中复杂的领域模型,另一个团队可以专注于读模型和用户界面。当读写比例失衡时,使用该模式也是明智的。数据读取的性能应该与数据写入的性能分开调优。
CQRS 不仅可以提高应用程序的性能,还能帮助多团队的设计和实现。由于其使用不同模型的特性,如果你使用模型和脚手架生成工具,CQRS 就不太适用:
图 3.14:CQRS 模式
请参考 Microsoft 文档 docs.microsoft.com/azure/architecture/patterns/cqrs
,了解有关该模式的更多信息。
事件溯源模式
由于大多数应用程序都涉及数据操作,并且用户也在操作数据,因此应用程序的经典方法是维护和更新数据的当前状态。从源头读取数据,修改数据,然后用修改后的值更新当前状态是典型的数据处理方法。然而,这种方法有一些局限性:
-
由于更新操作直接作用于数据存储,这会降低整体的性能和响应能力。
-
如果有多个用户在操作和更新数据,可能会出现冲突,并且一些相关的更新可能会失败。
解决方案是实现事件溯源(Event Sourcing)模式,其中变更将被记录在仅追加的存储中。应用程序代码会将一系列事件推送到事件存储中,并在那里持久化。这些持久化的事件充当当前数据状态的系统记录。消费者将在事件发布后收到通知,并在需要时处理这些事件。
事件溯源模式如图 3.15所示:
图 3.15:事件溯源模式
更多关于此模式的信息,请访问 docs.microsoft.com/azure/architecture/patterns/event-sourcing
。
限流模式
有些应用程序对性能和可扩展性有非常严格的 SLA(服务级别协议)要求,无论用户数量如何。在这种情况下,实施限流模式非常重要,因为它可以限制允许执行的请求数量。在所有情况下,无法准确预测应用程序的负载。当应用程序的负载激增时,限流通过控制资源消耗来减少服务器和服务的压力。Azure 基础设施是该模式的一个很好的示例。
当满足 SLA 是应用程序的优先事项时,应该使用此模式,以防止某些用户消耗超过分配的资源,优化需求的峰值和波动,并在成本方面优化资源消耗。这些是为部署在云上的应用程序设计的有效场景。
在应用程序中处理限流可以采用多种策略。限流策略可以在超过阈值后拒绝新的请求,或者可以让用户知道请求已在队列中,并且在请求数量减少后会有机会执行。
图 3.16展示了在多租户系统中实施限流模式的情况,其中每个租户都有固定的资源使用限制。一旦超过此限制,任何额外的资源需求都会受到限制,从而为其他租户保留足够的资源:
图 3.16:限流模式
阅读更多关于此模式的信息,请访问 docs.microsoft.com/azure/architecture/patterns/throttling
。
重试模式
重试模式是一个非常重要的模式,使应用程序和服务能够更好地应对瞬时故障。假设你正在尝试连接并使用一个服务,但该服务由于某种原因无法使用。如果该服务很快就会恢复,继续尝试建立连接是有意义的。这将使应用程序更加健壮、容错和稳定。在 Azure 中,大多数组件都运行在互联网环境下,而互联网连接可能会间歇性地产生瞬时故障。由于这些故障可以在几秒钟内修复,因此应用程序不应该崩溃。应用程序应该设计为在失败的情况下反复尝试使用服务,并在成功或最终确定存在需要时间修复的故障时停止重试。
当应用程序与远程服务交互或访问远程资源时可能会遇到瞬时故障时,应该实现此模式。这些故障预计会是短暂的,重复以前失败的请求可能在后续尝试中成功。
重试模式可以根据错误的性质和应用程序的需求采用不同的重试策略。
-
重试固定次数:这意味着应用程序在确定发生失败并引发异常之前,会尝试与服务通信固定的次数。例如,它会重试三次连接到另一个服务。如果在这三次尝试内成功连接,整个操作将成功;否则,它将引发异常。
-
基于计划的重试:这意味着应用程序将在固定的秒数或分钟数内反复尝试与服务通信,并在重试前等待固定的秒数或分钟数。例如,应用程序将在 60 秒内每三秒尝试连接一次服务。如果在此期间成功连接,整个操作将成功;否则,它将引发异常。
-
滑动和延迟重试:这意味着应用程序将根据计划反复尝试与服务通信,并在随后的尝试中逐渐增加延迟。例如,在总计 60 秒内,第一次重试发生在一秒后,第二次重试发生在上一次重试后两秒,第三次重试发生在上一次重试后四秒,以此类推。这减少了重试的总次数。
图 3.17 演示了重试模式。第一次请求得到 HTTP 500 响应,第二次重试仍然得到 HTTP 500 响应,最后请求成功并得到 HTTP 200 响应:
图 3.17:重试模式
请参考此 Microsoft 文档docs.microsoft.com/azure/architecture/patterns/retry
,了解更多关于此模式的信息。
电路断路器模式
这是一个非常有用的模式。再想象一下,当您尝试连接并使用某个服务,而该服务因某种原因不可用。如果该服务在短期内无法恢复,那么继续重试连接毫无意义。此外,在重试时占用其他资源会浪费大量本可以在其他地方使用的资源。
电路断路器模式有助于消除资源浪费。它可以防止应用程序重复尝试连接和使用一个不可用的服务。它还帮助应用程序检测服务是否已恢复运行,并允许应用程序连接到它。
要实现电路断路器模式,所有对服务的请求都应通过一个充当原始服务代理的服务。这个代理服务的目的是维护一个状态机,并充当原始服务的网关。它维持三种状态。根据应用程序的需求,可能会包含更多的状态。
实现此模式所需的最小状态如下:
-
打开:这表示服务不可用,应用程序会立即显示为异常,而不是允许它重试或等待超时。当服务恢复后,状态会过渡到半打开。
-
关闭:该状态表示服务正常,应用程序可以继续连接到它。通常,会显示一个计数器,显示在过渡到打开状态之前的失败次数。
-
半打开:在某个时刻,当服务恢复运行时,该状态允许有限数量的请求通过。这个状态是一个试金石,用来检查通过的请求是否成功。如果请求成功,状态将从半打开过渡到关闭。此状态还可以实现一个计数器,允许一定数量的请求成功后,再过渡到关闭状态。
图 3.18 中展示了三种状态及其过渡:
图 3.18:电路断路器模式
在 Microsoft 文档中阅读更多关于此模式的信息:docs.microsoft.com/azure/architecture/patterns/circuit-breaker
。
在本节中,我们讨论了可以用于构建可靠、可扩展且安全的云应用程序的设计模式。然而,还有其他模式,您可以在docs.microsoft.com/azure/architecture/patterns
上进行探索。
总结
Azure 提供了众多服务,大多数可以组合起来创建真正的解决方案。本章解释了 Azure 提供的三个最重要的服务——区域、存储和网络。它们构成了部署在任何云上的大多数解决方案的基础。本章详细介绍了这些服务及其配置和预配如何影响设计决策。
本章详细介绍了存储和网络的重要考虑因素。网络和存储都提供了许多选择,根据您的需求选择合适的配置至关重要。
最后,介绍了与消息相关的一些重要设计模式,例如竞争消费者、优先队列和负载平衡。还详细说明了诸如 CQRS 和节流等模式,并讨论了其他模式,如重试和断路器。在部署解决方案时,我们将把这些模式作为基准。
在下一章中,我们将讨论如何自动化我们打算设计的解决方案。随着自动化技术的发展,每个组织都希望消除逐一创建资源的开销,这是非常具有挑战性的。由于自动化是解决这一问题的方法,下一章将更深入地探讨这个话题。
第四章:4. 在 Azure 上自动化架构
每个组织都希望减少手动工作和错误,自动化在提高可预测性、标准化和一致性方面发挥着重要作用,不仅在产品开发中,也在运营中。自动化一直是几乎每个首席信息官(CIO)和数字化官员的关注重点,以确保他们的系统具备高可用性、可扩展性、可靠性,并能够满足客户的需求。
随着云计算的到来,自动化变得更加突出,因为新的资源可以随时配置,无需采购硬件资源。因此,云公司希望在几乎所有活动中都能实现自动化,以减少滥用、错误、治理、维护和管理。
本章将评估 Azure 自动化作为一项主要的自动化服务,以及它与其他看似相似的服务相比的差异化能力。本章将涵盖以下内容:
-
Azure 自动化生态
-
Azure 自动化服务
-
Azure 自动化服务的资源
-
编写 Azure 自动化运行书
-
Webhooks
-
混合工作者
让我们开始使用 Azure 自动化,这是一个用于过程自动化的云服务。
自动化
自动化是组织内部 IT 资源的配置、操作、管理和拆除的必要手段。图 4.1 给你展示了每个用例的详细信息:
图 4.1:自动化用例
在云计算到来之前,IT 资源主要是在本地,并且这些活动通常依赖手动过程。然而,随着云的采用增加,自动化得到了更多的关注。主要原因是,云技术的敏捷性和灵活性为实时配置、拆除和管理这些资源提供了机会,而这一过程比以前要快得多。随着这种灵活性和敏捷性而来的,是对云计算要求更加可预测和一致,因为组织现在能够轻松创建资源。
微软提供了一个非常棒的 IT 自动化工具——System Center Orchestrator。它是一个适用于本地和云环境的自动化工具,但它是一个产品,而不是服务。它需要许可并部署在服务器上,然后可以执行运行书,以对云和本地环境进行更改。
微软意识到,需要一种自动化解决方案,可以作为服务提供给客户,而不是作为产品购买和部署。于是,Azure 自动化应运而生。
Azure 自动化
Azure 提供了一项名为 Azure 自动化 的服务,这是一项用于自动化流程、活动和任务的核心服务,不仅适用于 Azure,还可以应用于本地环境。通过 Azure 自动化,组织可以自动化与处理、拆除、运营及管理其跨云、IT 环境、平台和语言资源相关的流程和任务。在图 4.2中,我们可以看到 Azure 自动化的一些功能:
图 4.2:Azure 自动化功能
Azure 自动化架构
Azure 自动化由多个组件组成,这些组件之间完全解耦。大部分集成发生在数据存储级别,且没有组件直接进行通信。
当在 Azure 上创建一个自动化账户时,它由一个管理服务进行管理。该管理服务是所有 Azure 自动化活动的单一联络点。来自门户的所有请求,包括保存、发布、创建运行簿,执行、停止、暂停、启动和测试,都会发送到自动化管理服务,服务将请求数据写入其数据存储。它还会在数据存储中创建一个作业记录,并根据运行簿工作者的状态,将作业分配给一个工作者。
图 4.3:Azure 自动化架构
工作者不断轮询数据库,查找分配给它的新作业。一旦找到作业分配,它会提取作业信息并使用其执行引擎开始执行该作业。结果会写回数据库,由管理服务读取,并显示在 Azure 门户上。
本章后面我们将要了解的混合工作者也是运行簿工作者,尽管它们未在图 4.3中显示。
开始使用 Azure 自动化的第一步是创建一个新账户。账户创建后,所有其他组件都将在该账户内创建。
账户作为主要的顶级资源,可以通过 Azure 资源组及其自身的控制平面进行管理。
账户应当在某个区域内创建,且该账户中的所有自动化操作都将在该区域的服务器上执行。
选择区域时要谨慎,最好选择靠近其他与自动化账户集成或管理的 Azure 资源的区域,以减少区域之间的网络流量和延迟。
自动化帐户还支持几个Run As帐户,可以从自动化帐户中创建。由于这些 Run As 帐户类似于服务帐户,我们通常创建它们以执行操作。尽管我们通常称其为 Run As 帐户,但实际上有两种类型的 Run As 帐户:一种叫做 Azure 经典 Run As 帐户,另一种则简称为 Run As 帐户,二者都用于连接到 Azure 订阅。Azure 经典 Run As 帐户用于通过Azure 服务管理API 连接到 Azure,而 Run As 帐户则用于通过Azure 资源管理(ARM)API 连接到 Azure。
这两个帐户使用证书进行身份验证以连接到 Azure。这些帐户可以在创建自动化帐户时创建,也可以选择稍后从 Azure 门户创建。
建议在稍后创建这些 Run As 帐户,而不是在创建自动化帐户时同时创建,因为如果在设置自动化帐户时创建,它们会在后台使用默认配置生成证书和服务主体。如果需要更多的控制和自定义配置(例如使用现有的证书或服务主体),则应在创建自动化帐户后再创建 Run As 帐户。
一旦创建了自动化帐户,它会提供一个仪表板,通过该仪表板可以启用多个自动化场景。
使用自动化帐户可以启用的一些重要场景包括:
-
流程自动化
-
配置管理
-
更新管理
自动化的目标是编写可重用且通用的脚本,以便它们可以在多个场景中重复使用。例如,一个自动化脚本应该足够通用,可以在任何资源组、任何订阅和管理组中启动和停止任何虚拟机(VM)。如果将虚拟机服务器信息与资源组、订阅和管理组的名称硬编码到脚本中,就会创建多个类似的脚本,并且任何一个脚本的更改都无可避免地会导致所有脚本的更改。为了避免这种情况,最好通过使用脚本参数和变量来创建一个通用的脚本,并确保执行者为这些脚本提供相应的值。
让我们更仔细地看一下前面提到的每个场景。
流程自动化
流程自动化指的是开发反映现实世界流程的脚本。流程自动化包括多个活动,每个活动执行一个独立的任务。所有这些活动共同组成一个完整的流程。活动的执行可能取决于前一个活动是否成功执行。
任何流程自动化都需要其执行所依赖的基础设施满足一些要求。以下是其中的一些要求:
-
创建工作流的能力
-
能够执行长时间运行的任务
-
能够在工作流未完成时保存执行状态,这也被称为检查点和水合作用
-
能够从最后保存的状态恢复,而不是从头开始
接下来我们要探讨的场景是配置管理。
配置管理
配置管理是指在整个生命周期内管理系统配置的过程。Azure 自动化状态配置是 Azure 的配置管理服务,允许用户为云节点和本地数据中心编写、管理和编译 PowerShell DSC 配置。
Azure 自动化状态配置让我们能够管理 Azure 虚拟机、Azure 经典虚拟机以及本地的物理机器或虚拟机(Windows/Linux),并且还支持其他云服务提供商的虚拟机。
Azure 自动化状态配置的最大优势之一是它提供了可扩展性。我们可以通过单一的中央管理界面管理成千上万台机器。我们可以轻松地将配置分配给机器,并验证它们是否符合预期的配置。
另一个优势是 Azure 自动化可以作为存储 所需状态配置(DSC)配置的仓库,且在需要时可以使用这些配置。
在下一节中,我们将讨论更新管理。
更新管理
正如你已经知道的那样,更新管理是客户在 IaaS 环境中负责管理更新和补丁的任务。Azure 自动化的更新管理功能可以用来自动化或管理 Azure 虚拟机的更新和补丁。有多种方式可以启用 Azure 虚拟机的更新管理:
-
从你的自动化帐户
-
通过浏览 Azure 门户
-
通过运行簿
-
从 Azure 虚拟机
从 Azure 虚拟机启用是最简单的方法。然而,如果你有大量虚拟机并且需要启用更新管理,那么你必须考虑一个可扩展的解决方案,例如运行簿或从自动化帐户进行操作。
既然你已经了解了相关场景,我们现在来探讨与 Azure 自动化相关的概念。
与 Azure 自动化相关的概念
现在你已经知道 Azure 自动化需要一个帐户,称为 Azure 自动化帐户。在我们深入探讨之前,让我们先了解与 Azure 自动化相关的概念。理解这些术语的含义非常重要,因为我们将在本章中贯穿使用这些术语。我们从运行簿开始。
运行簿
Azure 自动化运行簿是表示过程自动化中单个步骤或完整过程自动化的一组脚本语句。可以从父级运行簿调用其他运行簿,并且这些运行簿可以用多种脚本语言编写。支持编写运行簿的语言如下:
-
PowerShell
-
Python 2(截至目前)
-
PowerShell 工作流
-
图形化 PowerShell
-
图形化 PowerShell 工作流
创建自动化账户非常简单,可以通过 Azure 门户完成。在所有服务面板中,你可以找到自动化账户,或者你可以在 Azure 门户中搜索它。如前所述,在创建过程中你将有机会创建一个 Run As 账户。图 4.4展示了创建自动化账户所需的输入信息:
图 4.4:创建自动化账户
Run As 账户
默认情况下,Azure 自动化账户无法访问任何包含在 Azure 订阅中的资源,包括托管它们的订阅。账户需要访问 Azure 订阅及其资源,才能进行管理。Run As 账户是一种为订阅及其中的资源提供访问权限的方式。
这是一个可选练习。每个经典和资源管理器类型的订阅最多只能有一个 Run As 账户;然而,一个自动化账户可能需要连接到多个订阅。在这种情况下,建议为每个订阅创建共享资源并在 runbook 中使用。
创建自动化账户后,导航到门户中的Run As 账户视图,你将看到可以创建两种类型的账户。在图 4.5中,你可以看到Azure Run As 账户和Azure Classic Run As 账户的创建选项可用:
图 4.5:Azure Run As 账户选项
这些 Run As 账户可以通过 Azure 门户、PowerShell 和 CLI 创建。有关通过 PowerShell 创建这些账户的信息,请访问docs.microsoft.com/azure/automation/manage-runas-account
。
对于 ARM Run As 账户,该脚本会创建一个新的 Azure AD 服务主体和一个新的证书,并为新创建的服务主体提供在订阅上的贡献者 RBAC 权限。
作业
提交工作请求与执行工作请求并没有直接的关联,这是因为 Azure 自动化采用了松耦合架构。它们之间的联系是间接的,通过数据存储来实现。当自动化接收到执行 runbook 的请求时,它会在数据库中创建一条包含所有相关信息的新记录。Azure 中还运行着一个名为混合 Runbook Worker 的服务,它分布在多个服务器上,负责查找任何新添加到数据库中的记录,并执行 runbook。一旦它发现新记录,它会锁定该记录,以防其他服务读取,然后执行 runbook。
资源
Azure 自动化资产指的是可以在运行书之间共享并使用的工件。它们显示在图 4.6中:
图 4.6:Azure 自动化中的共享工件
凭证
凭证指的是用于连接到需要身份验证的其他集成服务的机密信息,如用户名/密码组合。这些凭证可以在运行书中使用 Get-AutomationPSCredential
PowerShell cmdlet 和其相关名称:
$myCredential = Get-AutomationPSCredential -Name 'MyCredential'
Python 语法要求我们导入 automationassets
模块,并使用 get_automation_credential
函数及其相关凭证名称:
import automationassets
cred = automationassets.get_automation_credential("credtest")
证书
证书指的是可以从证书颁发机构购买或自签的 X.509 证书。证书用于 Azure 自动化中的身份验证。每个证书都有一对密钥,称为私钥/公钥。私钥用于在 Azure 自动化中创建证书资产,公钥应在目标服务中可用。通过使用私钥,自动化账户可以创建数字签名,并将其附加到请求中,然后将请求发送到目标服务。目标服务可以使用已存在的公钥从数字签名中提取详细信息(哈希),从而确认请求发送者的身份。
证书资产存储 Azure 自动化中的证书信息和密钥。这些证书可以在运行书中直接使用,并且也被连接的资产所使用。下一节展示了如何在连接资产中使用证书。Azure 服务主体连接资产使用证书指纹来识别它想要使用的证书,而其他类型的连接则使用证书资产的名称来访问证书。
可以通过提供名称和上传证书来创建证书资产。可以上传公钥证书(.cer
文件)以及私钥证书(.pfx
文件)。证书的私钥部分也有一个密码,在访问证书之前需要使用该密码。
图 4.7:向 Azure 自动化添加证书
创建证书需要提供名称和描述,上传证书,提供密码(对于 .pfx
文件),并告知用户证书是否可以导出。
在创建此证书资产之前,必须有一个可用的证书。可以从证书颁发机构购买证书,也可以生成证书。生成的证书称为自签名证书。在生产环境等重要环境中,使用证书颁发机构的证书始终是最佳实践。用于开发目的时,使用自签名证书是可以的。
使用 PowerShell 生成自签名证书,请使用以下命令:
$cert = New-SelfSignedCertificate -CertStoreLocation "Cert:\CurrentUser\my" -KeySpec KeyExchange -Subject "cn=azureforarchitects"
这将在当前用户的个人文件夹中的证书存储中创建一个新证书。由于该证书还需要上传到 Azure 自动化证书资产,因此应将其导出到本地文件系统,如图 4.8所示:
图 4.8:导出证书
导出证书时,还应导出私钥,因此应该选择是,导出私钥。
选择个人信息交换选项,其他值应保持默认。
提供密码和文件名C:\azureforarchitects.pfx
,并且导出应该成功。
连接到 Azure 有多种方式。然而,最安全的方式是通过证书进行。服务主体是在 Azure 上使用证书创建的,可以使用证书进行身份验证。证书的私钥由用户持有,公钥部分由 Azure 持有。在下一节中,将使用本节中创建的证书来创建服务主体。
使用证书凭证创建服务主体
可以通过 Azure 门户、Azure CLI 或 Azure PowerShell 创建服务主体。使用 Azure PowerShell 创建服务主体的脚本在本节中提供。
登录 Azure 后,将上一节中创建的证书转换为 base64 编码。创建一个新的服务主体azureforarchitects
,并将证书凭证与新创建的服务主体关联。最后,为新服务主体提供基于角色的访问控制权限,以便访问该订阅:
Login-AzAccount
$certKey = [system.Convert]::ToBase64String($cert.GetRawCertData())
$sp = New-AzADServicePrincipal -DisplayName "azureforarchitects"
New-AzADSpCredential -ObjectId $sp.Id -CertValue $certKey -StartDate $cert.NotBefore -EndDate $cert.NotAfter
New-AzRoleAssignment -RoleDefinitionName contributor -ServicePrincipalName $sp.ApplicationId
Get-AzADServicePrincipal -ObjectId $sp.Id
$cert.Thumbprint
Get-AzSubscription
要创建连接资产,可以使用Get-AzADServicePrincipal
cmdlet 获取应用程序 ID,结果如图 4.9所示:
图 4.9:检查服务主体
可以使用证书引用和SubscriptionId
来获取证书指纹,SubscriptionId
可以通过Get-AzSubscription
cmdlet 获取。
连接
连接资产用于创建与外部服务的连接信息。在这方面,Azure 也被视为外部服务。连接资产包含成功连接到服务所需的所有必要信息。Azure 自动化提供了三种默认的连接类型:
-
Azure
-
Azure 经典证书
-
Azure 服务主体
使用 Azure 服务主体连接到 Azure 资源管理器资源,并使用 Azure 经典证书连接到 Azure 经典资源是一种良好的实践。需要注意的是,Azure 自动化不提供任何使用用户名和密码等凭据连接到 Azure 的连接类型。
Azure 和 Azure 经典证书本质上是相似的。它们都帮助我们连接到基于 Azure 服务管理 API 的资源。实际上,Azure 自动化在创建经典 Run As 帐户时,会创建一个 Azure 经典证书连接。
Azure 服务主体由 Run As 帐户内部使用,用于连接到基于 Azure 资源管理器的资源。
图 4.10 中显示了一个新的类型为 AzureServicePrincipal 的连接资产。它需要:
-
连接的名称。提供名称是必需的。
-
连接的描述。这个值是可选的。
-
在本章中,选择适当的
AzureServicePrincipal
用于创建连接资产。 -
clientid
是在创建服务主体时生成的应用程序 ID。下一部分将展示如何使用 Azure PowerShell 创建服务主体的过程。提供应用程序 ID 是必需的。 -
Get-AzSubscription
cmdlet。提供租户标识符是必需的。 -
CertificateThumbprint 是证书标识符。该证书应已通过证书资产上传到 Azure 自动化。提供证书指纹是必需的。
-
SubscriptionId 是订阅的标识符。提供订阅 ID 是必需的。
您可以使用自动化帐户中的连接面板添加新连接,如图 4.10所示:
图 4.10:将新连接添加到自动化帐户
Runbook 编写和执行
Azure 自动化允许创建称为 Runbook 的自动化脚本。可以通过 Azure 门户或 PowerShell ISE 创建多个 Runbook。它们也可以从Runbook 库导入。可以搜索特定功能,整个代码将在 Runbook 中显示。
Runbook 可以接受参数值,就像普通的 PowerShell 脚本一样。下一个示例接受一个名为 connectionName
的参数,类型为 string
。在执行该 Runbook 时,必须为此参数提供值:
param(
[parameter(mandatory=$true)]
[string] $connectionName
)
$connection = Get-AutomationConnection -name $connectionName
$subscriptionid = $connection.subscriptionid
$tenantid = $connection.tenantid
$applicationid = $connection.applicationid
$cretThumbprint = $connection.CertificateThumbprint
Login-AzureRMAccount -CertificateThumbprint $cretThumbprint -ApplicationId $applicationid -ServicePrincipal -Tenant $tenantid
Get-AzureRMVM
runbook 使用 Get-AutomationConnection
cmdlet 引用共享连接资产。资产的名称包含在参数值中。引用连接资产后,连接引用中的值会填充到 $connection
变量中,并随后分配给多个其他变量。
Login-AzureRMAccount
cmdlet 用于与 Azure 进行身份验证,并提供从连接对象中获得的值。它使用本章前面创建的服务主体进行身份验证。
最后,runbook 调用 Get-AzureRMVm
cmdlet 来列出订阅中的所有虚拟机。
默认情况下,Azure Automation 仍提供用于与 Azure 一起工作的 AzureRM
模块。默认情况下,它不会安装 Az
模块。稍后我们将在 Azure Automation 帐户中手动安装 Az
模块,并在 runbook 中使用 cmdlet。
父级和子级 runbook
Runbook 具有生命周期,从编写到执行。这些生命周期可以分为编写状态和执行状态。
编写生命周期如图 4.11所示。
当新创建一个 runbook 时,它的状态为 New,当进行多次编辑和保存后,状态变为 In edit,最终,当它被发布时,状态更改为 Published。已发布的 runbook 也可以进行编辑,在这种情况下,状态会返回为 In edit。
图 4.11:编写生命周期
接下来将描述执行生命周期。
生命周期从 runbook 执行请求开始。runbook 可以通过多种方式执行:
-
通过 Azure 门户手动启动
-
通过将父级 runbook 作为子级 runbook 使用
-
通过 webhook 方式
无论 runbook 是如何启动的,生命周期都是相同的。执行 runbook 的请求会被自动化引擎接收,自动化引擎会创建一个作业并将其分配给 runbook worker。目前,runbook 的状态为 Queued。
有多个 runbook worker,选定的 worker 会接收作业请求并将状态更改为 Starting。此时,如果脚本中存在任何脚本编写或解析问题,状态会变为 Failed,执行将被中止。
一旦 runbook 执行被 worker 启动,状态将变为 Running。runbook 在运行时可能会有多种不同的状态。
如果执行过程中没有未处理的终止异常,runbook 的状态会变为 Completed。
运行中的 runbook 可以由用户手动停止,状态将变为 Stopped。
图 4.12:runbook 的执行生命周期
用户还可以暂停和恢复 runbook 的执行。
创建一个运行簿
可以通过访问 Azure 门户中的左侧导航面板中的运行簿菜单项来创建运行簿。一个运行簿具有名称和类型。类型决定了用于创建运行簿的脚本语言。我们已经讨论了可能的语言,本章中将主要使用 PowerShell 进行所有示例。
创建 PowerShell 运行簿与创建 PowerShell 脚本完全相同。它可以声明并接受多个参数—这些参数可以具有数据类型等属性,其中一些是必填的(就像任何 PowerShell 参数属性一样)。它可以调用已加载和声明的 PowerShell cmdlet 模块,也可以调用函数并返回输出。
运行簿还可以调用另一个运行簿。它可以在原始流程和上下文内调用子运行簿,或者在单独的流程和上下文中调用。
内联调用运行簿类似于调用 PowerShell 脚本。下一个示例使用内联方法调用子运行簿:
.\ConnectAzure.ps1 -connectionName "azureforarchitectsconnection"
Get-AzSqlServer
在前面的代码中,我们看到ConnectAzure
运行簿如何接受一个名为connectionName
的参数,并向其提供适当的值。此运行簿在通过服务主体进行身份验证后创建与 Azure 的连接。请查看调用子运行簿的语法,它与调用一般 PowerShell 脚本并传递参数非常相似。
下一行代码Get-AzVm
从 Azure 获取相关信息并列出虚拟机的详细信息。你会注意到,尽管身份验证是在子运行簿中进行的,但Get-AzVm
cmdlet 成功执行,并列出了订阅中的所有虚拟机,因为子运行簿在与父运行簿相同的作业中执行,它们共享上下文。
另外,可以使用 Azure 自动化提供的Start-AzurermAutomationRunbook
cmdlet 来调用子运行簿。此 cmdlet 接受自动化帐户的名称、资源组名称以及运行簿的名称和参数,详情如下:
$params = @{"connectionName"="azureforarchitectsconnection"}
$job = Start-AzurermAutomationRunbook '
–AutomationAccountName 'bookaccount' '
–Name 'ConnectAzure' '
-ResourceGroupName 'automationrg' -parameters $params
if($job -ne $null) {
Start-Sleep -s 100
$job = Get-AzureAutomationJob -Id $job.Id -AutomationAccountName 'bookaccount'
if ($job.Status -match "Completed") {
$jobout = Get-AzureAutomationJobOutput '
-Id $job.Id '
-AutomationAccountName 'bookaccount' '
-Stream Output
if ($jobout) {Write-Output $jobout.Text}
}
}
使用这种方法会创建一个新的作业,它与父作业不同,并且在不同的上下文中运行。
使用 Az 模块
到目前为止,所有示例都使用了AzureRM
模块。之前展示的运行簿将重新编写,改为使用Az
模块中的 cmdlet。
如前所述,Az
模块默认并未安装。可以通过 Azure 自动化中的模块库菜单项来安装它们。
在库中搜索Az
,结果会显示与之相关的多个模块。如果选择导入并安装Az
模块,系统会抛出一个错误,表示其依赖的模块未安装,并且需要先安装这些模块才能安装当前模块。该模块可以在Az
上找到,如图 4.13所示:
图 4.13:在模块库面板中查找 Az 模块
不选择Az
模块,而是选择Az.Accounts并按照向导导入该模块,如图 4.14所示:
图 4.14:导入 Az.Accounts 模块
安装Az.Accounts
后,可以导入Az.Resources
模块。与 Azure 虚拟机相关的 cmdlet 位于Az.Compute
模块中,可以使用与导入Az.Accounts
相同的方法导入它。
导入这些模块后,runbook 可以使用这些模块提供的 cmdlet。之前展示的ConnectAzure
runbook 已被修改为使用Az
模块:
param(
[parameter(mandatory=$true)]
[string] $connectionName
)
$connection = Get-AutomationConnection -name $connectionName
$subscriptionid = $connection.subscriptionid
$tenantid = $connection.tenantid
$applicationid = $connection.applicationid
$cretThumbprint = $connection.CertificateThumbprint
Login-AzAccount -CertificateThumbprint $cretThumbprint -ApplicationId $applicationid -ServicePrincipal -Tenant $tenantid -SubscriptionId $subscriptionid
Get-AzVm
代码的最后两行很重要。它们使用的是Az
cmdlet,而不是AzureRM
cmdlet。
执行此 runbook 将得到类似以下的结果:
图 4.15:Az.Accounts 模块成功导入
在下一节中,我们将使用 Webhook。
Webhooks
Webhook 在 REST 端点和 JSON 数据负载出现后变得流行。Webhook 是任何应用程序可扩展性中的一个重要概念和架构决策。Webhook 是应用程序中特殊区域中的占位符,用户可以用包含自定义逻辑的端点 URL 填充这些占位符。应用程序将调用端点 URL,自动传递必要的参数,并执行其中的登录操作。
Azure Automation 的 runbook 可以通过 Azure 门户手动调用。它们也可以使用 PowerShell cmdlet 和 Azure CLI 调用。还有多种语言的 SDK 可用于调用 runbook。
Webhook 是调用 runbook 的最强大方式之一。需要注意的是,包含主要逻辑的 runbook 不应直接暴露为 Webhook。它们应该通过父级 runbook 来调用,且父级 runbook 应暴露为 Webhook。父级 runbook 应确保在调用子级 runbook 之前进行适当的检查。
创建 Webhook 的第一步是正常编写 runbook,如之前所做的。编写完 runbook 后,它将作为 Webhook 暴露。
创建了一个新的基于 PowerShell 的 runbook,名为exposedrunbook
。此 runbook 接受一个名为$WebhookData
的单一参数,类型为对象。它应命名为verbatim
。该对象由 Azure Automation 运行时创建,并传递给 runbook。Azure Automation 运行时在获取 HTTP 请求头值和正文内容后构建该对象,并填充此对象的RequestHeader
和RequestBody
属性:
param(
[parameter(mandatory=$true)]
[object] $WebhookData
)
$webhookname = $WebhookData.WebhookName
$headers = $WebhookData.RequestHeader
$body = $WebhookData.RequestBody
Write-output "webhook header data"
Write-Output $webhookname
Write-output $headers.message
Write-output $headers.subject
$connectionname = (ConvertFrom-Json -InputObject $body)
./connectAzure.ps1 -connectionName $connectionname[0].name
该对象的三个重要属性是WebhookName
、RequestHeader
和RequestBody
。这些属性的值将被检索,并由 runbook 发送到输出流。
头部和正文内容可以是用户在触发 webhook 时提供的任何内容。这些值会填充到相应的属性中,并在 runbook 中使用。在前面的示例中,调用者设置了两个头部,分别是 message
和 status
头部。调用者还将提供要作为正文内容一部分使用的共享连接名称。
在创建 runbook 后,必须先发布它,才能创建 webhook。发布 runbook 后,点击顶部的 Webhook 菜单,开始为该 runbook 创建一个新的 webhook,如 图 4.16 所示:
图 4.16:创建 webhook
应为 webhook 提供一个名称。此值可以在 runbook 中通过 WebhookData
参数与 WebhookName
属性名称进行访问。
webhook 可以处于 enabled
或 disabled
状态,并且可以在指定的日期和时间过期。它还会生成一个唯一的 URL,适用于此 webhook 和 runbook。此 URL 应提供给任何希望触发 webhook 的人。
触发 webhook
Webhook 是通过使用 POST
方法的 HTTP 请求来触发的。当触发 webhook 时,HTTP 请求会传递到 Azure Automation,以启动一个 runbook。它会创建 WebHookData
对象,填充传入的 HTTP 头部和正文数据,并创建一个任务,由 runbook 工作者处理。此调用使用在前一步中生成的 webhook URL。
webhook 可以通过 Postman 或任何能够使用 POST
方法调用 REST
端点的代码来触发。在下一个示例中,将使用 PowerShell 来触发 webhook:
$uri = "https://s16events.azure-automation.net/webhooks?token=rp0w93L60fAPYZQ4vryxl%2baN%2bS1Hz4F3qVdUaKUDzgM%3d"
$connection = @(
@{ name="azureforarchitectsconnection"}
)
$body = ConvertTo-Json -InputObject $ connection
$header = @{ subject="VMS specific to Ritesh";message="Get all virtual machine details"}
$response = Invoke-WebRequest -Method Post -Uri $uri -Body $body -Headers $header
$jobid = (ConvertFrom-Json ($response.Content)).jobids[0]
PowerShell 代码声明了 webhook 的 URL,并以 JSON 格式构建正文,name
设置为 azureforarchitectsconnection
,并设置了两个头部名称-值对:subject
和 message
。头部和正文数据都可以通过 WebhookData
参数在 runbook 中获取。
invoke-webrequest
cmdlet 使用 POST
方法在前面提到的端点上发起请求,提供头部和正文。
请求是异步的,返回的是任务标识符,而不是实际的 runbook 输出,并且该标识符也可以在响应内容中获取。任务显示在 图 4.17 中:
图 4.17:检查任务
点击 WEBHOOKDATA
会显示通过 HTTP 请求到达 runbook 自动化服务的值:
图 4.18:验证输出
点击输出菜单会显示订阅中虚拟机和 SQL 服务器的列表。
Azure 自动化中的下一个重要概念是 Azure Monitor 和混合工作者,接下来的章节将详细解释这些概念。
从 Azure Monitor 中调用运行书
Azure 自动化运行书可以作为响应来调用,响应 Azure 中生成的警报。Azure Monitor 是一个集中式服务,用于管理订阅中资源和资源组的日志与指标。您可以使用 Azure Monitor 创建新的警报规则和定义,触发时可以执行 Azure 自动化运行书。它们可以以默认形式调用 Azure 自动化运行书,或者调用一个 Webhook,Webhook 进一步执行其关联的运行书。Azure Monitor 与运行书的调用能力之间的集成为自动修正环境、上下调计算资源或在无需人工干预的情况下进行纠正操作提供了无数的自动化机会。
可以在单个资源和资源级别创建和配置 Azure 警报,但最佳实践是将警报定义集中管理,便于维护和管理。
让我们一步步讲解如何将运行书与警报关联,并在警报触发时调用运行书。
第一步是创建一个新的警报,如图 4.19所示:
图 4.19:创建警报规则
选择一个应被监控并评估以生成警报的资源。已经从列表中选择了一个资源组,它会自动启用资源组内的所有资源。也可以从资源组中移除资源选择:
图 4.20:选择警报的范围
配置应评估的条件和规则。在选择活动日志作为信号类型后,选择关闭虚拟机信号名称:
图 4.21:选择信号类型
结果窗口将允许您为成功
配置严重
级别:
图 4.22:设置警报逻辑
在确定警报条件之后,最重要的配置就是配置通过调用运行书响应警报。我们可以使用操作组来配置警报的响应。它提供了多种选项,可以调用 Azure 函数、Webhook 或 Azure 自动化运行书,还可以发送电子邮件和短信。
创建一个操作组,提供名称、简短名称、托管订阅、资源组,并将操作类型设置为自动化运行书
:
图 4.23 配置操作组
选择一个自动化运行簿将打开另一个面板,用于选择适当的 Azure 自动化帐户和运行簿。系统提供了多个预设的运行簿,本文中使用了其中一个:
图 4.24 创建运行簿
最后,提供一个名称和托管资源组来创建一个新的警报。
如果虚拟机被手动取消分配,警报条件将被满足,并会触发警报:
图 4.25 测试警报
如果你在几秒钟后检查虚拟机的详细信息,你应该会看到虚拟机正在被删除:
图 4.26 验证结果
混合工作者
到目前为止,所有的运行簿执行主要是在 Azure 提供的基础设施上进行的。运行簿工作者是由 Azure 提供的计算资源,在其中部署了适当的模块和资源。任何运行簿的执行都发生在这些计算资源上。然而,用户也可以提供自己的计算资源,并在用户提供的计算资源上执行运行簿,而不是在默认的 Azure 计算资源上。
这有多个优点。首先,整个执行过程及其日志由用户拥有,Azure 无法查看这些内容。其次,用户提供的计算资源可以位于任何云环境中,甚至可以是本地部署的。
添加混合工作者涉及多个步骤
-
首先,必须在用户提供的计算资源上安装一个代理。微软提供了一个脚本,可以自动下载并配置代理。此脚本可以从
www.powershellgallery.com/packages/New-OnPremiseHybridWorker/1.6
获取。脚本也可以通过 PowerShell ISE 以管理员身份在应成为混合工作者一部分的服务器上执行,使用以下命令:
Install-Script -Name New-OnPremiseHybridWorker -verbose
-
脚本安装后,可以与相关的 Azure 自动化帐户详细信息一起执行。同时还为混合工作者提供了一个名称。如果该名称不存在,将会创建;如果已存在,服务器将被添加到现有的混合工作者中。一个混合工作者中可以包含多个服务器,同时也可以有多个混合工作者:
New-OnPremiseHybridWorker.ps1 -AutomationAccountName bookaccount -AAResourceGroupName automationrg ' -HybridGroupName "localrunbookexecutionengine" ' -SubscriptionID xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
-
执行完成后,返回到门户将显示混合工作者的条目,如图 4.27所示:
图 4.27:检查用户的混合工作者组
- 如果此时执行一个依赖于
Az
模块和已上传到证书资产的自定义证书的 Azure 运行簿,它将由于找不到Az
模块和证书而失败,并显示相关错误:
图 4.28:检查错误
-
使用以下命令在服务器上安装
Az
模块:Install-module -name Az -AllowClobber -verbose
此外,在此服务器上还必须有
.pfx
证书。之前导出的证书应复制到服务器并手动安装。 -
安装
Az
模块和证书后,在 Hybrid Worker 上重新执行运行簿,如图 4.29所示,应该会显示订阅中的虚拟机列表:
图 4.29:在 Hybrid Worker 上设置运行簿
当我们讨论不同的场景时,我们谈到了配置管理。在下一节中,我们将更详细地讨论 Azure Automation 中的配置管理。
Azure Automation 状态配置
Azure Automation 为每个 Azure Automation 帐户提供期望状态配置(DSC)拉取服务器。拉取服务器可以保存配置脚本,供跨云和本地的服务器拉取。这意味着 Azure Automation 可以用于配置世界上任何地方托管的服务器。
DSC 需要在这些服务器上安装本地代理,也叫本地配置管理器(LCM)。它应该与 Azure Automation DSC 拉取服务器进行配置,以便能够下载所需的配置并自动配置服务器。
自动配置可以设置为周期性(默认情况下为半小时),如果代理发现服务器配置与 DSC 脚本中提供的配置有任何偏差,它将自动纠正并使服务器恢复到期望的状态。
在本节中,我们将配置一个托管在 Azure 上的服务器,无论该服务器是位于云端还是本地,整个过程将保持一致。
第一步是创建 DSC 配置。这里展示了一个示例配置,复杂的配置可以类似地编写:
configuration ensureiis {
import-dscresource -modulename psdesiredstateconfiguration
node localhost {
WindowsFeature iis {
Name = "web-server"
Ensure = "Present"
}
}
}
配置非常简单。它导入了PSDesiredStateConfiguration
基础 DSC 模块,并声明了一个单节点配置。此配置不与任何特定节点关联,可以用于配置任何服务器。该配置旨在配置 IIS web 服务器,并确保其在应用到的任何服务器上存在。
此配置尚未在 Azure 自动化 DSC 拉取服务器上可用,因此第一步是将配置导入到拉取服务器。这可以通过使用自动化帐户的 Import-AzAutomationDscConfiguration
cmdlet 来完成,如下所示:
Import-AzAutomationDscConfiguration -SourcePath "C:\Ritesh\ensureiis.ps1" -AutomationAccountName bookaccount -ResourceGroupName automationrg -Force -Published
这里有几个重要事项需要注意。配置名称应与文件名匹配,且只能包含字母数字字符和下划线。一个好的命名约定是使用动词/名词组合。cmdlet 需要配置文件的路径和 Azure 自动化帐户的详细信息来导入配置脚本。
此时,配置在门户中可见:
图 4.30:添加配置
一旦配置脚本被导入,它会使用 Start-AzAutomationDscCompilationJob
cmdlet 在 DSC 拉取服务器上进行编译并存储,如下所示:
Start-AzAutomationDscCompilationJob -ConfigurationName 'ensureiis' -ResourceGroupName 'automationrg' -AutomationAccountName 'bookaccount'
配置的名称应与最近上传的名称匹配,且已编译的配置现在应该可以在 已编译配置 标签页中找到,如 图 4.31 所示:
图 4.31:列出已编译的配置
需要注意的是,0
表示存在一个名为 ensureiss.localhost
的节点配置,但尚未分配给任何节点。下一步是将配置分配给该节点。
到目前为止,我们在 DSC 拉取服务器上有了一个已编译的 DSC 配置,但没有节点可以管理。下一步是将虚拟机加入并与 DSC 拉取服务器关联。这是通过使用 Register-AzAutomationDscNode
cmdlet 完成的:
Register-AzAutomationDscNode -ResourceGroupName 'automationrg' -AutomationAccountName 'bookaccount' -AzureVMLocation "west Europe" -AzureVMResourceGroup 'spark' -AzureVMName 'spark' -ConfigurationModeFrequencyMins 30 -ConfigurationMode 'ApplyAndAutoCorrect'
此 cmdlet 需要提供虚拟机和 Azure 自动化帐户的资源组名称。它还配置了虚拟机本地配置管理器的配置模式和configurationModeFrequencyMins
属性。此配置每 30 分钟检查并自动修正任何偏离已应用配置的情况。
如果未指定 VMresourcegroup
,cmdlet 会尝试在与 Azure 自动化帐户相同的资源组中查找虚拟机,如果未提供虚拟机位置值,它会尝试在 Azure 自动化区域中查找虚拟机。最好为它们提供值。请注意,此命令仅适用于 Azure 虚拟机,因为它明确要求提供 AzureVMname
。对于其他云和本地服务器,请使用 Get-AzAutomationDscOnboardingMetaconfig
cmdlet。
现在,新的节点配置条目也可以在门户中找到,如 图 4.32 所示:
图 4.32:验证节点状态
可以通过以下方式获取节点信息:
$node = Get-AzAutomationDscNode -ResourceGroupName 'automationrg' -AutomationAccountName 'bookaccount' -Name 'spark'
可以将配置分配给节点:
Set-AzAutomationDscNode -ResourceGroupName 'automationrg' -AutomationAccountName 'bookaccount' -NodeConfigurationName 'ensureiis.localhost' -NodeId $node.Id
一旦编译完成,就可以将其分配给节点。初始状态为待处理,如图 4.33所示:
图 4.33:验证节点状态
几分钟后,配置应用到节点,节点变为合规,状态变为已完成:
图 4.34:验证节点是否合规
稍后,通过登录到服务器并检查 Web 服务器(IIS)是否已安装,确认它已经安装,正如你在图 4.35中看到的:
图 4.35:检查是否已达到预期状态
下一节将讨论 Azure Automation 定价。
Azure Automation 定价
如果 Azure Automation 上没有执行任何 runbook,则不收取费用。Azure Automation 的费用按 runbook 任务执行的分钟数计费。这意味着,如果总的 runbook 执行分钟数为 10,000,则 Azure Automation 的费用为每分钟 0.002 美元,乘以 9,500,因为前 500 分钟是免费的。
在 Azure Automation 中,涉及其他费用,这取决于使用的功能。例如,DSC 拉取服务器在 Azure Automation 中是免费的;将 Azure 虚拟机添加到拉取服务器也不收费。然而,如果将非 Azure 服务器加入,通常是来自其他云或本地部署的服务器,那么前五台服务器是免费的,超出部分的费用是每台服务器每月 6 美元(在西美地区)。
定价可能会因地区而异,通常最好通过官方定价页面确认定价:azure.microsoft.com/pricing/details/automation
。
你可能会问,既然我们可以通过 Azure Functions 部署无服务器应用,为什么还需要 Automation 账户?在下一节中,我们将探讨 Azure Automation 与无服务器自动化之间的关键区别。
与无服务器自动化的比较
Azure Automation 和 Azure 无服务器技术,尤其是 Azure Functions,在功能上非常相似并有所重叠。然而,这些是不同的服务,具有不同的功能和定价。
重要的是要理解,Azure Automation 是一个完整的流程自动化和配置管理套件,而 Azure Functions 是用于实现业务功能的服务。
Azure 自动化用于自动化基础设施的供应、撤销、管理和操作过程,以及随后的配置管理。另一方面,Azure Functions 旨在创建服务,实现可以作为微服务和其他 API 一部分的功能。
Azure 自动化并不适用于无限扩展,负载预计为中等,而 Azure Functions 可以处理无限流量并自动扩展。
在 Azure 自动化中,有许多共享资产,如连接、变量和模块,可以在运行簿之间重用;然而,Azure Functions 中没有现成的共享概念。
Azure 自动化通过检查点管理中间状态,并能够从最后保存的状态继续,而 Azure Functions 通常是无状态的,不维护任何状态。
总结
Azure 自动化是 Azure 中一项重要服务,也是唯一用于流程自动化和配置管理的服务。本章涵盖了与 Azure 自动化和流程自动化相关的许多重要概念,包括共享资产,如连接、证书和模块。
本章介绍了运行簿的创建,包括以不同方式调用运行簿,如父子关系、Webhook 和使用门户。还讨论了运行簿的架构和生命周期。
我们还研究了混合工作者的使用,并在本章结尾探讨了使用 DSC 拉取服务器和本地配置管理器进行配置管理。最后,我们与其他技术(如 Azure Functions)进行了比较。
在下一章中,我们将探讨为 Azure 部署设计策略、锁定和标签。
第五章:5. 设计 Azure 部署的策略、锁定和标签
Azure 是一个多功能的云平台。客户不仅可以创建和部署他们的应用程序,还可以积极管理和治理他们的环境。云计算通常遵循按需付费的模式,客户可以订阅并将几乎任何东西部署到云端。它可以是一个简单的虚拟机,也可以是数千个具有更高库存单位(SKU)的虚拟机。Azure 不会阻止任何客户配置他们希望配置的资源。在一个组织内,可能有很多人可以访问该组织的 Azure 订阅。需要建立一个治理模型,以确保只有具有创建权限的人才能配置必要的资源。Azure 提供了资源管理功能,如Azure 基于角色的访问控制(RBAC)、Azure 策略、管理组、蓝图和资源锁定,用于管理和提供资源治理。
治理的其他主要方面包括成本、使用情况和信息管理。组织的管理团队总是希望实时了解云计算消耗和成本情况。他们希望能够识别出哪些团队、部门或单位使用了多少比例的总成本。简而言之,他们希望能够基于不同的消费和成本维度生成报告。Azure 提供了一种标签功能,可以帮助实时提供这类信息。
在本章中,我们将涵盖以下主题:
-
Azure 管理组
-
Azure 标签
-
Azure 策略
-
Azure 锁定
-
Azure RBAC
-
Azure 蓝图
-
实施 Azure 治理功能
Azure 管理组
我们从 Azure 管理组开始,因为在接下来的章节中,我们会引用或提到管理组。管理组充当作用域级别,使你能够有效地分配或管理角色和策略。如果你有多个订阅,管理组非常有用。
管理组充当组织订阅的占位符。你也可以拥有嵌套的管理组。如果在管理组层级应用策略或访问权限,它将被下层的管理组和订阅继承。从订阅层级开始,这些策略或访问权限将被资源组继承,最终被资源继承。
管理组的层次结构如下所示:
图 5.1:Azure 管理组的层次结构
在图 5.1 中,我们使用管理组将不同部门的操作分开,如市场营销、IT 和人力资源。在每个部门内部,有嵌套的管理组和订阅,这有助于将资源组织成层次结构,以便进行政策和访问管理。稍后,您将看到管理组如何作为治理、政策管理和访问管理的范围。
在下一部分,我们将讨论 Azure 标签,它在资源的逻辑分组中发挥着另一个重要作用。
Azure 标签
Azure 允许通过名称-值对对资源组和资源进行标签标记。标签帮助对资源进行逻辑组织和分类。Azure 还允许对资源组及其资源标记最多 50 个名称-值对。尽管资源组充当资源的容器或占位符,但标记资源组并不意味着标记其组成资源。资源组和资源应根据其使用情况进行标记,本节稍后将解释这一点。标签绑定到订阅、资源组或资源。Azure 接受任何名称-值对,因此组织需要定义名称及其可能的值。
那么,为什么标签很重要呢?换句话说,标签能解决哪些问题?标签具有以下优点:
-
资源分类:一个 Azure 订阅可以被组织内的多个部门使用。管理团队需要识别任何资源的所有者。标签有助于为资源分配标识符,这些标识符可以代表部门或角色。
-
Azure 资源的信息管理:同样,Azure 资源可以由任何有权限访问订阅的人进行配置。为了符合信息管理政策,组织通常希望对资源进行适当的分类。这些政策可以基于应用程序生命周期管理,如开发、测试和生产环境的管理。它们还可以基于使用情况或任何其他优先事项。每个组织都有自己定义信息类别的方式,Azure 通过标签满足这一需求。
-
成本管理:在 Azure 中使用标签可以根据资源的分类帮助识别资源。例如,可以针对 Azure 执行查询,以识别每个类别的成本。例如,Azure 中为财务部门和市场部门开发环境的资源成本可以轻松确定。此外,Azure 还提供基于标签的计费信息,这有助于识别团队、部门或小组的消耗率。
然而,Azure 中的标签确实存在一些限制:
-
Azure 允许最多 50 个标签名称-值对与资源组关联。
-
标签是不可继承的。应用于资源组的标签不会应用于其中的单个资源。然而,在为资源配置时,容易忘记为资源添加标签。Azure 策略提供了一种机制,确保在配置时为资源添加适当的标签值。我们将在本章稍后讨论这类策略的详细信息。
可以使用 PowerShell、Azure CLI 2.0、Azure 资源管理器模板、Azure 门户和 Azure 资源管理器 REST API 来为资源和资源组分配标签。
这里展示了使用 Azure 标签进行信息管理分类的示例:
图 5.2:使用 Azure 标签进行信息管理分类
在这个示例中,Department、Project、Environment、Owner、Approver、Maintainer、Start Date、Retire Date 和 Patched Date 等名称-值对用于为资源添加标签。使用 PowerShell、Azure CLI 或 REST API,非常容易查找具有特定标签或标签组合的所有资源。下一节将讨论如何使用 PowerShell 为资源分配标签。
使用 PowerShell 的标签
可以使用 PowerShell、Azure 资源管理器模板、Azure 门户和 REST API 来管理标签。在本节中,将使用 PowerShell 来创建和应用标签。PowerShell 提供了一个 cmdlet 用于检索并附加标签到资源组和资源:
-
要使用 PowerShell 检索与资源关联的标签,可以使用
Get-AzResource
cmdlet:(Get-AzResource -Tag @{ "Environment"="Production"}).Name
-
要使用 PowerShell 检索与资源组关联的标签,可以使用以下命令:
Get-AzResourceGroup -Tag @{"Environment"="Production"}
-
要为资源组设置标签,可以使用
Update-AzTag
cmdlet:$tags = @{"Dept"="IT"; "Environment"="Production"} $resourceGroup = Get-AzResourceGroup -Name demoGroup New-AzTag -ResourceId $resourceGroup.ResourceId -Tag $tags
-
要为资源设置标签,可以使用相同的
Update-AzTag
cmdlet:$tags = @{"Dept"="Finance"; "Status"="Normal"} $resource = Get-AzResource -Name demoStorage -ResourceGroup demoGroup New-AzTag -ResourceId $resource.id -Tag $tags
-
你可以使用
Update-AzTag
命令更新现有标签;但是,你需要指定操作为Merge
或Replace
。Merge
将把你传入的新标签附加到现有标签中;而Replace
操作将替换掉所有旧标签,使用新标签。下面是一个不替换现有标签的资源组标签更新示例:$tags = @{"Dept"="IT"; "Environment"="Production"} $resourceGroup = Get-AzResourceGroup -Name demoGroup Update-AzTag -ResourceId $resourceGroup.ResourceId -Tag $tags -Operation Merge
现在让我们来看一下使用 Azure 资源管理器模板的标签。
使用 Azure 资源管理器模板的标签
Azure 资源管理器模板也有助于为每个资源定义标签。可以使用它们为每个资源分配多个标签,如下所示:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"resources": [
{
"apiVersion": "2019-06-01",
"type": "Microsoft.Storage/storageAccounts",
"name": "[concat('storage', uniqueString(resourceGroup().id))]",
"location": "[resourceGroup().location]",
"tags": {
"Dept": "Finance",
"Environment": "Production"
},
"sku": {
"name": "Standard_LRS"
},
"kind": "Storage",
"properties": { }
}
]
}
在前面的示例中,使用 Azure 资源管理器模板为存储帐户资源添加了两个标签,Dept
和 Environment
。
资源组标签与资源标签的区别
架构师必须决定 Azure 资源和资源组的分类法和信息架构。他们应根据查询要求识别资源的分类标准。然而,他们还必须确定标签应该附加到单个资源上,还是附加到资源组上。
如果资源组内的所有资源都需要相同的标签,那么最好给资源组打标签,尽管标签不会继承到资源组中的资源。如果您的组织要求将标签传递到所有底层资源,可以考虑编写 PowerShell 脚本,从资源组获取标签,并更新资源组中资源的标签。在决定是否在资源级别或资源组级别应用标签之前,重要的是考虑对标签的查询。如果查询涉及跨订阅和跨资源组的单个资源类型,那么为单个资源分配标签更为合理。然而,如果仅通过识别资源组就能有效地进行查询,那么标签应仅应用于资源组。如果您将资源从一个资源组移动到另一个资源组,资源组级别应用的标签将丢失。如果您要移动资源,请考虑重新添加标签。
Azure 策略
在上一节中,我们讨论了如何为 Azure 部署应用标签。标签在组织资源方面非常有用;然而,还有一件事没有讨论:组织如何确保每次部署都应用了标签?应该对 Azure 标签进行自动化强制执行,确保资源和资源组都应用标签。Azure 本身没有检查机制来确保资源和资源组上应用了适当的标签。这不仅仅是标签的问题——这适用于 Azure 上任何资源的配置。例如,您可能希望限制资源的地理位置(例如,仅限于美国东部地区)。
你可能已经猜到,这一节主要是讲述如何在 Azure 上制定治理模型。治理是 Azure 中的重要元素,因为它确保每个访问 Azure 环境的人都能了解组织的优先事项和流程。它还有助于控制成本,并帮助定义管理资源的组织惯例。
每个策略可以通过多个规则构建,多个策略可以应用到订阅或资源组。根据规则是否满足,策略可以执行各种操作。操作可以是拒绝正在进行的交易、审计交易(即写入日志并允许其完成),或者如果发现缺少元数据,则将元数据附加到交易中。
策略可能与资源的命名约定、资源的标签、可配置的资源类型、资源的位置或这些的任意组合相关。
Azure 提供了众多内置策略,并且可以创建自定义策略。可以使用基于 JSON 的策略语言来定义自定义策略。
现在你已经了解了 Azure 策略的目的和使用场景,让我们继续讨论内置策略、策略语言和自定义策略。
内置策略
Azure 提供了一个用于创建自定义策略的服务;然而,它也提供了一些现成的策略,这些策略可以用于治理。这些策略涉及允许的位置、允许的资源类型和标签。有关这些内置策略的更多信息,请访问docs.microsoft.com/azure/azure-resource-manager/resource-manager-policy
。
策略语言
Azure 中的策略使用 JSON 来定义和描述策略。政策采用有两个步骤:首先定义策略,然后应用和分配它。策略具有作用域,可以在管理组、订阅或资源组级别应用。
策略是使用if...then
块定义的,类似于任何流行编程语言。if
块会执行以评估条件,基于这些条件的结果,then
块将会执行:
{
"if": {
<condition> | <logical operator>
},
"then": {
"effect": "deny | audit | append"
}
}
策略不仅允许简单的if
条件,还允许将多个if
条件逻辑地连接起来,创建复杂的规则。这些条件可以通过AND
、OR
和NOT
运算符连接:
-
AND
语法要求所有条件都为真。 -
OR
语法要求至少有一个条件为真。 -
NOT
语法反转条件的结果。
接下来是AND
语法,它由allOf
关键字表示:
"if": {
"allOf": [
{
"field": "tags",
"containsKey": "application"
},
{
"field": "type",
"equals": "Microsoft.Storage/storageAccounts"
}
]
},
接下来是OR
语法,它由anyOf
关键字表示:
"if": {
"anyOf": [
{
"field": "tags",
"containsKey": "application"
},
{
"field": "type",
"equals": "Microsoft.Storage/storageAccounts"
}
]
},
接下来是NOT
语法,它由not
关键字表示:
"if": {
"not": [
{
"field": "tags",
"containsKey": "application"
},
{
"field": "type",
"equals": "Microsoft.Storage/storageAccounts"
}
]
},
事实上,这些逻辑运算符可以组合在一起,如下所示:
"if": {
"allOf": [
{
"not": {
"field": "tags",
"containsKey": "application"
}
},
{
"field": "type",
"equals": "Microsoft.Storage/storageAccounts"
}
]
},
这与在流行编程语言(如 C#和 Node.js)中使用if
条件非常相似:
If ("type" == "Microsoft.Storage/storageAccounts") {
Deny
}
需要注意的是,虽然有Deny
操作,但没有allow
操作。这意味着策略规则应考虑到可能的拒绝,规则应评估条件并在满足条件时Deny
该操作。
允许的字段
在定义策略时,允许的条件字段如下:
-
Name
:应用策略的资源名称。这是非常具体的,并且适用于资源的使用。 -
Type
:资源类型,例如Microsoft.Compute/VirtualMachines
。这将把策略应用于所有虚拟机实例。 -
Location
:资源的位置(即 Azure 区域)。 -
标签
:与资源关联的标签。 -
属性别名
:特定资源的属性。这些属性对于不同的资源是不同的。
在下一节中,你将学习更多关于如何保护生产环境中的资源的信息。
Azure 锁定
锁定是一种停止对资源执行某些操作的机制。RBAC(基于角色的访问控制)为用户、组和应用程序提供在特定范围内的权限。有现成的 RBAC 角色,例如所有者、贡献者和读取者。使用贡献者角色,可以删除或修改资源。那么,即便用户拥有贡献者角色,如何避免这些操作呢?答案是:使用 Azure 锁定。
Azure 锁定可以提供以下两种帮助:
-
它们可以锁定资源,使其即便拥有所有者权限,也无法删除。
-
锁定可以以这样的方式保护资源,使它们既不能被删除,也不能修改其配置。
锁定通常对生产环境中的资源非常有帮助,这些资源不应被意外修改或删除。
锁定可以应用于订阅、资源组、管理组以及单个资源的级别。锁定可以在订阅、资源组和资源之间继承。对父级应用锁定将确保子级资源也继承该锁定。后续添加到子范围的资源也默认继承该锁定配置。在资源级别应用锁定还会阻止包含该资源的资源组被删除。
锁定仅应用于帮助管理资源的操作,而不涉及资源内部的操作。用户需要拥有 Microsoft.Authorization/*
或 Microsoft.Authorization/locks/*
的 RBAC 权限才能创建和修改锁定。
锁定可以通过 Azure 门户、Azure PowerShell、Azure CLI、Azure 资源管理器模板以及 REST API 创建和应用。
使用 Azure 资源管理器模板创建锁定的方法如下:
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"lockedResource": {
"type": "string"
}
},
"resources": [
{
"name": "[concat(parameters('lockedResource'), '/Microsoft.Authorization/myLock')]",
"type": "Microsoft.Storage/storageAccounts/providers/locks",
"apiVersion": "2019-06-01",
"properties": {
"level": "CannotDelete"
}
}
]
}
Azure 资源管理器模板代码中的 resources
部分包含了所有在 Azure 中将要配置或更新的资源列表。这里有一个存储账户资源,并且存储账户中包含一个锁定资源。锁定的名称是通过动态字符串拼接提供的,所应用的锁定是 CannotDelete
类型,这意味着该存储账户被锁定,无法删除。只有在移除锁定后,存储账户才能被删除。
使用 PowerShell 创建并应用锁定到资源的方法如下:
New-AzResourceLock -LockLevel CanNotDelete -LockName LockSite '
-ResourceName examplesite -ResourceType Microsoft.Web/sites '
-ResourceGroupName exampleresourcegroup
使用 PowerShell 创建并应用锁定到资源组的方法如下:
New-AzResourceLock -LockName LockGroup -LockLevel CanNotDelete '
-ResourceGroupName exampleresourcegroup
使用 Azure CLI 创建并应用锁定到资源的方法如下:
az lock create --name LockSite --lock-type CanNotDelete \
--resource-group exampleresourcegroup --resource-name examplesite \
--resource-type Microsoft.Web/sites
使用 Azure CLI 创建并应用锁定到资源组的方法如下:
az lock create --name LockGroup --lock-type CanNotDelete \ --resource-group exampleresourcegroup
要创建或删除资源锁定,用户应当具有对 Microsoft.Authorization/*
或 Microsoft.Authorization/locks/*
操作的访问权限。你还可以进一步授予更细粒度的权限。拥有者和用户访问管理员默认将具有创建或删除锁定的权限。
如果你想知道 Microsoft.Authorization/*
和 Microsoft.Authorization/locks/*
关键字是什么,下一节你会了解更多相关内容。
现在我们来看一下 Azure RBAC。
Azure RBAC
Azure 使用 Azure Active Directory 进行资源的身份验证。身份验证完成后,应该确定该身份可以访问哪些资源。这就是授权。授权评估已赋予身份的权限。任何拥有 Azure 订阅访问权限的人应该仅被赋予足够的权限来执行他们的特定工作,其他的权限不需要提供。
授权也常被称为 RBAC。Azure 中的 RBAC 是指在某个范围内为身份分配权限。该范围可以是管理组、订阅、资源组或单个资源。
RBAC 帮助创建和分配不同的权限给不同的身份。这有助于在团队内部分配职责,而不是每个人都有所有的权限。RBAC 帮助让每个人只对自己的工作负责,因为其他人可能没有执行该工作的必要访问权限。需要注意的是,在更大范围内提供权限会自动确保子资源继承这些权限。例如,给一个身份提供对资源组的读取权限意味着该身份也会对该组内的所有资源拥有读取权限。
Azure 提供了三种通用的内建角色,具体如下:
-
拥有者角色,具有对所有资源的完全访问权限
-
贡献者角色,具有读取/写入资源的权限
-
读者角色,具有只读资源权限
Azure 提供了更多的角色,但它们是特定于资源的,如网络贡献者和安全管理员角色。
要获取 Azure 为所有资源提供的所有角色,请在 PowerShell 控制台中执行 Get-AzRoleDefinition
命令。
每个角色定义都有特定的允许和不允许的操作。例如,拥有者角色允许所有操作;没有任何操作是禁止的:
PS C:\Users\riskaria> Get-AzRoleDefinition -Name "Owner"
Name : Owner
Id : 8e3af657-a8ff-443c-a75c-2fe8c4bcb635
IsCustom : False
Description : Lets you manage everything, including access to resources.
Actions : {*}
NotActions : {}
DataActions : {}
NotDataActions : {}
AssignableScopes : {/}
每个角色由多个权限组成。每个资源提供一组操作。可以通过 Get-AzProviderOperation
cmdlet 获取某个资源支持的操作。此 cmdlet 需要提供提供者和资源的名称来检索操作:
PS C:\Users\riskaria> Get-AzProviderOperation -OperationSearchString "Microsoft.Insights/*" | select Operation
这将导致以下输出:
PS C:\Users\riskaria> Get-AzProviderOperation -OperationSearchString "Microsoft.Insights/*" | select Operation
Operation
---------
Microsoft.Insights/Metrics/Action
Microsoft.Insights/Register/Action
Microsoft.Insights/Unregister/Action
Microsoft.Insights/ListMigrationDate/Action
Microsoft.Insights/MigrateToNewpricingModel/Action
Microsoft.Insights/RollbackToLegacyPricingModel/Action
.
.
.
.
.
.
.
.
Microsoft.Insights/PrivateLinkScopes/PrivateEndpointConnectionProxies/Read
Microsoft.Insights/PrivateLinkScopes/PrivateEndpointConnectionProxies/Write
Microsoft.Insights/PrivateLinkScopes/PrivateEndpointConnectionProxies/Delete
Microsoft.Insights/PrivateLinkScopeOperationStatuses/Read
Microsoft.Insights/DiagnosticSettingsCategories/Read
这里显示的输出提供了 Microsoft.Insights
资源提供程序中所有可用的操作,包括其关联的资源。资源包括 Metrics
、Register
等,而操作包括 Read
、Write
等。
现在我们来看看自定义角色。
自定义角色
Azure 提供了许多现成的通用角色,如所有者、贡献者和阅读者,以及专门的资源特定角色,如虚拟机贡献者。当为用户/组或服务主体分配阅读者角色时,意味着会将阅读者权限分配给某个范围。这个范围可以是资源、资源组或订阅。同样,贡献者能够读取并修改分配的范围。而虚拟机贡献者则只能修改虚拟机的设置,而不能修改其他资源的设置。然而,有时现有的角色可能不符合我们的需求。在这种情况下,Azure 允许创建自定义角色。它们可以分配给用户、组和服务主体,并且适用于资源、资源组和订阅。
自定义角色是通过组合多个权限来创建的。例如,一个自定义角色可以由多个资源的操作组成。在下一个代码块中,正在创建一个新的角色定义,但不是手动设置所有属性,而是获取其中一个现有的“虚拟机贡献者”角色,因为它几乎与新自定义角色的配置匹配。避免使用与内置角色相同的名称,因为这会导致冲突。然后,将 ID 属性置为空,提供一个新的名称和描述。代码还清除了所有操作,添加了一些操作,在清除现有范围后添加了新范围,最后创建了一个新的自定义角色:
$role = Get-AzRoleDefinition "Virtual Machine Contributor"
$role.Id = $null
$role.Name = "Virtual Machine Operator"
$role.Description = "Can monitor and restart virtual machines."
$role.Actions.Clear()
$role.Actions.Add("Microsoft.Storage/*/read")
$role.Actions.Add("Microsoft.Network/*/read")
$role.Actions.Add("Microsoft.Compute/*/read")
$role.Actions.Add("Microsoft.Compute/virtualMachines/start/action")
$role.Actions.Add("Microsoft.Compute/virtualMachines/restart/action")
$role.Actions.Add("Microsoft.Authorization/*/read")
$role.Actions.Add("Microsoft.Resources/subscriptions/resourceGroups/read")
$role.Actions.Add("Microsoft.Insights/alertRules/*")
$role.Actions.Add("Microsoft.Support/*")
$role.AssignableScopes.Clear()
$role.AssignableScopes.Add("/subscriptions/548f7d26-b5b1-468e-ad45-6ee12accf7e7")
New-AzRoleDefinition -Role $role
在 Azure 门户中,有一个预览功能,可以让你直接在门户中创建自定义 RBAC 角色。你可以选择从头开始创建角色、克隆现有角色或直接编写 JSON 清单。图 5.3 显示了创建自定义角色窗格,它位于 IAM > +添加 部分:
图 5.3:从 Azure 门户创建自定义角色
这使得创建自定义角色的过程变得轻松无忧。
锁与 RBAC 有什么不同?
锁与 RBAC 不同。RBAC 帮助允许或拒绝对资源的权限。这些权限与执行操作相关,如对资源进行读取、写入和更新等操作。而锁则与禁止配置或删除资源的权限有关。
在接下来的章节中,我们将讨论 Azure 蓝图,它有助于我们组织已经讨论过的工件,如角色分配、策略分配等。
Azure 蓝图
你将会熟悉“蓝图”这个词,它指的是建筑师用来设计解决方案的计划或图纸。同样,在 Azure 中,云架构师可以利用 Azure Blueprints 来定义一组可重复的 Azure 资源,符合组织的标准、流程和模式。
Blueprints 允许我们编排各种资源和其他工件的部署,例如:
-
角色分配
-
策略分配
-
Azure 资源管理器模板
-
资源组
Azure 蓝图对象会复制到多个区域,并由 Azure Cosmos DB 提供支持。复制有助于提供一致的资源访问,并保持组织标准,无论你将资源部署到哪个区域。
Azure Blueprints 包含了各种工件,你可以在这里找到支持的工件列表:docs.microsoft.com/azure/governance/blueprints/overview#blueprint-definition
。
可以通过 Azure 门户、Azure PowerShell、Azure CLI、REST API 或 ARM 模板创建蓝图。
在下一节中,我们将看到一个实施 Azure 治理功能的示例。示例中将使用 RBAC、Azure 策略和 Azure 资源锁等服务和功能。
实施 Azure 治理功能的示例
在本节中,我们将介绍一个示例架构实施,针对一个虚构的组织,该组织希望实现 Azure 治理和成本管理功能。
背景
公司 Inc 是一家全球性公司,正在 Azure IaaS 平台上实现社交媒体解决方案。他们使用部署在 Azure 虚拟机和网络上的 Web 服务器和应用服务器。Azure SQL Server 作为后台数据库。
Company Inc 的 RBAC
第一个任务是确保适当的团队和应用程序所有者能够访问他们的资源。需要注意的是,每个团队有不同的需求。为了清晰起见,Azure SQL 被部署在与 Azure IaaS 工件不同的资源组中。
管理员为订阅分配以下角色:
表 5.1:不同角色及访问详情
Azure 策略
该公司应该实施 Azure 策略,以确保其用户始终按照公司指南配置资源。
Azure 中的策略治理与资源部署相关的各个方面。策略还将治理初始部署后的更新。以下部分列出了应实施的一些策略。
部署到特定位置
Azure 资源和部署只能在选定的位置执行。无法在政策以外的区域部署资源。例如,允许的区域是西欧和东美。应该无法在其他任何区域部署资源。
资源和资源组的标签
Azure 中的每一个资源,包括资源组,都必须强制分配标签。标签至少应包括有关部门、环境、创建日期和项目名称的详细信息。
所有资源的诊断日志和应用程序洞察
在 Azure 上部署的每个资源都应该在可能的情况下启用诊断日志和应用程序日志。
Azure 锁定
企业应实施 Azure 锁定,确保重要资源不会被意外删除。所有对解决方案功能至关重要的资源都需要锁定。这意味着即使是 Azure 上运行服务的管理员也没有权限删除这些资源;删除资源的唯一方法是先移除锁定。
你还需要注意:
除了开发和测试环境外,所有生产和预生产环境将会被锁定,禁止删除。
所有具有单实例的开发和测试环境也将被锁定,禁止删除。
所有与 Web 应用相关的资源将在所有生产环境中被锁定,禁止删除。
所有共享资源无论环境如何,都将被锁定,禁止删除。
总结
在本章中,你了解到治理和成本管理是企业迁移到云端时的首要任务之一。拥有一个按需付费的 Azure 订阅可能会对公司预算造成影响,因为任何拥有访问权限的人都可以根据需要创建资源。某些资源是免费的,但其他资源则非常昂贵。
你还了解到,组织保持云端成本控制非常重要。标签有助于生成计费报告,这些报告可以基于部门、项目、所有者或任何其他标准。虽然成本很重要,但治理同样重要。Azure 提供了锁定、策略和 RBAC 来实施适当的治理。策略确保可以拒绝或审计资源操作,锁定确保资源无法被修改或删除,RBAC 确保员工具有执行工作所需的权限。通过这些功能,企业可以实现对 Azure 部署的良好治理和成本控制。
在下一章中,我们将讨论 Azure 中的成本管理。我们将讲解不同的优化方法、成本管理和计费 API。
第六章:6. Azure 解决方案的成本管理
在上一章中,我们讨论了标签、策略和锁,以及如何从合规性的角度利用它们。标签允许我们为资源添加元数据,它们还帮助我们在资源的逻辑管理中发挥作用。在 Azure 门户中,我们可以根据标签来筛选资源。如果假设有大量资源(这在企业中非常常见),筛选将帮助我们更轻松地管理资源。标签的另一个好处是它们可以用于根据标签来筛选我们的账单报告或使用报告。在本章中,我们将探讨 Azure 解决方案的成本管理。
企业迁移到云端的主要原因是节省成本。订阅 Azure 不需要前期费用。Azure 提供了按需付费的订阅方式,计费是基于实际消耗的。Azure 会测量资源使用情况并提供每月账单。Azure 消耗没有上限。作为一个公共云,Azure(像任何其他服务提供商一样)对可以部署的资源数量设定了硬性和软性限制。软性限制可以通过与 Azure 支持团队合作来增加。有些资源有硬性限制。服务限制可以在 docs.microsoft.com/azure/azure-resource-manager/management/azure-subscription-service-limits
查看,默认限制取决于您所拥有的订阅类型。
对于公司来说,密切关注 Azure 的消耗和使用情况非常重要。尽管他们可以创建策略来设定组织标准和惯例,但同样需要跟踪账单和消耗数据。此外,他们还应该采用最佳实践来消耗 Azure 资源,以最大化回报。为此,架构师需要了解 Azure 资源和功能,它们相应的费用,以及功能和解决方案的成本/效益分析。
在本章中,我们将讨论以下内容:
-
Azure 服务详情
-
计费
-
开具发票
-
使用情况和配额
-
使用情况和计费 API
-
Azure 定价计算器
-
成本优化的最佳实践
让我们继续讨论每个要点。
Azure 服务详情
Azure 提供了不同的服务套餐可以购买。到目前为止,我们已经讨论了按需付费,但还有其他服务套餐,例如 企业协议(EAs)、Azure 赞助和 CSP 中的 Azure。我们将逐一讨论这些内容,因为它们对计费非常重要:
-
按需付费:这是一种常见的服务方式,客户根据实际使用情况支付费用,相关的费率可以在 Azure 的公开文档中查看。客户每月都会收到来自微软的使用账单,并可以通过信用卡或账单支付方式付款。
-
EA:EA 代表与 Microsoft 的货币承诺,意味着组织与 Microsoft 签署协议,并承诺使用一定数量的 Azure 资源。如果使用量超过约定的额度,客户将收到超额费用账单。客户可以在 EA 下创建多个帐户,并在这些帐户中拥有多个订阅。EA 有两种类型:直接 EA 和间接 EA。直接 EA 客户与 Microsoft 之间有直接的账单关系;而在间接 EA 中,账单由合作伙伴管理。EA 客户因与 Microsoft 的承诺而获得更好的优惠和折扣。EA 通过名为 EA 门户的门户管理(
ea.azure.com
),您需要拥有注册权限才能访问此门户。 -
Azure 在 CSP 中:Azure 在 CSP 中是指客户联系 云解决方案提供商(CSP)合作伙伴,由该合作伙伴为客户提供订阅。账单将完全由合作伙伴管理;客户与 Microsoft 不会有直接的账单关系。Microsoft 向合作伙伴开具账单,合作伙伴再向客户开具账单,并加上其利润。
-
Azure 赞助:Microsoft 向初创公司、非政府组织(NGO)和其他非营利组织提供赞助,以使用 Azure。赞助是有固定期限和固定额度的信用。如果期限到期或信用用尽,订阅将转换为按需计费订阅。如果组织希望续订其赞助资格,必须与 Microsoft 合作。
我们刚刚概述了 Azure 的部分产品。完整列表请参见 azure.microsoft.com/support/legal/offer-details
,其中包括其他产品,如 Azure 学生计划、Azure Pass 和 Dev/Test 订阅。
接下来,我们来讨论 Azure 中的账单。
理解账单
Azure 是一项具有以下特点的服务工具:
-
无需预付费用
-
无解约费用
-
根据资源类型按秒、按分钟或按小时计费
-
按实际消费进行付费
在这种情况下,很难估算使用 Azure 资源的预付成本。Azure 中的每种资源都有自己的成本模型,并根据存储、使用情况和时间跨度收费。对于管理、行政和财务部门来说,跟踪使用情况和成本非常重要。Azure 提供使用和账单报告功能,帮助高级管理人员和管理员根据多种标准生成成本和使用报告。
Azure 门户通过 成本管理 + 账单 功能提供详细的账单和使用信息,该功能可以从主导航窗格访问,如 图 6.1 所示:
图 6.1:Azure 门户中的成本管理 + 账单服务
请注意,如果你的计费由 CSP 管理,你将无法访问此功能。CSP 客户可以在将其 CSP 传统订阅转换为 Azure 计划后,按需查看其成本。我们将在本章后续部分讨论 Azure 计划和现代商务平台。
成本管理 + 计费显示所有你有权限访问的订阅和计费范围,如图 6.2所示:
图 6.2:用户订阅的计费概述
成本管理部分有几个页面,例如:
-
成本分析用于分析某个范围内的使用情况。
-
预算用于设置预算。
-
成本警报用于在使用超过某个阈值时通知管理员。
-
Advisor 推荐用于获取如何实现潜在节省的建议。我们将在本章最后一部分讨论 Azure Advisor。
-
导出用于将使用数据自动导出到 Azure 存储。
-
Cloudyn 是 CSP 合作伙伴用来分析成本的工具,因为他们无法访问成本管理。
-
AWS 连接器用于将你的 AWS 消耗数据连接到 Azure 成本管理。
在 Azure 成本管理中提供的不同选项如图 6.3所示:
图 6.3:成本管理概述
点击此页面上的 成本分析 菜单,可以获得一个全面的交互式仪表盘,使用它可以通过不同的维度和度量分析成本:
图 6.4:通过成本分析选项分析订阅成本
该仪表盘不仅显示当前成本,还预测成本,并根据多个维度进行拆分。默认提供服务名称、位置和资源组名称,但也可以更改为其他维度。每个视图始终会与一个范围相关联。可用的一些范围包括计费账户、管理组、订阅和资源组。你可以根据需要分析的层级切换范围。
左侧的预算菜单允许我们设置预算以更好地管理成本,并提供在实际成本即将超出预算估算时的警报功能:
图 6.5:创建预算
成本管理还允许我们在当前的仪表盘中获取来自其他云(如 AWS)的成本数据,从而在单一的仪表盘和页面中管理多个云的成本。然而,在写作时,此功能仍处于预览阶段。此连接器将于 2020 年 8 月 25 日之后开始收费。
您需要填写您的 AWS 角色详细信息及其他信息,以便提取成本信息,如图 6.5所示。如果您不确定如何在 AWS 中创建策略和角色,请参考docs.microsoft.com/azure/cost-management-billing/costs/aws-integration-set-up-configure#create-a-role-and-policy-in-aws
:
图 6.6:在成本管理中创建 AWS 连接器
成本报告还可以根据计划定期导出到存储帐户中。
部分成本分析也可以在订阅面板中查看。在概览部分,您可以看到资源及其成本。此外,还有另一张图表,您可以查看当前花费、预测花费以及余额信用(如果您使用的是基于信用的订阅)。
图 6.7显示了成本信息:
图 6.7:订阅的成本分析
点击图 6.7中的任何一个成本项将会将您重定向到成本管理 – 成本分析部分。成本管理中有许多维度,您可以根据这些维度对数据进行分组分析。可用的维度将根据您选择的范围而有所不同。以下是一些常用的维度:
-
资源类型
-
资源组
-
标签
-
资源位置
-
资源 ID
-
计量类别
-
计量子类别
-
服务
在本章开始时,我们提到过标签可以用于成本管理。例如,假设您有一个名为“部门”的标签,值为 IT、HR 和财务。正确地为资源打上标签将帮助您了解每个部门产生的成本。您还可以通过下载按钮将成本报告下载为 CSV、Excel 或 PNG 文件。
此外,成本管理支持多种视图。您可以创建自己的仪表板并保存它。EA 客户还可以额外享受成本管理连接器或 Power BI 的优势。通过连接器,用户可以将使用统计数据拉取到 Power BI 并创建可视化。
到目前为止,我们一直在讨论如何使用成本管理来跟踪我们的使用情况。在接下来的部分,我们将探讨我们所使用的服务的计费方式。
开票
Azure 的计费系统还提供有关每月生成的发票的信息。
根据优惠类型,计费方式可能会有所不同。对于按需付费用户,发票将每月发送给帐户管理员。然而,对于 EA 客户,发票将发送给注册时的联系人。
点击发票菜单将显示所有生成的发票列表,点击任何一张发票将提供该发票的详细信息。图 6.8显示了如何在 Azure 门户中查看发票:
图 6.8:发票及其详细信息列表
发票有两种类型:一种是针对 Azure 服务,如 SQL、虚拟机和网络的发票;另一种是针对 Azure 市场和预订的发票。Azure 市场提供来自不同供应商的合作伙伴服务供客户选择。稍后我们将讨论 Azure 预订。
默认情况下,对于按需付费订阅,账户管理员可以访问发票。如果需要,他们可以通过选择图 6.8中的访问发票选项,将访问权限委托给其他用户,例如组织的财务团队。此外,账户管理员还可以选择希望将发票副本发送到的电子邮件地址。
电子邮件发票选项目前不适用于支持计划。您可以访问账户门户并下载发票。微软正在逐步淘汰该门户,大部分功能正在被集成到 Azure 门户中。
到目前为止,我们已经讨论了订阅和发票处理的方式。微软推出的一个新概念是现代商务。通过这一新的商务体验,购买流程和体验得到了简化。让我们仔细看看现代商务,并了解它与我们迄今讨论的传统平台有何不同。
现代商务体验
如果您的组织已经与微软合作,您会知道每个报价都有多个协议,例如 Web Direct、EA、CSP、微软服务与产品协议(MSPA)、服务器云注册(SCE)等。除此之外,每个协议都有自己的门户;例如,EA 有 EA 门户,CSP 有合作伙伴中心门户,Volume Licensing 也有自己的门户。
每个报价都有不同的条款和条件,客户在每次购买时都需要了解这些条款和条件。从一个报价转换到另一个报价并不容易,因为每个报价的条款和条件各不相同。假设您已经有了 EA 订阅,并希望将其转换为 CSP 订阅;您可能需要删除一些合作伙伴服务,因为这些服务在 CSP 中不被支持。对于每个产品,每个报价都有不同的规则。从客户的角度来看,理解哪些支持哪些内容以及规则如何不同是非常困难的。
为了解决这个问题,微软最近发布了一项新的协议,称为微软客户协议(MCA)。该协议将作为基本条款和条件。每当您注册新项目时,您可以根据需要对其进行修改。
对于 Azure,将有三个市场推广(GTM)计划:
-
以客户为主导:客户将直接与微软账户团队互动,发票将由微软直接管理。最终,这将取代 EA。
-
合作伙伴主导:这相当于 Azure-in-CSP 项目,其中合作伙伴管理你的账单。全球有不同的合作伙伴,快速搜索一下即可找到周围的合作伙伴。这个项目将取代 Azure-in-CSP 项目。作为现代商务的第一步,合作伙伴将与微软签署 微软合作伙伴协议(MPA),并通过让他们的客户签署 MCA 来转换他们现有的客户。在撰写本书时,许多合作伙伴已经将他们的客户转移到现代商务,新商业体验已在 139 个国家/地区提供。
-
自助服务:这将取代 Web Direct。它不需要合作伙伴或微软账户团队的任何参与。客户可以直接从 microsoft.com 购买,并且在购买时签署 MCA。
在 Azure 中,账单将根据 Azure 计划进行,并且账单总是与日历月份对齐。购买 Azure 计划与购买其他订阅非常相似。不同之处在于,在过程中会签署 MCA。
Azure 计划可以托管多个订阅,并将作为根级容器。所有的使用情况都与单一的 Azure 计划相关联。Azure 计划中的所有订阅将作为容器来托管服务,如虚拟机、SQL 数据库和网络服务。
我们可以观察到在现代商务引入后的一些变化和进展如下:
-
最终,门户网站将被弃用。例如,之前的 EA 客户只能从 EA 门户下载注册使用信息。现在,微软已经将其集成到 Azure 成本管理中,提供比 EA 门户更丰富的体验。
-
定价将以美元(USD)进行,并以当地货币计费。如果你的货币不是美元,则将应用 外汇(FX)汇率,并会显示在发票中。微软使用来自 Thomson Reuters 的外汇汇率,这些汇率将在每个月的第一天进行分配。这个汇率在整个一个月内保持一致,无论市场汇率如何变化。
-
转到新 Azure 计划的 CSP 客户将能够使用成本管理。访问成本管理打开了一个全新的成本跟踪世界,因为它提供了所有原生的成本管理功能。
到目前为止我们讨论的所有订阅最终都将迁移到 Azure 计划,这是 Azure 的未来。现在你已经理解了现代商务的基础,接下来让我们讨论一个在架构解决方案时起着非常重要作用的话题。大多数服务默认都有限制;其中一些限制可以增加,而有些是硬性限制。当我们在设计解决方案时,需要确保有足够的配额。容量规划是架构设计中的一个至关重要的部分。在下一节,你将了解更多有关订阅限制的信息。
使用情况和配额
如前所述,容量规划需要成为我们设计解决方案时的首要步骤之一。我们需要验证订阅是否有足够的配额来容纳我们设计的新资源。如果没有,在部署过程中可能会遇到问题。
每个订阅对每种资源类型都有有限的配额。例如,使用 MSDN Microsoft 帐户时,最多可以分配 10 个公共 IP 地址。类似地,所有资源对每种资源类型都有一个最大默认限制。通过联系 Azure 支持或在订阅页面的使用情况 + 配额窗格中点击请求增加按钮,可以增加这些资源类型的配额。
考虑到每个区域的资源数量,要浏览整个列表将是一个挑战。门户提供了筛选数据集并查找所需项的选项。在图 6.9中,您可以看到如果我们将位置筛选为美国中部并将资源提供者设置为Microsoft.Storage,我们可以确认存储帐户的可用配额:
图 6.9:给定位置和资源提供者的使用情况和配额
在图 6.9中,您可以清楚地看到我们在美国中部尚未创建任何存储帐户,这使得我们拥有 250 个帐户的配额。如果我们构建的解决方案需要超过 250 个帐户,则需要点击请求增加,这将联系 Azure 支持。
此窗格使我们能够在部署前进行容量规划。
在筛选报告时,我们使用了资源提供者一词并选择了Microsoft.Storage。在下一节中,我们将更详细地了解这个术语的含义。
资源提供者和资源类型
无论您是与 Azure 门户交互,筛选服务,还是筛选账单使用报告,您可能需要与资源提供者和资源类型打交道。例如,当您创建虚拟机时,您正在与Microsoft.Compute
资源提供者和virtualMachines
资源类型交互。其格式为{resource-provider}/{resource-type}
。因此,虚拟机的资源类型是Microsoft.Compute/virtualMachines
。简而言之,资源提供者帮助创建资源类型。
资源提供者需要在 Azure 订阅中注册。如果资源提供者没有注册,则资源类型将在订阅中不可用。默认情况下,大多数提供者会自动注册;不过,也会有一些情况需要我们手动注册。
要获取可用的提供商列表,包括已注册和未注册的提供商,并注册未注册的提供商或反之,可以使用 图 6.10 所示的仪表板。进行此操作时,您需要拥有必要的角色——Owner 或 Contributor 角色即可。图 6.10 显示了仪表板的样子:
图 6.10:已注册和未注册的资源提供商列表
在前一部分中,我们讨论了如何下载发票和使用信息。如果您需要通过编程方式下载数据并保存,您可以使用 API。下一部分将全面介绍 Azure 计费 API。
使用情况和计费 API
尽管门户是手动查找使用、计费和发票信息的好方法,但 Azure 还提供了以下 API,以便通过编程方式检索详细信息并创建定制的仪表板和报告。这些 API 会根据您使用的订阅类型有所不同。由于 API 很多,我们将分享每个 API 的 Microsoft 文档,以便您可以逐一探索它们。
Azure 企业计费 API
EA 客户有一组专门的 API 可供他们处理计费数据。以下 API 使用来自 EA 门户的 API 密钥进行身份验证;来自 Azure Active Directory 的令牌无法与它们一起使用:
-
余额和摘要 API:如前所述,EA 依赖于货币承诺,因此跟踪余额、超额费用、信用调整和 Azure Marketplace 费用非常重要。使用此 API,客户可以提取计费期间的余额和摘要。
-
使用详情 API:使用详情 API 将帮助您获取关于注册的每日使用信息,精确到实例级别。此 API 的响应将类似于可以从 EA 门户下载的使用报告。
-
Marketplace 商店费用 API:这是一个专门的 API,用于提取 Marketplace 购买的费用。
-
价格表 API:每个注册都会有一个特殊的价格表,折扣因客户而异。价格表 API 可以拉取价格列表。
-
预留实例详情 API:到目前为止我们还没有讨论 Azure 预留实例,但本章末会进行讨论。使用此 API,您可以获取有关预留实例的使用信息以及注册中的预留实例列表。
这是 EA API 文档的链接:docs.microsoft.com/azure/cost-management-billing/manage/enterprise-api
。
现在让我们来看一下 Azure 消费 API。
Azure 消费 API
Azure 消耗 API 可以与 EA 和 Web Direct(有些例外)订阅一起使用。此 API 需要一个令牌,该令牌需要通过 Azure Active Directory 认证生成。由于这些 API 也支持 EA,请不要将此令牌与之前提到的 EA API 密钥混淆。以下是一些显而易见的关键 API:
-
使用详情 API
-
市场费用 API
-
预订推荐 API
-
预订详情和总结 API
EA 客户支持以下额外的 API:
-
价格表
-
预算
-
余额
文档可以在此处查看:docs.microsoft.com/azure/cost-management-billing/manage/consumption-api-overview
。
此外,还有一组仅可供 Web Direct 客户使用的 API:
-
Azure 资源使用 API:此 API 可以与 EA 或按需订阅一起使用,用于下载使用数据。
-
Azure 资源价格表 API:仅适用于 Web Direct,不支持 EA。Web Direct 客户可以使用此 API 下载价格表。
-
Azure 发票下载 API:仅适用于 Web Direct 客户。用于通过编程下载发票。
这些 API 的名称可能看起来很熟悉,区别仅在于我们调用的端点。对于 Azure 企业计费 API,URL 以 https://consumption.azure.com
开头;对于 Azure 消耗 API,URL 以 https://management.azure.com
开头。这样你就可以区分它们。在接下来的部分,你将看到一组专门供成本管理使用的 API。
Azure 成本管理 API
随着 Azure 成本管理的引入,客户可以使用一组新的 API。这些 API 是成本管理的核心,我们之前在 Azure 门户中使用过。主要的 API 如下:
-
查询使用 API:这是 Azure 门户中的成本分析使用的同一 API。我们可以通过负载自定义响应内容。当我们需要定制报告时,这个 API 非常有用。日期范围不能超过 365 天。
-
预算 API:预算是 Azure 成本管理的另一项功能,使用此 API 可以通过编程与预算进行交互。
-
预测 API:此 API 可用于获取范围的预测。预测 API 目前仅适用于 EA 客户。
-
维度 API:之前在讨论成本管理时,我们提到过成本管理支持基于范围的多维度。如果你想根据特定的范围获取支持的维度列表,可以使用此 API。
-
导出 API:成本管理的另一个功能是我们可以自动将报告导出到存储帐户。导出 API 可用于与导出配置进行交互,如存储帐户的名称、定制化、频率等。
查看官方文档:docs.microsoft.com/rest/api/cost-management
。
由于现代商务正在扩展 MCA,这里有一组全新的 API 可供探索:docs.microsoft.com/rest/api/billing
。
你可能注意到我们在这些场景中没有提到 CSP。在 CSP 中,客户无法访问账单,因为它由合作伙伴管理,因此 API 不对外开放。然而,迁移到 Azure 计划将允许 CSP 客户使用 Azure 成本管理 API 查看零售价格。
任何编程或脚本语言都可以用于调用这些 API,并将它们组合在一起,创建完整的综合账单解决方案。在下一部分中,我们将重点介绍 Azure 定价计算器,帮助客户或架构师了解部署成本。
Azure 定价计算器
Azure 提供了一个成本计算器,供用户和客户估算他们的成本和使用情况。该计算器可通过 azure.microsoft.com/pricing/calculator
访问:
图 6.11:Azure 定价计算器
用户可以从左侧菜单中选择多个资源,它们将被添加到计算器中。在以下示例中,添加了一个虚拟机。接下来,需要提供有关虚拟机区域、操作系统、类型、层级、实例大小、小时数和数量的更多配置,以便计算成本:
图 6.12:提供配置详情以计算资源成本
同样,Azure Functions 的成本与虚拟机内存大小、执行时间和每秒执行次数相关,见 图 6.13:
图 6.13:计算 Azure Functions 的成本
Azure 提供不同的级别和支持计划:
-
默认支持:免费
-
开发者支持:每月 $29
-
标准支持:每月 $300
-
专业版直达:每月 $1,000
要查看支持计划的完整对比,请参考:azure.microsoft.com/support/plans
。
你可以根据自己的需求选择所需的支持计划。最后,系统将显示总体估算成本:
图 6.14:所选支持计划的成本估算
架构师了解他们架构和解决方案中使用的每个 Azure 功能非常重要。Azure 计算器的成功取决于所选择的资源及其配置。任何错误的表示都会导致偏颇和不准确的估算,且与实际账单不同。
我们已经进入本章的最后一部分。我们已经涵盖了计费的基础知识,现在是时候学习最佳实践了。遵循最佳实践将帮助你实现成本优化。
最佳实践
架构师需要了解他们的架构和所使用的 Azure 组件。基于主动监控、审计和使用情况,他们应该确定微软在 SKU、大小和功能方面的最佳选择。本节将详细介绍一些从成本优化角度应采纳的最佳实践。
Azure 治理
Azure 治理可以定义为一套可以利用的过程或机制,用于保持对在 Azure 中部署的资源的完全控制。以下是一些关键要点:
-
为所有资源类型和资源组设置命名规范。确保命名规范在所有资源和资源组中始终如一、全面地遵循。这可以通过建立 Azure 策略来实现。
-
通过为资源、资源组和订阅应用标签,设置逻辑组织和多个分类法。标签对资源进行分类,还能帮助从不同角度评估成本。这可以通过建立 Azure 策略来实现,多个策略可以组合成计划。应用这些计划后,所有的策略将用于合规性检查和报告。
-
使用 Azure 蓝图,而不是直接使用 ARM 模板。这将确保新的环境、资源和资源组的部署可以按照企业标准进行标准化,包括命名规范和标签的使用。
计算最佳实践
计算指的是帮助执行服务的服务。Azure 架构师应遵循的一些最佳计算实践,以实现资源的最佳利用和成本效益,如下所示:
-
利用 Azure Advisor 查看节省虚拟机成本的可用选项,并找出虚拟机是否被低效使用。Advisor 使用机器学习模式和人工智能分析你的使用情况,并提供建议。这些建议在成本优化中起着重要作用。
-
使用 Azure 预留实例 (RI)。预留实例通过提前支付虚拟机费用(按月或一次性支付)为计算成本提供潜在节省。预留实例的期限可以是一年或三年。如果购买了预留实例,就可以降低计算成本,之后只需支付虚拟机的磁盘、网络和许可费用(如果有)。如果你有五个虚拟机,可以选择购买五个预留实例,从而完全压缩计算成本。预留实例会自动寻找与虚拟机匹配的 SKU 并附加到它上面。潜在节省可能会根据虚拟机的大小有所不同,通常在 20% 到 40% 之间。
-
使用 Azure Hybrid Benefit(AHUB),您可以使用自己的 Windows Server 或 SQL 许可证来降低许可证费用。结合 RIs 和 AHUB 可以带来巨大的节省。
-
选择最适合您的计算服务的区域,例如虚拟机。选择一个所有 Azure 功能都在同一区域的地点,这样可以避免外部流量。
-
为虚拟机选择最佳的大小。大型虚拟机比小型虚拟机更贵,而且有时候大型虚拟机根本不需要。
-
在需求高峰期间调整虚拟机大小,并在需求下降时缩小其规模。Azure 会频繁发布新的 SKU。如果新的大小更适合您的需求,就必须使用它。
-
在非工作时间或不需要时关闭计算服务。这适用于非生产环境。
-
取消分配虚拟机,而不是关闭它们。这将释放所有资源,并停止计量它们的消耗。
-
使用开发/测试实验室进行开发和测试。它们提供策略、自动关机和自动启动功能。
-
使用虚拟机规模集,从少量虚拟机开始,需求增加时再进行扩展。
-
为应用网关选择正确的大小(小型、中型或大型)。它们由虚拟机支持,可以帮助降低成本。
-
如果不需要 Web 应用防火墙,则选择基本层应用网关。
-
选择正确的 VPN 网关层级(基本 VPN、标准、高性能和超高性能)。
-
减少 Azure 区域之间的网络流量。
-
使用带有公共 IP 的负载均衡器来访问多个虚拟机,而不是为每个虚拟机分配公共 IP。
-
监控虚拟机并计算性能和使用指标。根据这些计算,确定是否需要扩展或缩小虚拟机。这可能会导致缩小规模并减少虚拟机数量。
在架构时考虑这些最佳实践将不可避免地带来成本节省。现在我们已经覆盖了计算部分,让我们采用类似的方法来处理存储。
存储最佳实践
由于我们在云中托管应用程序,Azure 存储将用于存储与这些应用程序相关的数据。如果不遵循正确的实践,可能会导致问题。以下是一些存储的最佳实践:
-
选择适当的存储冗余类型(GRS、LRS、RA-GRS)。GRS 比 LRS 更贵。
-
将存储数据归档到冷存储或归档存取层。将经常访问的数据保存在热存储层。
-
删除不需要的 Blob。
-
删除虚拟机后,如果不再需要操作系统磁盘,请显式删除它们。
-
存储账户应根据其大小、写入、读取、列出和容器操作进行计量。
-
优先选择标准磁盘而非高级磁盘;只有在业务需求时才使用高级磁盘。
-
使用 CDN 和缓存来处理静态文件,而不是每次都从存储中获取。
-
Azure 提供预留容量,以节省 Blob 数据的成本。
随时掌握这些最佳实践有助于你架构出具有成本效益的存储解决方案。在接下来的章节中,我们将讨论部署 PaaS 服务时的最佳实践。
PaaS 最佳实践
Azure 提供了许多 PaaS 服务,如果这些服务配置不当,可能会导致账单中出现意外费用。为了避免这种情况,你可以利用以下最佳实践:
-
选择合适的 Azure SQL 层级(基本版、标准版、Premium RS 或 Premium)和合适的性能等级。
-
在单一数据库和弹性数据库之间做出合适选择。如果数据库数量较多,使用弹性数据库比单一数据库更具成本效益。
-
将你的解决方案重新架构为使用 PaaS(无服务器或容器化的微服务)解决方案,而不是 IaaS 解决方案。这些 PaaS 解决方案可以消除维护成本,并且按每分钟消费计费。如果你不使用这些服务,即便你的代码和服务全天候可用,也不会产生费用。
针对特定资源有成本优化,但无法在一个章节中涵盖所有内容。建议你阅读与每个功能相关的成本和使用文档。
一般最佳实践
到目前为止,我们已经看过了服务特定的最佳实践,接下来我们将总结一些通用的指导原则:
-
资源的成本在不同地区有所不同。尝试选择另一个区域,前提是它不会造成性能或延迟问题。
-
企业协议(EA)提供的折扣优于其他优惠。你可以联系微软账户团队,了解签署 EA 后你可以获得哪些优惠。
-
如果 Azure 成本可以预付,那么所有类型的订阅都可以享受折扣。
-
删除或移除未使用的资源。找出那些使用率低的资源并减少它们的 SKU 或大小。如果不需要,删除它们。
-
使用 Azure Advisor,并认真对待其建议。
如前所述,这些是一些通用的指导原则,随着你架构更多的解决方案,你将能够为自己制定一套最佳实践。但一开始,你可以考虑这些建议。尽管如此,Azure 中的每个组件都有其自身的最佳实践,架构设计时参考文档有助于你创建具有成本效益的解决方案。
总结
在本章中,我们学习了在云环境中工作时,成本管理和管理的重要性。我们还讨论了各种 Azure 定价选项和 Azure 提供的各种价格优化功能。管理项目的成本至关重要,主要是因为每月的费用可能非常低,但如果没有定期监控资源,费用可能会增加。云架构师应该以成本效益的方式设计他们的应用程序。他们应该使用适当的 Azure 资源、适当的 SKU、层级和大小,并且知道何时启动、停止、向上扩展、向外扩展、向下扩展、向内扩展、转移数据等。正确的成本管理将确保实际费用符合预算费用。
在下一章,我们将介绍与数据服务相关的各种 Azure 功能,例如 Azure SQL、Cosmos DB 和分片。
第七章:7. Azure OLTP 解决方案
Azure 提供了基础设施即服务(IaaS)和平台即服务(PaaS)服务。这些服务为组织提供了不同层次的存储、计算和网络控制。存储是处理数据存储和传输时使用的资源。Azure 提供了多种存储数据的选项,如 Azure Blob 存储、表存储、Cosmos DB、Azure SQL 数据库、Azure 数据湖等。虽然其中一些选项适用于大数据存储、分析和呈现,但也有一些是针对处理事务的应用程序。Azure SQL 是 Azure 中与事务数据配合使用的主要资源。
本章将重点讨论使用事务数据存储的各个方面,如 Azure SQL 数据库以及其他通常用于在线事务处理(OLTP)系统的开源数据库,并将涵盖以下主题:
-
OLTP 应用程序
-
关系型数据库
-
部署模型
-
Azure SQL 数据库
-
单一实例
-
弹性池
-
托管实例
-
Cosmos DB
我们将从了解 OLTP 应用程序是什么开始,并列出 Azure 的 OLTP 服务及其用例。
OLTP 应用程序
如前所述,OLTP 应用程序是帮助处理和管理事务的应用程序。一些最常见的 OLTP 实现可以在零售销售、金融交易系统和订单输入中找到。这些应用程序执行数据捕获、数据处理、数据检索、数据修改和数据存储。然而,OLTP 应用程序不仅限于此。OLTP 应用程序将这些数据任务视为事务。事务具有一些重要的特性,OLTP 应用程序需要考虑这些特性。这些特性被归纳为ACID,让我们详细讨论这些特性:
-
原子性:该特性表示一个事务必须由多个语句组成,且这些语句要么都执行成功,要么都不执行。如果多个语句被组合在一起,它们就形成了一个事务。原子性意味着每个事务被视为最小的执行单元,要么成功完成,要么失败。
-
一致性:该特性关注数据库中数据的状态。它规定任何状态的变化应当是完整的,并基于数据库的规则和约束,且不允许部分更新。
-
隔离性:该特性表示系统上可以同时执行多个并发事务,并且每个事务应当在隔离状态下执行。一个事务不应了解或干扰任何其他事务。如果事务按顺序执行,那么最终的数据状态应与执行前相同。
-
持久性:此属性表明,一旦数据提交到数据库,它应该被持久化并可用,即使发生故障。已提交的事务变为事实。
现在你已经了解了什么是 OLTP 应用程序,让我们来讨论关系型数据库在 OLTP 应用程序中的作用。
关系型数据库
OLTP 应用程序通常依赖关系型数据库进行事务管理和处理。关系型数据库通常以表格格式呈现,由行和列组成。数据模型被转换为多个表,每个表通过关系与另一个表相连接(基于规则)。这个过程也称为规范化。
Azure 中有多个支持 OLTP 应用程序和关系型数据库部署的服务。在接下来的部分中,我们将查看与 OLTP 应用程序相关的 Azure 服务。
Azure 云服务
在 Azure 门户中搜索sql会提供多个结果。我已经标记出其中一些,显示可以直接用于 OLTP 应用程序的资源:
图 7.1:Azure SQL 服务列表
图 7.1展示了在 Azure 上创建基于 SQL Server 的数据库时可用的各种功能和选项。
再次,在 Azure 门户中快速搜索数据库会提供多个资源,图7.2中标记的部分可以用于 OLTP 应用程序:
图 7.2:用于 OLTP 应用程序的 Azure 服务列表
图 7.2展示了 Azure 提供的可以承载数据的资源,这些资源支持多种数据库,包括以下内容:
-
MySQL 数据库
-
MariaDB 数据库
-
PostgreSQL 数据库
-
Cosmos DB
接下来,让我们讨论部署模型。
部署模型
Azure 中的部署模型是根据管理或控制的级别来分类的。用户可以根据个人偏好选择管理或控制的级别;他们可以选择通过使用虚拟机等服务来获得完全控制,或者使用由 Azure 为其管理的托管服务。
在 Azure 上部署数据库有两种部署模型:
-
在 Azure 虚拟机上托管数据库(IaaS)
-
托管为托管服务(PaaS)的数据库
现在,我们将尝试了解在 Azure 虚拟机和托管实例上的部署区别。让我们从虚拟机开始。
在 Azure 虚拟机上托管的数据库
Azure 提供了多个 库存单位 (SKUs) 用于虚拟机。除了通用虚拟机外,还提供了高计算、高吞吐量(IOPS)虚拟机。与其在本地服务器上托管 SQL Server、MySQL 或其他数据库,不如将这些数据库部署在这些虚拟机上。这些数据库的部署和配置与本地部署没有区别。唯一的区别是数据库托管在云端,而不是使用本地服务器。管理员需要执行与本地部署相同的活动和步骤。尽管当客户希望完全控制其部署时,这个选项是一个不错的选择,但与此选项相比,还有一些模型可能在成本效益、可扩展性和高可用性方面更具优势,本章稍后将讨论这些模型。
在 Azure 虚拟机上部署任何数据库的步骤如下:
-
创建一个适应应用程序性能需求的虚拟机。
-
在其上部署数据库。
-
配置虚拟机和数据库配置。
该选项不提供任何现成的高可用性,除非配置多个服务器。它也不提供任何自动扩展功能,除非有自定义自动化来支持它。
灾难恢复仍然是客户的责任。服务器应部署在多个区域,并通过全球对等、VPN 网关、ExpressRoute 或 Virtual WAN 等服务进行连接。这些虚拟机可以通过站点对站点的 VPN 或 ExpressRoute 连接到本地数据中心,而无需暴露到外部网络。
这些数据库也被称为 非托管数据库。另一方面,托管在 Azure 上的数据库(除了虚拟机之外)由 Azure 管理,并称为 托管服务。在下一节中,我们将详细介绍这些内容。
托管服务中的数据库
托管服务意味着 Azure 提供数据库的管理服务。这些托管服务包括数据库的托管、确保主机的高可用性、确保数据在灾难恢复期间进行内部复制以提高可用性、确保在所选 SKU 的约束下实现可扩展性、监控主机和数据库并生成通知警报或执行操作、提供日志和审计服务以便于故障排除,并负责性能管理和安全警报。
简而言之,客户在使用 Azure 托管服务时,能够立刻获得大量服务,并且不需要对这些数据库进行主动管理。在本章中,我们将深入探讨 Azure SQL 数据库,并提供关于其他数据库的信息,如 MySQL 和 Postgres。同时,我们还将介绍非关系型数据库,如 Cosmos DB,它是一个 NoSQL 数据库。
Azure SQL 数据库
Azure SQL 服务器提供了作为 PaaS 托管的关系型数据库。客户可以配置此服务,带入自己的数据库架构和数据,并将应用程序连接到它。它提供了在虚拟机上部署 SQL Server 时的所有功能。这些服务不提供用于创建表格及其架构的用户界面,也不直接提供查询功能。应使用 SQL Server 管理工作室和 SQL CLI 工具连接到这些服务并直接操作。
Azure SQL 数据库提供三种不同的部署模型:
-
单实例: 在这种部署模型中,单个数据库被部署在一个逻辑服务器上。这涉及到在 Azure 上创建两个资源:一个 SQL 逻辑服务器和一个 SQL 数据库。
-
弹性池: 在这种部署模式下,多个数据库会被部署在一个逻辑服务器上。再次强调,这涉及到在 Azure 上创建两个资源:一个 SQL 逻辑服务器和一个 SQL 弹性数据库池——它包含所有的数据库。
-
托管实例: 这是 Azure SQL 团队推出的一种相对较新的部署模型。这种部署模式反映了在逻辑服务器上的一组数据库,提供对系统数据库资源的完全控制。通常,在其他部署模型中,系统数据库是不可见的,但在该模型中可以访问。该模型与 SQL Server 本地部署非常接近:
图 7.3:Azure SQL 数据库的部署模型
如果你在疑惑什么时候使用哪种服务,你应该查看 SQL 数据库与 SQL 托管实例之间的功能对比。完整的功能对比可以在docs.microsoft.com/azure/azure-sql/database/features-comparison
找到。
接下来,我们将介绍 SQL 数据库的一些特性。让我们从应用程序功能开始。
应用程序特性
Azure SQL 数据库提供了多种面向应用程序的特性,以满足 OLTP 系统的不同需求:
-
列式存储: 该特性允许数据以列的格式而不是行的格式存储。
-
内存中 OLTP: 通常,数据存储在 SQL 的后端文件中,并在应用程序需要时从中提取数据。与此相反,内存中 OLTP 将所有数据存储在内存中,读取存储的数据时没有延迟。将内存中 OLTP 数据存储在 SSD 上为 Azure SQL 提供了最佳性能。
-
所有本地 SQL Server 的功能。
接下来我们要讨论的功能是高可用性。
高可用性
默认情况下,Azure SQL 的高可用性为 99.99%。它根据 SKU 具有两种不同的架构来保持高可用性。对于基础、标准和通用 SKU,整个架构被划分为以下两层。
-
计算层
-
存储层
这两个层次都有冗余设计,以提供高可用性:
图 7.4:标准 SKU 中的计算和存储层
对于高级和业务关键型 SKU,计算和存储都在同一层。高可用性通过在四节点集群中复制计算和存储来实现,使用类似于 SQL Server Always On 可用性组的技术:
图 7.5:四节点集群部署
现在你了解了高可用性是如何处理的,接下来我们讨论下一个功能:备份。
备份
Azure SQL 数据库还提供了自动备份数据库并将其存储在存储账户中的功能。这个功能在数据库损坏或用户不小心删除表时尤其重要。此功能在服务器级别可用,如图 7.6所示:
图 7.6:在 Azure 中备份数据库
架构师应准备备份策略,以便在需要时可以使用备份。在配置备份时,确保备份频率既不太少也不太频繁。根据业务需求,可以配置每周备份,甚至每日备份,或根据需要配置更频繁的备份。这些备份可用于恢复目的。
备份将有助于业务连续性和数据恢复。您还可以使用地理复制来恢复区域故障时的数据。在下一部分,我们将介绍地理复制。
地理复制
Azure SQL 数据库还提供了将数据库复制到不同区域(也称为次级区域)的功能;这完全取决于您选择的计划。次级区域中的数据库可以被应用程序读取。Azure SQL 数据库允许可读的次级数据库。这是一个很好的业务连续性解决方案,因为任何时刻都可以使用可读数据库。通过地理复制,可以在不同区域或相同区域最多拥有四个次级数据库。通过地理复制,也可以在发生灾难时故障转移到次级数据库。地理复制在数据库级别进行配置,如图 7.7所示:
图 7.7:Azure 中的地理复制
如果你在这个屏幕上向下滚动,将列出可以作为副本的区域,如图 7.8所示:
图 7.8:可用于地理复制的副本列表
在设计涉及地理复制的解决方案之前,我们需要验证数据驻留和合规性法规。如果由于合规原因不允许将客户数据存储在区域外,我们就不应该将其复制到其他区域。
在下一节中,我们将探讨可扩展性选项。
可扩展性
Azure SQL 数据库通过增加更多资源(如计算、内存和 IOPS)提供垂直可扩展性。这可以通过增加数据库吞吐量单位(DTU)或在vCore模型中增加计算和存储资源来实现:
图 7.9:Azure SQL 数据库中的可扩展性
我们在本章后面介绍了基于 DTU 模型和基于 vCore 模型之间的区别。
在下一节中,我们将介绍安全性,帮助你理解如何在 Azure 中构建安全的数据解决方案。
安全性
安全性是任何数据库解决方案和服务的重要因素。Azure SQL 为 Azure SQL 提供了企业级的安全性,本节将列出一些 Azure SQL 中的重要安全功能。
防火墙
默认情况下,Azure SQL 数据库不提供任何请求的访问权限。必须显式接受源 IP 地址才能访问 SQL 服务器。也可以选择允许所有基于 Azure 的服务访问 SQL 数据库。此选项包括托管在 Azure 上的虚拟机。
防火墙可以在服务器级别进行配置,而不是在数据库级别进行配置。允许访问 Azure 服务选项允许所有服务,包括虚拟机,访问托管在逻辑服务器上的数据库。
默认情况下,由于安全原因,此功能将被禁用;启用此功能将允许所有 Azure 服务访问:
图 7.10:在 Azure 中配置服务器级别的防火墙
Azure SQL 服务器专用网络
尽管 SQL 服务器通常可以通过互联网访问,但也可以将 SQL 服务器的访问限制为来自虚拟网络的请求。这是 Azure 中一个相对较新的功能。它帮助通过虚拟网络中的另一台服务器上的应用程序访问 SQL 服务器中的数据,而不通过互联网发出请求。
为此,应该在虚拟网络中添加一个Microsoft.Sql类型的服务端点,并且虚拟网络应与 Azure SQL 数据库所在的区域相同:
图 7.11:添加 Microsoft.Sql 服务端点
应选择虚拟网络中的一个合适的子网:
图 7.12:为 Microsoft.Sql 服务选择子网
最后,在 Azure SQL Server 配置面板中,应添加一个已启用Microsoft.Sql服务终结点的现有虚拟网络:
图 7.13:添加具有 Microsoft.Sql 服务终结点的虚拟网络
静态时加密的数据库
数据库在静态时应以加密形式存在。这里的静态意味着数据处于数据库的存储位置。尽管你可能无法访问 SQL Server 及其数据库,但最好还是加密数据库存储。
文件系统上的数据库可以使用密钥进行加密。这些密钥必须存储在 Azure 密钥保管库中,并且该保管库必须与 Azure SQL 服务器位于同一地区。可以通过 SQL Server 配置面板中的透明数据加密菜单项,并选择是来启用使用您自己的密钥来加密文件系统。
密钥是一个 RSA 2048 密钥,必须存在于保管库中。SQL Server 在需要读取数据并将其发送给调用方时,会在页面级别解密数据;然后,它会在写入数据库后对其进行加密。应用程序无需任何更改,并且这对它们是完全透明的:
图 7.14:SQL Server 中的透明数据加密
动态数据屏蔽
SQL Server 还提供了一种功能,能够屏蔽包含敏感数据的单个列,这样除了特权用户之外,其他人无法通过 SQL Server Management Studio 查询来查看实际数据。数据将保持屏蔽状态,只有当经过授权的应用程序或用户查询表时,数据才会被解屏蔽。架构师应确保像信用卡信息、社会安全号码、电话号码、电子邮件地址和其他财务信息等敏感数据被屏蔽。
可以在表中的列上定义屏蔽规则。有四种主要的屏蔽类型—你可以在这里查看它们:docs.microsoft.com/sql/relational-databases/security/dynamic-data-masking?view=sql-server-ver15#defining-a-dynamic-data-mask
。
图 7.15 显示了如何添加数据屏蔽:
图 7.15:SQL 数据库中的动态数据屏蔽
Azure Active Directory 集成
另一个重要的 Azure SQL 安全特性是,它可以与 Azure Active Directory(AD)集成,用于身份验证。如果没有与 Azure AD 集成,SQL Server 唯一的身份验证机制是通过用户名和密码进行身份验证,即 SQL 身份验证。无法使用集成的 Windows 身份验证。SQL 身份验证的连接字符串包括明文的用户名和密码,这并不安全。与 Azure AD 集成可以启用 Windows 身份验证、服务主体名称或基于令牌的身份验证,从而对应用程序进行身份验证。将 Azure SQL 数据库与 Azure AD 集成是一个好做法。
还有其他安全功能,如高级威胁防护、环境审计和监控,应该在任何企业级的 Azure SQL 数据库部署中启用。
到此,我们已经结束了对 Azure SQL 数据库功能的介绍,现在可以继续讨论 SQL 数据库的类型。
单实例
单实例数据库作为单个数据库托管在单个逻辑服务器上。这些数据库无法访问 SQL Server 提供的所有完整功能。每个数据库都是隔离的且可移植的。单实例支持我们之前讨论的 vCPU 和 DTU 购买模型。
单数据库的另一个优势是成本效益。如果您使用 vCore 模型,可以选择较低的计算和存储资源来优化成本。如果需要更多的计算或存储能力,您可以随时进行扩展。动态可扩展性是单实例的一个突出特性,可以根据业务需求动态地扩展资源。单实例使现有的 SQL Server 客户能够将本地应用程序迁移到云端。
其他功能包括可用性、监控和安全性。
当我们开始介绍 Azure SQL 数据库时,我们也提到过弹性池。您还可以将单一数据库转换为弹性池,以便共享资源。如果您在疑惑什么是资源共享和弹性池,下一节我们将详细介绍这一点。
弹性池
弹性池是一个逻辑容器,可以在单个逻辑服务器上托管多个数据库。弹性池适用于 vCore 模型和 DTU 模型的购买方式。vCPU 购买模型是默认且推荐的部署方式,您可以根据业务负载选择计算和存储资源。如图 7.16所示,您可以选择需要的核心数和存储量:
图 7.16:在 vCore 模型中设置弹性池
此外,在前面的图表顶部,你可以看到一个选项,上面写着 Looking for basic, standard, premium? 如果选择此项,模型将切换为 DTU 模型。
DTU 基础模型中可用于弹性池的 SKU 如下:
-
基本
-
标准
-
高级
图 7.17 显示了每个 SKU 可提供的最大 DTU 数量:
图 7.17:弹性池每个 SKU 的 DTU 数量
针对 Azure SQL 单实例讨论的所有功能同样适用于弹性池;然而,水平可扩展性是一个额外功能,支持分片。分片指的是数据的垂直或水平分区,并将数据存储在不同的数据库中。还可以通过消耗比实际分配的 DTU 更多的 DTU 来实现弹性池中各个数据库的自动扩展。
弹性池还在成本方面提供了另一项优势。你将在后续部分看到,Azure SQL 数据库是按 DTU 定价的,且 DTU 在 SQL Server 服务配置完成后立即分配。无论是否使用这些 DTU,都会对其收费。如果有多个数据库,可以将这些数据库放入弹性池中,并在它们之间共享 DTU。
实现使用 Azure SQL 弹性池分片的所有信息可以在 docs.microsoft.com/azure/sql-database/sql-database-elastic-scale-introduction
找到。
接下来,我们将讨论托管实例部署选项,它是一种可扩展、智能、基于云的完全托管数据库。
托管实例
托管实例是一项独特的服务,提供类似于本地服务器上可用的托管 SQL 服务器。用户可以访问主数据库、模型数据库和其他系统数据库。托管实例非常适合多个数据库和客户将其实例迁移到 Azure。托管实例由多个数据库组成。
Azure SQL 数据库提供了一种新的部署模型,即 Azure SQL 数据库托管实例,它与 SQL Server 企业版数据库引擎几乎 100% 兼容。该模型提供了本地虚拟网络实现,解决了常见的安全问题,是本地 SQL Server 客户非常推荐的业务模型。托管实例允许现有的 SQL Server 客户将其本地应用程序迁移到云端,几乎不需要对应用程序和数据库进行更改,同时保留所有 PaaS 能力。这些 PaaS 能力大大减少了管理开销和总拥有成本,如 图 7.18 所示:
图 7.18:Azure SQL 数据库托管实例
Azure SQL 数据库、Azure SQL 托管实例和在 Azure 虚拟机上的 SQL Server 之间的完整比较可在此查看:docs.microsoft.com/azure/azure-sql/azure-sql-iaas-vs-paas-what-is-overview#comparison-table
。
托管实例的关键功能显示在图 7.19中:
图 7.19:SQL 数据库托管实例功能
我们在本章中提到过 vCPU 定价模型和 DTU 定价模型。现在是时候更仔细地了解这些定价模型了。
SQL 数据库定价
Azure SQL 之前只有一种定价模型——基于 DTU 的模型——但现在也推出了基于 vCPU 的替代定价模型。定价模型根据客户的需求进行选择。当客户希望使用简单且预配置的资源选项时,选择基于 DTU 的模型;而基于 vCore 的模型则提供选择计算和存储资源的灵活性,同时也提供更多的控制和透明度。
让我们更仔细地看看这些模型。
基于 DTU 的定价
DTU 是 Azure SQL 数据库性能衡量的最小单位。每个 DTU 对应一定量的资源。这些资源包括存储、CPU 周期、IOPS 和网络带宽。例如,一个 DTU 可能提供三个 IOPS、少量 CPU 周期,以及 5 毫秒的读操作延迟和 10 毫秒的写操作延迟。
Azure SQL 数据库提供多种 SKU 用于创建数据库,每种 SKU 都有定义的 DTU 最大限制。例如,Basic SKU 只提供5个 DTU 和最大2 GB的数据,如图 7.20所示:
图 7.20:不同 SKU 的 DTU
另一方面,标准 SKU 提供从10个 DTU 到300个 DTU 之间的任何数量,最大数据量为250 GB。如你所见,每个 DTU 的费用大约为 991 卢比,或大约$1.40:
图 7.21:标准 SKU 中选择数量的 DTU 费用总结
Microsoft 提供了这些 SKU 在性能和资源方面的比较,并显示在图 7.22中:
图 7.22:Azure 中的 SKU 比较
一旦你配置了特定数量的 DTU,后端资源(CPU、IOPS 和内存)就会被分配,并且无论是否使用,都需要为其付费。如果采购的 DTU 数量超过实际需要,就会造成浪费;而如果配置的 DTU 数量不足,则会导致性能瓶颈。
正因如此,Azure 提供了弹性池。如您所知,弹性池中有多个数据库,DTU 是分配给弹性池的,而不是单个数据库。池内的所有数据库可以共享 DTU。这意味着,如果某个数据库的使用量较低,仅消耗了 5 个 DTU,则会有其他数据库消耗 25 个 DTU 来进行补偿。
需要注意的是,总体上,DTU 的消耗不能超过为弹性池分配的 DTU 数量。此外,弹性池内的每个数据库应分配最小的 DTU 数量,这个最小的 DTU 数量是预分配给数据库的。
弹性池有自己的 SKU:
图 7.23:弹性池中的 SKU
此外,单个弹性池中可以创建的数据库数量有限。完整的限制可以在此查看:docs.microsoft.com/azure/azure-sql/database/resource-limits-dtu-elastic-pools
。
基于 vCPU 的定价
这是 Azure SQL 的新定价模型。此定价模型提供了根据服务器分配的虚拟 CPU(vCPU)数量来采购,而不是为应用设置所需的 DTU 数量的选项。vCPU 是附带硬件的逻辑 CPU,例如存储、内存和 CPU 核心。
在此模型中,有三个 SKU:通用型、超大规模和业务关键型,每个 SKU 提供不同数量的 vCPU 和资源。此定价适用于所有 SQL 部署模型:
图 7.24:通用 SKU 的 vCPU 定价
如何选择合适的定价模型
架构师应能够为 Azure SQL 数据库选择合适的定价模型。DTU 是一种很好的定价机制,适用于有适用和可用使用模式的数据库。由于 DTU 方案中的资源可用性是线性的,如下图所示,数据库的使用可能更多的是内存密集型而非 CPU 密集型。在这种情况下,可以为数据库选择不同级别的 CPU、内存和存储。
在 DTU 模型中,资源是打包在一起的,无法对这些资源进行细粒度配置。而在 vCPU 模型中,可以为不同的数据库选择不同级别的内存和 CPU。如果已知某应用的使用模式,使用 vCPU 定价模型可能比 DTU 模型更合适。事实上,vCPU 模型还为已拥有本地 SQL Server 许可证的组织提供了混合许可证的好处。这些 SQL Server 实例可获得最高 30% 的折扣。
在图 7.25中,你可以从左侧的图表看到,随着 DTU 数量的增加,资源可用性也线性增长;然而,在右侧的 vCPU 定价图表中,你可以为每个数据库选择独立的配置:
图 7.25:DTU 和 vCore 模式的存储计算图
有了这些内容,我们可以结束对 Azure SQL 数据库的介绍。我们讨论了与 Azure SQL 数据库相关的不同部署方法、功能、定价和计划。在接下来的章节中,我们将介绍 Cosmos DB,它是一个 NoSQL 数据库服务。
Azure Cosmos DB
Cosmos DB 是 Azure 真实的跨区域、高可用、分布式、多模型数据库服务。如果你希望你的解决方案具有高度响应性并且始终可用,那么 Cosmos DB 适合你。由于这是一个跨区域的多模型数据库,我们可以将应用程序部署在离用户位置更近的地方,从而实现低延迟和高可用性。
只需点击按钮,就可以在任意数量的 Azure 区域之间扩展吞吐量和存储。为了涵盖几乎所有非关系型数据库的需求,提供了几种不同的数据库模型,包括:
-
SQL(文档)
-
MongoDB
-
Cassandra
-
表
-
Gremlin 图
Cosmos DB 中的对象层次结构从 Cosmos DB 账户开始。一个账户可以拥有多个数据库,每个数据库可以拥有多个容器。根据数据库的类型,容器可能包含文档(例如 SQL 的情况);在 Table 存储中包含半结构化的键值数据;或者如果使用 Gremlin 和 Cassandra 存储 NoSQL 数据,则包含实体及其之间的关系。
Cosmos DB 可用于存储 OLTP 数据。它在事务数据方面符合 ACID 原则,但有一些例外情况。
Cosmos DB 在单个文档级别提供 ACID 要求。这意味着文档中的数据在更新、删除或插入时,其原子性、一致性、隔离性和持久性将得到维护。然而,在文档之外,一致性和原子性需要由开发者自己管理。
Cosmos DB 的定价可以在这里找到:azure.microsoft.com/pricing/details/cosmos-db
。
图 7.26 展示了 Azure Cosmos DB 的一些特性:
图 7.26:Azure Cosmos DB 概览
在接下来的章节中,我们将介绍 Azure Cosmos DB 的一些关键特性。
特性
Azure Cosmos DB 的一些主要优点包括:
-
全球分布:可以使用 Azure Cosmos DB 构建全球范围内的高度响应和高可用应用程序。在复制的帮助下,数据副本可以存储在接近用户的 Azure 区域,从而提供更低的延迟和全球分布。
-
复制:你可以随时选择是否将数据复制到某个地区。假设你的数据在东部美国地区有一个副本,而你的组织计划在东部美国停用该服务并迁移到英国南部。只需几次点击,你就可以移除东部美国并将英国南部添加到账户中进行复制。
-
始终在线:Cosmos DB 提供 99.999% 的高可用性,支持读取和写入。通过 Azure 门户或编程方式,可以触发 Cosmos DB 账户的区域故障切换到其他地区。这确保了应用在发生区域故障时的业务连续性和灾难恢复计划。
-
可扩展性:Cosmos DB 提供无与伦比的全球弹性可扩展性,支持读取和写入。其扩展响应非常强大,意味着你可以通过一次 API 调用将请求量从数千增加到数亿次每秒。值得注意的是,这一切是在全球范围内完成的,但你只需要为吞吐量和存储付费。这种可扩展性非常适合应对意外的流量高峰。
-
低延迟:如前所述,将数据副本复制到离用户更近的地方可以显著减少延迟,这意味着用户可以在毫秒级别访问数据。Cosmos DB 保证全球范围内的读取和写入延迟低于 10 毫秒。
-
TCO 节省:由于 Cosmos DB 是完全托管的服务,客户需要的管理程度较低。此外,客户无需在全球范围内设置数据中心来支持其他地区的用户。
-
SLA:它提供 99.999% 的高可用性 SLA。
-
对开源软件(OSS) API的支持:Cosmos DB 还支持开源软件 API,另一个额外的优势。Cosmos DB 实现了 Cassandra、Mongo DB、Gremlin 和 Azure 表存储的 API。
使用案例场景
如果你的应用涉及全球范围的大规模数据读写,那么 Cosmos DB 是理想的选择。这类应用通常包括网页应用、移动应用、游戏和物联网应用。这些应用将从 Cosmos DB 的高可用性、低延迟和全球覆盖中获益。
此外,Cosmos DB 提供的响应时间接近实时。你可以利用 Cosmos DB SDK 开发基于 Xamarin 框架的 iOS 和 Android 应用。
一些使用 Cosmos DB 的热门游戏包括行尸走肉:无人之地(由 Next Games 开发)和光环 5:守护者。
完整的使用案例和示例列表可以在此找到:docs.microsoft.com/azure/cosmos-db/use-cases
。
Cosmos DB 是 Azure 中用于存储半结构化数据的首选服务,尤其适用于 OLTP 应用程序。我可以单独写一本书来讲解 Cosmos DB 的功能和特性;本节的目的是为你介绍 Cosmos DB 以及它在处理 OLTP 应用程序中的作用。
总结
在本章中,你学习到 Azure SQL 数据库是 Azure 的旗舰服务之一。今天,众多客户正在使用此服务,它提供了构建任务关键型数据库管理系统所需的所有企业级功能。
你发现 Azure SQL 数据库有多种部署类型,如单实例、托管实例和弹性池。架构师应该全面评估他们的需求并选择合适的部署模型。选择部署模型后,他们还需要在 DTU 和 vCPU 之间选择定价策略。除此之外,他们还应该配置 Azure SQL 数据库中所有与数据相关的安全性、可用性、灾难恢复、监控、性能和可扩展性需求。
在下一章,我们将讨论如何在 Azure 中构建安全的应用程序。我们将涵盖大多数服务的安全实践和功能。
第八章:8. 在 Azure 上构建安全应用的架构
在上一章中,我们讨论了 Azure 数据服务。由于我们正在处理敏感数据,安全性成为一个大问题。毫无疑问,安全性是架构师必须实现的最重要的非功能性需求。企业非常重视正确实施其安全策略。实际上,安全性是几乎所有利益相关者在应用的开发、部署和管理过程中关注的重点之一。当应用被构建并部署到云时,安全性变得更加重要。
为了帮助你了解如何根据部署的性质保护在 Azure 上的应用,本章将涵盖以下内容:
-
了解 Azure 中的安全性
-
基础设施层的安全性
-
应用层的安全性
-
Azure 应用中的认证与授权
-
使用 OAuth、Azure Active Directory 和其他通过联合身份验证的方法,包括第三方身份提供商如 Facebook
-
了解托管身份并使用它们访问资源
安全性
如前所述,安全性是任何软件或服务的重要元素。应实施适当的安全措施,使得应用仅能被允许访问的人使用,且用户不应执行他们无权操作的功能。同样,整个请求-响应机制应该使用确保只有目标方能够理解消息的方法构建,并确保能够轻松检测消息是否已被篡改。
以下原因使得 Azure 中的安全性变得尤为重要。首先,部署应用的组织无法完全控制底层硬件和网络。其次,安全性必须在每一层中构建,包括硬件、网络、操作系统、平台和应用。任何疏漏或配置错误都可能导致应用暴露于入侵者的攻击之下。例如,你可能听说过最近影响 Zoom 会议的漏洞,该漏洞允许黑客即使在会议主持人禁用与会者录音功能时,仍能录制会议。有消息称,数百万个 Zoom 账户已被销售到暗网。公司已经采取了必要的措施来解决这个漏洞。
安全性是当前一个重要的问题,尤其是在云环境中托管应用时,如果处理不当可能会导致严重后果。因此,理解保护工作负载的最佳实践非常必要。随着 DevOps 领域的进展,开发和运维团队借助工具和实践进行有效协作,安全性也成为一个重要关注点。
为了将安全原则和实践作为 DevOps 的重要组成部分,而不影响整体生产力和效率,已经引入了一种新的文化,称为DevSecOps。DevSecOps 帮助我们在开发阶段及早识别安全问题,而不是在发布后再进行缓解。在一个将安全作为每个阶段关键原则的开发过程中,DevSecOps 减少了后期雇佣安全专业人员来查找软件安全漏洞的成本。
保护应用程序意味着未知和未经授权的实体无法访问它。这也意味着与应用程序的通信是安全的且未被篡改。包括以下安全措施:
-
身份验证:身份验证检查用户的身份,并确保给定的身份可以访问应用程序或服务。在 Azure 中,身份验证使用基于 OAuth 2.0 构建的身份验证协议 OpenID Connect 来执行。
-
授权:授权允许并确定身份在应用程序或服务内能够执行的权限。授权在 Azure 中使用 OAuth 来执行。
-
机密性:机密性确保用户与应用程序之间的通信保持安全。实体之间的有效载荷交换是加密的,只有发送方和接收方能够理解,而其他人无法解读。消息的机密性通过对称加密和非对称加密来保障。证书用于实现加密,即消息的加密和解密。
对称加密使用一个共享的密钥,发送方和接收方都使用这个密钥,而非对称加密则使用一对私钥和公钥进行加密,提供更高的安全性。Linux 中的 SSH 密钥对,作为身份验证的工具,就是非对称加密的一个很好的例子。
-
完整性:完整性确保发送方和接收方之间的有效载荷和消息交换不会被篡改。接收方收到的消息与发送方发送的消息完全相同。数字签名和哈希是检查传入消息完整性的实现机制。
安全性是服务提供者与服务消费者之间的合作。双方对部署堆栈有不同的控制级别,每方都应实施安全最佳实践,以确保所有威胁被识别并得到缓解。从第一章,开始使用 Azure中,我们已经知道云计算大致提供三种模式——IaaS、PaaS 和 SaaS——每种模式在部署堆栈的协作控制上有所不同。每方应对其控制和范围内的组件实施安全实践。若在任何层面或任何一方未实施安全性,整个部署和应用将容易受到攻击。每个组织都需要有一个安全生命周期模型,就像对待任何其他流程一样。这确保了安全实践不断改进,以避免任何安全漏洞。在下一节中,我们将讨论安全生命周期及其如何使用。
安全生命周期
安全性通常被视为解决方案的非功能性需求。然而,随着网络攻击数量的增加,现在它被视为每个解决方案的功能性需求。
每个组织都会遵循某种形式的应用生命周期管理。当安全性被视为功能性需求时,它应该遵循与应用开发相同的流程。安全性不应是事后考虑的问题;它应从一开始就成为应用的一部分。在应用的整体规划阶段,安全性也应该进行规划。根据应用的性质,应识别不同类型和类别的威胁,并根据这些识别,应该在范围和应对措施方面进行文档化。应进行威胁建模演练,以说明每个组件可能面临的威胁。这将有助于为应用设计安全标准和政策。这通常是安全设计阶段。下一阶段称为威胁缓解或构建阶段。在这一阶段,实施安全性的代码和配置,以缓解安全威胁和风险。
系统在未经测试之前无法被认为是安全的。应执行适当的渗透测试和其他安全测试,以识别未实施或被忽视的潜在威胁缓解措施。通过测试发现的漏洞将得到修复,生命周期将在应用的整个过程中持续进行。这种应用生命周期管理过程,如图 8.1所示,应遵循安全性:
图 8.1:安全生命周期
规划、威胁建模、识别、缓解、测试和修复是一个迭代的过程,即使在应用程序或服务投入使用后,这些过程仍然会继续。应该积极监控整个环境和应用程序,以便主动识别威胁并进行缓解。监控还应启用警报和审计日志,以帮助进行反应性诊断、故障排除以及消除威胁和漏洞。
任何应用程序的安全生命周期从规划阶段开始,最终进入设计阶段。在设计阶段,应用程序的架构被分解成细化的组件,并具有独立的通信和托管边界。威胁是基于它们与其他组件之间的交互以及跨托管边界的交互来识别的。在整体架构中,通过实施适当的安全特性来缓解威胁,一旦缓解措施到位,进一步的测试会验证威胁是否仍然存在。应用程序部署到生产环境并投入使用后,将对其进行安全监控,以检测任何安全漏洞和风险,并采取主动或被动的修复措施。
如前所述,不同的组织有不同的流程和方法来实施安全生命周期;同样,微软提供了有关安全生命周期的完整指导和信息,详细信息请访问www.microsoft.com/securityengineering/sdl/practices
。通过微软分享的实践,每个组织都可以专注于构建更加安全的解决方案。在云计算时代的进步以及企业和客户数据迁移到云端的过程中,学习如何保护这些数据至关重要。在接下来的部分,我们将探讨 Azure 安全性以及不同级别的安全性,这将帮助我们在 Azure 中构建安全的解决方案。
Azure 安全性
Azure 通过多个 Azure 区域的数据中心提供所有服务。这些数据中心在区域内部以及区域之间互联。Azure 了解它为客户托管着关键任务应用程序、服务和数据,因此必须确保数据中心和区域的安全性是至关重要的。
客户将应用程序部署到云端,是基于他们相信 Azure 会保护他们的应用程序和数据免受漏洞和泄露的威胁。如果这种信任被打破,客户将不会迁移到云端,因此 Azure 在所有层次上实施安全措施,如图 8.2所示,从数据中心的物理边界到逻辑软件组件。每一层都有保护措施,甚至 Azure 数据中心团队也无法访问它们:
图 8.2:Azure 数据中心不同层次的安全特性
安全对微软和 Azure 至关重要。微软通过确保客户的部署、解决方案和数据在物理和虚拟层面上都得到完全的保护,从而建立起客户的信任。如果一个云平台不安全,无论是物理还是数字层面的,用户是不会使用它的。
为了确保客户对 Azure 的信任,Azure 开发中的每个活动都从安全角度进行规划、记录、审计和监控。物理 Azure 数据中心受到防止入侵和未经授权访问的保护。事实上,甚至微软的员工和运营团队也无法访问客户的解决方案和数据。以下是 Azure 提供的一些开箱即用的安全功能:
-
安全用户访问:只有客户可以访问自己的部署、解决方案和数据。即使是 Azure 数据中心的人员也无法访问客户的资料。客户可以允许其他人访问,但这是由客户自行决定的。
-
静态数据加密:Azure 对所有管理数据进行加密,包括各种企业级存储解决方案,以满足不同的需求。微软还为像 Azure SQL 数据库、Azure Cosmos DB 和 Azure Data Lake 等托管服务提供加密。由于数据是静态加密的,因此无法被任何人读取。它还为客户提供此功能,客户可以加密自己的静态数据。
-
传输加密:Azure 对所有从其网络传输的数据进行加密,同时确保其网络主干不会受到未经授权的访问。
-
主动监控和审计:Azure 会持续主动监控所有数据中心,及时识别任何违反规定、威胁或风险,并加以缓解。
Azure 符合各国、地方、国际及行业特定的合规标准。你可以在www.microsoft.com/trustcenter/compliance/complianceofferings
上查阅微软合规性服务的完整清单。在部署符合合规要求的解决方案时,务必将其作为参考。现在我们已经了解了 Azure 的主要安全功能,接下来让我们深入探讨 IaaS 安全。在接下来的部分中,我们将探索客户如何利用 Azure 提供的 IaaS 安全功能。
IaaS 安全
Azure 是一个成熟的 IaaS 解决方案部署平台。许多 Azure 用户希望完全控制他们的部署,这些用户通常会使用 IaaS 来处理他们的解决方案。确保这些部署和解决方案的安全性是至关重要的,无论是默认的还是设计时的。Azure 提供了丰富的安全功能来保护 IaaS 解决方案。在本部分中,我们将介绍一些主要的安全功能。
网络安全组
IaaS 部署的最基本组成包括虚拟机和虚拟网络。虚拟机可能通过将公共 IP 分配给其网络接口暴露到互联网,或者仅对内部资源可用。其中一些内部资源可能会反过来暴露到互联网。无论如何,虚拟机应当确保其安全,以便未经授权的请求根本无法到达它们。虚拟机应通过能够过滤网络本身请求的机制进行安全保护,而不是让请求到达虚拟机后再采取行动。
隔离机制(Ring-fencing)是虚拟机使用的安全机制之一。此防护墙可以根据协议、源 IP、目标 IP、源端口和目标端口允许或拒绝请求。此功能通过 Azure 网络安全组(NSGs)资源进行部署。NSGs 由规则组成,评估传入和传出的请求。根据这些规则的执行和评估,决定是否允许或拒绝访问请求。
NSGs 灵活且可以应用于虚拟网络子网或单个网络接口。当应用于子网时,安全规则会应用到该子网上托管的所有虚拟机。另一方面,应用于网络接口时,只影响与该网络接口关联的特定虚拟机的请求。也可以同时将 NSGs 应用到网络子网和网络接口。通常,应该使用这种设计在网络子网级别应用通用安全规则,在网络接口级别应用独特的安全规则。这有助于设计模块化的安全规则。
评估 NSGs 的流程如图 8.3所示:
图 8.3:表示评估 NSGs 的流程图
当请求到达 Azure 主机时,根据请求是传入请求还是传出请求,适当的规则会加载并应用到请求/响应上。如果规则与请求/响应匹配,则请求/响应被允许或拒绝。规则匹配由重要的请求/响应信息组成,如源 IP 地址、目标 IP 地址、源端口、目标端口和使用的协议。此外,NSGs 支持服务标签。服务标签表示来自特定 Azure 服务的一组 IP 地址前缀。微软管理这些地址前缀并自动更新,从而消除了每次地址前缀变更时需要更新安全规则的麻烦。
可用于的服务标签集可以在docs.microsoft.com/azure/virtual-network/service-tags-overview#available-service-tags
中找到。服务标签可以与 NSG 一起使用,也可以与 Azure 防火墙一起使用。现在你已经了解了 NSG 的工作原理,我们来看看 NSG 设计,这将帮助你在创建 NSG 规则以提高安全性时,确定应该考虑的主要点。
NSG 设计
设计 NSG 的第一步是确定资源的安全需求。应确定或考虑以下内容:
-
该资源仅从互联网可访问吗?
-
该资源是否同时可以从内部资源和互联网访问?
-
该资源仅能从内部资源访问吗?
-
根据正在部署的解决方案架构,确定所依赖的资源、负载均衡器、网关和虚拟机。
-
配置虚拟网络及其子网。
根据这些调查结果,应创建合适的 NSG 设计。理想情况下,每个工作负载和资源类型应该有多个网络子网。建议不要在同一子网上部署负载均衡器和虚拟机。
根据项目需求,应确定适用于不同虚拟机工作负载和子网的通用规则。例如,对于 SharePoint 部署,前端应用程序和 SQL 服务器部署在不同的子网中,因此应该为每个子网确定规则。
在识别常见的子网级规则后,应识别单个资源的规则,并将这些规则应用于网络接口级别。需要理解的是,如果某个规则允许某个端口的入站请求,那么该端口也可以用于发出的请求,而无需额外配置。
如果资源可以通过互联网访问,应尽可能使用特定的 IP 范围和端口创建规则,而不是允许来自所有 IP 范围的流量(通常表示为 0.0.0.0/0)。应执行仔细的功能和安全性测试,以确保打开和关闭了足够且最佳的 NSG 规则。
防火墙
NSG 提供请求的外部安全边界。然而,这并不意味着虚拟机不需要实施额外的安全措施。最好同时在内部和外部实施安全性。无论是 Linux 还是 Windows 虚拟机,都提供一种机制来在操作系统级别过滤请求。这在 Windows 和 Linux 中都称为防火墙。
建议为操作系统实现防火墙。它们帮助建立一个虚拟安全墙,只允许那些被认为可信的请求。任何不可信的请求都会被拒绝访问。虽然也有物理防火墙设备,但在云端,通常使用操作系统防火墙。图 8.4展示了 Windows 操作系统的防火墙配置:
图 8.4:防火墙配置
防火墙过滤网络数据包,并识别传入的端口和 IP 地址。利用这些数据包中的信息,防火墙评估规则并决定是否允许或拒绝访问。
就 Linux 而言,有多种防火墙解决方案可供选择。某些防火墙方案非常特定于所使用的发行版;例如,SUSE 使用 SuSefirewall2,Ubuntu 使用 ufw。最广泛使用的实现是 firewalld 和 iptables,这些在每个发行版中都可以找到。
防火墙设计
作为最佳实践,应该评估每个操作系统的防火墙。每个虚拟机在整体部署和解决方案中都有独特的责任。应该明确这些责任的规则,并根据情况适当地打开和关闭防火墙。
在评估防火墙规则时,重要的是要考虑子网和单个网络接口级别的 NSG 规则。如果没有正确处理,可能会出现规则在 NSG 级别被拒绝,但在防火墙级别保持开放,反之亦然。如果请求在 NSG 级别被允许但在防火墙级别被拒绝,应用程序将无法按预期工作;而如果请求在 NSG 级别被拒绝但在防火墙级别被允许,则安全风险将增加。
防火墙帮助你建立多个通过其安全规则隔离的网络。应该进行仔细的功能性和安全性测试,确保适当且优化的防火墙规则被正确地开启和关闭。
使用 Azure 防火墙最为合理,它是建立在 NSG 之上的云端网络服务。它非常容易设置,提供中央管理功能,并且无需维护。结合 Azure 防火墙和 NSG 可以为虚拟机、虚拟网络,甚至不同的 Azure 订阅之间提供安全性。话虽如此,如果一个解决方案需要额外的安全级别,我们可以考虑实现操作系统级别的防火墙。我们将在接下来的章节中更深入地讨论Azure 防火墙。
应用程序安全组
NSG(网络安全组)可以应用于虚拟网络子网级别或直接应用于单个网络接口。虽然在子网级别应用 NSG 已经足够,但有时这还不够。在同一个子网内有不同类型的工作负载,每个工作负载需要不同的安全组。可以将安全组分配给虚拟机的单个网络接口卡(NICs),但如果虚拟机数量很大,这种做法容易变成维护的噩梦。
Azure 有一个相对较新的功能,叫做应用安全组。我们可以创建应用安全组,并将其直接分配给多个 NIC,即使这些 NIC 属于不同子网和资源组中的虚拟机。应用安全组的功能类似于 NSG,只是它提供了一种替代方法,将组分配给网络资源,并在跨资源组和子网分配时提供更多的灵活性。应用安全组可以简化 NSG;然而,它有一个主要的限制。我们可以在安全规则的源和目标中使用一个应用安全组,但当前不支持在源或目标中使用多个应用安全组。
创建规则的最佳实践之一是尽量减少所需的安全规则数量,以避免维护显式规则。在前一节中,我们讨论了如何使用服务标签与 NSG 配合,消除维护每个服务的单独 IP 地址前缀的麻烦。同样,使用应用安全组时,我们可以减少显式 IP 地址和多个规则的复杂性。推荐在可能的情况下使用这种做法。如果你的解决方案要求使用单独的 IP 地址或 IP 地址范围的显式规则,那么才应该选择这种方式。
Azure 防火墙
在前一节中,我们讨论了如何在 Windows/Linux 操作系统中使用 Azure 防火墙来允许或拒绝通过特定端口和服务的请求与响应。虽然操作系统防火墙在安全方面起着重要作用,并且必须在任何企业部署中实施,但 Azure 提供了一种名为 Azure 防火墙的安全资源,它具有类似的功能,可以基于规则过滤请求并确定是否应允许或拒绝该请求。
使用 Azure 防火墙的优点是,它会在请求到达操作系统之前进行评估。Azure 防火墙是一个网络资源,是一项独立服务,保护虚拟网络级别的资源。任何与虚拟网络直接关联的资源,包括虚拟机和负载均衡器,都可以通过 Azure 防火墙进行保护。
Azure 防火墙是一项高可用、可扩展的服务,不仅能保护基于 HTTP 的请求,还能保护从虚拟网络进出任何类型的请求,包括 FTP、SSH 和 RDP。Azure 防火墙还可以在部署期间跨多个可用性区域,提供更高的可用性。
强烈建议在 Azure 上部署 Azure 防火墙,以保护关键任务工作负载,并结合其他安全措施一起使用。还需注意,即使使用其他服务,如 Azure 应用程序网关和 Azure Front Door,仍应使用 Azure 防火墙,因为这些工具具有不同的作用范围和功能。此外,Azure 防火墙还支持服务标签和威胁情报。在前面的部分中,我们讨论了使用服务标签的优势。威胁情报可以用于在流量来自或去往已知恶意 IP 地址和域时生成警报,这些地址和域记录在微软的威胁情报数据流中。
减少攻击面
NSG 和防火墙有助于管理授权请求进入环境。然而,环境不应过度暴露于攻击。系统的表面区域应充分启用以实现其功能,但应禁用足够的部分,以便攻击者无法找到漏洞并访问那些没有预期用途或没有足够安全保护的开放区域。安全性应充分加固,使任何攻击者都难以入侵系统。
应该完成的一些配置包括以下内容:
-
从操作系统中移除所有不必要的用户和组。
-
确定所有用户的组成员身份。
-
使用目录服务实施组策略。
-
阻止脚本执行,除非它是由受信任的机构签名的。
-
记录并审计所有活动。
-
安装恶意软件和防病毒软件,定期进行扫描,并频繁更新定义。
-
禁用或关闭不需要的服务。
-
锁定文件系统,只允许授权访问。
-
锁定对注册表的更改。
-
必须根据要求配置防火墙。
-
PowerShell 脚本执行应设置为
Set-ExecutionPolicy -ExecutionPolicy Restricted
或Set-ExecutionPolicy -ExecutionPolicy RemoteSigned
PowerShell 命令。 -
通过 Internet Explorer 启用增强保护。
-
限制创建新用户和组的权限。
-
移除互联网访问权限,并为 RDP 实施跳板服务器。
-
禁止通过互联网使用 RDP 登录到服务器。相反,应该使用站点到站点 VPN、点对站点 VPN 或 ExpressRoute 通过网络内部远程登录到远程计算机。
-
定期部署所有安全更新。
-
在环境中运行安全合规性管理工具,并实施其所有建议。
-
使用安全中心和操作管理套件主动监控环境。
-
部署虚拟网络设备,将流量路由到内部代理和反向代理。
-
所有敏感数据,如配置、连接字符串和凭据,应该进行加密。
上述内容是从安全角度应该考虑的一些关键点。这个列表将不断扩展,我们需要不断改进安全性,以防止任何形式的安全漏洞。
实现跳板服务器
从虚拟机中移除互联网访问是一个好主意。限制远程桌面服务从互联网访问虚拟机也是一种良好的做法,但那么如何访问虚拟机呢?一种可行的方法是仅允许内部资源通过 Azure VPN 选项进行 RDP 访问虚拟机。然而,还有另一种方法——使用跳板服务器。
跳板服务器是部署在隔离区(DMZ)中的服务器。这意味着它不在托管核心解决方案和应用程序的网络上,而是位于一个单独的网络或子网中。跳板服务器的主要目的是接受用户的 RDP 请求,并帮助他们登录。通过这个跳板服务器,用户可以进一步通过 RDP 连接到其他虚拟机。它可以访问两个或多个网络:一个是与外部世界连接的网络,另一个是与解决方案内部网络连接的网络。跳板服务器实施所有安全限制,并提供一个安全客户端来连接到其他服务器。通常,跳板服务器会禁用访问电子邮件和互联网。
使用 Azure 资源管理器模板部署带有虚拟机规模集(VMSS)的跳板服务器示例,请访问 azure.microsoft.com/resources/templates/201-vmss-windows-jumpbox
。
Azure Bastion
在上一节中,我们讨论了实现跳板服务器。Azure Bastion 是一个完全托管的服务,可以在虚拟网络中进行配置,以便通过 TLS 在 Azure 门户中直接为您的虚拟机提供 RDP/SSH 访问。Bastion 主机将充当跳板服务器,消除了为虚拟机配置公共 IP 地址的需求。使用 Bastion 的概念与实现跳板服务器相同;然而,由于这是一个托管服务,因此完全由 Azure 管理。
由于 Bastion 是 Azure 提供的完全托管服务,并且内部已经进行了加固,因此我们无需在 Bastion 子网中应用额外的 NSG(网络安全组)。另外,由于我们没有为虚拟机附加任何公共 IP,它们就可以防止端口扫描。
应用安全
Web 应用可以在基于 IaaS 的解决方案中托管,这些解决方案建立在虚拟机之上,也可以在 Azure 提供的托管服务中托管,例如应用服务(App Service)。应用服务是 PaaS 部署模式的一部分,我们将在下一节中详细介绍。在这一节中,我们将探讨应用层安全性。
SSL/TLS
安全套接层(SSL)现在已经被弃用,取而代之的是传输层安全性(TLS)。TLS 通过加密提供端到端的安全性。它提供了两种类型的加密:
-
对称加密:发送者和接收者都可以使用相同的密钥,该密钥用于加密和解密消息。
-
非对称加密:每个利益相关者都有两把密钥——一把私钥和一把公钥。私钥保留在服务器上或用户手中并保持机密,而公钥可以自由分发给所有人。公钥持有者使用它来加密信息,而该信息只能通过对应的私钥解密。由于私钥保留在所有者手中,只有他们才能解密信息。Rivest–Shamir–Adleman(RSA)是用于生成这些公私密钥对的算法之一。
-
这些密钥也可以通过证书的形式提供,这些证书通常被称为 X.509 证书,尽管证书除了包含密钥外,还有更多的详细信息,并且通常由受信任的证书颁发机构签发。
Web 应用程序应该使用 TLS 来确保用户与服务器之间的消息交换是安全和机密的,并且身份得到保护。这些证书应该从受信任的证书颁发机构购买,而不是自签名证书。
托管身份
在我们了解托管身份之前,了解没有托管身份时应用程序是如何构建的非常重要。
传统的应用程序开发方式是在配置文件中使用机密,例如用户名、密码或 SQL 连接字符串。将这些机密放入配置文件使得对这些机密的应用程序更改变得容易且灵活,而无需修改代码。它帮助我们遵循“对扩展开放,对修改封闭”的原则。然而,从安全角度来看,这种方法有一个缺点。任何能够访问配置文件的人都可以查看这些机密,因为通常这些机密以明文列在其中。虽然有一些方法可以加密它们,但它们并非万无一失。
在应用程序中使用密钥和凭证的更好方法是将其存储在像 Azure Key Vault 这样的机密库中。Azure Key Vault 提供了通过硬件安全模块(HSM)的完全安全性,并且机密以加密方式存储,并通过存储在独立硬件中的密钥进行按需解密。机密可以存储在 Key Vault 中,每个机密都有一个显示名称和密钥。密钥以 URI 的形式存在,应用程序可以使用它来引用机密,如图 8.5所示:
图 8.5:将机密存储在密钥库中
在应用程序配置文件中,我们可以使用名称或密钥来引用机密。然而,现在又有一个新挑战。应用程序如何连接到并验证密钥保管库?
密钥保管库有访问策略,定义了用户或组在密钥保管库中访问密钥和凭证的权限。可以提供访问权限的用户、组或服务应用程序都在Azure Active Directory(Azure AD)中配置和托管。尽管可以通过密钥保管库的访问策略为单个用户账户提供访问权限,但更好的做法是使用服务主体来访问密钥保管库。服务主体有一个标识符,也称为应用程序 ID 或客户端 ID,以及一个密码。可以使用客户端 ID 和密码来验证 Azure 密钥保管库。这种服务主体可以被授权访问机密。Azure 密钥保管库的访问策略在密钥保管库的访问策略窗格中授予。在图 8.6中,您可以看到服务主体—https://keyvault.book.com—已获得访问名为 keyvaultbook 的密钥保管库的权限:
图 8.6:授予服务主体访问密钥保管库的权限
这引出了另一个挑战:要访问密钥保管库,我们需要在配置文件中使用客户端 ID 和密钥来连接到密钥保管库,获取密钥,并检索其值。这几乎相当于在配置文件中使用用户名、密码和 SQL 连接字符串。
这就是托管身份可以发挥作用的地方。Azure 推出了托管服务身份,并随后将其更名为托管身份。托管身份是由 Azure 管理的身份。在后台,托管身份还会创建一个服务主体,并附带一个密码。通过托管身份,您无需将凭证放入配置文件中。
托管身份只能用于与支持 Azure AD 作为身份提供者的服务进行身份验证。托管身份仅用于身份验证。如果目标服务没有为该身份提供基于角色的访问控制(RBAC)权限,则该身份可能无法在目标服务上执行其预期的操作。
托管身份有两种类型:
-
系统分配的托管身份
-
用户分配的托管身份
系统分配的身份由服务本身生成。例如,如果应用服务想要连接到 Azure SQL 数据库,它可以在其配置选项中生成系统分配的托管身份。这些托管身份在父资源或服务删除时也会被删除。如图 8.7所示,系统分配的身份可以由应用服务用于连接 Azure SQL 数据库:
图 8.7:为应用服务启用系统分配的托管标识
用户分配的托管标识是作为独立的单独标识创建的,之后将其分配给 Azure 服务。由于其生命周期不依赖于它们所分配的资源,它们可以应用并在多个 Azure 服务中重复使用。
一旦托管标识被创建并且通过 RBAC 或访问权限赋予目标资源,它就可以在应用程序中用于访问目标资源和服务。
Azure 提供了一个 SDK 和一个 REST API,用于与 Azure AD 交互并获取托管标识的访问令牌,然后使用该令牌访问和消费目标资源。
SDK 是 Microsoft.Azure.Services.AppAuthentication
NuGet 包的一部分,适用于 C#。一旦访问令牌可用,它就可以用来消费目标资源。
获取访问令牌所需的代码如下:
var tokenProvider = new AzureServiceTokenProvider();
string token = await tokenProvider.GetAccessTokenAsync("https://vault.azure.net");
或者,使用此方法:
string token = await tokenProvider.GetAccessTokenAsync("https://database.windows.net");
应该注意,应用程序代码需要在应用服务或函数应用的上下文中运行,因为标识是附加在它们上的,只有在从这些上下文中运行时,代码才能访问标识。
上面的代码有两个不同的使用场景。访问密钥库和 Azure SQL 数据库的代码是一起展示的。
需要注意的是,应用程序不会在代码中提供任何与托管标识相关的信息,所有这些信息都通过配置进行完全管理。开发人员、单个应用程序管理员和操作员不会接触到任何与托管标识相关的凭证,而且在代码中也没有提到它们。凭证轮换完全由托管 Azure 服务的资源提供者进行管理。默认情况下,每 46 天会进行一次轮换。如果需要,资源提供者可以要求新的凭证,因此提供者可能会等超过 46 天才请求新的凭证。
在下一节中,我们将讨论一个云原生的安全信息和事件管理器(SIEM):Azure Sentinel。
Azure Sentinel
Azure 提供了一个 SIEM 和安全编排自动响应(SOAR)作为一个独立服务,可以与任何自定义部署的 Azure 服务集成。图 8.8 显示了 Azure Sentinel 的一些关键功能:
图 8.8:Azure Sentinel 的关键功能
Azure Sentinel 收集来自部署和资源的信息日志,并进行分析,以找出与各种安全问题相关的模式和趋势,这些问题从数据源中提取。
应该对环境进行主动监控,收集日志,并从这些日志中提取信息,作为与代码实现分离的单独活动。这时,SIEM 服务发挥了作用。Azure Sentinel 可以使用许多连接器;这些连接器将用于向 Azure Sentinel 添加数据源。Azure Sentinel 提供了与 Microsoft 服务(如 Office 365、Azure AD 和 Azure 威胁保护)兼容的连接器。收集到的数据将被馈送到日志分析工作区,您可以编写查询来搜索这些日志。
像 Azure Sentinel 这样的 SIEM 工具可以在 Azure 上启用,从日志分析和 Azure 安全中心获取所有日志,而这些日志又可以从多个来源、部署和服务中获取。SIEM 然后可以在收集到的数据上运行其智能分析并生成洞察。它可以根据发现的智能生成报告和仪表板供消费使用,但它也可以调查可疑活动和威胁,并对其采取行动。
虽然 Azure Sentinel 在功能上可能与 Azure 安全中心非常相似,但 Azure Sentinel 的功能远超过 Azure 安全中心。它通过使用连接器从其他途径收集日志的能力,使其与 Azure 安全中心有所不同。
PaaS 安全性
Azure 提供了许多 PaaS 服务,每个服务都有自己的安全特性。通常,PaaS 服务可以通过凭据、证书和令牌进行访问。PaaS 服务允许生成短期有效的安全访问令牌。客户端应用程序可以发送这些安全访问令牌来表示受信任的用户。在本节中,我们将介绍一些在几乎所有解决方案中使用的最重要的 PaaS 服务。
Azure Private Link
Azure Private Link 提供通过虚拟网络中的私有端点访问 Azure PaaS 服务以及 Azure 托管的客户拥有/合作伙伴共享服务。在使用 Azure Private Link 时,我们不必将服务暴露到公共互联网,并且我们服务与虚拟网络之间的所有流量都通过微软的骨干网络进行。
Azure Private Endpoint 是一种网络接口,可帮助私密且安全地连接到由 Azure Private Link 提供支持的服务。由于私有端点映射到 PaaS 服务的实例,而不是整个服务,因此用户只能连接到资源。对任何其他服务的连接都会被拒绝,这样可以防止数据泄露。Private Endpoint 还允许您通过 ExpressRoute 或 VPN 隧道从本地安全访问。这消除了设置公共对等连接或通过公共互联网访问服务的需求。
Azure 应用程序网关
Azure 提供了一个称为 Azure 应用网关的 7 层负载均衡器,它不仅可以进行负载均衡,还可以根据 URL 中的值进行路由。它还具有称为 Web 应用程序防火墙的功能。Azure 应用网关支持在网关处终止 TLS,因此后端服务器将收到未加密的流量。这有几个优点,如更好的性能,更好地利用后端服务器以及数据包的智能路由。在前面的部分中,我们讨论了 Azure 防火墙及其如何在网络层保护资源。另一方面,Web 应用程序防火墙则在应用程序层保护部署。
任何部署在互联网上的应用程序都面临着多种安全挑战。以下是一些重要的安全威胁:
-
跨站脚本攻击
-
远程代码执行
-
SQL 注入
-
拒绝服务 (DoS) 攻击
-
分布式拒绝服务 (DDoS) 攻击
当然,还有更多的安全威胁。
开发人员可以通过编写防御性代码并遵循最佳实践来解决大量这些攻击;然而,仅仅是代码不应该负责在实时网站上识别这些问题。Web 应用程序防火墙配置规则可以识别此类问题,并拒绝请求,正如前文所述。
建议使用应用网关 Web 应用程序防火墙功能来保护应用程序免受实时安全威胁。Web 应用程序防火墙将根据配置的方式要么允许请求通过,要么阻止它。
Azure 前门
Azure 推出了一个相对较新的服务,称为 Azure 前门。Azure 前门的角色与 Azure 应用网关非常相似;然而,它在范围上有所不同。虽然应用网关在单个区域内工作,但 Azure 前门在全球范围内跨区域和数据中心工作。它也有一个 Web 应用程序防火墙,可以配置以保护部署在多个区域中的应用程序免受各种安全威胁,如 SQL 注入、远程代码执行和跨站脚本攻击。
应用网关可以部署在 Front Door 后面以解决连接排干。此外,将应用网关部署在 Front Door 后面还将有助于负载均衡需求,因为 Front Door 只能在全局层面进行基于路径的负载均衡。在架构中添加应用网关将为虚拟网络中的后端服务器提供进一步的负载均衡。
Azure 应用服务环境
Azure App Service 部署在共享网络中,并且在后台运行。所有 App Service 的 SKU 都使用虚拟网络,这些虚拟网络也可能被其他租户使用。为了更好地控制和确保在 Azure 上安全部署 App Service,可以将服务托管在专用虚拟网络上。可以通过使用 Azure App Service Environment(ASE)实现这一点,它提供完全隔离的环境,以高规模运行你的 App Service。这还通过允许你部署 Azure 防火墙、应用安全组、NSG、应用网关、Web 应用防火墙和 Azure Front Door 提供额外的安全性。所有在 App Service Environment 中创建的 App Service 计划将位于隔离的定价层,且无法选择其他层次。
这个虚拟网络和计算的所有日志可以在 Azure Log Analytics 和 Security Center 中整理,最终与 Azure Sentinel 配合使用。
然后,Azure Sentinel 可以提供洞察并执行工作簿和运行簿,以自动化方式响应安全威胁。安全行动手册可以在 Azure Sentinel 中响应警报时运行。每个安全行动手册包含在警报发生时需要采取的措施。安全行动手册基于 Azure Logic Apps,这使你可以自由使用并自定义与 Logic Apps 一起提供的内置模板。
Log Analytics
Log Analytics 是一个新的分析平台,用于管理云部署、内部数据中心和混合解决方案。
它提供了多个模块化解决方案——一种帮助实现特定功能的功能。例如,安全和审计解决方案帮助获取组织部署的完整安全视图。同样,还有许多其他解决方案,如自动化和变更跟踪,应该从安全角度实施。Log Analytics 的安全和审计服务提供以下五个类别的信息:
-
安全领域:这些提供了查看安全记录、恶意软件评估、更新评估、网络安全、身份和访问信息,以及具有安全事件的计算机的能力。还可以访问 Azure Security Center 控制面板。
-
反恶意软件评估:这有助于识别未受到恶意软件保护且存在安全问题的服务器。它提供有关潜在安全问题暴露的信息,并评估任何风险的严重性。用户可以根据这些建议采取主动措施。Azure Security Center 子类别提供由 Azure Security Center 收集的信息。
-
显著问题:这可以快速识别活动问题并评估其严重性。
-
检测:此类别处于预览模式。它通过可视化安全警报来识别攻击模式。
-
威胁情报:通过可视化拥有外发恶意 IP 流量的服务器总数、恶意威胁类型以及显示这些 IP 来源的地图,帮助识别攻击模式。
在门户中查看上述详细信息时,如图 8.9所示:
图 8.9:在 Log Analytics 的“安全与审计”面板中显示的信息
现在你已经了解了 PaaS 服务的安全性,接下来让我们探索如何保护存储在 Azure 存储中的数据。
Azure 存储
存储帐户在整体解决方案架构中扮演重要角色。存储帐户可以存储重要信息,如用户的个人可识别信息(PII)数据、商业交易以及其他敏感和机密数据。确保存储帐户安全并仅允许授权用户访问至关重要。存储的数据在传输时会进行加密,并使用安全通道传输。存储本身,以及使用存储帐户及其数据的用户和客户端应用程序,在数据整体安全性中扮演着至关重要的角色。数据应该始终保持加密状态。这也包括连接到数据存储的凭证和连接字符串。
Azure 提供 RBAC 来管理谁可以管理 Azure 存储帐户。这些 RBAC 权限赋予 Azure AD 中的用户和组。然而,当要部署到 Azure 的应用程序创建时,它将拥有不在 Azure AD 中的用户和客户。为了让用户能够访问存储帐户,Azure 存储提供存储访问密钥。存储帐户级别有两种访问密钥——主密钥和辅助密钥。拥有这些密钥的用户可以连接到存储帐户。这些存储访问密钥在访问存储帐户时用于身份验证步骤。应用程序可以使用主密钥或辅助密钥来访问存储帐户。提供两把密钥是为了防止主密钥被泄露时,应用程序可以更新为使用辅助密钥,同时主密钥被重新生成。这有助于最小化应用程序停机时间。此外,它通过移除被泄露的密钥来提高安全性,而不影响应用程序。通过 Azure 门户查看存储密钥详情,如图 8.10所示:
图 8.10:存储帐户的访问密钥
Azure 存储提供四种服务——blob、文件、队列和表格——在一个帐户中。每项服务还提供用于其自身安全性的基础设施,采用安全访问令牌。
共享访问签名(SAS)是一个 URI,它授予对 Azure 存储服务(如 Blob、文件、队列和表格)的受限访问权限。这些 SAS 令牌可以与不应信任整个存储账户密钥的客户端共享,从而限制对特定存储账户资源的访问。通过将 SAS URI 分发给这些客户端,可以在指定的时间段内授予资源访问权限。
SAS 令牌存在于存储账户及单个 Blob、文件、表格和队列级别。存储账户级别的签名功能更强大,具有在单个服务级别上允许或拒绝权限的权利。它还可以替代单个资源服务级别使用。
SAS 令牌提供了对资源的精细访问控制,并且可以组合使用。这些令牌包括读取、写入、删除、列出、添加、创建、更新和处理权限。此外,在生成 SAS 令牌时,还可以确定对资源的访问权限。可以单独针对 Blob、表格、队列和文件,也可以对它们的组合进行访问控制。存储账户密钥适用于整个账户,无法针对单个服务进行限制——也无法从权限角度进行限制。创建和撤销 SAS 令牌比存储账户访问密钥要容易得多。SAS 令牌可以为指定时间段创建,过期后自动失效。
需要注意的是,如果存储账户密钥被重新生成,那么基于这些密钥的 SAS 令牌将失效,需要创建新的 SAS 令牌并与客户端共享。在图 8.11中,您可以看到选择范围、权限、开始日期、结束日期、允许的 IP 地址、允许的协议和签名密钥的选项,以创建 SAS 令牌:
图 8.11:创建 SAS 令牌
如果我们正在重新生成key1
(之前用于签署 SAS 令牌的密钥),那么我们需要使用key2
或新的key1
创建一个新的 SAS 令牌。
Cookie 偷窃、脚本注入和 DoS 攻击是攻击者常用的破坏环境和窃取数据的手段。浏览器和 HTTP 协议实现了内建机制,确保无法执行这些恶意活动。通常,任何跨域的请求都不被 HTTP 或浏览器允许。一个域中的脚本无法请求另一个域的资源。然而,在某些有效的用例中,应该允许此类请求。HTTP 协议实现了跨域资源共享(CORS)。借助 CORS,可以跨域访问资源并使其工作。Azure 存储为 blob、文件、队列和表资源配置 CORS 规则。Azure 存储允许创建在每个身份验证请求中进行评估的规则。如果规则满足,请求将被允许访问该资源。在图 8.12 中,您可以看到如何为每个存储服务添加 CORS 规则:
图 8.12:为存储账户创建 CORS 规则
数据不仅在传输过程中必须得到保护;在静态状态下也应该得到保护。如果静态数据没有加密,任何有权限访问数据中心物理硬盘的人都能读取这些数据。尽管数据泄露的可能性微乎其微,客户仍然应该加密他们的数据。存储服务加密有助于保护静态数据。该服务透明地工作,且用户无需知晓。它在数据保存到存储账户时进行加密,并在数据读取时自动解密。整个过程无需用户进行任何额外操作。
Azure 账户密钥必须定期轮换。这将确保攻击者无法访问存储账户。
重新生成密钥也是一个好主意;然而,必须根据其在现有应用程序中的使用情况进行评估。如果它破坏了现有应用程序,那么这些应用程序应优先考虑变更管理,并且变更应逐步应用。
始终建议为每个服务使用具有有限时间范围的独立 SAS 令牌。此令牌应仅提供给需要访问资源的用户。始终遵循最小权限原则,仅提供必要的权限。
SAS 密钥和存储账户密钥应存储在 Azure 密钥保管库中。这提供了安全的存储和访问方式。应用程序可以在运行时从密钥保管库读取这些密钥,而不是将它们存储在配置文件中。
此外,您还可以使用 Azure AD 来授权对 Blob 和队列存储的请求。我们将使用 RBAC(角色基于访问控制)为服务主体授予必要的权限,一旦我们使用 Azure AD 对服务主体进行身份验证,将生成一个 OAuth 2.0 令牌。该令牌可以添加到 API 调用的授权头中,以授权对 Blob 或队列存储的请求。微软建议在使用 Blob 和队列应用程序时使用 Azure AD 授权,因为 Azure AD 提供了更强的安全性,并且相比于 SAS 令牌更为简便。
在下一节中,我们将评估 Azure SQL 数据库的安全选项。
Azure SQL
SQL Server 在 Azure 上存储关系数据,它是一个托管的关系数据库服务。它也被称为数据库即服务(DBaaS),为数据存储提供了一个高可用、可扩展、注重性能并且安全的平台。它可以从任何地方、使用任何编程语言和平台访问。客户端需要一个包含服务器、数据库和安全信息的连接字符串才能连接到该服务。
SQL Server 提供防火墙设置,默认情况下防止任何人访问。IP 地址和范围应列入白名单才能访问 SQL Server。架构师应仅允许他们信任的、属于客户或合作伙伴的 IP 地址。对于一些在 Azure 上部署的应用程序,可能有很多 IP 地址或这些 IP 地址是未知的,例如部署在 Azure Functions 或 Logic Apps 中的应用程序。为了使此类应用程序能够访问 Azure SQL,Azure SQL 允许将所有 IP 地址列入白名单,以便跨订阅的 Azure 服务能够访问。
需要注意的是,防火墙配置是在服务器级别而不是数据库级别。这意味着在此处进行的任何更改都会影响服务器中的所有数据库。在图 8.13中,您可以看到如何将客户端的 IP 地址添加到防火墙中以授予访问服务器的权限:
图 8.13:配置防火墙规则
Azure SQL 还通过加密静态数据提供了增强的安全性。这确保没有人,包括 Azure 数据中心的管理员,能够查看存储在 SQL Server 中的数据。SQL Server 用于加密静态数据的技术被称为透明数据加密(TDE)。实施 TDE 不需要在应用程序级别进行任何更改。SQL Server 会在用户保存和读取数据时透明地加密和解密数据。此功能在数据库级别可用。我们还可以将 TDE 与 Azure Key Vault 集成,使用自带密钥(BYOK)功能。通过使用 BYOK,我们可以在 Azure Key Vault 中使用客户管理的密钥来启用 TDE。
SQL Server 还提供动态数据屏蔽(DDM),这对于屏蔽某些类型的数据(如信用卡详情或用户个人身份信息数据)特别有用。屏蔽与加密不同,屏蔽并不加密数据,而是只将其遮蔽,从而确保数据不以人类可读的格式呈现。用户应在 Azure SQL Server 中屏蔽并加密敏感数据。
SQL Server 还为所有服务器提供审计和威胁检测服务。这些数据库上运行着先进的数据收集和智能服务,用于发现威胁和漏洞,并提醒用户。审计日志由 Azure 保存在存储帐户中,管理员可以查看并采取行动。像 SQL 注入和匿名客户端登录等威胁可以生成警报,管理员可以通过电子邮件接收通知。在图 8.14中,您可以看到如何启用威胁检测:
图 8.14:启用威胁保护并选择要检测的威胁类型
数据可以在 Azure SQL 中被屏蔽。这样可以以无法被人类读取的格式存储数据:
图 8.15:配置设置以屏蔽数据
Azure SQL 还提供 TDE 来加密静态数据,如图 8.16所示:
图 8.16:启用 TDE
要对 SQL Server 进行漏洞评估,您可以利用 SQL 漏洞评估,它是高级 SQL 安全功能统一包“高级数据安全”的一部分。SQL 漏洞评估可供客户主动使用,通过发现、跟踪并帮助修复潜在的数据库漏洞,从而提高数据库的安全性。
在前面的部分中,我们已经多次提到 Azure 密钥库,当时我们讨论了托管身份、SQL 数据库等。现在您已经了解了 Azure 密钥库的用途,在接下来的部分中,我们将探讨一些方法,帮助您保护密钥库的内容。
Azure 密钥库
使用密码、密钥、凭证、证书和唯一标识符来保护资源是任何环境和应用程序从安全角度来看至关重要的一个环节。这些资源需要得到保护,确保它们保持安全且不被泄露是安全架构的重要支柱。管理和操作这些秘密和密钥的安全,同时确保在需要时能够访问它们,是不能忽视的重要方面。通常,这些秘密资源无处不在——在源代码中、配置文件里、纸张上以及其他数字格式中。为了克服这些挑战并将所有秘密资源统一存储在集中式的安全存储中,应使用 Azure Key Vault。
Azure Key Vault 与其他 Azure 服务紧密集成。例如,使用存储在 Azure Key Vault 中的证书并将其部署到 Azure 虚拟机的证书存储中是非常容易的。各种类型的密钥,包括存储密钥、IoT 密钥和事件密钥、连接字符串,都可以作为秘密存储在 Azure Key Vault 中。它们可以被透明地检索并使用,无需任何人查看或临时存储它们。SQL Server 和其他服务的凭证也可以存储在 Azure Key Vault 中。
Azure Key Vault 是基于每个区域运作的。这意味着 Azure Key Vault 资源应部署在与应用程序和服务相同的区域。如果部署涉及多个区域并需要 Azure Key Vault 服务,则应配置多个 Azure Key Vault 实例。
Azure Key Vault 的一个重要特点是,秘密、密钥和证书不会存储在一般存储中。这些敏感数据由 HSM(硬件安全模块)备份。这意味着这些数据存储在 Azure 上的独立硬件中,只有拥有密钥的用户才能解锁。为了提供额外的安全性,您还可以为 Azure Key Vault 实施虚拟网络服务终端。这将限制对密钥库的访问,仅限特定的虚拟网络。您还可以限制对某个 IPv4 地址范围的访问。
在 Azure 存储 部分,我们讨论了使用 Azure AD 来授权对 Blob 和队列的请求。提到我们使用的是从 Azure AD 获取的 OAuth 令牌,用于认证 API 调用。在接下来的部分中,您将学习如何使用 OAuth 进行身份验证和授权。完成下一部分后,您将能够将其与我们在 Azure 存储 部分讨论的内容联系起来。
使用 OAuth 进行身份验证和授权
Azure AD 是一个身份提供者,可以基于租户内已有的用户和服务主体来验证用户。Azure AD 实现了 OAuth 协议,并支持互联网授权。它实现了一个授权服务器和服务,以启用 OAuth 授权流,包括隐式流和客户端凭证流。这些是客户端应用程序、授权端点、用户和受保护资源之间不同的、文档化良好的 OAuth 交互流。
Azure AD 还支持单点登录(SSO),它在登录到注册在 Azure AD 中的应用程序时提供了更高的安全性和便利性。在开发新应用程序时,您可以使用 OpenID Connect、OAuth、SAML、基于密码的方法,或是联动或禁用的 SSO 方法。如果您不确定使用哪种方法,请参考 Microsoft 提供的流程图:docs.microsoft.com/azure/active-directory/manage-apps/what-is-single-sign-on#choosing-a-single-sign-on-method
。
Web 应用程序、基于 JavaScript 的应用程序和本地客户端应用程序(如移动应用和桌面应用)都可以使用 Azure AD 进行身份验证和授权。有一些社交媒体平台,如 Facebook、Twitter 等,也支持 OAuth 协议进行授权。
启用使用 Facebook 进行 Web 应用程序身份验证的最简单方法之一如下所示。还有其他使用安全二进制文件的方法,但这超出了本书的范围。
在本操作步骤中,将配置一个 Azure 应用服务,并配合一个应用服务计划来托管自定义 Web 应用程序。需要一个有效的 Facebook 账户作为前提条件,以便将用户重定向到 Facebook 进行身份验证和授权。
可以使用 Azure 门户创建一个新的资源组,如图 8.17所示:
图 8.17:创建新资源组
创建资源组后,可以使用门户创建新的应用服务,如图 8.18所示:
图 8.18:创建新应用程序
请注意 Web 应用程序的 URL,因为在配置 Facebook 应用程序时需要使用该 URL。
一旦在 Azure 中配置好 Web 应用程序,下一步是在 Facebook 中创建一个新应用程序。这是为了在 Facebook 中表示您的 Web 应用程序,并生成适当的客户端凭证。通过这种方式,Facebook 才能识别您的 Web 应用程序。
访问 developers.facebook.com 并使用适当的凭据登录。通过在右上角的 我的应用 下选择 创建应用 选项来创建一个新应用,如图 8.19所示:
图 8.19:从 Facebook 开发者门户创建一个新应用
网页会提示你为网页应用提供一个名称,以便在 Facebook 内创建新应用:
图 8.20:添加新应用
添加一个新的 Facebook 登录 产品,并点击 设置 来配置在 Azure 应用服务上托管的自定义网页应用的登录:
图 8.21:将 Facebook 登录添加到应用中
设置按钮提供了几种选项,如图 8.22所示,这些选项配置 OAuth 流程,如授权流、隐式流或客户端凭证流。选择Web选项,因为这需要 Facebook 授权:
图 8.22:选择平台
提供我们在 Azure 上创建网页应用后记录的网页应用 URL:
图 8.23:为应用提供站点 URL
点击 domain name/.auth/login/facebook/callback
:
图 8.24:添加 OAuth 重定向 URI
从左侧菜单进入 基本 设置,并记下 应用 ID 和 应用密钥 的值。这些值用于配置 Azure 应用服务的认证/授权:
图 8.25:查找应用 ID 和应用密钥
在 Azure 门户中,返回到本节前几步中创建的 Azure 应用服务,并导航到认证/授权面板。开启 应用服务认证,选择 使用 Facebook 登录 进行认证,然后从列表中点击 Facebook 项目:
图 8.26:在 App 服务中启用 Facebook 认证
在结果页面上,提供已记录的应用 ID 和应用密钥,并选择作用域。作用域决定 Facebook 与网页应用共享的信息:
图 8.27:选择作用域
点击 确定 然后点击 保存 按钮以保存身份验证/授权设置。
现在,如果启动一个新的隐身浏览器会话并访问自定义网页应用,请求应该会重定向到 Facebook。如你在其他网站上看到的,当使用 Facebook 登录 时,你将被要求输入凭证:
图 8.28:使用 Facebook 登录网站
一旦输入凭证,用户同意对话框将询问是否允许将 Facebook 的数据与网页应用共享:
图 8.29:用户同意将信息分享给应用程序
如果同意,网页应用的网页应该会出现:
图 8.30:访问登陆页面
可以使用类似的方法通过 Azure AD、Twitter、Microsoft 和 Google 来保护你的网页应用。如果需要,你还可以集成自己的身份提供者。
这里展示的方法只是其中一种通过将凭证存储在其他地方,并授权外部应用访问受保护资源来保护网站的方式。Azure 还提供 JavaScript 库和 .NET 程序集,使用命令式编程方法来调用 Azure AD 和其他社交媒体平台提供的 OAuth 端点。建议使用这种方法,以便在应用程序中对身份验证和授权进行更好的控制和灵活性。
到目前为止,我们讨论了安全特性及其如何实现。建立监控和审计机制也很重要。实施审计解决方案可以帮助你的安全团队审核日志并采取预防措施。在接下来的部分中,我们将讨论 Azure 中的安全监控和审计解决方案。
安全监控和审计
环境中的每一项活动,从电子邮件到更改防火墙,都可以被归类为安全事件。从安全角度来看,必须有一个中央日志系统来监控和跟踪所做的更改。在审计过程中,如果发现可疑活动,您可以发现架构中的漏洞是什么,以及如何修复它。此外,如果发生了数据泄露,日志将帮助安全专业人员理解攻击模式及其执行方式。同时,可以采取必要的预防措施,以避免未来发生类似事件。Azure 提供了以下两个重要的安全资源,用于管理 Azure 订阅、资源组和资源的所有安全方面:
-
Azure Monitor
-
Azure Security Center
在这两个安全资源中,我们将首先探讨 Azure Monitor。
Azure Monitor
Azure Monitor 是一个一站式的 Azure 资源监控平台。它提供有关 Azure 资源及其状态的信息。它还提供一个丰富的查询界面,使用可以通过订阅、资源组、单个资源和资源类型级别的数据进行切片和切块。Azure Monitor 收集来自多个数据源的数据,包括 Azure 的指标和日志、客户应用程序以及运行在虚拟机中的代理。其他服务,如 Azure Security Center 和 Network Watcher,也将数据导入 Log Analytics 工作区,可以通过 Azure Monitor 进行分析。您还可以使用 REST API 将自定义数据发送到 Azure Monitor。
可以通过 Azure 门户、PowerShell、CLI 和 REST API 使用 Azure Monitor:
图 8.31:查看活动日志
以下是 Azure Monitor 提供的日志:
-
活动日志:此功能显示对资源执行的所有管理级操作。它提供有关创建时间、创建者、资源类型和资源状态的详细信息。
-
操作日志(经典):此功能提供关于在资源组和订阅内对资源执行的所有操作的详细信息。
-
指标:此功能获取单个资源的性能信息并设置警报。
-
诊断设置:此功能通过设置 Azure 存储来存储日志、将日志实时流式传输到 Azure Event Hubs,并将其发送到 Log Analytics,帮助我们配置影响日志。
-
日志搜索:此功能有助于将 Log Analytics 与 Azure Monitor 集成。
Azure Monitor 可以识别与安全相关的事件并采取适当的行动。非常重要的一点是,只有授权人员才能访问 Azure Monitor,因为它可能包含敏感信息。
Azure Security Center
如其名称所示,Azure 安全中心是满足所有安全需求的一站式平台。安全通常涉及两项活动——实施安全措施和监控威胁与漏洞。安全中心主要是为了帮助完成这两项活动而构建的。Azure 安全中心使用户能够定义安全策略,并在 Azure 资源上实现这些策略。基于 Azure 资源的当前状态,Azure 安全中心提供安全建议,以加固解决方案和单个 Azure 资源。这些建议包括几乎所有 Azure 安全最佳实践,涵盖数据和磁盘加密、网络保护、端点保护、访问控制列表、来访请求的白名单以及阻止未经授权的请求等。资源涵盖从基础设施组件,如负载均衡器、网络安全组和虚拟网络,到 PaaS 资源,如 Azure SQL 和存储等。以下是 概述 面板的摘录,显示了订阅的整体安全评分、资源安全卫生状况等信息:
图 8.32:Azure 安全中心概述
Azure 安全中心是一个功能丰富的平台,提供多种服务的推荐,如 图 8.33 所示。此外,这些建议可以导出为 CSV 文件以供参考:
图 8.33:Azure 安全中心推荐
正如本节开始时提到的,监控和审计在企业环境中至关重要。Azure Monitor 可以拥有多个数据源,并可用于审计来自这些数据源的日志。Azure 安全中心提供持续的评估和优先级安全建议,以及整体的安全评分。
摘要
安全始终是任何部署或解决方案中的一个重要方面。由于云部署的兴起,安全变得更加重要和相关。此外,网络攻击的威胁也日益增加。在这种情况下,安全已成为组织的焦点。无论是 IaaS、PaaS 还是 SaaS 类型的部署或解决方案,都需要进行安全保障。Azure 数据中心完全安全,且拥有十多个国际安全认证。它们默认情况下是安全的。它们提供 IaaS 安全资源,如 NSG、网络地址转换、安全端点、证书、密钥库、存储、虚拟机加密等,以及为单个 PaaS 资源提供的 PaaS 安全功能。安全有完整的生命周期,应该像其他应用功能一样,进行适当的规划、设计、实施和测试。
我们讨论了操作系统防火墙和 Azure 防火墙,以及如何利用它们来增强解决方案的整体安全性。我们还探索了 Azure 的一些新服务,如 Azure Bastion、Azure Front Door 和 Azure Private Link。
应用程序安全是另一个关键领域,我们讨论了如何使用 OAuth 进行身份验证和授权。我们演示了如何创建一个应用服务并集成 Facebook 登录。Facebook 只是一个例子,你也可以使用 Google、Twitter、Microsoft、Azure AD 或任何自定义身份提供商。
我们还探讨了 Azure SQL 提供的安全选项,Azure SQL 是由 Azure 提供的托管数据库服务。我们讨论了安全功能的实现,最后一节我们通过 Azure Monitor 和 Azure Security Center 来进行监控和审计。安全在你的环境中扮演着至关重要的角色。架构师应始终将安全性作为架构的主要支柱之一进行设计和架构;Azure 提供了许多选项来实现这一目标。
现在你已经了解了如何在 Azure 中保护数据,接下来的章节我们将重点讲解 Hadoop 的大数据解决方案,随后是数据湖存储、数据湖分析和数据工厂。
第九章:9. Azure 大数据解决方案
在上一章中,你学习了可以在 Azure 上实施的各种安全策略。通过安全的应用程序,我们可以管理大量数据。近年来,大数据获得了显著的关注。处理大数据需要专用的工具、软件和存储。有趣的是,几年前这些工具、平台和存储选项还不以服务形式提供。然而,随着新云技术的出现,Azure 提供了众多工具、平台和资源,可以轻松创建大数据解决方案。本章将详细介绍数据的摄取、清理、过滤和可视化的完整架构。
本章将涵盖以下主题:
-
大数据概览
-
数据集成
-
抽取-转换-加载 (ETL)
-
数据工厂
-
数据湖存储
-
像 Spark、Databricks 和 Hadoop 这样的工具生态系统
-
Databricks
大数据
随着廉价设备的涌入——如物联网设备和手持设备——生成和捕捉的数据量呈指数级增长。几乎每个组织都拥有大量数据,并且如果需要,他们也准备好购买更多。当大量数据以多种格式并以不断增加的速度到达时,我们就可以说我们在处理大数据。简而言之,大数据有三个关键特征:
-
体量:体量指的是数据的数量,包括大小(例如 GB、TB 和 PB)以及记录的数量(例如在层级数据存储中的百万行、10 万张图片、5 亿个 JSON 文档等)。
-
速度:速度指的是数据到达或被摄取的速度。如果数据变化不频繁或新数据不常到达,则数据的速度被认为是低的;而如果频繁更新并且有大量新数据持续不断地到达,则数据的速度被认为是高的。
-
多样性:多样性指的是数据的不同种类和格式。数据可以来自不同来源,且格式各异。数据可以是结构化数据(如逗号分隔文件、JSON 文件或层级数据)、半结构化数据库(如无模式的 NoSQL 文档),或是非结构化数据(如二进制大对象(blobs)、图片、PDF 等)。由于存在如此多的变体,因此必须有一个明确的处理流程来处理接收的数据。
在下一部分,我们将查看大数据的通用处理过程。
大数据处理过程
当数据来自不同来源,格式不同,且速度不同的时候,制定一个存储、整合、过滤和清理数据的过程变得至关重要,这样可以帮助我们更轻松地处理数据,并使数据能够服务于其他流程。必须有一个明确的数据管理流程。大数据的通用处理流程应遵循 图 9.1 所示:
图 9.1:大数据处理
大数据处理有四个主要阶段。让我们详细探讨它们:
-
Ingest:这是将数据引入和摄入到大数据环境中的过程。数据可以来自多个来源,应使用连接器将该数据摄入到大数据平台中。
-
Store:摄入后,数据应存储在数据池中以进行长期存储。存储应包括历史数据和实时数据,并且必须能够存储结构化、半结构化和非结构化数据。应该有连接器从数据源读取数据,或者数据源应能够将数据推送到存储中。
-
Analysis:从存储中读取数据后,应对其进行分析,这个过程需要过滤、分组、连接和转换数据以获取洞察。
-
Visualize:分析结果可以作为报告通过多种通知平台发送,也可以用于生成带有图表和图形的仪表板。
以前,由于涉及昂贵的硬件和大量投资,组织机构无法轻易获得捕获、摄入、存储和分析大数据所需的工具。此外,也没有平台可供处理它们。随着云计算的出现,组织机构现在可以更轻松地使用他们首选的工具和框架捕获、摄入、存储和执行大数据分析。他们可以支付云提供商使用其基础设施,避免任何资本支出。而且,与任何本地解决方案相比,云计算的成本非常便宜。
大数据需要大量的计算、存储和网络资源。通常,所需资源量不适合在单台计算机或服务器上拥有。即使在某种程度上,可以在单台服务器上提供足够的资源,处理整个大数据池所需的时间也相当长,因为每个作业按顺序完成,每个步骤都依赖于前一步骤。需要专门的框架和工具来分布工作到多个服务器,并最终从这些服务器返回结果,并在适当地结合所有服务器的结果后呈现给用户。这些工具是专门的大数据工具,帮助实现可用性、可扩展性和分发,以确保大数据解决方案能够通过内置的稳健性和稳定性快速运行。
显著的 Azure 大数据服务包括 HD Insights 和 Databricks。让我们继续探索大数据领域中提供的各种工具。
大数据工具
大数据空间中有许多工具和服务,我们将在本章中介绍其中一些。
Azure 数据工厂
Azure 数据工厂是 Azure 中的旗舰 ETL 服务。它定义了传入数据(根据其格式和模式),根据业务规则和过滤器转换数据,增强现有数据,并最终将数据传输到目标存储,供其他下游服务轻松消费。它能够在 Azure 上运行管道(包含 ETL 逻辑),以及在自定义基础设施上运行,还可以运行 SQL Server 集成服务包。
Azure 数据湖存储
Azure 数据湖存储是企业级的大数据存储,开箱即用即具备弹性、高可用性和安全性。它与 Hadoop 兼容,能够扩展到 PB 级别的数据存储。它建立在 Azure 存储帐户之上,因此直接获得所有存储帐户的优势。当前版本称为 Gen2,源自 Azure 存储和数据湖存储 Gen1 的能力合并。
Hadoop
Hadoop 由 Apache 软件基金会创建,是一个分布式、可扩展且可靠的框架,用于处理大数据。它将大数据拆分成较小的数据块并将它们分布在集群中。一个 Hadoop 集群由两种类型的服务器组成——主节点和从节点。主节点包含 Hadoop 的管理组件,而从节点是进行数据处理的地方。Hadoop 负责在从节点之间进行逻辑数据分区;从节点执行所有数据转换、收集洞察并将其返回给主节点,主节点将它们整理成最终输出。Hadoop 可以扩展到数千台服务器,每台服务器为作业提供计算和存储服务。Hadoop 也可以通过 Azure 的HDInsight服务作为一种服务提供。
Hadoop 核心系统由三个主要组件组成:
HDFS:Hadoop 分布式文件系统(HDFS)是一个用于存储大数据的文件系统。它是一个分布式框架,通过将大数据文件分解为较小的数据块并将其放置在集群中的不同从节点上来帮助处理数据。HDFS 是一个容错的文件系统。这意味着,尽管不同的数据块分配给集群中的不同从节点,但数据在从节点之间也会进行复制,以确保在某个从节点失败时,数据也能在另一个服务器上可用。它还提供快速高效的数据访问。
MapReduce:MapReduce 是另一个重要的框架,使 Hadoop 能够并行处理数据。该框架负责处理存储在 HDFS 从节点中的数据并将其映射到从节点。在从节点完成处理后,“reduce”部分将来自每个从节点的信息汇总到一起,生成最终输出。通常,HDFS 和 MapReduce 会在同一节点上运行,这样数据就不需要在从节点之间传输,从而提高处理效率。
YARN:Yet Another Resource Negotiator(YARN)是一个重要的 Hadoop 架构组件,帮助在集群内调度与应用程序和资源管理相关的作业。YARN 作为 Hadoop 2.0 的一部分发布,许多人将其视为 MapReduce 的继任者,因为它在批处理和资源分配方面更为高效。
Apache Spark
Apache Spark 是一个分布式、可靠的大规模数据处理分析平台。它提供一个集群,能够并行运行转换和机器学习作业,并将汇总结果返回给客户端。它由主节点和工作节点组成,其中主节点负责在作业内划分和分发操作和数据到工作节点之间,并将所有工作节点的结果汇总并返回给客户端。在使用 Spark 时要记住的一件重要事情是,逻辑或计算应易于并行化,并且数据量太大以至于无法适应一台机器。Spark 在 Azure 中作为 HDInsight 和 Databricks 的服务提供。
Databricks
Databricks 构建在 Apache Spark 之上。它是一个平台即服务,为用户提供管理的 Spark 集群。它提供许多附加功能,如完整的门户管理 Spark 集群及其节点,以及帮助创建笔记本、调度和运行作业,以及为多个用户提供安全性和支持。
现在,是时候学习如何从多个源集成数据并使用我们讨论过的工具共同处理它们了。
数据集成
我们深知集成模式如何用于应用程序;由多个服务组成的应用程序使用各种模式进行集成。然而,还有另一种范例对许多组织来说是关键需求,即被称为数据集成。数据集成的激增主要发生在过去十年间,当时数据的生成和可用性显著增加。数据生成的速度、多样性和数量大幅增加,数据几乎无处不在。
每个组织都有许多不同类型的应用程序,它们都以自己的专有格式生成数据。通常,数据也从市场购买。即使在组织合并和合并期间,也需要迁移和组合数据。
数据集成是指从多个源带入数据并生成新输出的过程,该输出具有更多的意义和可用性。
在以下场景中明确需要数据集成:
-
从源或一组源迁移数据到目标位置。这是为了让数据以不同的格式对各种利益相关者和消费者可用。
-
从数据中获取洞察。随着数据的快速增加,组织希望从中获取洞察。它们希望创建提供洞察的解决方案;来自多个源的数据应该被合并、清洗、增强,并存储在数据仓库中。
-
生成实时仪表盘和报告。
-
创建分析解决方案。
应用程序集成在用户使用应用程序时具有运行时行为——例如,在信用卡验证和集成的情况下。另一方面,数据集成是在后台执行的,并且不直接与用户活动相关联。
让我们继续了解如何使用 Azure 数据工厂理解 ETL 过程。
ETL
一个非常流行的过程称为 ETL,它有助于构建目标数据源,以存储应用程序可以使用的数据。通常,数据是以原始格式存在的,为了使其可用,数据需要经过以下三个不同的阶段:
-
提取:在这个阶段,数据从多个地方提取。例如,可能有多个数据源,它们需要连接在一起以便检索数据。提取阶段通常使用包含目标数据源连接信息的数据连接器。它们还可能有临时存储,用于将数据从数据源提取并存储,以便更快地检索。这个阶段负责数据的摄取。
-
转换:在提取阶段之后的数据可能无法直接被应用程序使用。这可能是由于多种原因;例如,数据可能存在不规则性,可能有缺失的数据,或数据可能存在错误。或者,可能有一些数据根本不需要。或者,数据的格式可能不适合目标应用程序的使用。在所有这些情况下,必须对数据进行转换,使其能够高效地被应用程序使用。
-
加载:在数据转换后,应该将数据加载到目标数据源中,格式和架构使其能够更快、更容易地提供给应用程序,以提高性能。通常,这包括目标数据源的数据连接器以及将数据加载到其中的过程。
接下来,让我们来了解一下 Azure 数据工厂如何与 ETL 过程相关联。
Azure 数据工厂简介
Azure 数据工厂是一个完全托管、高可用、高可扩展、易于使用的工具,用于创建集成解决方案并实现 ETL 阶段。数据工厂帮助你以拖放方式通过用户界面创建新的管道,而无需编写任何代码;然而,它仍然提供功能,允许你用自己喜欢的编程语言编写代码。
在使用数据工厂服务之前,有一些重要的概念需要了解,我们将在接下来的章节中更详细地探讨这些概念:
-
活动:活动是能够在数据工厂管道中运行和处理逻辑的单个任务。活动有多种类型,涉及数据移动、数据转换和控制活动。每个活动都有一个策略,可以通过该策略决定重试机制和重试间隔。
-
管道:数据工厂中的管道由一组活动组成,负责将活动集合在一起。管道是工作流和调度器,能够实现 ETL 阶段的运行。管道允许将活动编织在一起,并允许声明它们之间的依赖关系。通过使用依赖关系,可以使某些任务并行执行,其他任务按顺序执行。
-
数据集:数据集是数据的来源和目的地。这些可以是 Azure 存储账户、数据湖存储或其他多个来源。
-
链接服务:这些是包含数据集连接和连接信息的服务,并由各个任务用于连接到它们。
-
集成运行时:负责运行数据工厂的主要引擎叫做集成运行时。集成运行时有以下三种配置:
-
Azure:在此配置下,数据工厂运行在 Azure 提供的计算资源上。
-
自托管:在此配置下,数据工厂在你提供自己的计算资源时运行。这可以通过本地或基于云的虚拟机服务器来实现。
-
Azure SQL Server 集成服务 (SSIS): 此配置允许运行使用 SQL Server 编写的传统 SSIS 包。
-
版本:数据工厂有两个不同的版本。需要理解的是,所有新开发将发生在 V2 上,V1 将保持原样,或者在某个时候逐渐淘汰。V2 优先的原因如下:
它提供了运行 SQL Server 集成包的功能。
它相较于 V1 提供了增强的功能。
它提供了 V1 中缺少的增强监控功能。
现在你已经对数据工厂有了较为清晰的理解,让我们来看一下 Azure 上可用的各种存储选项。
Azure 数据湖入门
Azure 数据湖为大数据解决方案提供存储。它专门设计用于存储大数据解决方案中通常需要的大量数据。它是 Azure 提供的托管服务。客户需要将他们的数据带来并存储在数据湖中。
Azure 数据湖存储有两个版本:版本 1(Gen1)和当前版本,版本 2(Gen2)。Gen2 拥有 Gen1 的所有功能,但有一个特别的区别是它建立在 Azure Blob 存储之上。
由于 Azure Blob 存储具有高可用性、可以多次复制、具备灾难恢复能力并且成本较低,这些优势也被继承到 Gen2 Data Lake 中。Data Lake 可以存储任何类型的数据,包括关系型、非关系型、基于文件系统和层次化数据。
创建 Data Lake Gen2 实例与创建新存储账户一样简单。唯一需要做的更改是在存储账户的 高级 选项卡中启用层次命名空间。需要注意的是,无法直接将通用存储账户迁移或转换为 Azure Data Lake,反之亦然。此外,存储账户用于存储文件,而 Data Lake 则针对读取和摄取大量数据进行了优化。
接下来,我们将探讨处理大数据时的流程和主要阶段。这些是不同的阶段,每个阶段负责数据的不同操作。
将数据从 Azure 存储迁移到 Data Lake 存储 Gen2
在本节中,我们将把数据从 Azure Blob 存储迁移到同一 Azure Blob 存储实例中的另一个 Azure 容器,并且我们还将使用 Azure Data Factory 管道将数据迁移到 Azure Data Lake Gen2 实例。以下各节概述了创建此端到端解决方案所需的步骤。
准备源存储账户
在我们可以创建 Azure Data Factory 管道并将其用于迁移之前,需要创建一个新的存储账户,存储账户由多个容器组成,并上传数据文件。在实际操作中,这些文件和存储连接通常已经准备好。创建新 Azure 存储账户的第一步是创建一个新的资源组,或者在 Azure 订阅内选择一个现有的资源组。
配置新的资源组
Azure 中的每个资源都与一个资源组关联。在我们配置 Azure 存储账户之前,需要创建一个资源组来承载存储账户。创建资源组的步骤如下所示。需要注意的是,在配置 Azure 存储账户时,可以创建一个新的资源组,或者使用现有的资源组:
-
导航到 Azure 门户,登录并点击
资源组
。 -
从搜索结果中选择 资源组,然后创建一个新的资源组。提供名称并选择合适的位置。请注意,所有资源应该托管在同一资源组和位置,这样删除时会更方便。
在配置资源组之后,我们将在其中配置一个存储账户。
配置存储账户
在本节中,我们将介绍创建新的 Azure 存储账户的步骤。这个存储账户将从中获取数据源,并迁移数据。执行以下步骤来创建存储账户:
-
点击
存储账户
。从搜索结果中选择 存储账户,然后创建一个新的存储账户。 -
提供名称和位置,然后选择基于之前创建的资源组的订阅。
-
在帐户类型中选择StorageV2 (通用目的 v2),在性能中选择标准,在复制中选择本地冗余存储(LRS),如图 9.2所示:
图 9.2:配置存储帐户
-
现在在存储帐户中创建几个容器。
rawdata
容器包含将由数据工厂管道提取的文件,并将作为源数据集,而finaldata将包含数据工厂管道将写入数据的文件,并将作为目标数据集:图 9.3:创建容器
-
将数据文件(该文件随源代码一起提供)上传到rawdata容器,如图 9.4所示:
图 9.4:上传数据文件
完成这些步骤后,源数据准备工作完成。现在我们可以专注于创建 Data Lake 实例。
配置 Data Lake Gen2 服务
如我们所知,Data Lake Gen2 服务是建立在 Azure 存储帐户之上的。因此,我们将以与之前相同的方式创建一个新的存储帐户——唯一的区别是在新 Azure 存储帐户的高级选项卡中选择启用,以支持层次命名空间。这将创建新的 Data Lake Gen2 服务:
图 9.5:创建新存储帐户
在创建数据湖之后,我们将专注于创建一个新的 Data Factory 管道。
配置 Azure Data Factory
现在我们已经配置了资源组和 Azure 存储帐户,是时候创建一个新的 Data Factory 资源了:
-
通过选择V2并提供名称和位置,以及资源组和订阅选择,创建一个新的 Data Factory 管道。
Data Factory 有三个不同的版本,如图 9.6所示。我们已经讨论了V1和V2:
图 9.6:选择数据工厂的版本
-
创建完数据工厂资源后,点击中央窗格中的Author & Monitor链接。
这将打开另一个窗口,其中包含用于管道设计的 Data Factory 设计器。
管道的代码可以存储在版本控制仓库中,这样可以跟踪代码更改,并促进开发人员之间的协作。如果在这些步骤中错过了仓库设置,可以稍后进行设置。
下一部分将重点介绍与版本控制仓库设置相关的配置,如果你的数据工厂资源在没有配置任何仓库设置的情况下创建,我们将在这里进行相关配置。
仓库设置
在创建任何数据工厂工件(如数据集和管道)之前,最好先设置代码仓库,以托管与数据工厂相关的文件:
-
在创作页面,点击管理按钮,然后在左侧菜单中选择Git 配置。这将打开另一个面板;在此面板中点击设置代码仓库按钮:
图 9.7:设置 Git 仓库
-
从结果面板中,选择你希望存储数据工厂代码文件的仓库类型。在本例中,我们选择Azure DevOps Git:
图 9.8:选择合适的 Git 仓库类型
-
创建一个新的仓库,或从 Azure DevOps 重用现有仓库。你应该已经在 Azure DevOps 中有一个账户。如果没有,可以访问
dev.azure.com
,使用与你在 Azure 门户中相同的账户登录,并在其中创建一个新的组织和项目。有关在 Azure DevOps 中创建组织和项目的更多信息,请参考第十三章,集成 Azure DevOps。现在,我们可以回到数据工厂创作窗口,开始为我们的新管道创建工件。
在下一部分中,我们将准备将在数据工厂管道中使用的数据集。
数据工厂数据集
现在我们可以返回到数据工厂管道。首先,创建一个新的数据集,作为源数据集。它将是我们创建的第一个存储账户,我们将在其中上传示例product.csv
文件:
-
点击
AutoResolveIntegrationRuntime
用于运行时环境,这意味着 Azure 将在 Azure 托管的计算上提供运行时环境。链接服务提供多种身份验证方法,我们正在使用共享访问签名(SAS)统一资源定位符(URI)方法。也可以使用账户密钥、服务主体和托管身份作为身份验证方法:图 9.9:实现身份验证方法
-
然后,在结果的下方窗格中的常规选项卡中,点击打开属性链接并为数据集提供一个名称:
图 9.10:为数据集命名
-
在连接选项卡中,提供有关容器、存储帐户中的 Blob 文件名、行分隔符、列分隔符和其他有助于 Data Factory 正确读取源数据的信息。
配置后的连接选项卡应类似于图 9.11。请注意,路径包括容器的名称和文件的名称:
图 9.11:配置连接
-
此时,如果点击
product.csv
文件。在ProductID
和ProductPrice
列上,架构有助于为列提供标识符,并在源数据集和目标数据集之间映射源列到目标列,即使列名不一致。
现在第一个数据集已创建,让我们创建第二个数据集。
创建第二个数据集
以之前相同的方式为目标 Blob 存储帐户创建一个新的数据集和关联服务。请注意,存储帐户与源相同,但容器不同。确保传入的数据也附带有架构信息,如图 9.12所示:
图 9.12:创建第二个数据集
接下来,我们将创建第三个数据集。
创建第三个数据集
为 Data Lake Gen2 存储实例创建一个新的数据集,作为目标数据集。为此,选择新数据集,然后选择Azure Data Lake Storage Gen2(预览版)。
给新数据集命名,并在连接选项卡中创建一个新的关联服务。选择使用帐户密钥作为身份验证方法,选择存储帐户名称后,其余配置将自动填充。然后,通过点击测试连接按钮来测试连接。保持其他选项卡的默认配置,如图 9.13所示:
图 9.13:连接选项卡中的配置
现在,我们已经连接到源数据,并且连接到源和目标数据存储的连接都已建立,是时候创建包含数据转换逻辑的管道了。
创建管道
创建所有数据集后,我们可以创建一个管道来消费这些数据集。创建管道的步骤如下:
-
从左侧菜单点击+ 管道 => 新建管道菜单以创建新管道。然后,将复制数据活动从移动与转换菜单拖放,如图 9.14所示:
图 9.14:管道菜单
-
结果的常规标签可以保持不变,但源标签应配置为使用我们之前配置的源数据集:
图 9.15:源标签
-
接收标签用于配置目标数据存储和数据集,应配置为使用我们之前配置的目标数据集:
图 9.16:接收标签
-
在映射标签中,将源数据集的列映射到目标数据集的列,如图 9.17所示:
图 9.17:映射标签
添加另一个复制数据活动
在我们的管道中,我们可以添加多个活动,每个活动负责特定的转换任务。本节讨论的任务负责将数据从 Azure 存储帐户复制到 Azure Data Lake Storage:
-
添加另一个
product.csv
文件。接收配置将目标指向 Data Lake Gen2 存储帐户。
-
对于第二个复制数据活动,其余配置可以保留为默认设置。
在完成管道的编写后,可以将其发布到版本控制库,如 GitHub。
接下来,我们将探讨如何使用 Databricks 和 Spark 创建解决方案。
使用 Databricks 创建解决方案
Databricks 是一个将 Spark 作为服务使用的平台。我们无需在虚拟机上配置主节点和工作节点。相反,Databricks 为我们提供了一个由主节点和工作节点组成的托管环境,并且对其进行管理。我们只需提供数据处理的步骤和逻辑,其余的都由 Databricks 平台负责。
在本节中,我们将通过步骤介绍如何使用 Databricks 创建解决方案。我们将下载示例数据进行分析。
示例 CSV 文件已从ourworldindata.org/coronavirus-source-data
下载,尽管它也可以在本书的代码中找到。前述网址会提供更为最新的数据,但格式可能发生变化,因此建议使用本书代码示例中提供的文件:
-
创建 Databricks 解决方案的第一步是通过 Azure 门户进行预配。从 Azure 门户中可以选择 14 天评估版 SKU,以及标准和高级版两个其他 SKU。高级版 SKU 在笔记本、集群、作业和表格级别提供 Azure 基于角色的访问控制:
图 9.19:Azure 门户—Databricks 服务
-
在 Databricks 工作区预配完成后,从 概述 面板点击 启动工作区 按钮。这将打开一个新的浏览器窗口,并最终将你登录到 Databricks 门户。
-
从 Databricks 门户中,从左侧菜单选择 集群,并创建一个新集群,如 图 9.20 所示:
图 9.20:创建一个新集群
-
提供名称、Databricks 运行时版本、工作节点类型、虚拟机大小配置以及驱动程序类型服务器配置。
-
创建集群可能需要几分钟时间。集群创建完成后,点击 主页,从其上下文菜单中选择一个用户,并创建一个新的笔记本:
图 9.21:选择一个新笔记本
-
为笔记本提供一个名称,如下所示:
图 9.22:创建笔记本
-
创建一个新的存储账户,如下所示。这将作为存储原始 COVID 数据的 CSV 格式存储:
图 9.23:创建一个新的存储账户
-
为存储 CSV 文件创建一个容器,如下所示:
图 9.24:创建一个容器
-
将
owid-covid-data.csv
文件上传到此容器中。
完成上述步骤后,下一步是加载数据。
加载数据
第二个主要步骤是将 COVID 数据加载到 Databricks 工作区。这可以通过两种主要方式完成:
-
在 Databricks 中挂载 Azure 存储容器,然后加载挂载中的文件。
-
从存储账户直接加载数据。以下示例使用了这种方法。
以下步骤应执行以使用 Databricks 加载和分析数据:
-
第一步是连接并访问存储帐户。需要存储帐户的密钥,该密钥存储在 Spark 配置中。注意,这里的密钥是
"fs.azure.account.key.coronadatastorage.blob.core.windows.net"
,其值是关联的密钥:spark.conf.set("fs.azure.account.key.coronadatastorage.blob.core.windows.net","xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx==")
-
Azure 存储帐户的密钥可以通过导航到设置并使用
wasbs://{{container}}@{{storage account name}}.blob.core.windows.net/{{filename}}
来获取。 -
SparkSession
对象的read
方法提供了读取文件的方法。要读取 CSV 文件,应该使用csv
方法,并传递其所需的参数,例如 CSV 文件的路径。还可以提供额外的可选参数来定制数据文件的读取过程。Spark 支持多种文件格式,如 JSON、优化行列格式(ORC)和 Parquet,以及关系型数据库如 SQL Server 和 MySQL、NoSQL 数据存储如 Cassandra 和 MongoDB,以及大数据平台如 Apache Hive。让我们通过以下命令了解 Spark DataFrame 的实现:coviddata = spark.read.format("csv").option("inferSchema", "true").option("header", "true").load("wasbs://coviddata@coronadatastorage.blob.core.windows.net/owid-covid-data.csv")
使用此命令会在 Spark 中创建一个新的 DataFrame 类型对象。Spark 提供弹性分布式数据集(RDD)对象来操作和处理数据。RDD 是低级对象,任何针对它们编写的代码可能不会经过优化。DataFrame 是 RDD 之上的高级构造,提供了优化访问和处理 RDD 的功能。与 RDD 一起工作时,最好使用 DataFrame。
DataFrame 以行列格式提供数据,这使得可视化和处理数据变得更容易。Spark 的 DataFrame 类似于 pandas 的 DataFrame,区别在于它们是不同的实现。
-
以下命令显示了 DataFrame 中的数据,展示了 DataFrame 中所有可用的行和列:
coviddata.show()
你应该得到类似于图 9.25中所看到的输出:
图 9.25:DataFrame 中的原始数据
-
加载数据的模式由 Spark 推断,可以使用以下命令检查:
coviddata.printSchema()
这应该会给你类似于以下的输出:
图 9.26:获取 DataFrame 每列的模式
-
要计算 CSV 文件中的行数,可以使用以下命令,输出显示文件中有 19,288 行:
coviddata.count()
图 9.27:查找 DataFrame 中的记录数量
-
原始的 DataFrame 有超过 30 列。我们也可以选择其中的一部分列并直接使用,如下所示:
CovidDataSmallSet = coviddata.select("location","date", "new_cases", "new_deaths") CovidDataSmallSet.show()
代码的输出将如下所示,正如图 9.28所示:
图 9.28:从所有列中选择几个列
-
也可以使用
filter
方法过滤数据,如下所示:CovidDataSmallSet.filter(" location == 'United States' ").show()
-
还可以使用 AND(
&
)或 OR(|
)运算符将多个条件组合在一起:CovidDataSmallSet.filter((CovidDataSmallSet.location == 'United States') | (CovidDataSmallSet.location == 'Aruba')).show()
-
要找出行数及其他统计细节,如均值、最大值、最小值和标准差,可以使用
describe
方法:CovidDataSmallSet.describe().show()
使用前面的命令后,你将获得类似这样的输出:
图 9.29:使用 describe 方法显示每个列的统计信息
-
还可以找出指定列中空值或缺失数据的百分比。以下是几个示例:
from pyspark.sql.functions import col (coviddata.where(col("diabetes_prevalence").isNull()).count() * 100)/coviddata.count()
输出显示
5.998548320199087
,这意味着 95% 的数据是空值。我们应该从数据分析中删除这些列。同样,在total_tests_per_thousand
列上运行相同命令返回73.62090418913314
,这比前一个列的结果要好得多。 -
要从 DataFrame 中删除某些列,可以使用以下命令:
coviddatanew=coviddata.drop("iso_code").drop("total_tests").drop("total_tests").drop("new_tests").drop("total_tests_per_thousand").drop("new_tests_per_thousand").drop("new_tests_smoothed").drop("new_tests_smoothed_per_thousand ")
-
有时,您需要对数据进行聚合。在这种情况下,可以执行数据分组,如下所示:
coviddatanew = coviddata.groupBy('location').agg({'date': 'max'})
这将显示来自
groupBy
语句的数据:图 9.30:来自 groupby 语句的数据
-
如你在
max (date)
列中看到的,所有国家的日期大多相同,我们可以使用这个值来过滤记录,并获取每个国家的最大日期对应的一行数据:coviddatauniquecountry = coviddata.filter("date='2020-05-23 00:00:00'") coviddatauniquecountry.show()
-
如果我们对新 DataFrame 中的记录进行计数,结果是
209
。我们可以将新的 DataFrame 保存到另一个 CSV 文件中,其他数据处理器可能需要该文件:
coviddatauniquecountry.rdd.saveAsTextFile("dbfs:/mnt/coronadatastorage/uniquecountry.csv")
我们可以使用以下命令检查新创建的文件:
%fs ls /mnt/coronadatastorage/
挂载路径将显示如下图所示的 图 9.31:
图 9.31:Spark 节点中的挂载路径
-
还可以使用
createTempView
或createOrReplaceTempView
方法将数据添加到 Databricks 目录中。将数据放入目录后,可以在给定的上下文中使用它。要将数据添加到目录中,可以使用 DataFrame 的createTempView
或createOrReplaceTempView
方法,为目录中的表提供一个新视图:coviddatauniquecountry.createOrReplaceTempView("corona")
-
一旦表格进入目录,就可以从你的 SQL 会话中访问,如下所示:
spark.sql("select * from corona").show()
SQL 语句中的数据将显示为 图 9.32 所示:
图 9.32:来自 SQL 语句的数据
-
可以对表执行额外的 SQL 查询,如下所示:
spark.sql("select * from corona where location in ('India','Angola') order by location").show()
这只是 Databricks 可能性的一小部分。它内部还有许多更多的功能和服务,无法在单一章节中全面覆盖。您可以在 azure.microsoft.com/services/databricks
上了解更多相关信息。
总结
本章介绍了 Azure Data Factory 服务,它负责提供 Azure 中的 ETL 服务。作为一个平台即服务,它提供无限的可扩展性、高可用性和易于配置的管道。它与 Azure DevOps 和 GitHub 的集成也非常流畅。我们还探索了使用 Azure Data Lake Gen2 存储大数据的功能和优势。它是一种成本效益高、具有高度可扩展性、分层的数据存储方式,用于处理大数据,并且与 Azure HDInsight、Databricks 和 Hadoop 生态系统兼容。
我们并没有对本章中提到的所有主题进行全面深入的探讨。重点更多的是探索 Azure 中的可能性,特别是 Databricks 和 Spark。Azure 中涉及大数据的多个技术,包括 HDInsight、Hadoop、Spark 及其相关生态系统,还有 Databricks,它是一个为 Spark 提供附加功能的“平台即服务”环境。在下一章中,您将学习 Azure 中的无服务器计算能力。
第十章:10. Azure 中的无服务器——与 Azure Functions 一起工作
在上一章中,你了解了 Azure 上的各种大数据解决方案。在本章中,你将学习无服务器技术如何帮助你处理大量数据。
无服务器(Serverless)是当前技术领域最热门的流行词之一,大家都想赶上这股潮流。无服务器在整体计算、软件开发流程、基础设施和技术实现方面带来了许多优势。这个行业中有许多变化:一端是基础设施即服务(IaaS),另一端则是无服务器。在两者之间的是平台即服务(PaaS)和容器。我遇到了许多开发人员,似乎他们对 IaaS、PaaS、容器和无服务器计算之间存在一些困惑。此外,人们对于无服务器范式的使用场景、适用性、架构和实现也有很多混淆。无服务器是一个新的范式,正在改变不仅是技术,甚至是组织内部的文化和流程。
本章将通过介绍无服务器开始,并将在接下来的内容中涵盖以下主题:
-
函数即服务
-
Azure Functions
-
Azure Durable Functions
-
Azure Event Grid
无服务器
无服务器是指一种部署模型,用户只需要负责他们的应用程序代码和配置。在无服务器计算中,客户不需要为自己的底层平台和基础设施操心,而是可以专注于解决业务问题。
无服务器并不意味着没有服务器。代码和配置始终需要计算、存储和网络来运行。然而,从客户的角度来看,他们看不到这些计算、存储和网络。他们不关心底层的平台和基础设施,不需要管理或监控基础设施和平台。无服务器提供了一个可以自动按需扩展、收缩、进出环境,而客户甚至对此一无所知的环境。与平台和基础设施相关的所有操作都发生在幕后,并由云服务提供商执行。客户会获得与性能相关的服务级别协议(SLA),Azure 会确保在任何需求下都能满足这些 SLA。
客户只需要带入他们的代码;云服务提供商负责提供运行代码所需的基础设施和平台。让我们深入探讨 Azure Functions 的各种优势。
Azure Functions 的优势
无服务器计算是一种相对较新的范式,帮助组织将大型功能转化为较小的、离散的按需功能,这些功能可以通过自动触发器和计划任务被调用和执行。这些功能也被称为 功能即服务 (FaaS),在这种模式下,组织可以专注于领域挑战,而非底层基础设施和平台。FaaS 还有助于将解决方案架构分解为更小、可重用的功能,从而提高投资回报率。
目前有大量的无服务器计算平台可供选择。以下是一些重要的平台:
-
Azure Functions。
-
AWS Lambda。
-
IBM OpenWhisk。
-
Iron.io。
-
Google Cloud Functions。
事实上,每隔几天就会有新的平台/框架被推出,企业越来越难以决定哪个框架最适合他们。Azure 提供了一个丰富的无服务器环境,称为 Azure Functions,以下是它支持的一些功能:
-
有多种方式调用函数——手动调用、按计划调用或基于事件触发。
-
支持多种绑定类型。
-
可以同步和异步运行函数。
-
基于多种触发器类型执行函数的能力。
-
可以运行长时间和短时间的函数。然而,不推荐运行大型和长时间的函数,因为它们可能导致意外超时。
-
能够使用代理功能来支持不同的函数架构。
-
多种使用模型,包括消费模型和应用服务模型。
-
能够使用多种编程语言(如 JavaScript、Python 和 C#)编写函数。
-
基于 OAuth 的授权。
-
Durable Functions 扩展帮助编写有状态的函数。
-
多种身份验证选项,包括 Azure AD、Facebook、Twitter 和其他身份提供商。
-
可以轻松配置输入和输出参数。
-
通过 Visual Studio 集成来编写 Azure 函数。
-
大规模并行处理。
让我们来看看 FaaS 及其在无服务器架构中扮演的角色。
FaaS。
Azure 提供 FaaS。这些是 Azure 的无服务器实现。使用 Azure Functions,用户可以用任何熟悉的语言编写代码,Azure Functions 会提供一个运行时来执行它。根据选择的语言,平台为用户提供适当的环境来运行自己的代码。函数是部署的基本单元,可以自动扩展和缩减。在处理函数时,用户无法查看底层的虚拟机和平台,但 Azure Functions 提供了一个小窗口,通过 Kudu Console 查看它们。
Azure Functions 有两个主要组件:
-
Azure Functions 运行时。
-
Azure Functions 的绑定和触发器。
让我们详细了解这些组件。
Azure Functions 运行时。
Azure Functions 的核心是其运行时。Azure Functions 的前身是 Azure WebJobs。Azure WebJobs 的代码也是 Azure Functions 的核心。Azure WebJobs 增加了额外的功能和扩展,以创建 Azure Functions。Azure Functions 运行时是使函数能够工作的魔法。Azure Functions 托管在 Azure App Service 中。Azure App Service 加载 Azure 运行时,并等待外部事件或手动活动的发生。请求到达或触发器发生时,App Service 加载传入的负载,读取函数的 function.json
文件以查找函数的绑定和触发器,将传入数据映射到传入参数,并使用参数值调用函数。一旦函数完成执行,值通过 function.json
文件中定义为绑定的输出参数再次传回 Azure Functions 运行时。函数运行时将值返回给调用者。Azure Functions 运行时充当粘合剂,支持整个函数的执行。
当前的 Azure 运行时版本是 ~3。它基于 .NET Core 3.1 框架。在此之前,版本 ~2 基于 .NET Core 2.2 框架。第一个版本 ~1 基于 .NET 4.7 框架。
从版本 1 到版本 2 由于底层框架本身的变化,发生了重大变化。然而,从版本 2 到版本 3 几乎没有破坏性变化,大多数在版本 2 中编写的函数仍然能够在版本 3 上运行。然而,建议在从版本 2 升级到版本 3 后进行充分的测试。关于触发器和绑定,从版本 1 到版本 2 也存在破坏性变化。触发器和绑定现在作为扩展提供,在版本 2 和 3 中,每个扩展都位于不同的程序集。
Azure Functions 绑定和触发器
如果 Azure Functions 运行时是 Azure Functions 的大脑,那么 Azure Functions 绑定和触发器就是它的心脏。Azure Functions 通过触发器和绑定促进服务之间的松耦合和高内聚。针对非无服务器环境编写的应用程序使用命令式语法实现传入和传出的参数以及返回值的代码。Azure Functions 使用声明式机制通过触发器调用函数,并使用绑定配置数据流。
绑定是指创建传入数据与 Azure 函数之间连接的过程,并映射数据类型。该连接可以是从运行时到 Azure Functions 的单向连接,也可以是双向的——绑定可以在 Azure 运行时和 Azure Functions 之间双向传输数据。Azure Functions 以声明的方式定义绑定。
触发器是一种特殊类型的绑定,函数可以通过它根据外部事件被调用。除了调用函数,触发器还会将传入的数据、有效负载和元数据传递给函数。
绑定在 function.json
文件中定义,如下所示:
{ "bindings": [ { "name": "checkOut", "type": "queueTrigger", "direction": "in", "queueName": "checkout-items", "connection": "AzureWebJobsDashboard" }, { "name": "Orders", "type": "table", "direction": "out", "tableName": "OrderDetails", "connection": "<<Connection to table storage account>>" } ], "disabled": false }
在此示例中,声明了一个触发器,当存储队列中有新项时,会调用该函数。类型为 queueTrigger
,方向为输入,queueName
为 checkout-items
,并且显示了目标存储帐户连接和表名称的详细信息。所有这些值对于此绑定的功能至关重要。checkOut
名称可以在函数代码中作为变量使用。
类似地,声明了返回值的绑定。这里,返回值命名为 Orders
,数据是来自 Azure Functions 的输出。该绑定将返回数据写入 Azure 表存储,使用提供的连接字符串。
绑定和触发器都可以通过更新 function.json
文件进行修改和编写。checkOut
触发器声明如下:
图 10.1:集成选项卡的触发器部分
Orders 输出如下所示:
图 10.2:为存储帐户添加输出详细信息
Azure 函数的作者无需编写任何管道代码来获取来自多个源的数据。他们只需决定预期的 Azure 运行时数据类型。下一段代码示例中显示了这一点。请注意,结账功能作为字符串提供给函数。可以使用多种数据类型作为函数的绑定。例如,队列绑定可以提供以下内容:
-
一个普通的 CLR(公共语言运行时)对象 (POCO)
-
一个字符串
-
一个字节
-
CloudQueueMessage
函数的作者可以使用这些数据类型中的任何一种,Azure Functions 运行时会确保将正确的对象作为参数传递给函数。以下是一个接受字符串数据的代码片段,运行时会在调用函数之前将传入的数据封装为 string
数据类型。如果运行时无法将传入的数据转换为字符串,则会生成异常:
using System;public static void Run(string checkOut, TraceWriter log){ log.Info($"C# Queue trigger function processed: { checkOut }");}
同样需要了解的是,在图 10.2中,存储帐户名称为 AzureWebJobsStorage
和 AzureWebJobsDashboard
。这两个是定义在 appSettings
部分的密钥,包含存储帐户连接字符串。Azure Functions 内部使用这些存储帐户来维护其状态和函数执行的状态。
有关 Azure 绑定和触发器的更多信息,请参阅 docs.microsoft.com/azure/azure-functions/functions-bindings-storage-queue
。
现在我们已经对 Azure 绑定和触发器有了一个基本的理解,让我们来看看 Azure Functions 提供的各种配置选项。
Azure Functions 配置
Azure Functions 提供了多级配置选项。它为以下内容提供配置:
-
平台本身
-
函数应用服务
这些设置会影响它们所包含的每个函数。关于这些设置的更多信息,请访问 docs.microsoft.com/azure/azure-functions/functions-how-to-use-azure-function-app-settings
。
平台配置
Azure 函数托管在 Azure App Service 中,因此它们可以享受所有的 App Service 特性。可以使用平台功能轻松配置诊断和监控日志。此外,App Service 提供了分配 SSL 证书、使用自定义域名、身份验证和授权等网络功能的选项。
尽管客户无需关心函数实际执行的基础设施、操作系统、文件系统或平台,但 Azure Functions 提供了必要的工具,可以深入了解底层系统并进行更改。门户内控制台和 Kudu 控制台是用于此目的的工具。它们提供了丰富的编辑器,用于编写 Azure 函数并编辑其配置。
与 App Service 一样,Azure Functions 允许你将配置信息存储在 web.config
应用程序设置部分,可以按需读取。一些函数应用的 платформ功能如 图 10.3 所示:
图 10.3:函数应用的 플랫폼功能
这些平台功能可以用来配置身份验证、自定义域名、SSL 等等。此外,平台功能选项卡提供了可以与函数应用一起使用的开发工具概览。在接下来的章节中,我们将查看在平台功能中可用的函数应用设置。
App Service 函数设置
这些设置会影响所有函数。应用程序设置可以在此处管理。Azure Functions 中的代理可以启用和禁用。我们将在本章后面讨论代理。它们还帮助更改函数应用的编辑模式和部署到槽:
图 10.4:函数应用设置
预算是任何项目成功的一个非常重要的方面。让我们来探索 Azure Functions 提供的各种计划。
Azure Functions 费用计划
Azure Functions 基于 Azure App Service,为用户提供了一种经济实惠的模型。它有三种费用模型。
消费计划
这是基于按秒计费的函数消费和执行费用。该计划根据函数的实际消费和执行的计算使用情况来计算费用。如果一个函数没有执行,则不会产生费用。然而,这并不意味着该计划会影响性能。Azure 函数会根据需求自动扩展和缩减,以确保基本的最小性能水平得以保持。一个函数的执行允许 10 分钟完成。
该计划的一个主要缺点是,如果函数几秒钟内没有被消费,函数可能会变冷,接下来的请求可能会因函数处于空闲状态而出现短暂的响应延迟。这种现象称为冷启动。然而,有一些解决方法可以保持函数在没有合法请求时也保持“热”状态。可以通过编写一个计划任务函数,不断调用目标函数,保持其活跃。
高级计划
这是一个相对较新的计划,与应用服务计划和消费计划相比,提供了许多好处。在该计划中,Azure 函数没有冷启动。函数可以与私有网络关联,客户可以选择自己的虚拟机大小来执行函数。它提供了许多之前在其他两种计划中无法实现的现成功能。
应用服务计划
该计划为函数提供了完全专用的虚拟机后端,因此其费用与虚拟机的成本及其大小直接相关。即使函数没有被调用,也会有固定的费用与此计划相关联。函数代码可以运行所需的时间。尽管没有时间限制,但默认限制设置为 30 分钟。可以通过更改 hosts.json
文件中的值来更改此限制。在应用服务计划中,如果函数长时间未使用,函数运行时会进入空闲状态,只能通过 HTTP 触发器激活。可以使用 Always On 设置来防止函数运行时进入空闲状态。扩展可以是手动的,也可以基于自动扩展设置。
除了灵活的定价选项外,Azure 还提供了多种架构部署的托管选项。
Azure Functions 目标主机
Azure Functions 运行时可以托管在 Windows 和 Linux 主机上。基于 PowerShell Core、Node.js、Java、Python 和 .NET Core 的函数可以在 Windows 和 Linux 操作系统上运行。了解函数所需的底层操作系统类型非常重要,因为此配置设置与函数应用程序及其包含的所有函数相关联。
此外,函数还可以在 Docker 容器中运行。这是因为 Azure 提供了预先构建的函数运行时的 Docker 镜像,可以使用这些镜像来托管函数。现在,Docker 镜像可以用于在 Kubernetes Pod 中创建容器,并托管在 Azure Kubernetes 服务、Azure 容器实例或非托管的 Kubernetes 集群中。这些镜像可以存储在 Docker Hub、Azure 容器注册表或任何其他全球和私有镜像库中。
为了更清楚地理解,我们来看看 Azure Functions 中一些最突出使用案例。
Azure Functions 使用案例
Azure Functions 有多种实现方式。让我们来看一下这些使用案例。
实现微服务
Azure Functions 帮助将大型应用程序拆分为更小的独立功能代码单元。每个单元都独立于其他单元发展,拥有自己的生命周期。每个代码单元都有其自己的计算、硬件和监控要求。每个函数可以与所有其他函数连接。这些单元由协调器交织在一起,以构建完整的功能。例如,在一个电子商务应用程序中,可以有多个独立的函数(代码单元),每个函数负责列出目录、推荐、分类、子分类、购物车、结账、支付类型、支付网关、收货地址、账单地址、税费、运费、取消、退货、电子邮件、短信等。其中一些函数被组合在一起,创建用于电子商务应用程序的使用案例,如产品浏览和结账流程。
多个端点之间的集成
Azure Functions 可以通过集成多个函数来构建整体应用程序功能。这种集成可以基于事件触发,也可以是推送方式。这有助于将大型的单体应用程序拆分为小型组件。
数据处理
Azure Functions 可用于批量处理传入数据。它可以帮助处理多种格式的数据,如 XML、CSV、JSON 和 TXT。它还可以运行转换、增强、清理和过滤算法。事实上,可以使用多个函数,每个函数执行转换或增强、清理或过滤操作。Azure Functions 还可以用于结合先进的认知服务,如 光学字符识别(OCR)、计算机视觉、图像处理和转换。如果您想处理 API 响应并进行转换,这是理想的选择。
集成遗留应用程序
Azure Functions 可以帮助将遗留应用程序与更新的协议和现代应用程序集成。遗留应用程序可能未使用行业标准协议和格式。Azure Functions 可以充当这些遗留应用程序的代理,接受用户或其他应用程序的请求,将数据转换为遗留应用程序可以理解的格式,并使用其理解的协议与其进行通信。这为集成和将旧有遗留应用程序引入主流应用组合提供了巨大的机会。
定时作业
Azure Functions 可用于执行持续或定期的某些应用程序功能。这些应用程序功能可以执行诸如定期备份、恢复、批处理作业、导入导出数据和批量发送电子邮件等任务。
通信网关
Azure Functions 可以在使用通知中心、短信、电子邮件等时用作通信网关。例如,你可以使用 Azure Functions 通过 Azure 通知中心向 Android 和 iOS 设备发送推送通知。
Azure 函数有不同的类型,需要根据它们与工作负载优化的关系进行选择。让我们仔细了解它们。
Azure 函数的类型
Azure 函数可以分为三种不同的类型:
-
按需函数:这些函数在被显式调用或触发时执行。例如,HTTP 基础的函数和 Webhook 就是这类函数。
-
定时函数:这些函数像定时任务一样,按固定时间间隔执行。
-
基于事件的函数:这些函数基于外部事件执行。例如,向 Azure Blob 存储上传新文件会生成一个事件,从而启动 Azure 函数的执行。
在接下来的部分中,你将学习如何创建一个事件驱动的函数,该函数将连接到一个 Azure 存储帐户。
创建事件驱动的函数
在此示例中,将创建一个 Azure 函数并将其连接到 Azure 存储帐户。该存储帐户有一个容器来存放所有 Blob 文件。存储帐户的名称是 incomingfiles,容器的名称是 orders,如 图 10.5 所示:
图 10.5:存储帐户详情
执行以下步骤从 Azure 门户创建一个新的 Azure 函数:
-
点击左侧 Functions 菜单旁边的 + 按钮。
-
从结果页面选择 In-Portal 并点击 继续 按钮。
-
选择 Azure Blob 存储触发器,如 图 10.6 所示:
图 10.6:选择 Azure Blob 存储触发器
目前,这个 Azure 函数与存储帐户没有连接。Azure 函数需要存储帐户的连接信息,而这些信息可以从存储帐户的访问密钥标签中获取。同样的信息也可以通过 Azure Functions 编辑器环境获取。事实上,该环境允许从同一个编辑器环境中创建一个新的存储帐户。
可以通过点击存储帐户连接输入框旁的新建按钮来添加 Azure Blob 存储触发器。它允许选择现有的存储帐户或创建一个新的存储帐户。由于我已经有几个存储帐户,所以我在重复使用它们,但你应该创建一个单独的 Azure 存储帐户。选择一个存储帐户后,将更新appSettings部分的设置,并将连接字符串添加到其中。
确保目标 Azure 存储帐户的 Blob 服务中已存在一个容器。路径输入指的是容器的路径。在这种情况下,orders 容器已经存在于存储帐户中。这里显示的创建按钮将为新的函数提供服务,监控存储帐户容器:
图 10.7:创建一个监控存储帐户容器的函数
storagerelatedfunctions
函数的代码如下:
public static void Run(Stream myBlob, TraceWriter log){ log.Info($"C# Blob trigger function Processed blob\n \n Size {myBlob.Length} Bytes");}
绑定如下所示:
{ "bindings": [ { "name": "myBlob", "type": "blobTrigger", "direction": "in", "path": "orders", "connection": "azureforarchitead2b_STORAGE" } ], "disabled": false }
现在,将任何 blob 文件上传到 orders
容器应该会触发该函数:
图 10.8:C# Blob 触发函数处理的 blob
在接下来的部分,我们将深入探讨 Azure Function Proxies,它将帮助你高效处理 API 的请求和响应。
函数代理
Azure Function Proxies 是 Azure Functions 的一个相对较新的功能。函数代理有助于隐藏 Azure 函数的细节,并向客户公开完全不同的端点。函数代理可以接收端点的请求,通过改变值来修改请求的内容、主体、头部和 URL,增加额外数据,并将其传递给 Azure 函数。一旦它们从这些函数获得响应,它们可以再次转换、覆盖和增强响应,并将其发送回客户端。
它还帮助通过使用不同的头部信息调用不同的函数进行 CRUD(创建、读取、删除和更新)操作,从而将大型函数拆分成更小的函数。它通过不暴露原始函数端点提供了一定的安全性,并且在不影响调用者的情况下,帮助更改内部函数实现和端点。函数代理通过为客户端提供单一的函数 URL,然后在后台调用多个 Azure 函数来完成工作流。有关 Azure Function Proxies 的更多信息,请访问 docs.microsoft.com/azure/azure-functions/functions-proxies
。
在下一节中,我们将详细介绍 Durable Functions。
Durable Functions
Durable Functions 是 Azure Functions 中最新的功能之一。它允许架构师在 Orchestrator 函数中编写有状态的工作流,这是一个新的函数类型。作为开发者,你可以选择编写代码或使用任何形式的 IDE。使用 Durable Functions 的一些优势包括:
-
函数输出可以保存到本地变量中,你可以同步和异步调用其他函数。
-
状态会为你保留。
以下是调用 Durable Functions 的基本机制:
图 10.9:调用 Durable Functions 的机制
Azure Durable Functions 可以通过 Azure Functions 提供的任何触发器进行调用。这些触发器包括 HTTP、Blob 存储、表存储、服务总线队列等。它们可以由具有访问权限的用户手动触发,也可以由应用程序触发。图 10.9 展示了几个触发器作为示例。这些也被称为启动型 Durable Functions。启动型 Durable Functions 调用 durable orchestrator trigger,该触发器包含编排的主要逻辑,并负责编排活动函数的调用。
在持久编排器中编写的代码必须是确定性的。这意味着,无论代码执行多少次,返回的值应该保持不变。编排器函数本质上是一个长时间运行的函数。这意味着它可以被注水、状态序列化,并在调用持久活动函数后进入休眠状态。因为它不知道持久活动函数何时完成,所以它不想等待。当持久活动函数执行完成时,编排器函数将再次执行。函数执行从顶部开始,并一直执行,直到它调用另一个持久活动函数或完成函数执行。它必须重新执行之前已经执行过的代码行,并且应该得到之前的相同结果。请注意,在持久编排器中编写的代码必须是确定性的。这意味着,无论代码执行多少次,返回的值应该保持不变。
让我通过一个例子来解释这一点。如果我们使用通用的.NET Core 日期时间类并返回当前的日期时间,每次执行函数时,它都会返回一个新的值。持久函数上下文对象提供了CurrentUtcDateTime
,它将在重新执行时返回与第一次执行时相同的日期时间值。
这些编排函数也可以等待外部事件,并支持与人工交接相关的场景。这个概念将在本节稍后解释。
这些活动函数可以在有或没有重试机制的情况下被调用。持久函数可以帮助解决许多挑战,并提供以下功能来编写可以执行以下操作的函数:
-
执行长时间运行的函数
-
维护状态
-
并行或按顺序执行子函数
-
容易从故障中恢复
-
在工作流中编排函数的执行
现在你对持久函数的内部工作机制有了基本了解,接下来让我们探索如何在 Visual Studio 中创建持久函数。
使用 Visual Studio 创建持久函数的步骤
以下是创建持久函数的步骤:
-
导航到 Azure 门户并点击左侧菜单中的资源组。
-
点击顶部菜单中的+添加按钮来创建一个新的资源组。
-
在生成的表单中提供资源组信息并点击创建按钮,如下所示:
图 10.10:创建资源组
-
导航到新创建的资源组,并通过点击生成的搜索框中的
功能应用
来添加一个新的功能应用。 -
选择功能应用并点击创建按钮。填写生成的功能应用表单并点击创建按钮。你也可以重新使用我们之前创建的功能应用。
-
一旦函数应用创建完成,我们将进入本地开发环境,安装了 Visual Studio 2019 的环境中。我们将开始使用 Visual Studio 创建一个新的
Azure functions
类型项目,提供名称,并为 Function runtime 选择 Azure Functions v3(.NET core)。 -
创建项目后,我们需要将
DurableTask
NuGet 包添加到项目中,以便与 Durable Functions 一起使用。编写本章时使用的版本是 2.2.2:图 10.11:添加 DurableTask NuGet 包
-
现在,我们可以在 Visual Studio 中编写持久化函数。添加一个新函数,给它命名,并选择 Durable Functions Orchestration 触发器类型:
图 10.12:选择 Durable Functions Orchestration 触发器
-
Visual Studio 会为 Durable Functions 生成样板代码,我们将利用这些代码来学习 Durable Functions。Durable Functions 活动是由主 Orchestrator 函数调用的函数。通常会有一个主 Orchestrator 函数和多个 Durable Functions 活动。一旦扩展安装完成,提供一个函数名称并编写一些有用的代码,比如发送电子邮件或短信,连接外部系统并执行逻辑,或者使用其端点执行服务,如认知服务。
Visual Studio 会在一行代码中生成三组函数:
-
BlobTrigger
,ServiceBus
队列或基于触发器的函数。 -
RunOrchestrator:这是主要的持久化协调函数。它负责从启动函数接收参数,并依次调用多个持久化任务函数。每个持久化任务函数负责一个特定功能,这些持久化任务可以根据需要并行或顺序调用。
-
SayHello:这是从持久化函数协调器调用的持久化任务函数,用于执行特定任务。
-
-
启动函数(
HttpStart
)的代码如下所示。此函数的触发器类型为 HTTP,并接受一个类型为DurableClient
的附加绑定。此DurableClient
对象有助于调用 Orchestrator 函数:图 10.13:启动函数的代码
-
Orchestrator 函数(
RunOrchestrator
)的代码如下所示。此函数的触发器类型为OrchestrationTrigger
,并接受类型为IDurableOrchestrationContext
的参数。此上下文对象有助于调用持久化任务:图 10.14:Orchestrator 触发器函数的代码
-
持久化任务函数的代码(
HelloFunction
)如下所示。该函数的触发器类型为ActivityTrigger
,并接受一个参数,该参数可以是执行其功能所需的任何类型。它的返回值类型为string
,并且该函数负责返回一个字符串值给协调函数:
图 10.15:持久化任务函数的代码
接下来,我们可以在本地执行该函数,这将启动一个存储仿真器(如果尚未启动),并为 HTTP 触发器函数提供一个 URL:
图 10.16:启动存储仿真器
我们将使用一个工具Postman来调用此 URL(该工具可以从www.getpostman.com/
下载)。我们只需要复制该 URL 并在 Postman 中执行。这个操作如图 10.17所示:
图 10.17:使用 Postman 调用 URL
注意,当你启动协调器时,会生成五个 URL:
statusQueryGetUri
URL 用于查找协调器的当前状态。在 Postman 中点击该 URL 会打开一个新标签页,如果执行此请求,它将显示工作流的状态:
图 10.18:协调器的当前状态
-
terminatePostUri
URL 用于停止已经在运行的协调器函数。 -
sendEventPostUri
URL 用于向挂起的持久化函数发布事件。当持久化函数在等待外部事件时,它们可以被挂起。在这种情况下,将使用此 URL。 -
purgeHistoryDeleteUri
URL 用于从持久化函数的表存储帐户中删除某个调用的历史记录。
现在你已经知道如何使用 Visual Studio 操作持久化函数,让我们讨论 Azure 函数的另一个方面:将它们链接在一起。
创建具有函数的连接架构
具有函数的连接架构指的是创建多个函数,其中一个函数的输出触发另一个函数,并为下一个函数提供数据以执行其逻辑。在本节中,我们将继续之前的存储帐户场景。在此情况下,使用 Azure 存储 Blob 文件触发的函数输出将把文件的大小写入 Azure Cosmos DB。
接下来展示的是 Cosmos DB 的配置。默认情况下,Cosmos DB 中没有创建任何集合。
在创建一个函数时,Cosmos DB 接收到任何数据时将自动创建一个集合,该函数将被触发:
图 10.19:创建 Azure Cosmos DB 账户
让我们按照以下步骤,从一个函数的输出中获取数据,供下一个函数使用。
-
在 Cosmos DB 中创建一个新的数据库
testdb
,并在其中创建一个名为testcollection
的新集合。在配置 Azure 函数时,您需要同时提供数据库和集合名称:图 10.20:添加容器
-
创建一个新的函数,该函数将具有 Blob 存储触发器和 Cosmos DB 输出绑定。该函数返回的值将是上传文件的数据大小。该返回值将写入 Cosmos DB。输出绑定将写入 Cosmos DB 集合。导航到集成标签页,点击新建输出按钮,位于输出标签下方,并选择Azure Cosmos DB:
图 10.21:将输出绑定到 Azure Cosmos DB
-
提供适当的数据库和集合名称(如果集合不存在,请勾选复选框以创建集合),点击新建按钮选择您新创建的 Azure Cosmos DB,并将参数名称保持为outputDocument:
图 10.22:新创建的 Azure Cosmos DB
-
按照图 10.23中的方式修改函数:
图 10.23:修改函数
-
现在,将新文件上传到 Azure 存储账户中的 orders 集合,将会触发一个写入 Azure Cosmos DB 集合的函数。另一个函数可以使用新创建的 Azure Cosmos DB 账户作为触发绑定。它将提供文件的大小,函数可以对其进行处理。如下所示:
图 10.24:编写触发器绑定函数
本节介绍了如何使用一个函数的输出数据来为下一个函数获取数据。在下一节中,您将学习如何通过了解 Azure Event Grid 来启用无服务器事件处理。
Azure 事件网格
Azure Event Grid 是一个相对较新的服务,也被称为无服务器事件平台。它帮助基于事件(也称为事件驱动设计)创建应用程序。了解事件是什么以及在 Event Grid 出现之前我们如何处理事件是非常重要的。事件是指发生的事情——即改变某个主题状态的活动。当一个主题的状态发生变化时,通常会触发一个事件。
事件通常遵循发布/订阅模式(也称为pub/sub 模式),在该模式中,主题因其状态变化而触发事件,其他多个感兴趣的方(即订阅者)可以订阅该事件。事件的作用是通知订阅者这些变化,并将相关数据作为事件的一部分提供给他们。订阅者可以根据需要采取相应的行动,这些行动因订阅者而异。
在事件网格之前,并没有可以称作实时事件平台的服务。曾经有多个独立服务,每个服务都提供了各自的事件处理机制。
例如,Log Analytics,也称为操作管理套件(OMS),提供了一个捕获环境日志和遥测数据的基础设施,基于这些数据可以生成警报。这些警报可以用于执行 Runbook、Webhook 或函数。这接近实时,但并不完全是实时的。而且,捕获单个日志并对其进行处理非常繁琐。同样,Application Insights 也提供了类似于 Log Analytics 的功能,但它是为应用程序提供的。
还有其他日志,例如活动日志和诊断日志,但它们同样依赖于与其他日志相关功能类似的原理。解决方案部署在多个资源组中,跨多个区域,从任何这些区域引发的事件应该能被部署在其他地方的资源访问。
事件网格去除了所有障碍,因此,几乎所有资源都可以生成事件(这些资源正变得越来越可用),甚至可以生成自定义事件。这些事件可以被任何资源、任何区域、任何资源组内的订阅者所订阅。
事件网格已经作为 Azure 基础设施的一部分铺设好了,包括数据中心和网络。一个区域内触发的事件可以轻松地被其他区域的资源订阅,并且由于这些网络是互联的,因此事件传递给订阅者的效率极高。
事件网格
事件网格让你可以创建基于事件的架构应用程序。既有事件的发布者,也有事件的消费者;然而,针对同一事件,可能会有多个订阅者。
事件的发布者可以是一个 Azure 资源,例如 Blob 存储、物联网(IoT)中心等。这些发布者也称为事件源。它们使用现成的 Azure 主题将事件发送到事件网格,无需配置资源或主题。Azure 资源触发的事件已经通过内部使用主题的方式将事件发送到事件网格。一旦事件到达网格,订阅者就可以消费它。
订阅者或消费者是对事件感兴趣并希望基于这些事件执行操作的资源。这些订阅者在订阅主题时提供事件处理程序。事件处理程序可以是 Azure 函数、自定义 Webhook、逻辑应用程序或其他资源。执行事件处理程序的事件源和订阅者如图 10.25所示:
图 10.25:事件网格架构
当事件到达主题时,可以同时执行多个事件处理程序,每个处理程序执行自己的操作。
还可以引发自定义事件并将自定义主题发送到事件网格。事件网格提供了创建自定义主题的功能,这些主题会自动附加到事件网格。这些主题知道事件网格的存储位置,并会自动将消息发送到该位置。自定义主题有两个重要属性,如下所示:
-
端点:这是主题的端点。发布者和事件源通过此端点将事件发送并发布到事件网格。换句话说,主题是通过其端点来识别的。
-
密钥:自定义主题提供了一些密钥。这些密钥为端点的使用提供安全保障。只有拥有这些密钥的发布者才能将消息发送并发布到事件网格。
每个事件都有一个事件类型,并通过它来识别。例如,Blob 存储提供了事件类型,如 blobAdded
和 blobDeleted
。自定义主题可以用来发送自定义定义的事件,如 KeyVaultSecretExpired
类型的自定义事件。
另一方面,订阅者有能力接受所有消息,或者仅根据筛选器获取事件。这些筛选器可以基于事件类型或事件有效负载中的其他属性。
每个事件至少具有以下五个属性:
-
id
:这是事件的唯一标识符。 -
eventType
:这是事件类型。 -
eventTime
:这是事件引发的日期和时间。 -
subject
:这是事件的简短描述。 -
data
:这是一个字典对象,包含特定资源的数据或任何自定义数据(用于自定义主题)。
目前,事件网格的功能并非所有资源都支持;然而,Azure 正在不断增加更多支持事件网格功能的资源。
要了解更多关于能够引发与事件网格相关事件的资源以及能够处理这些事件的处理程序,请访问docs.microsoft.com/azure/event-grid/overview
。
资源事件
本节提供了以下步骤,以创建一个解决方案,其中由 Blob 存储引发的事件发布到事件网格,并最终路由到 Azure 函数:
-
使用适当的凭据登录到 Azure 门户,并在现有或新的资源组中创建一个新的存储账户。存储账户应该是 StorageV2 或 Blob 存储。如 图 10.26 所示,事件网格不支持 StorageV1:
图 10.26:创建新的存储账户
-
创建一个新的函数应用程序,或者重用现有的函数应用程序来创建 Azure 函数。Azure 函数将托管在该函数应用程序中。
-
使用 Azure Event Grid 触发器 模板创建一个新函数。如果尚未安装 Microsoft.Azure.WebJobs.Extensions.EventGrid 扩展,请安装该扩展,如 图 10.27 所示:
图 10.27:为 Azure Event Grid 触发器安装扩展
-
为
StorageEventHandler
函数命名并创建它。以下是将作为事件处理程序使用的默认生成代码:图 10.28:事件处理程序代码
存储事件的订阅可以通过 Azure Functions 用户界面 (UI) 配置,方法是点击 添加事件网格订阅,或者通过存储账户本身进行配置。
-
在 Azure Functions UI 中点击 添加事件网格订阅 链接,为前一步创建的存储账户添加事件订阅。为订阅提供一个有意义的名称,然后选择 事件模式,接着选择 事件网格模式。将 主题类型 设置为 存储账户,选择适当的 订阅,并选择包含存储账户的资源组:
图 10.29:创建事件网格订阅
确保选中 订阅所有事件类型 复选框,然后点击 创建 按钮(选中存储账户后该按钮应自动启用)。
-
如果我们现在导航到 Azure 门户中的存储账户,并点击左侧菜单中的 事件 链接,则应能看到该存储账户的订阅:
图 10.30:事件订阅列表
-
在创建容器后,将文件上传到 Blob 存储,Azure 函数应该会被执行。上传操作将触发一个
blobAdded
类型的新事件,并将其发送到存储账户的事件网格主题。如 图 10.31 所示,订阅已经设置为接收来自该主题的所有事件,函数将作为事件处理程序的一部分执行:
图 10.31:触发新事件
在本节中,你学习了如何将 Blob 存储引发的事件路由到 Azure 函数。在下一节中,你将学习如何利用自定义事件。
自定义事件
在这个示例中,我们将使用自定义事件,而不是使用现成的资源来生成事件。我们将使用 PowerShell 创建这个解决方案,并重用在上一个练习中创建的相同 Azure 函数作为处理器:
-
使用
Login-AzAccount
和Set-AzContext
cmdlet 登录并连接到你选择的 Azure 订阅。 -
下一步是在 Azure 的一个资源组中创建一个新的事件网格主题。使用
New-AzEventGridTopic
cmdlet 创建新的主题:New-AzEventGridTopic -ResourceGroupName CustomEventGridDemo -Name "KeyVaultAssetsExpiry" -Location "West Europe"
-
一旦主题创建完成,需要获取其端点 URL 和密钥,因为它们是发送并发布事件到该主题所必需的。
Get-AzEventGridTopic
和Get-AzEventGridTopicKey
cmdlet 被用来获取这些值。请注意,获取的是Key1
,用于连接到端点:$topicEndpoint = (Get-AzEventGridTopic -ResourceGroupName containers -Name KeyVaultAssetsExpiry).Endpoint $keys = (Get-AzEventGridTopicKey -ResourceGroupName containers -Name KeyVaultAssetsExpiry).Key1
-
创建一个新的哈希表,包含所有五个重要的事件网格事件属性。为 ID 生成一个新的
id
属性,将subject
属性设置为Key vault
Asset Expiry
,将eventType
设置为Certificate Expiry
,将eventTime
设置为当前时间,并将data
填充证书相关信息:$eventgridDataMessage = @{id = [System.guid]::NewGuid()subject = "Key Vault Asset Expiry"eventType = "Certificate Expiry"eventTime = [System.DateTime]::UtcNow data = @{CertificateThumbprint = "sdfervdserwetsgfhgdg"ExpiryDate = "1/1/2019"Createdon = "1/1/2018"}}
-
由于事件网格数据应以 JSON 数组的形式发布,因此有效负载会被转换为 JSON 数组。
"["
和"]"
方括号代表 JSON 数组:$finalBody = "[" + $(ConvertTo-Json $eventgridDataMessage) + "]"
-
事件将通过 HTTP 协议发布,必须向请求中添加适当的头信息。请求使用应用程序/JSON 内容类型发送,属于主题的密钥被分配给
aeg-sas-key
头部。必须命名头部并将密钥设置为aeg-sas-key
:$header = @{"contentType" = "application/json""aeg-sas-key" = $keys}
-
创建一个新的订阅,订阅自定义主题,包含名称、包含主题的资源组、主题名称、WebHook 端点和实际作为事件处理器的端点。在此情况下,事件处理器是 Azure 函数:
New-AzEventGridSubscription -TopicName KeyVaultAssetsExpiry -EventSubscriptionName "customtopicsubscriptionautocar" -ResourceGroupName CustomEventGridDemo -EndpointType webhook '-Endpoint "https://durablefunctiondemoapp.azurewebsites.net/runtime/webhooks/EventGrid?functionName=StorageEventHandler&code=0aSw6sxvtFmafXHvt7iOw/Dsb8o1M9RKKagzVchTUkwe9EIkzl4mCg=='-Verbose
Azure 函数的 URL 可以从集成选项卡获取,如图 10.31所示:
图 10.32:集成选项卡中的事件网格订阅 URL
-
到目前为止,订阅者(事件处理器)和发布者都已配置完成。下一步是向自定义主题发送并发布事件。事件数据已经在上一步创建,使用
Invoke-WebRequest
cmdlet,带着请求体和头部将请求发送到端点:Invoke-WebRequest -Uri $topicEndpoint -Body $finalBody -Headers $header -Method Post
API 调用将触发事件,事件网格会向我们配置的端点发送消息,该端点是功能应用。通过这项操作,我们将结束本章内容。
摘要
从传统方法到函数的演变,催生了松耦合、独立演化、自给自足的无服务器架构,这在早期只是一个概念。函数是部署单元,提供一个完全无需用户管理的环境。用户只需要关注为功能编写的代码。Azure 提供了一个成熟的平台,用于托管函数并根据事件或按需无缝集成它们。Azure 中几乎所有资源都可以参与由 Azure 函数组成的架构。未来是函数,因为越来越多的组织希望摆脱管理基础设施和平台的任务,想将这些工作交给云服务提供商。对于每个处理 Azure 的架构师来说,掌握 Azure Functions 是一项基本技能。
本章详细介绍了 Azure Functions、函数即服务(Functions as a Service)、持久化函数(Durable Functions)和事件网格(Event Grid)。下一章将重点讲解 Azure Logic Apps,并且我们将构建一个完整的端到端解决方案,结合多个无服务器服务以及其他 Azure 服务,如 Azure Key Vault 和 Azure Automation。
第十一章:11. 使用 Azure Logic Apps、Event Grid 和 Functions 的 Azure 解决方案
本章接续上一章内容,进一步深入探讨 Azure 中可用的无服务器服务。在上一章中,你详细了解了 Azure Functions、函数即服务、耐久性函数以及 Event Grid。接下来,本章将重点讲解 Logic Apps,并且将展示如何创建一个完整的端到端无服务器解决方案,该解决方案结合了多个无服务器服务及其他服务,例如 Key Vault 和 Azure Automation。
在本章中,我们将通过以下主题进一步探索 Azure 服务:
-
Azure Logic Apps
-
使用无服务器技术创建端到端解决方案
Azure Logic Apps
Logic Apps 是 Azure 提供的一种无服务器工作流服务。它具有所有无服务器技术的特点,例如按使用量计费和无限的可扩展性。Logic Apps 帮助我们通过 Azure 门户轻松构建业务流程和工作流解决方案。它提供了一个拖拽式界面,用于创建和配置工作流。
使用 Logic Apps 是集成服务和数据、创建业务项目以及创建完整逻辑流的首选方式。在构建 Logic Apps 之前,应该理解几个重要的概念。
活动
活动是一个独立的工作单元。活动的例子包括将 XML 转换为 JSON、从 Azure 存储读取 Blob 和写入 Cosmos DB 文档集合。Logic Apps 提供了一个工作流定义,包含多个相关活动按顺序执行。Logic Apps 中有两种类型的活动:
-
触发器:触发器是指启动活动的事件。所有 Logic Apps 都有一个触发器,它是第一个活动。触发器创建 Logic Apps 实例并启动执行。触发器的例子包括 Event Grid 消息的到达、电子邮件、HTTP 请求或计划任务。
-
操作:任何不是触发器的活动都是步骤活动,每个步骤负责执行一个任务。步骤按顺序连接在工作流中。每个步骤都需要完成一个操作,才能继续到下一个步骤。
连接器
连接器是 Azure 资源,用于将 Logic Apps 与外部服务连接。这些服务可以位于云端或本地。例如,有一个连接器可以将 Logic Apps 连接到 Event Grid。同样,还有一个连接器可以连接到 Office 365 Exchange。Logic Apps 中几乎所有类型的连接器都可以用来连接服务。连接器包含连接信息,并利用这些信息提供连接外部服务的逻辑。
所有连接器的完整列表可以在 docs.microsoft.com/connectors
查看。
现在你了解了连接器,你需要了解如何按步骤将它们对齐,以便工作流按预期运行。在接下来的部分,我们将重点介绍逻辑应用的工作原理。
逻辑应用的工作原理
让我们创建一个逻辑应用工作流,当电子邮件账户收到邮件时触发。它会回复发件人一封默认的电子邮件,并对邮件内容进行情感分析。对于情感分析,应该在创建逻辑应用之前配置 Cognitive Services 中的 Text Analytics 资源:
-
导航到 Azure 门户,登录到你的账户,并在资源组中创建一个Text Analytics资源。Text Analytics 是 Cognitive Services 的一部分,提供情感分析、关键短语提取和语言检测等功能。你可以在 Azure 门户中找到该服务,如图 11.1所示:
图 11.1:从 Azure 门户导航到 Text Analytics 服务
-
提供名称、位置、订阅、资源组和定价层值。我们将在此演示中使用该服务的免费层(F0 层)。
-
资源配置完成后,导航到概览页面,复制端点 URL,并将其存储在临时位置。配置逻辑应用时将需要此值。
-
导航到密钥页面,复制密钥 1的值并将其存储在临时位置。配置逻辑应用时将需要此值。
-
下一步是创建一个逻辑应用。要创建逻辑应用,请在 Azure 门户中导航到应创建逻辑应用的资源组。搜索“Logic App”,并通过提供名称、位置、资源组和订阅值来创建它。
-
创建完逻辑应用后,导航到该资源,点击左侧菜单中的Logic app designer,然后选择当在 Outlook.com 中收到新邮件时模板来创建新工作流。该模板通过添加基本触发器和活动来为你提供一个起点。这将自动向工作流中添加一个 Office 365 Outlook 触发器。
-
点击触发器上的登录按钮,它将打开一个新的 Internet Explorer 窗口。然后,登录到你的账户。成功登录后,将创建一个新的 Office 365 邮件连接器,包含连接到账户的相关信息。
-
点击继续按钮,并将触发器配置为每 3 分钟轮询一次,如图 11.2所示:
图 11.2:配置触发器为 3 分钟轮询频率
-
在搜索栏中点击
variable
。然后,选择初始化变量操作,如图 11.3所示:图 11.3:添加初始化变量操作
-
接下来,配置变量操作。当点击值框时,会弹出一个窗口,显示动态内容和表达式。动态内容是指当前操作可用的属性,并填充来自先前操作和触发器的运行时值。变量有助于保持工作流的通用性。从此窗口中,选择动态内容中的正文:
图 11.4:配置变量操作
-
通过点击搜索栏中的
outlook
,然后选择回复电子邮件操作,添加另一个操作:图 11.5:添加回复电子邮件操作
-
配置新操作。确保消息 ID已设置为动态内容,消息 ID,然后在评论框中输入你希望发送给收件人的回复:
图 11.6:配置回复电子邮件操作
-
添加另一个操作,在搜索栏中输入
text analytics
,然后选择检测情感(预览):图 11.7:添加检测情感(预览)操作
-
按照图 11.8中的示例配置情感操作——此处应使用端点和密钥值。现在点击创建按钮,如图 11.8所示:
图 11.8:配置检测情感(预览)操作
-
通过添加动态内容并选择之前创建的变量emailContent,向操作提供文本。然后,点击显示高级选项,并为语言选择en:
图 11.9:选择情感操作的语言
-
接下来,通过选择Outlook并选择发送电子邮件来添加一个新操作。此操作会将包含情感评分的电子邮件内容发送给原始收件人,并将其作为主题。它应该如图 11.10所示进行配置。如果动态内容窗口中未显示评分,请点击旁边的查看更多链接:
图 11.10:添加发送电子邮件操作
-
保存逻辑应用,返回概述页面,然后点击运行触发器。该触发器每隔 3 分钟检查一次新邮件,回复发件人,执行情感分析,并将电子邮件发送给原始收件人。一个包含负面含义的电子邮件样本会发送到指定的电子邮件 ID:
图 11.11:电子邮件示例
-
几秒钟后,逻辑应用执行,发件人收到以下回复:
图 11.12:回复原始发件人的电子邮件
-
原始收件人收到包含情感评分和原始邮件文本的电子邮件,如图 11.13所示:
图 11.13:电子邮件消息的 HTML 视图
通过这个活动,我们了解了逻辑应用的工作原理。当用户的收件箱收到电子邮件时,应用会被触发,随后流程按照逻辑应用中给定的步骤顺序执行。在下一节中,您将学习如何使用无服务器技术创建端到端解决方案。
使用无服务器技术创建端到端解决方案
在本节中,我们将创建一个端到端解决方案,包含我们在前几节中讨论的无服务器技术。以下示例将帮助您了解如何智能地实现工作流,避免管理开销。在接下来的活动中,我们将创建一个工作流,当密钥、机密和证书存储在 Azure Key Vault 中时,通知用户。我们将以此为问题陈述,找出解决方案,架构解决方案,并实现它。
问题陈述
我们要解决的问题是,用户和组织未收到关于其密钥保管库中密钥过期的通知,且密钥过期后应用程序会停止工作。用户抱怨 Azure 没有提供监控 Key Vault 密钥、机密和证书的基础设施。
解决方案
解决这个问题的方法是将多个 Azure 服务组合并集成,以便用户能主动收到密钥过期的通知。该解决方案将通过电子邮件和短信两种渠道发送通知。
用于创建此解决方案的 Azure 服务包括:
-
Azure 密钥库
-
Azure 活动目录(Azure AD)
-
Azure 事件网格
-
Azure 自动化
-
逻辑应用
-
Azure 函数
-
SendGrid
-
Twilio 短信
现在您已经了解了解决方案中将使用的服务,让我们开始为这个解决方案创建架构。
架构
在上一节中,我们探索了将用于解决方案的服务列表。如果我们要实现该解决方案,这些服务应按正确的顺序布局。架构将帮助我们开发工作流,并让我们更接近解决方案。
该解决方案的架构由多个服务组成,如图 11.14所示:
图 11.14:解决方案架构
让我们逐一了解这些服务,并理解它们在整个解决方案中提供的角色和功能。
Azure 自动化
Azure 自动化提供了运行簿,这些运行簿可以执行逻辑,使用 PowerShell、Python 以及其他脚本语言。脚本可以在本地或云端执行,这为创建脚本提供了丰富的基础设施和工具。这些脚本被称为运行簿。通常,运行簿实现的场景包括停止或启动虚拟机,或创建和配置存储帐户。通过资产如变量、证书和连接,连接到 Azure 环境变得非常简单。
在当前的解决方案中,我们希望连接到 Azure 密钥库,读取其中存储的所有机密和密钥,并获取它们的到期日期。这些到期日期应与今天的日期进行比较,如果到期日期在一个月内,则运行簿应使用事件网格自定义主题在事件网格上触发一个自定义事件。
将实现一个使用 PowerShell 脚本的 Azure 自动化运行簿。与运行簿一起,还将创建一个调度器,每天在凌晨 12:00 执行该运行簿。
自定义 Azure 事件网格主题
一旦运行簿识别到某个机密或密钥将在一个月内到期,它将触发一个新的自定义事件,并将其发布到专门为此目的创建的自定义主题上。我们将在下一节中详细介绍实现的细节。
Azure 逻辑应用
逻辑应用是一种无服务器服务,提供工作流功能。我们的逻辑应用将被配置为在自定义 Event Grid 主题上发布事件时触发。触发后,它将调用工作流并依次执行其中的所有活动。通常,工作流中有多个活动,但为了本例的目的,我们将调用一个 Azure 函数,发送电子邮件和短信通知。在全面实施中,这些通知功能应该在单独的 Azure 函数中分别实现。
Azure Functions
使用 Azure Functions 通知用户和利益相关者有关机密和密钥过期的信息,通过电子邮件和短信发送通知。使用 SendGrid 发送电子邮件,Twilio 用于通过 Azure Functions 发送短信。
在下一部分,我们将了解实施解决方案之前的先决条件。
先决条件
您至少需要一个具有贡献者权限的 Azure 订阅。由于我们仅将服务部署到 Azure,并且没有部署外部服务,因此订阅是唯一的先决条件。现在让我们开始实施解决方案。
实施
应该已经存在一个密钥库。如果没有,需要创建一个。
如果需要配置一个新的 Azure Key Vault 实例,则应该执行此步骤。Azure 提供了多种方式来配置资源,其中突出的方式有 Azure PowerShell 和 Azure CLI。Azure CLI 是一个跨平台的命令行接口。首要任务是配置一个 Azure 密钥库。在本次实施中,我们将使用 Azure PowerShell 来配置密钥库。
在使用 Azure PowerShell 创建密钥库之前,重要的是要登录 Azure,以便后续的命令能够成功执行以创建密钥库。
步骤 1:配置 Azure Key Vault 实例
第一步是为示例准备环境。这包括登录 Azure 门户,选择合适的订阅,然后创建一个新的 Azure 资源组和一个新的 Azure Key Vault 资源:
-
执行
Connect-AzAccount
命令以登录 Azure。系统会在新窗口中提示输入凭据。 -
成功登录后,如果提供的登录 ID 有多个订阅,它们都会列出。需要选择一个合适的订阅——可以通过执行
Set-AzContext
cmdlet 来完成:Set-AzContext -SubscriptionId xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx
-
在您选择的区域创建一个新的资源组。此处的资源组名称为
IntegrationDemo
,并且它被创建在西欧
区域:New-AzResourceGroup -Name IntegrationDemo -Location "West Europe" -Verbose
-
创建一个新的 Azure Key Vault 资源——此处的密钥库名称为
keyvaultbook
,并且启用了部署、模板部署、磁盘加密、软删除和清除保护功能:New-AzKeyVault -Name keyvaultbook -ResourceGroupName IntegrationDemo -Location "West Europe" -EnabledForDeployment -EnabledForTemplateDeployment -EnabledForDiskEncryption -EnablePurgeProtection -Sku Standard - Verbose
请注意,密钥库名称需要是唯一的。您可能无法为两个密钥库使用相同的名称。成功执行前面的命令后,将创建一个新的 Azure 密钥库资源。下一步是为服务主体提供对密钥库的访问权限。
步骤 2:创建服务主体
Azure 提供服务主体,而不是使用个人账户连接到 Azure,服务主体本质上是服务账户,可以用于连接到 Azure 资源管理器并执行活动。将用户添加到 Azure 目录/租户后,由于 Azure 安全继承的性质,用户在所有资源组和资源中都可用。若不允许用户访问某些资源组,必须显式地从这些资源组中撤销访问权限。服务主体通过分配细粒度的访问权限和控制权限来提供帮助,必要时,可以授予它们订阅级别的访问权限。它们还可以被分配细粒度的权限,如读取者、贡献者或所有者权限。
简而言之,服务主体应成为使用 Azure 服务的首选机制。它们可以通过密码或证书密钥进行配置。可以使用 New-AzAdServicePrinicipal
命令创建服务主体,如下所示:
$sp = New-AzADServicePrincipal -DisplayName "keyvault-book" -Scope "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" -Role Owner -StartDate ([datetime]::Now) -EndDate $([datetime]::now.AddYears(1)) -Verbose
重要的配置值是范围和角色。范围决定了服务应用的访问区域——当前显示的是在订阅级别。范围的有效值如下:
/subscriptions/{subscriptionId}/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{parentResourcePath}/{resourceType}/{resourceName}
该角色为分配的范围提供权限。有效值如下:
-
所有者
-
贡献者
-
读取者
-
特定资源权限
在前面的命令中,已将所有者权限提供给新创建的服务主体。
如果需要,我们也可以使用证书。为了简化起见,我们将继续使用密码。
使用我们创建的服务主体时,密钥将被隐藏。要查看密钥,您可以尝试以下命令:
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($sp. Secret)
$UnsecureSecret = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
$UnsecureSecret
将包含您的密钥。
与服务主体一起,将创建一个应用程序目录应用。该应用程序作为我们应用在各个目录中的全局表示,服务主体则像是该应用的本地表示。我们可以使用相同的应用在不同目录中创建多个服务主体。我们可以使用 Get-AzAdApplication
命令获取所创建应用程序的详细信息。我们将该命令的输出保存到一个变量 $app
中,因为稍后我们需要用到它:
$app = Get-AzAdApplication -DisplayName $sp.DisplayName
我们现在已经使用密钥创建了一个服务主体;创建服务主体的另一种安全方式是使用证书。在接下来的部分,我们将使用证书创建服务主体。
步骤 3:使用证书创建服务主体
要使用证书创建服务主体,应执行以下步骤:
-
创建自签名证书或购买证书:自签名证书用于创建此示例的端到端应用程序。对于实际部署,应该从证书授权机构购买有效的证书。
要创建一个自签名证书,可以运行以下命令。自签名证书是可导出的,并存储在本地机器的个人文件夹中——它也有一个到期日期:
$currentDate = Get-Date $expiryDate = $currentDate.AddYears(1)$finalDate = $expiryDate.AddYears(1)$servicePrincipalName = "https://automation.book.com"$automationCertificate = New-SelfSignedCertificate -DnsName $servicePrincipalName -KeyExportPolicy Exportable -Provider "Microsoft Enhanced RSA and AES Cryptographic Provider" -NotAfter $finalDate -CertStoreLocation "Cert:\LocalMachine\My"
-
Get-Item
cmdlet 从证书存储中读取证书并将其存储在$cert1
变量中。Export-PfxCertificate
cmdlet 实际上将证书从证书存储导出到文件系统中。在此案例中,它位于C:\book
文件夹中。 -
X509Certificate2
被创建用于在内存中保存证书,并且数据通过System.Convert
函数转换为 Base64 字符串:$newCert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 -ArgumentList "C:\azureautomation.pfx", $securepfxpwd $newcertdata = [System.Convert]::ToBase64String($newCert.GetRawCertData())
我们将使用相同的服务主体从 Azure 自动化帐户连接到 Azure。重要的是,应用程序 ID、租户 ID、订阅 ID 和证书指纹值需要存储在临时位置,以便用于配置后续资源:
$adAppName = "azure-automation-sp"$ServicePrincipal = New-AzADServicePrincipal -DisplayName $adAppName -CertValue $newcertdata -StartDate $newCert.NotBefore -EndDate $newCert.NotAfter Sleep 10 New-AzRoleAssignment -ServicePrincipalName $ServicePrincipal.ApplicationId -RoleDefinitionName Owner -Scope /subscriptions/xxxxx-xxxxxxx-xxxxxx-xxxxxxx
我们已经准备好服务主体。我们创建的密钥保管库没有设置访问策略,这意味着没有用户或应用程序能够访问该保管库。在接下来的步骤中,我们将授予我们创建的应用程序目录应用程序访问密钥保管库的权限。
步骤 4:创建密钥保管库策略
在此阶段,我们已经创建了服务主体和密钥保管库。然而,服务主体仍然没有访问密钥保管库的权限。这个服务主体将用于查询并列出密钥保管库中的所有机密、密钥和证书,它应该拥有执行此操作所需的权限。
为了为新创建的服务主体提供访问密钥保管库的权限,我们将返回 Azure PowerShell 控制台并执行以下命令:
Set-AzKeyVaultAccessPolicy -VaultName keyvaultbook -ResourceGroupName IntegrationDemo -ObjectId $ServicePrincipal.Id -PermissionsToKeys get,list,create -PermissionsToCertificates get,list,import -PermissionsToSecrets get,list -Verbose
参考之前的命令块,请查看以下几点:
Set-AzKeyVaultAccessPolicy
提供对用户、组和服务主体的访问权限。它接受密钥保管库名称和服务主体的对象 ID。这个对象与应用程序 ID 不同。服务主体的输出包含Id
属性,如下所示:
图 11.15:查找服务主体的对象 ID
-
PermissionsToKeys
提供对密钥保管库中密钥的访问权限,且为该服务主体提供了get
、list
和create
权限。没有为该主体提供写入或更新权限。 -
PermissionsToSecrets
提供对密钥保管库中机密的访问权限,get
和list
权限已授予此服务主体。此服务主体没有提供写入或更新权限。 -
PermissionsToCertificates
提供对密钥保管库中机密的访问权限,并且get
、import
和list
权限已授予此服务主体。此服务主体没有提供写入或更新权限。
此时,我们已配置服务主体以便与 Azure 密钥保管库一起使用。解决方案的下一部分是创建一个自动化帐户。
步骤 5:创建自动化帐户
就像之前一样,我们将使用 Azure PowerShell 在资源组中创建一个新的 Azure 自动化帐户。在创建资源组和自动化帐户之前,应该先建立与 Azure 的连接。不过,这次,我们将使用服务主体的凭据连接到 Azure。步骤如下:
-
使用服务应用程序连接到 Azure 的命令如下。该值来自我们在之前步骤中初始化的变量:
Login-AzAccount -ServicePrincipal -CertificateThumbprint $newCert.Thumbprint -ApplicationId $ServicePrincipal.ApplicationId -Tenant "xxxx-xxxxxx-xxxxx-xxxxx"
-
通过检查
Get-AzContext
来确保你有权限,如下所示。记下订阅 ID,因为后续命令需要用到它:Get-AzContext
-
连接到 Azure 后,应该创建一个包含解决方案资源的新资源以及一个新的 Azure 自动化帐户。你将资源组命名为
VaultMonitoring
,并在West Europe
区域创建它。其余资源也将创建在此资源组中:$IntegrationResourceGroup = "VaultMonitoring"$rgLocation = "West Europe"$automationAccountName = "MonitoringKeyVault"New-AzResourceGroup -name $IntegrationResourceGroup -Location $rgLocation New-AzAutomationAccount -Name $automationAccountName -ResourceGroupName $IntegrationResourceGroup -Location $rgLocation -Plan Free
-
接下来,创建三个自动化变量。它们的值,即订阅 ID、租户 ID 和应用程序 ID,应该已经通过之前的步骤获得:
New-AzAutomationVariable -Name "azuresubscriptionid" -AutomationAccountName $automationAccountName -ResourceGroupName $IntegrationResourceGroup -Value " xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx " -Encrypted $true New-AzAutomationVariable -Name "azuretenantid" -AutomationAccountName $automationAccountName -ResourceGroupName $IntegrationResourceGroup -Value " xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx " -Encrypted $true New-AzutomationVariable -Name "azureappid" -AutomationAccountName $automationAccountName -ResourceGroupName $IntegrationResourceGroup -Value " xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx " -Encrypted $true
-
现在是时候上传证书了,这个证书将用于从 Azure 自动化连接到 Azure:
$securepfxpwd = ConvertTo-SecureString -String 'password' -AsPlainText -Force # Password for the private key PFX certificate New-AzAutomationCertificate -Name "AutomationCertifcate" -Path "C:\book\azureautomation.pfx" -Password $securepfxpwd -AutomationAccountName $automationAccountName -ResourceGroupName $IntegrationResourceGroup
-
下一步是安装与密钥保管库和事件网格相关的 PowerShell 模块,因为这些模块默认没有安装。
-
从 Azure 门户,点击左侧菜单中的 资源组,然后导航到已经创建的
VaultMonitoring
资源组。 -
点击已经配置的 Azure 自动化帐户,
Az.profile
模块,所以我们必须先安装它,然后再安装事件网格模块。 -
如 图 11.16 所示,在搜索框中点击
Az.profile
:图 11.16:模块库中的 Az.Profile 模块
-
从搜索结果中,选择
Az.Profile
,然后点击顶部菜单中的 导入 按钮。最后,点击 确定 按钮。此步骤需要几秒钟完成。几秒钟后,模块应已安装。 -
可以从 模块 菜单项检查安装状态。图 11.17 展示了如何导入模块:
图 11.17:Az.Profile 模块状态
-
请再次执行步骤 9、步骤 10和步骤 11,以导入和安装
Az.EventGrid
模块。如果在继续操作之前出现安装任何依赖项的提示,请先安装这些依赖项。 -
请再次执行步骤 9、步骤 10和步骤 11,以导入和安装
Az.KeyVault
模块。如果在继续操作之前出现安装任何依赖项的提示,请先安装这些依赖项。
由于我们已经导入了必要的模块,接下来让我们创建 Event Grid 主题。
步骤 6:创建 Event Grid 主题
如果你还记得我们使用的架构,我们需要一个 Event Grid 主题。让我们来创建一个。
使用 PowerShell 创建 Event Grid 主题的命令如下:
New-AzEventGridTopic -ResourceGroupName VaultMonitoring -Name azureforarchitects-topic -Location "West Europe"
使用 Azure 门户创建 Event Grid 主题的过程如下:
-
在 Azure 门户中,点击左侧菜单中的资源组,然后导航到已创建的
Vaultmonitoring
资源组。 -
接下来,在搜索框中点击
Event Grid Topic
。选择它后,点击创建按钮。 -
在生成的表单中填写适当的值,包括提供名称、选择订阅、选择新创建的资源组、位置和事件架构。
正如我们之前讨论的,Event Grid 主题提供了一个端点,源系统将通过该端点发送数据。既然我们已经准备好主题,接下来让我们准备源 Automation 帐户。
步骤 7:设置 Runbook
这一步将重点介绍如何创建 Azure Automation 帐户和 PowerShell Runbooks,这些 Runbooks 包含读取 Azure 密钥保管库并检索其中存储的秘密的核心逻辑。配置 Azure Automation 所需的步骤如下:
-
通过点击左侧菜单中的资源组来访问
Vaultmonitoring
资源组。 -
点击已配置好的 Azure Automation 帐户
MonitoringKeyVault
,然后在左侧菜单中点击Runbooks,再点击顶部菜单中的+添加 Runbook。 -
点击创建新 Runbook并提供一个名称。我们将这个 Runbook 命名为CheckExpiredAssets,然后将Runbook 类型设置为PowerShell:
图 11.18:创建 Runbook
-
AutomationCertifcate
。这些值会从这些存储中获取并赋给变量,如下所示:$subscriptionID = get-AutomationVariable "azuresubscriptionid"$tenantID = get-AutomationVariable "azuretenantid"$applicationId = get-AutomationVariable "azureappid"$cert = get-AutomationCertificate "AutomationCertifcate"$certThumbprint = ($cert.Thumbprint).ToString()
-
Runbook 中的下一段代码帮助使用之前声明的变量中的值,通过服务主体登录到 Azure。同时,代码还会选择一个合适的订阅。代码如下所示:
Login-AzAccount -ServicePrincipal -CertificateThumbprint $certThumbprint -ApplicationId $applicationId -Tenant $tenantID Set-AzContext -SubscriptionId $subscriptionID
由于 Azure Event Grid 已在本节的步骤 6中进行了配置,因此可以使用
Get-AzEventGridTopic
和Get-AzEventGridTopicKey
cmdlet 来检索其端点和密钥。Azure Event Grid 会生成两个密钥——一个主密钥和一个辅助密钥。第一个密钥的引用如下:
$eventGridName = "ExpiredAssetsKeyVaultEvents"$eventGridResourceGroup = "VaultMonitoring"$topicEndpoint = (Get-AzEventGridTopic -ResourceGroupName $eventGridResourceGroup -Name $eventGridName).Endpoint $keys = (Get-AzEventGridTopicKey -ResourceGroupName $eventGridResourceGroup -Name $eventGridName ).Key1
-
接下来,使用迭代检索订阅中所有已配置的密钥库。在循环过程中,使用
Get-AzKeyVaultSecret
cmdlet 检索所有机密。每个机密的过期日期与当前日期进行比较,如果差异小于一个月,则生成一个 Event Grid 事件,并使用
invoke-webrequest
命令发布。对于存储在密钥库中的证书,执行相同的步骤。用于检索所有证书的 cmdlet 是
Get-AzKeyVaultCertificate
。发布到 Event Grid 的事件应为 JSON 数组。生成的消息通过
ConvertTo-Json
cmdlet 转换为 JSON,然后通过添加[
和]
作为前缀和后缀转换为数组。为了连接到 Azure Event Grid 并发布事件,发送方应在其请求头中提供密钥。如果请求负载中缺少此数据,请求将失败:
$keyvaults = Get-AzureRmKeyVault foreach($vault in $keyvaults) {$secrets = Get-AzureKeyVaultSecret -VaultName $vault.VaultName foreach($secret in $secrets) {if( ![string]::IsNullOrEmpty($secret.Expires) ) {if($secret.Expires.AddMonths(-1) -lt [datetime]::Now){$secretDataMessage = @{id = [System.guid]::NewGuid()subject = "Secret Expiry happening soon !!"eventType = "Secret Expiry"eventTime = [System.DateTime]::UtcNow data = @{"ExpiryDate" = $secret.Expires "SecretName" = $secret.Name.ToString()"VaultName" = $secret.VaultName.ToString()"SecretCreationDate" = $secret.Created.ToString()"IsSecretEnabled" = $secret.Enabled.ToString()"SecretId" = $secret.Id.ToString()}}...Invoke-WebRequest -Uri $topicEndpoint -Body $finalBody -Headers $header -Method Post -UseBasicParsing }}Start-Sleep -Seconds 5 }}
-
点击发布按钮发布运行手册,如图 11.19所示:
图 11.19:发布运行手册
-
调度器:创建一个 Azure Automation 调度器资产,使此运行手册每天在午夜 12:00 执行一次。点击 Azure Automation 左侧菜单中的调度,然后在顶部菜单中点击+添加调度。
-
在生成的表单中提供调度信息。
这应该完成 Azure Automation 帐户的配置。
步骤 8:与 SendGrid 合作
在本步骤中,我们将创建一个新的 SendGrid 资源。SendGrid 资源用于从应用程序发送电子邮件,而无需安装简单邮件传输协议(SMTP)服务器。它提供一个 REST API 和一个 C# 软件开发工具包(SDK),通过这些工具,发送批量电子邮件变得非常容易。在当前的解决方案中,将使用 Azure Functions 来调用 SendGrid API 发送电子邮件,因此需要配置此资源。该资源有单独的费用,并不包括在 Azure 成本中—可以使用一个免费的层级来发送电子邮件:
-
SendGrid
资源的创建方式与其他 Azure 资源相同。搜索sendgrid
,我们将在结果中看到SendGrid 电子邮件投递。 -
选择资源并点击创建按钮以打开其配置表单。
-
选择一个合适的定价层。
-
提供适当的联系信息。
-
勾选使用条款复选框。
-
完成表单后,点击创建按钮。
-
在资源配置后,点击顶部菜单中的管理按钮—这将打开 SendGrid 网站。网站可能会请求进行电子邮件配置。然后,从设置部分选择API 密钥,并点击创建 API 密钥按钮:
图 11.20:为 SendGrid 创建 API 密钥
-
在弹出的窗口中,选择Full Access并点击Create & View按钮。这将为 SendGrid 资源创建密钥;请记下此密钥,因为它将在 Azure Functions 配置中与 SendGrid 一起使用:
图 11.21:在 SendGrid 门户中设置访问级别
现在我们已经配置好了 SendGrid 的访问级别,接下来让我们配置另一个第三方服务,即 Twilio。
步骤 9:开始使用 Twilio
在此步骤中,我们将创建一个新的 Twilio 帐户。Twilio 用于发送批量短信。要在 Twilio 上创建帐户,请导航到twilio.com并创建一个新帐户。成功创建帐户后,会生成一个可以用来向接收者发送短信的手机号码:
图 11.22:选择 Twilio 号码
Twilio 帐户提供生产和测试密钥。将测试密钥和令牌复制到临时位置(例如记事本),因为稍后在 Azure Functions 中将需要它们:
图 11.23:设置 Twilio
我们已经为通知服务配置好了 SendGrid 和 Twilio;然而,我们还需要一些东西来接收事件并通知用户。这就是功能应用程序的作用。在接下来的部分中,我们将创建一个功能应用程序,它将有助于发送短信和电子邮件。
步骤 10:设置功能应用程序
在此步骤中,我们将创建一个新的功能应用程序,用于发送电子邮件和短信通知。功能应用程序在解决方案中的作用是向用户发送关于密钥库中机密到期的通知消息。一个功能将负责发送电子邮件和短信消息——请注意,这本可以分成两个独立的功能。第一步是创建一个新的功能应用程序,并在其中托管一个功能:
-
如我们之前所做,导航到资源组,点击
function app
资源。然后点击Create按钮以获取Function App表单。 -
填写Function App表单并点击Create按钮。功能应用程序的名称必须在 Azure 中是唯一的。
-
一旦功能应用程序被配置好,点击左侧菜单中Functions项目旁的+按钮,创建一个名为
SMSandEMailFunction
的新功能。然后,在中央仪表盘中选择In-portal。 -
选择
SMSandEMailFunction
。然后点击Create按钮——Authorization level选项可以是任何值。 -
移除默认代码,替换为以下清单中显示的代码,然后点击顶部菜单中的保存按钮:
#r "SendGrid"#r "Newtonsoft.Json"#r "Twilio.Api"using System.Net;using System;using SendGrid.Helpers.Mail;using Microsoft.Azure.WebJobs.Host;using Newtonsoft.Json;using Twilio;using System.Configuration;public static HttpResponseMessage Run(HttpRequestMessage req, TraceWriter log, out Mail message,out SMSMessage sms){log.Info("C# HTTP trigger function processed a request.");string alldata = req.Content.ReadAsStringAsync().GetAwaiter().GetResult();message = new Mail();var personalization = new Personalization();personalization.AddBcc(new Email(ConfigurationManager.AppSettings["bccStakeholdersEmail"]));personalization.AddTo(new Email(ConfigurationManager.AppSettings["toStakeholdersEmail"]));var messageContent = new Content("text/html", alldata);message.AddContent(messageContent);message.AddPersonalization(personalization);message.Subject = "Key Vault assets Expiring soon..";message.From = new Email(ConfigurationManager.AppSettings["serviceEmail"]);string msg = alldata;sms = new SMSMessage();sms.Body = msg;sms.To = ConfigurationManager.AppSettings["adminPhone"];sms.From = ConfigurationManager.AppSettings["servicePhone"];return req.CreateResponse(HttpStatusCode.OK, "Hello ");}
-
点击左侧菜单中的函数应用名称,然后再次点击主窗口中的应用程序设置链接:
图 11.24:导航到应用程序设置
-
导航到
adminPhone
和servicePhone
,这两个号码应该已经在 Twilio 网站上配置。servicePhone
是由 Twilio 生成的用于发送短信的电话号码,adminPhone
是管理员的电话号码,短信将发送到该号码。还要注意,Twilio 要求目标电话号码根据国家/地区采用特定格式(例如,印度的格式是
+91 xxxxx xxxxx
)。请注意号码中的空格和国家代码。我们还需要在应用程序设置中添加 SendGrid 和 Twilio 的密钥。这些设置在以下清单中提到。你可能已经通过之前的步骤获取了这些值:
-
SendGridAPIKeyAsAppSetting
的值是 SendGrid 的密钥。 -
TwilioAccountSid
是 Twilio 账户的系统标识符。该值已在步骤 9:开始使用 Twilio中复制并存储在临时位置。 -
TwilioAuthToken
是 Twilio 账户的令牌。该值已在之前的步骤中复制并存储在临时位置。
-
-
通过点击顶部菜单中的保存按钮保存设置:
图 11.25:配置应用程序设置
-
点击左侧菜单中函数名称下方的集成链接,然后点击+ 新输出。这是为了为 SendGrid 服务添加输出:
图 11.26:向函数应用添加输出
-
接下来,选择SendGrid;系统可能会要求你安装 SendGrid 扩展。安装扩展,这可能需要几分钟:
图 11.27:配置函数应用
-
安装扩展后,输出配置表单将出现。表单中的重要配置项是消息参数名称和SendGrid API 密钥应用设置。保持消息参数名称的默认值,然后点击下拉列表选择SendGridAPIKeyAsAppSetting作为 API 应用设置密钥。该配置已在应用设置配置的前一步中完成。表单应按图 11.28所示进行配置,然后点击保存按钮:
图 11.28:设置 SendGrid
-
再次点击+ 新建输出;这是为了为 Twilio 服务添加输出。
-
然后,选择Twilio SMS。系统可能会提示你安装 Twilio SMS 扩展。安装该扩展,安装过程大约需要几分钟。
-
安装扩展后,输出配置表单会出现。此表单中的重要配置项是
sms
。这样做是因为message
参数已经被用于 SendGrid 服务参数。确保TwilioAccountSid
的值以及Auth Token 设置的值是TwilioAuthToken。这些值在应用设置配置的前一个步骤中已经配置过了。该表单应该按图 11.29的示例进行配置,然后点击保存:
图 11.29:设置 Twilio SMS 输出
我们的 SendGrid 和 Twilio 账户已准备好。现在是时候使用连接器并将其添加到逻辑应用中。在接下来的部分,我们将创建逻辑应用,并使用连接器与我们迄今为止创建的资源进行交互。
步骤 11:创建逻辑应用
在此步骤中,我们将创建一个新的逻辑应用工作流。我们已经编写了一个 Azure 自动化运行簿,它查询所有密钥保管库中的密钥,并在发现其中任何密钥将在一个月内到期时发布事件。逻辑应用的工作流作为这些事件的订阅者:
-
逻辑应用菜单中的第一步是创建一个逻辑应用工作流。
-
点击创建按钮后填写弹出的表单。我们正在将逻辑应用配置到与该解决方案其他资源相同的资源组中。
-
在逻辑应用被配置后,它将打开设计器窗口。请选择空白逻辑应用,该选项位于模板部分。
-
在弹出的窗口中,添加一个可以订阅 Event Grid 的触发器。逻辑应用提供了一个 Event Grid 触发器,你可以搜索它以查看是否可用。
-
接下来,选择当资源事件发生时(预览)触发器:
图 11.30:从 Event Grid 选择触发器
-
在弹出的窗口中,选择与服务主体连接。
提供服务主体详细信息,包括应用 ID(客户端 ID)、租户 ID 和密码。此触发器不接受使用证书进行身份验证的服务主体,它仅接受使用密码的服务主体。在此阶段创建一个使用密码进行身份验证的新服务主体(有关基于密码身份验证的服务主体创建步骤,请参考之前的第 2 步),并使用新创建的服务主体的详细信息进行 Azure Event Grid 配置,如图 11.31所示:
图 11.31:提供服务主体的连接详细信息
-
选择订阅。根据服务主体的范围,相关内容会自动填充。选择Microsoft.EventGrid.Topics作为资源类型值,并将自定义主题的名称设置为ExpiredAssetsKeyVaultEvents:
图 11.32:提供事件网格触发器详细信息
-
上一步将创建一个连接器,连接信息可以通过点击更改连接来修改。
-
事件网格触发器的最终配置应类似于图 11.33:
图 11.33:事件网格触发器概览
-
在事件网格触发器后添加一个新的解析 JSON活动——此活动需要 JSON 架构。通常,架构不可用,但如果提供有效的 JSON,它会帮助生成架构:
图 11.34:解析 JSON 活动
-
点击使用示例负载生成架构并提供以下数据:
{"ExpiryDate": "","SecretName": "","VaultName": "","SecretCreationDate": "","IsSecretEnabled": "","SecretId": ""}
这里可能会有一个问题,关于示例负载。在此阶段,如何计算事件网格发布者生成的负载?答案在于这个示例负载与在 Azure 自动化运行簿中数据元素所使用的完全相同。你可以再次查看那个代码片段:
data = @{"ExpiryDate" = $certificate.Expires "CertificateName" = $certificate.Name.ToString()"VaultName" = $certificate.VaultName.ToString()"CertificateCreationDate" = $certificate.Created.ToString()"IsCertificateEnabled" = $certificate.Enabled.ToString()"CertificateId" = $certificate.Id.ToString()}
-
内容框应包含来自先前触发器的动态内容,如图 11.35所示:
图 11.35:将动态内容提供给解析 JSON 活动
-
在解析 JSON后添加另一个Azure Functions操作,然后选择选择 Azure 函数。选择先前创建的名为NotificationFunctionAppBook和SMSAndEmailFunction的 Azure 函数应用:
图 11.36:添加 Azure Functions 操作
-
点击请求正文文本区域,并用以下代码填充它。这是为了在将数据发送到 Azure 函数之前将其转换为 JSON:
{"alldata" :}
-
将光标放在前述代码中的
":"
后,点击添加动态内容 | 正文,从先前的活动中获取:图 11.37:在将数据发送到 Azure 函数之前将数据转换为 JSON
-
保存整个逻辑应用程序,它应如下所示:
图 11.38:逻辑应用程序工作流
一旦保存了逻辑应用程序,您的解决方案就准备好进行测试。如果没有密钥或机密,请尝试添加具有过期日期的密钥或机密,以便您可以确认解决方案是否正常工作。
测试
将一些具有过期日期的机密和证书上传到 Azure Key Vault,并执行 Azure 自动化运行簿。该运行簿已安排按计划运行。此外,运行簿还将向 Event Grid 发布事件。逻辑应用程序应启用,它会捕捉到事件,并最终调用 Azure 函数以发送电子邮件和短信通知。
电子邮件应如下所示:
图 11.39:关于即将过期密钥的电子邮件
在本练习中,我们遇到了一个问题,设计了一个解决方案并加以实施。这正是架构师角色中会发生的事情。客户会提出具体的需求,基于这些需求,您必须开发解决方案。基于此,我们即将结束本章内容。让我们快速回顾一下我们讨论过的内容。
总结
本章介绍了逻辑应用程序,并展示了使用多个 Azure 服务的完整端到端解决方案。本章重点介绍了创建集成多个 Azure 服务的架构,以实现端到端解决方案。解决方案中使用的服务包括 Azure 自动化、Azure 逻辑应用程序、Azure 事件网格、Azure 函数、SendGrid 和 Twilio。这些服务通过 Azure 门户和 PowerShell 实现,并使用服务主体作为服务帐户。本章还展示了多种使用密码和证书身份验证创建服务主体的方法。
解决问题的方法有多种。您可以在逻辑应用程序中使用 Outlook 触发器,而不是 SendGrid。一个问题有许多解决方案,选择哪一种取决于您采取的方案。您对服务越熟悉,选择的余地就越大。在下一章中,您将学习到事件在 Azure 和 Azure 应用程序架构中的重要性。
第十二章:12. Azure 大数据事件解决方案
事件无处不在!任何改变工作项状态的活动或任务都会生成一个事件。由于基础设施不足以及廉价设备的缺乏,物联网(IoT)此前并未获得太多关注。从历史上看,组织使用的是来自互联网服务提供商(ISP)的托管环境,这些环境上仅有监控系统。这些监控系统产生的事件少之又少。
然而,随着云计算的兴起,事物正在迅速变化。随着云端部署的增加,尤其是平台即服务(PaaS)服务的普及,组织不再需要过多地控制硬件和平台,每当环境发生变化时,都会触发一个事件。随着云事件的出现,物联网变得越来越重要,事件也开始成为中心。
另一个最近的现象是数据可用性迅速增长。数据的速度、种类和数量急剧增加,存储和处理数据的需求也随之上升。多个解决方案和平台相继出现,例如 Hadoop、用于存储的数据湖、用于分析的数据湖和机器学习服务。
除了存储和分析外,还有一种需求是能够从各种来源摄取成千上万事件和消息的服务。还需要能够处理时间数据的服务,而不是处理整个数据快照的服务。例如,事件数据/物联网数据被用于做出基于实时或近实时数据的决策的应用程序,例如交通管理系统或监控温度的系统。
Azure 提供了大量帮助捕获和分析传感器实时数据的服务。在本章中,我们将介绍 Azure 中的几种事件服务,具体如下:
-
Azure Event Hubs
-
Azure Stream Analytics
还有其他事件服务,例如 Azure Event Grid,本章未涉及;然而,它们在第十章,使用 Azure 函数的 Azure 集成服务(耐久函数和代理函数)中有广泛介绍。
引入事件
事件是 Azure 和 Azure 应用架构中的重要构件。事件遍布整个软件生态系统。一般来说,任何采取的行动都会导致一个事件的发生,该事件可以被捕捉,然后采取进一步的行动。为了推动这个讨论,首先需要理解事件的基本概念。
事件有助于捕获目标资源的新状态。消息是条件或状态变化的轻量级通知。事件与消息不同。消息与业务功能相关,例如将订单详情发送到另一个系统。它们包含原始数据,并且可能很大。相比之下,事件则不同;例如,虚拟机被停止就是一个事件。图 12.1演示了从当前状态到目标状态的转变:
图 12.1:由于事件引起的状态转变
事件可以作为历史数据存储在持久存储中,事件还可以用来发现持续出现的模式。事件可以被视为不断流动的数据。为了捕获、摄取和分析一连串的数据,需要特定的基础设施组件,这些组件能够读取一小段数据并提供洞察力,这就是 Stream Analytics 服务的作用所在。
事件流处理
在数据流式传输过程中对事件进行处理,能够提供有关数据的实时洞察。时间窗口可以是 15 分钟或一小时——窗口由用户定义,并取决于要从数据中提取的洞察。例如,信用卡刷卡,每分钟会有成千上万次刷卡事件,欺诈检测可以在流式事件上进行,时间窗口为一到两分钟。
事件流处理指的是能够随时接受数据的服务,而不是按周期性接收数据。例如,事件流应能够随时接收设备发送的温度信息,而不是让数据在队列或暂存环境中等待。
事件流处理还具有在数据传输过程中查询数据的能力。这是暂时存储的数据,查询发生在移动数据上;因此,数据不是静态的。其他数据平台无法实现这一功能,它们只能查询已存储的数据,而无法查询刚刚摄取的临时数据。
事件流服务应能够轻松扩展,接受数百万甚至数十亿个事件。它们应具有高度可用性,使得源可以随时向其发送事件和数据。实时数据摄取并能够在这些数据上工作,而不是在其他位置存储的数据,是事件流处理的关键。
但当我们已经有了许多具备高级查询执行能力的数据平台时,为什么还需要事件流处理呢?事件流处理的主要优势之一是它提供实时洞察和信息,而这些信息的价值依赖于时间。几分钟或几小时后得到的相同信息可能就不那么有用了。让我们考虑一些处理传入数据非常重要的场景。这些场景是现有数据平台无法有效且高效解决的:
-
信用卡欺诈检测:应该在发生欺诈交易时及时进行。
-
来自传感器的遥测信息:对于发送环境关键信息的物联网设备,用户应在发现异常时及时收到通知。
-
实时仪表盘:事件流处理用于创建显示实时信息的仪表盘。
-
数据中心环境遥测:这将让用户知道是否有入侵、安保漏洞、组件故障等问题发生。
企业内应用事件流处理的可能性非常多,它的重要性无法过分强调。
Event Hubs
Azure Event Hubs 是一个流处理平台,提供与流式事件的获取和存储相关的功能。
它可以从多种来源获取数据;这些来源可以是物联网传感器或任何使用 Event Hubs 软件开发工具包 (SDK) 的应用程序。它支持多种协议来获取和存储数据。这些协议是行业标准,包括以下几种:
-
HTTP:这是一种无状态的选项,不需要活动会话。
-
高级消息队列协议 (AMQP):这需要一个活动会话(即通过套接字建立的连接),并与 传输层安全性 (TLS) 和 安全套接字层 (SSL) 一起使用。
-
Apache Kafka:这是一种类似于流分析的分布式流处理平台。然而,流分析旨在对来自多个数据源(如物联网传感器和网站)的数据流进行实时分析。
Event Hubs 是一个事件获取服务。它不能查询请求并将查询结果输出到其他位置。这是 Stream Analytics 的责任,后文将介绍。
要从门户创建 Event Hubs 实例,请在市场中搜索 Event Hubs 并点击 创建。选择一个订阅和现有的资源组(或创建一个新的)。为 Event Hubs 命名空间提供名称,选择首选的 Azure 区域进行托管,定价层级(后文将解释 Basic 或 Standard),以及吞吐量单元的数量(后文将解释):
图 12.2:创建 Event Hubs 命名空间
Event Hubs 作为一个 PaaS 服务,具有高度分布式、高可用性和高度可扩展性。
Event Hubs 提供以下两种 SKU 或定价层:
-
基础版:此 SKU 支持一个消费者组,并且可以保留消息 1 天。最多支持 100 个中介连接。
-
标准版:此 SKU 最多支持 20 个消费者组,能够保留消息 1 天,并且可以额外存储 7 天的消息。最多支持 1,000 个中介连接。还可以在此 SKU 中定义策略。
图 12.3展示了在创建新 Event Hubs 命名空间时可用的不同 SKU。它提供了选择适当定价层的选项,以及其他重要细节:
图 12.3:Event Hubs SKUs
吞吐量也可以在命名空间级别进行配置。命名空间是容器,由同一订阅和区域中的多个事件中心组成。吞吐量以吞吐量单元(TUs)来计算。每个 TU 提供:
-
每秒最多 1 MB 的入站流量,或者每秒最多 1,000 个入站事件和管理操作。
-
每秒最多 2 MB 的出站流量,或者每秒最多 4,096 个事件和管理操作。
-
最多可存储 84 GB 的存储空间。
TUs 的数量可以从 1 到 20 不等,并且按小时计费。
需要注意的是,Event Hubs 命名空间创建后无法更改 SKU。选择 SKU 之前需要进行充分的考虑和规划。规划过程应包括确定所需的消费者组数量以及感兴趣读取事件的应用程序数量。
此外,并非每个区域都提供标准版 SKU。在设计和实现 Event Hub 时应检查其可用性。检查区域可用性的 URL 是azure.microsoft.com/global-infrastructure/services/?products=event-hubs
。
Event Hubs 架构
Event Hubs 架构有三个主要组成部分:事件生产者、事件中心和事件消费者,如下图所示:
图 12.4:Event Hubs 架构
事件生产者生成事件并将其发送到事件中心。事件中心存储接收的事件,并将这些数据提供给事件消费者。事件消费者是对这些事件感兴趣的任何实体,它连接到事件中心以提取数据。
创建 Event Hubs 时必须先创建 Event Hubs 命名空间。Event Hubs 命名空间作为容器,可以托管多个事件中心。每个 Event Hubs 命名空间提供一个唯一的基于 REST 的端点,供客户端用于向 Event Hubs 发送数据。此命名空间与 Service Bus 组件(如主题和队列)所需的命名空间相同。
事件中心命名空间的连接字符串由其 URL、策略名称和密钥组成。以下代码块展示了一个示例连接字符串:
Endpoint=sb://demoeventhubnsbook.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=M/E4eeBsr7DAlXcvw6ziFqlSDNbFX6E49Jfti8CRkbA=
这个连接字符串可以在命名空间的共享访问签名(SAS)菜单项中找到。命名空间可以定义多个策略,每个策略具有不同的访问级别。访问级别如下:
-
管理:此选项可以从管理角度管理事件中心。它还具有发送和监听事件的权限。
-
发送:此选项可以将事件写入事件中心。
-
监听:此选项可以从事件中心读取事件。
默认情况下,在创建事件中心时会创建RootManageSharedAccessKey
策略,如图 12.5所示。策略有助于在事件中心上创建细粒度的访问控制。与每个策略相关联的密钥由消费者用来确定其身份;还可以创建附加策略,并使用之前提到的三种访问级别的任何组合:
图 12.5:事件中心中的共享访问策略
可以通过执行以下操作,从事件中心命名空间服务中创建事件中心:
-
点击左侧菜单中的事件中心,然后在结果屏幕中点击+ 事件中心:
图 12.6:从 Azure 门户创建事件中心
-
接下来,提供分区数和消息保留字段的值,以及你选择的名称。然后,选择关闭作为捕获选项,如图 12.7所示:
图 12.7:创建新的事件中心
创建事件中心后,你将在事件中心列表中看到它,如图 12.8所示:
图 12.8:已创建的事件中心列表
事件中心还允许通过名为“捕获”的功能直接将事件存储到存储账户或数据湖中。
捕获功能帮助将摄取的数据自动存储到 Azure 存储账户或 Azure 数据湖中。此功能确保数据的摄取和存储在一个步骤中完成,而不是将数据转移到存储中作为单独的活动:
图 12.9:捕获功能选项
可以通过在事件中心级别添加新策略,将单独的策略分配给每个事件中心。
创建策略后,可以从 Azure 门户中安全访问签名左侧菜单项获取连接字符串。
由于一个命名空间可以包含多个事件中心,单个事件中心的连接字符串将类似于以下代码块。这里的区别在于密钥值和添加了EntityPath
,它指向事件中心的名称:
Endpoint=sb://azuretwittereventdata.servicebus.windows
=rxEu5K4Y2qsi5wEeOKuOvRnhtgW8xW35UBex4VlIKqg=;EntityPath=myeventhub
在创建事件中心时,我们必须保持捕获选项设置为关闭,但在事件中心创建后可以重新打开它。它有助于将事件自动保存到 Azure Blob 存储或 Azure 数据湖存储帐户中。大小和时间间隔的配置如图 12.10所示:
图 12.10:选择捕获事件的大小和时间间隔
在创建事件中心时,我们没有涵盖分区和消息保留选项的概念。
分区是与任何数据存储的可扩展性相关的重要概念。事件在事件中心内会保留特定的时间。如果所有事件都存储在同一个数据存储中,那么扩展这个数据存储将变得极其困难。每个事件生产者都会连接到同一个数据存储并将事件发送到其中。与此相比,具有分区能力的数据存储可以将相同的数据分割成多个更小的数据存储,每个存储都有一个唯一的标识值。
更小的数据存储被称为分区,定义该分区的值被称为分区键。这个分区键是事件数据的一部分。
现在,事件生产者可以连接到事件中心,并根据分区键的值,事件中心会将数据存储在适当的分区中。这将允许事件中心同时并行地接收多个事件。
确定分区数量是事件中心可扩展性的一个关键方面。图 12.11 显示了事件中心如何使用分区键将接收到的数据存储在适当的分区中:
图 12.11:事件中心中的分区
需要理解的是,一个分区可能有多个键。用户决定需要多少个分区,事件中心则会内部决定最佳的方式在这些分区之间分配分区键。每个分区都会使用时间戳按顺序存储数据,较新的事件会附加到分区的末尾。
需要注意的是,一旦事件中心创建完成,就无法更改分区的数量。
还需要记住,分区还可以为读取事件的应用程序带来并行性和并发性。例如,如果有 10 个分区,10 个并行读取器可以同时读取事件,而不会出现性能下降。
消息保留期指的是事件应该存储的时间段。在保留期过后,事件将被丢弃。
消费者组
消费者是从事件中心读取事件的应用程序。消费组是为消费者创建的,以便消费者连接到并读取事件。一个事件中心可以有多个消费组,每个消费组都可以访问事件中心中的所有分区。每个消费组都会针对事件中心中的事件形成一个查询。应用程序可以使用消费组,每个应用程序将看到事件中心事件的不同视图。在创建事件中心时,会自动创建一个默认的$default
消费组。为了优化性能,最好将一个消费者与一个消费组关联。然而,每个消费组中的每个分区最多可以有五个读取器:
图 12.12:消费组中的事件接收器
现在你已经理解了消费组的概念,接下来我们将深入了解 Event Hubs 吞吐量的概念。
吞吐量
分区有助于扩展性,而吞吐量则决定了每秒的容量。那么,在 Event Hubs 中,容量是什么?它是每秒可以处理的数据量。
在 Event Hubs 中,一个单一的 TU 支持以下内容:
-
每秒 1 MB 的数据摄取或每秒 1,000 个事件(以先发生者为准)
-
每秒 2 MB 的数据输出或每秒 4,096 个事件(以先发生者为准)
自动扩展选项在当传入/传出事件的数量或传入/传出的总大小超过阈值时,自动增加吞吐量。吞吐量会随需求自动扩展或收缩,而不是进行限速。在命名空间创建时的吞吐量配置如图 12.13所示。再次强调,决定 TUs 时需要慎重考虑:
图 12.13:选择 TUs 并启用自动扩展
Stream Analytics 入门
Event Hubs 是一个高度可扩展的数据流平台,因此我们需要另一个可以将这些事件作为流处理的服务,而不仅仅是存储数据。Stream Analytics 帮助处理和检查大数据流,Stream Analytics 作业则帮助执行事件处理。
Stream Analytics 可以处理每秒数百万个事件,而且入门非常简单。Azure Stream Analytics 是一个完全由 Azure 管理的 PaaS 服务。Stream Analytics 的客户无需管理底层硬件和平台。
每个作业包含多个输入、输出和一个查询,该查询将传入数据转换为新的输出。Stream Analytics 的整个架构如图 12.14所示:
图 12.14:Azure Stream Analytics 架构
在图 12.14中,事件源显示在最左侧。这些是生成事件的源。它们可以是物联网设备、用任何编程语言编写的自定义应用程序,或者来自其他 Azure 平台的事件,例如 Log Analytics 或 Application Insights。
这些事件必须首先被摄取到系统中,Azure 提供了许多服务来帮助摄取这些数据。我们已经查看了 Event Hubs 以及它们如何帮助摄取数据。还有其他服务,如 IoT Hub,也有助于摄取特定设备和传感器的数据。IoT Hub 和数据摄取的详细信息请参见第十一章,设计物联网解决方案。这些摄取的数据在到达流时会进行处理,处理工作由 Stream Analytics 完成。Stream Analytics 的输出可以传输到展示平台,如 Power BI,向利益相关者展示实时数据,或传输到存储平台,如 Cosmos DB、Data Lake Storage 或 Azure 存储,数据可以稍后通过 Azure Functions 和 Service Bus 队列进行读取和处理。
Stream Analytics 有助于从实时摄取的数据中在时间窗口框架内获取洞察,并帮助识别模式。
它通过三种不同的任务来完成这一过程:
-
输入:数据应该在分析过程中被摄取。数据可以来源于 Event Hubs、IoT Hub 或 Azure Blob 存储。可以使用存储账户和 SQL 数据库的多个独立参考输入来查询数据中的查找数据。
-
查询:这是 Stream Analytics 执行核心任务的地方,它分析摄取的数据并提取有意义的洞察和模式。它通过 JavaScript 用户定义函数、JavaScript 用户定义聚合、Azure 机器学习和 Azure 机器学习工作室来实现。
-
输出:查询结果可以发送到多种不同类型的目标,其中突出的目标包括 Cosmos DB、Power BI、Synapse Analytics、Data Lake Storage 和 Functions:
图 12.15:Stream Analytics 过程
Stream Analytics 能够每秒摄取数百万个事件,并可以在这些事件上执行查询。
输入数据支持以下三种格式之一:
-
JavaScript 对象表示法(JSON):这是一种轻量级的基于文本的格式,易于人类阅读。它由名称-值对组成;以下是一个 JSON 事件示例:
{ "SensorId" : 2, "humidity" : 60, "temperature" : 26C }
-
逗号分隔值(CSV):这些也是纯文本值,使用逗号分隔。图 12.16中展示了一个 CSV 示例。第一行是表头,包含三个字段,后面是两行数据:
图 12.16:纯文本值
-
Avro:这种格式类似于 JSON;然而,它以二进制格式存储,而不是文本格式:
{ "firstname": "Ritesh", "lastname": "Modi", "email": "ritesh.modi@outlook.com" }
然而,这并不意味着流分析只能使用这三种格式来摄取数据。它还可以创建自定义的 .NET 序列化器,通过这些序列化器,任何格式的数据都可以根据序列化器的实现进行摄取。您可以按照docs.microsoft.com/azure/stream-analytics/custom-deserializer-examples
中的步骤编写自定义序列化器。
流分析不仅可以接收事件,还提供对接收到数据的高级查询功能。这些查询可以从时间数据流中提取重要见解并输出。
如图 12.17所示,有一个输入数据集和一个输出数据集;查询将事件从输入移动到输出。INTO
子句指向输出位置,FROM
子句指向输入位置。查询非常类似于 SQL 查询,因此 SQL 程序员的学习曲线不会太陡峭:
图 12.17:接收 Twitter 数据的流分析查询
事件中心提供了将查询输出发送到目标位置的机制。撰写本文时,流分析支持多种事件和查询输出的目标位置,如前所示。
还可以定义可以在查询中重复使用的自定义函数。提供了四种选项来定义自定义函数。
-
Azure 机器学习
-
JavaScript 用户定义的函数
-
JavaScript 用户定义的聚合
-
Azure 机器学习工作室
托管环境
流分析作业可以在云端运行的主机上运行,也可以在物联网边缘设备上运行。物联网边缘设备是靠近物联网传感器的设备,而不是在云上。图 12.18展示了新建流分析作业面板:
图 12.18:创建一个新的流分析作业
让我们详细查看流处理单元。
流处理单元
从图 12.18中可以看到,流分析中唯一的配置是流处理单元。流处理单元指的是为运行流分析作业分配的资源(即 CPU 和内存)。最小和最大流处理单元分别为 1 和 120。
流处理单元必须根据数据量和在该数据上执行的查询数量预先分配;否则,作业将失败。
可以通过 Azure 门户向上或向下扩展流处理单元。
使用事件中心和流分析的示例应用程序
在本节中,我们将创建一个包含多个 Azure 服务的示例应用程序,包含 Azure 逻辑应用、Azure 事件中心、Azure 存储和 Azure 流分析。
在这个示例应用程序中,我们将读取所有包含“Azure”一词的推文,并将其存储在 Azure 存储账户中。
要创建这个解决方案,我们首先需要配置所有必要的资源。
配置一个新的资源组
导航到 Azure 门户,使用有效凭据登录,点击 + 创建资源,搜索 资源组。从搜索结果中选择 资源组,然后创建一个新的资源组。接着,提供一个名称并选择一个合适的位置。请注意,所有资源应托管在同一个资源组和位置中,以便于删除它们:
图 12.19:在 Azure 门户中配置一个新的资源组
接下来,我们将创建一个 Event Hubs 命名空间。
创建一个 Event Hubs 命名空间
点击 + 创建资源,并搜索 Event Hubs。从搜索结果中选择 Event Hubs,然后创建一个新的事件中心。接着,提供一个名称和位置,并根据之前创建的资源组选择一个订阅。选择 Standard 作为定价层,并且勾选 启用自动扩展,如 图 12.20 所示:
图 12.20:创建一个 Event Hubs 命名空间
到现在为止,应该已经创建了一个 Event Hubs 命名空间。在创建事件中心之前,必须先有一个命名空间。下一步是配置事件中心。
创建一个事件中心
在 Event Hubs 命名空间服务中,点击左侧菜单中的 Events Hubs,然后点击 + Event Hubs 创建一个新的事件中心。命名为 azuretwitterdata,并提供一个最佳的分区数量和 消息保留 值:
图 12.21:创建 azuretwitterdata 事件中心
在此步骤之后,您将拥有一个事件中心,用于将事件数据发送到下游服务,这些数据将存储在持久存储中,如数据湖或 Azure 存储帐户中。
配置一个逻辑应用
在资源组配置完成后,点击 + 创建资源,搜索 Logic Apps。从搜索结果中选择 Logic Apps,然后创建一个新的逻辑应用。接着,提供一个名称和位置,并根据之前创建的资源组选择一个订阅。启用 Log Analytics 是一个好习惯。Logic Apps 的详细内容请参考 第十一章,使用 Azure Logic Apps、Event Grid 和 Functions 构建 Azure 解决方案。该逻辑应用负责使用一个账户连接 Twitter 并获取所有包含 Azure 的推文:
图 12.22:创建一个逻辑应用
创建逻辑应用后,选择设计表面上的 当发布新推文时 触发器,登录并按 图 12.23 中所示进行配置。配置此触发器之前,您需要一个有效的 Twitter 账户:
图 12.23:配置推文接收频率
接下来,在设计器表面上拖动一个发送事件动作;该动作负责将推文发送到事件中心:
图 12.24:添加一个动作将推文发送到事件中心
选择先前步骤中创建的事件中心的名称。
内容文本框中指定的值是一个表达式,动态组合了 Logic Apps 提供的函数和 Twitter 数据。点击添加动态内容,会弹出一个对话框,通过它可以构建表达式:
图 12.25:使用动态表达式配置 Logic Apps 活动
表达式的值如下:
json(concat('{','tweetdata:' ,'"',triggerBody()?['TweetText'],'"', '}'))
在接下来的部分,我们将配置存储账户。
配置存储账户
点击+ 创建资源并搜索存储账户。从搜索结果中选择存储账户并创建一个新的存储账户。然后,提供名称和位置,并根据之前创建的资源组选择一个订阅。最后,选择StorageV2作为账户类型,Standard作为性能,并选择本地冗余存储(LRS)作为复制字段。
接下来,我们将创建一个 Blob 存储容器,以存储来自流分析的数据。
创建存储容器
流分析将数据输出为文件,这些文件将存储在 Blob 存储容器中。一个名为twitter的容器将被创建在 Blob 存储中,如图 12.26所示:
图 12.26:创建存储容器
我们将在云端创建一个新的流分析作业,并将流单位设置为默认配置。
创建流分析作业
该流分析作业的输入来自事件中心,因此我们需要从输入菜单进行配置:
图 12.27:创建一个输入流分析作业
流分析作业的输出是一个 Blob 存储账户,因此需要相应地配置输出。提供适合本练习的路径模式;例如,{datetime:ss} 是我们在此练习中使用的路径模式:
图 12.28:创建一个作为输出的 Blob 存储账户
该查询非常简单;你只是将数据从输入复制到输出:
图 12.29:查询以复制 Twitter 信息流
虽然这个例子只是涉及数据复制,但也可以有更复杂的查询,用于在将数据加载到目标之前执行转换。
这就完成了应用程序的所有步骤;现在你应该能够运行它了。
运行应用程序
Logic App 应该已经启用,且流分析(Stream Analytics)应该正在运行。现在,运行 Logic App;它会创建一个作业来执行其中的所有活动,如图 12.30所示:
图 12.30:GetAzureTwitterData 应用概述
存储账户容器应该获取数据,如图 12.31所示:
图 12.31:检查存储账户容器数据
作为一个练习,你可以扩展这个示例解决方案,并每三分钟评估一次推文的情感。这样的 Logic Apps 工作流如下所示:
图 12.32:分析推文情感的流程图
为了检测情感,你需要使用文本分析 API,且在 Logic Apps 中使用之前需要进行配置。
摘要
本章重点介绍了与事件流和存储相关的主题。事件已经成为整体解决方案架构中的一个重要考虑因素。我们介绍了重要的资源,如事件中心(Event Hubs)和流分析(Stream Analytics),以及一些基础概念,如消费者组(consumer groups)和吞吐量(throughputs),并通过与 Logic Apps 一起使用它们创建了端到端的解决方案。你了解到,事件来自多个源,并且为了实时获取活动及其相关事件的洞察,事件中心和流分析等服务发挥着重要作用。在下一章,我们将学习如何集成 Azure DevOps 和 Jenkins,并在开发解决方案时实施一些行业最佳实践。
第十三章:13. 集成 Azure DevOps
在上一章中,您了解了大数据事件和它与 Azure 的 Event Hubs 和 Stream Analytics 服务的关系。软件开发是一个复杂的工作,涉及多个流程和工具,并且涉及来自不同部门的人们。他们需要共同合作,协调一致。由于有这么多变量,当您向最终客户交付时,风险是非常高的。一个小小的疏漏或配置错误可能导致应用程序崩溃。本章将讨论采纳和实施减少这些风险的实践,确保能够一次又一次地向客户交付高质量的软件。
在深入了解 DevOps 之前,以下是软件公司面临的 DevOps 解决的一些问题:
-
不欢迎变革的僵化组织
-
耗时的过程
-
孤立的团队在信息孤岛中工作
-
单体设计和大爆炸式部署
-
手动执行
-
缺乏创新
在本章中,我们将涵盖以下主题:
-
DevOps
-
DevOps 实践
-
Azure DevOps
-
DevOps 准备
-
DevOps 针对 PaaS 解决方案
-
基于虚拟机的 DevOps(IaaS)解决方案
-
基于容器的 DevOps(IaaS)解决方案
-
Azure DevOps 和 Jenkins
-
Azure 自动化
-
Azure DevOps 工具
DevOps
目前,行业内尚未就 DevOps 的定义达成共识。各组织已经制定了自己的 DevOps 定义,并尝试实施它们。他们有自己的视角,并认为一旦实施了自动化、配置管理,并使用了敏捷流程,就算是实现了 DevOps。
根据我在行业中从事 DevOps 项目的经验,我将 DevOps 定义如下:DevOps 是关于软件系统交付机制的,它涉及将人们聚集在一起,使他们协作和沟通,共同朝着一个共同的目标和愿景努力。它意味着共同承担责任、问责和所有权。它是实施促进协作和服务心态的流程。它使交付机制能够为组织带来敏捷性和灵活性。与普遍的看法相反,DevOps 并非只是关于工具、技术和自动化。这些只是帮助协作、实施敏捷流程并加快更好地交付给客户的促进因素。
网络上有多个 DevOps 的定义,它们并没有错。DevOps 并不提供框架或方法论。它是一组原则和实践,当这些原则和实践在组织、项目或合作中应用时,可以实现 DevOps 及组织的目标和愿景。这些原则和实践不要求使用特定的流程、工具、技术或环境。DevOps 提供的指导可以通过任何工具、技术或流程来实现,尽管某些技术和流程可能比其他技术和流程更适用于实现 DevOps 原则和实践的愿景。
尽管 DevOps 实践可以在任何提供服务和产品的组织中实施,但在本书接下来的部分,我们将从软件开发和任何组织的运维部门的角度来看待 DevOps。
那么,什么是 DevOps?DevOps 被定义为一组原则和实践,将所有团队(包括开发人员和运维人员)从项目一开始就聚集在一起,以更快、更高效、更一致和可预测的方式一次又一次地向最终客户交付价值,从而减少市场推出时间,获得竞争优势。
前述对 DevOps 的定义并未指明或提及任何特定的流程、工具或技术。它也没有规定任何方法论或环境。
在任何组织中实施 DevOps 原则和实践的目标是确保高效且有效地满足利益相关者(包括客户)的需求和期望。
当以下情况发生时,客户的需求和期望得以满足:
-
客户获得他们想要的功能
-
客户在需要的时候获得他们想要的功能
-
客户更快速地获得功能更新
-
交付的质量很高
当一个组织能够满足这些期望时,客户会感到满意并保持忠诚。这反过来又提高了组织的市场竞争力,从而带来更大的品牌和市场估值。它直接影响组织的收入和利润。组织可以进一步投资于创新和客户反馈,带来系统和服务的持续变化,从而保持相关性。
在任何组织中实施 DevOps 原则和实践的过程受到其周围生态系统的指导。这个生态系统由组织所属的行业和领域组成。
DevOps 基于一组原则和实践。我们将在本章稍后的部分详细探讨这些原则和实践。DevOps 的核心原则包括:
-
敏捷性:采用敏捷方法可以增加对变化的整体适应能力,确保能够适应不断变化的环境并保持高效。敏捷流程具有较短的工作周期,且在开发生命周期的早期就能发现问题,而不是在后期,从而减少技术债务。
-
自动化:采用工具和自动化可以提高过程和最终产品的整体效率和可预测性。它有助于更快、更简便且更经济地完成任务。
-
协作:协作指的是共享一个共同的代码库、轮换工作职责、共享数据和信息以及其他有助于提高团队成员生产力的方面,从而支持产品的整体有效交付。
-
反馈:指的是多个团队之间关于有效和无效事物的快速和早期反馈循环。它帮助团队优先处理问题,并在随后的发布版本中修复这些问题。
DevOps 的核心实践包括:
-
持续集成:指的是验证和确认开发人员在代码库中提交的代码质量和正确性的过程。它可以是定时的、手动的或持续的。持续意味着每次开发人员推送代码时,过程都会检查各种质量属性,而定时则意味着按照预定的时间表进行检查。手动是指由管理员或开发人员手动执行。
-
配置管理:这是 DevOps 的重要组成部分,为配置基础设施和应用程序提供指导,配置可以通过从配置管理服务器拉取或按计划推送这些配置来实现。每次执行时,配置管理应将环境恢复到预期的理想状态。
-
持续交付:持续交付指的是应用程序在任何现有环境以及新环境中都能随时准备好部署的状态。它通常通过在开发和测试等较低环境中定义发布来执行。
-
持续部署:持续部署指的是能够自动将环境和应用程序部署到生产环境中的能力。它通常通过生产环境中的发布定义来执行。
-
持续学习:指的是理解运营和客户面临的问题,并确保将这些问题传达给开发和测试团队,以便他们在随后的发布版本中解决这些问题,从而改善应用程序的整体健康和可用性。
DevOps 的本质
DevOps 并不是一种新范式;然而,它正获得越来越多的关注和推广。其采用率处于最高水平,越来越多的公司正在踏上这条道路。我特意将 DevOps 称为“旅程”,因为在 DevOps 的实施过程中有不同的成熟度水平。虽然成功实施持续部署和交付被视为这一旅程中的最高成熟度水平,但采用源代码管理和敏捷软件开发则被视为 DevOps 旅程的第一步。
DevOps 讨论的第一件事之一是打破开发团队和运维团队之间的壁垒。它促使多个团队之间进行紧密合作。DevOps 的核心思想是打破开发者只负责编写代码并在测试完成后将其交给运维进行部署的思维模式。它还意味着打破运维在开发活动中没有角色的观念。运维应当参与产品规划,并且应该清楚即将发布的功能。他们还应持续向开发者提供有关运维问题的反馈,以便在后续版本中进行修复。运维应该影响系统的设计,以改善系统的运作性能。同样,开发者也应当帮助运维团队部署系统,并在发生故障时协助解决问题。
DevOps 的定义提到更快速、更高效地向利益相关者交付系统的端到端流程。但它没有具体说明交付应该多么快速或高效。交付速度应当足够满足组织的领域、行业、客户细分和需求。对于一些组织,季度发布就足够了,而对于其他组织来说,可能需要每周发布。就 DevOps 而言,这两种方式都是有效的,组织可以部署相应的流程和技术来达到他们的发布目标。DevOps 并没有强制规定持续集成/持续交付(CI/CD)的具体时间框架。组织应当根据他们的整体项目、参与情况和组织愿景来识别最适合的 DevOps 原则和实践的实现方式。
定义中还提到了端到端交付。这意味着从系统的规划和交付到服务和运维的各个方面,都应成为 DevOps 采用的一部分。流程应当允许在应用开发生命周期中更大的灵活性、模块化和敏捷性。虽然组织可以自由选择最合适的流程——瀑布模型、敏捷开发、Scrum 等——但通常,组织倾向于采用基于迭代的敏捷流程。这种方式可以在较小的单元中实现更快速的交付,这些单元比大规模交付更容易测试和管理。
DevOps 一直以一致且可预测的方式谈论终端客户。这意味着组织应通过自动化不断交付更新和升级的功能给客户。没有自动化的帮助,我们无法实现一致性和可预测性。手动工作应该不存在,以确保高水平的一致性和可预测性。自动化应当是端到端的,以避免失败。这也表明系统设计应当是模块化的,从而在可靠、可用和可扩展的系统上更快地交付。测试在一致和可预测的交付中扮演着重要角色。
实施这些实践和原则的最终结果是,组织能够满足客户的期望和需求。组织能够比竞争对手更快地增长,并通过持续的创新和改进,进一步提高其产品和服务的质量和能力。
现在,您已经理解了 DevOps 背后的理念,接下来让我们深入了解核心的 DevOps 实践。
DevOps 实践
DevOps 包含多个实践,每个实践为整体流程提供独特的功能。下图展示了它们之间的关系。配置管理、持续集成和持续部署构成了 DevOps 的核心实践。通过结合这三项服务交付软件服务,我们实现了持续交付。持续交付是组织的能力和成熟度,取决于配置管理、持续集成和持续部署的成熟度。持续反馈贯穿于所有阶段,形成反馈环路,帮助提供更优质的客户服务。它贯穿所有 DevOps 实践。接下来,让我们深入了解每项能力和 DevOps 实践:
图 13.1:DevOps 实践
配置管理
商业应用程序和服务需要一个可以部署的环境。通常,这个环境是由多个服务器、计算机、网络、存储、容器等多个服务组成的基础设施,这些服务共同工作,以便商业应用程序能够在其上部署。商业应用程序被分解成多个服务,这些服务运行在多个服务器上,可以是本地服务器或云服务器,每个服务都有自己的配置以及与基础设施配置相关的需求。简而言之,基础设施和应用程序都是交付系统给客户所需要的,它们都有各自的配置。如果配置发生漂移,应用程序可能无法按预期工作,导致停机和故障。此外,由于应用生命周期管理(ALM)过程要求使用多个阶段和环境,应用程序将被部署到多个不同配置的环境中。应用程序将首先部署到开发环境,供开发人员查看他们工作的结果。然后,它将被部署到多个测试环境,这些环境有不同的配置,用于功能测试、负载和压力测试、性能测试、集成测试等;它还将被部署到预生产环境进行用户验收测试,最后进入生产环境。确保应用程序能够部署到多个环境中而无需进行任何手动配置更改非常重要。
配置管理提供了一套流程和工具,它们帮助确保每个环境和应用程序都有自己的配置。配置管理跟踪配置项,任何从一个环境到另一个环境发生变化的内容都应视为配置项。配置管理还定义了配置项之间的关系,以及一个配置项的变化如何影响其他配置项。
配置管理的使用
配置管理在以下方面提供帮助:
-
基础设施即代码:当通过代码表示基础设施的配置和配置过程,并且相同的代码贯穿整个应用生命周期过程时,这就是基础设施即代码(IaC)。IaC 有助于自动化基础设施的供应和配置。它还以代码的形式表示整个基础设施,可以存储在代码库中并进行版本控制。这使得用户在需要时可以使用先前环境的配置。它还使得能够以一致且可预测的方式多次供应环境。以这种方式供应的所有环境在所有 ALM 阶段中都是一致的和平等的。有许多工具可以帮助实现 IaC,包括 ARM 模板、Ansible 和 Terraform。
-
在服务器上使用
webdeploy
包,部署 SQL 服务器架构和数据 (bacpac
) 到另一台服务器,并更改 Web 服务器上的 SQL 连接字符串,以指向适当的 SQL 服务器。配置管理为每个部署环境存储应用配置的值。
应用的配置也应当被监控。预期的和期望的配置应始终保持一致。任何偏离预期和期望配置的情况都会使应用不可用。配置管理还能够发现这种偏差,并重新配置应用和环境到其期望的状态。
在实施了自动化配置管理后,团队中的任何人都不需要在生产环境中部署和配置环境及应用。运营团队不再依赖开发团队或繁琐的部署文档。
配置管理的另一个方面是源代码控制。商业应用和服务由代码及其他构件组成,多个团队成员在相同的文件上工作。源代码应始终保持最新,并且应仅由经过身份验证的团队成员访问。代码及其他构件本身就是配置项。源代码控制有助于团队内的协作和沟通,因为每个人都知道其他人的工作内容,并且冲突能够在早期得到解决。
配置管理可以大致分为两类:
-
虚拟机内部
-
虚拟机外部
配置管理工具
接下来讨论虚拟机内部可用的配置管理工具。
所需状态配置
所需状态配置 (DSC) 是微软的一种配置管理平台,作为 PowerShell 的扩展构建。DSC 最初作为 Windows 管理框架 (WMF) 4.0 的一部分发布。它作为 WMF 4.0 和 5.0 的一部分,适用于所有 Windows Server 操作系统,直到 Windows 2008 R2 为止。WMF 5.1 在 Windows Server 2016/2019 和 Windows 10 上开箱即用。
Chef、Puppet 和 Ansible
除了 DSC,还有一系列配置管理工具,如 Chef、Puppet 和 Ansible,这些工具得到 Azure 的支持。本书未涵盖这些工具的详细信息。你可以在这里了解更多:docs.microsoft.com/azure/virtual-machines/windows/infrastructure-automation
。
接下来讨论虚拟机外部可用的配置管理工具。
ARM 模板
ARM 模板是 ARM 中资源配置的主要手段。ARM 模板提供了一种声明性模型,通过该模型可以指定资源及其配置、脚本和扩展。ARM 模板基于JavaScript 对象表示法(JSON)格式。它使用 JSON 语法和约定来声明和配置资源。JSON 文件是基于文本的,用户友好且易于阅读。它们可以存储在源代码仓库中,并对其进行版本控制。它们还是表示基础架构即代码的一种方式,可用于在 Azure 资源组中反复地、可预测、一致和统一地配置资源。
模板提供了在设计和实现中保持通用性和模块化的灵活性。模板使我们能够接受用户参数、声明内部变量、帮助定义资源之间的依赖关系、在同一资源组或不同资源组之间链接资源,并执行其他模板。它们还提供了类似脚本语言的表达式和函数,使得模板在运行时动态且可定制。本书有两章专门讲解 ARM 模板:第十五章,使用 ARM 模板进行跨订阅部署 和 第十六章,ARM 模板的模块化设计与实现。
现在是时候关注下一个重要的 DevOps 原则:持续集成。
持续集成
多个开发者编写代码,并最终将其存储在一个公共仓库中。当开发者完成功能开发后,通常会将代码提交到仓库中。这可能在一天内完成,也可能需要几天或几周。一些开发者可能在同一个功能上工作,并且他们可能也会遵循相同的代码推送/提交实践,这些操作可能发生在几天或几周内。这可能会导致代码质量问题。DevOps 的一个原则是尽早发现问题。开发者应该经常将代码提交/推送到仓库,并进行编译检查,确保自己没有引入错误,并且代码与同事编写的代码兼容。如果开发者没有遵循这一实践,他们机器上的代码会变得过于庞大,且很难与其他代码进行集成。此外,如果编译失败,修复过程中产生的问题也会变得困难且耗时。
代码集成
持续集成解决了这些挑战。持续集成通过一系列验证步骤,帮助编译和验证开发人员推送/检查的代码。持续集成创建了一个包含多个步骤的流程。持续集成由持续自动构建和持续自动测试组成。通常,第一个步骤是编译代码。在成功编译之后,每个步骤负责从特定角度验证代码。例如,可以在编译后的代码上执行单元测试,然后执行代码覆盖率测试,检查单元测试执行了哪些代码路径。这些可以揭示是否编写了全面的单元测试,或者是否还有进一步添加单元测试的空间。持续集成的最终结果是可以由持续部署用于将代码部署到多个环境的部署包。
频繁的代码推送
鼓励开发人员每天多次提交代码,而不是几天或几周后才提交。持续集成会在代码提交或推送后立即启动整个管道的执行。如果编译成功,代码测试以及管道中的其他活动会无错误地执行;代码会被部署到测试环境,并进行集成测试。
提高生产力
持续集成提高了开发人员的生产力。开发人员不需要手动编译代码、连续运行多种类型的测试,然后再生成打包文件。它还减少了代码中引入错误的风险,避免代码过时。它为开发人员提供了有关代码质量的早期反馈。总体而言,通过采用持续集成实践,交付的质量更高,交付速度更快。以下是一个持续集成管道的示例:
图 13.2:持续集成管道
构建自动化
构建自动化由多个任务按顺序执行。通常,第一个任务负责从代码仓库获取最新的源代码。源代码可能包含多个项目和文件。它们会被编译生成构件,如可执行文件、动态链接库和程序集。成功的构建自动化反映了代码中没有编译时错误。
根据项目的性质和类型,构建自动化可能还会包含更多步骤。
测试自动化
测试自动化包括负责验证代码不同方面的任务。这些任务从不同的角度对代码进行测试,并按顺序执行。一般来说,第一步是对代码运行一系列单元测试。单元测试是指通过验证特性在与其他特性隔离的情况下的行为,来测试特性最小单位的过程。它可以是自动化的,也可以是手动的;然而,自动化单元测试更受偏好。
代码覆盖率是另一种自动化测试类型,能够在运行单元测试时执行代码,找出多少代码被执行。它通常以百分比表示,指的是有多少代码可以通过单元测试进行测试。如果代码覆盖率没有接近 100%,那可能是因为开发者没有为该行为编写单元测试,或者未覆盖的代码根本不需要。
测试自动化的成功执行,并且没有出现显著的代码失败后,应开始执行打包任务。根据项目的性质和类型,测试自动化可能还包括更多的步骤。
打包
打包是指生成可部署的工件的过程,例如MSI
、NuGet
和webdeploy
包以及数据库包;对其进行版本控制;然后将它们存储在一个位置,以便其他管道和过程可以使用。
一旦持续集成过程完成,持续部署的过程就会开始,接下来将重点讲解这个过程。
持续部署
当流程达到持续部署时,持续集成已经确保我们拥有完全可用的应用程序部分,接下来可以通过不同的持续部署活动进行处理。持续部署是指通过自动化将业务应用程序和服务部署到预生产环境和生产环境的能力。例如,持续部署可以配置和部署预生产环境,部署应用程序并进行配置。在对预生产环境进行多次有效验证,如功能测试和性能测试后,生产环境将被配置和部署,应用程序通过自动化完成部署。在部署过程中没有手动步骤。每个部署任务都是自动化的。持续部署可以从零开始配置环境并部署应用程序,也可以仅在环境已存在的情况下,部署增量变化。
所有环境都通过自动化使用基础设施即代码(IaC)来配置。这确保了所有环境,无论是开发、测试、预生产还是生产,都是一致的。同样,应用程序通过自动化部署,确保它在所有环境中也被统一部署。这些环境中的配置对于应用程序可能是不同的。
持续部署通常与持续集成集成。当持续集成完成其工作,生成最终的可部署包时,持续部署将启动并开始执行自己的管道。这个管道被称为发布管道。发布管道包含多个环境,每个环境由负责环境配置、环境设置、应用程序部署、应用程序配置、环境操作验证以及在多个环境中测试应用程序的任务组成。
使用持续部署带来了巨大的好处。对整体部署过程有高度的信心,这有助于更快、更无风险地发布到生产环境。出现问题的机会大幅减少。团队的压力也会减轻,如果当前发布存在问题,可以回滚到之前的工作环境:
图 13.3:持续部署管道
尽管每个系统都要求其发布管道具有自己的配置,但前面图示中展示了一个持续部署的示例。需要注意的是,通常情况下,配置和设置多个环境是发布管道的一部分,并且在进入下一个环境之前,应获取相关的批准。批准过程可以是手动的,也可以是自动的,这取决于组织的成熟度。
接下来,我们将关注与测试环境相关的方面。
测试环境部署
一旦从持续集成中获得构建产物,发布管道就开始启动。发布管道的第一步应该是获取所有的构建产物。此后,发布管道可能会创建一个全新的裸机测试环境,或者重用现有的环境。这再次取决于项目类型和计划在该环境中执行的测试类型。环境会被配置并准备好。应用程序的构建产物会被部署并配置。
测试自动化
在部署应用程序后,可以在环境中执行一系列测试。其中一个测试是功能测试。功能测试主要用于验证应用程序的功能完整性和功能性。这些测试是根据客户需求收集的信息编写的。还可以执行另一组测试,主要与应用程序的可扩展性和可用性相关。这通常包括负载测试、压力测试和性能测试。还应该包括对基础设施环境的操作验证。
预生产环境部署
这与测试环境部署非常相似,唯一的区别是环境和应用程序的配置值会有所不同。
验收测试
验收测试通常由应用程序的相关方进行,可以是手动的,也可以是自动化的。这一步骤是从客户的角度对应用程序功能的正确性和完整性的验证。
部署到生产环境
一旦客户批准,执行与测试和预生产环境部署相同的步骤,唯一的区别是环境和应用程序的配置值专门针对生产环境。部署后进行验证,确保应用程序按照预期运行。
持续交付是一个重要的 DevOps 原则,并且与持续部署非常相似;然而,它们之间还是有一些区别。在下一节中,我们将深入探讨持续交付。
持续交付
持续交付和持续部署听起来可能很相似,但它们并不完全相同。持续部署指的是通过自动化将应用程序部署到多个环境,最终部署到生产环境,而持续交付则是能够生成可随时在任何环境中部署的应用程序包。为了生成可以随时部署的工件,应使用持续集成来生成应用程序工件;然后应使用新的或现有的环境来部署这些工件,并通过自动化进行功能测试、性能测试和用户验收测试。一旦这些活动成功执行且没有错误,应用程序包就被认为是可以随时部署的。持续交付包括持续集成和部署到环境中进行最终验证。它有助于更快地获得来自操作团队和最终用户的反馈,这些反馈可以用于实施后续的迭代。
在下一节中,我们将探讨持续学习。
持续学习
使用之前提到的所有 DevOps 实践,可以创建出色的业务应用程序并将其自动部署到生产环境;然而,如果没有持续改进和反馈原则,DevOps 的好处不会持久。至关重要的是,关于应用程序行为的实时反馈需要从最终用户和运维团队传递给开发团队作为反馈。
反馈应传递给团队,提供有关进展顺利与否的相关信息。
应用程序的架构和设计应考虑到监控、审计和遥测。运维团队应从生产环境收集遥测信息,捕捉任何漏洞和问题,并将其传递给开发团队,以便在随后的版本中修复。
持续学习有助于使应用程序更加健壮,并增强其对故障的韧性。它有助于确保应用程序满足消费者需求。图 13.4 显示了不同团队之间应该实施的反馈循环:
图 13.4:反馈循环
在了解了与 DevOps 相关的重要实践之后,现在是时候深入了解那些使这些实践成为可能的工具和服务了。
Azure DevOps
让我们来看看另一个顶级在线服务,它能无缝实现持续集成、持续部署和持续交付:Azure DevOps。事实上,称其为一个服务套件并将其整合为一个名称可能更合适。Azure DevOps 是微软提供的 PaaS 服务,托管在云端。相同的服务也可以作为Team Foundation Services(TFS)在本地部署。书中所有示例都使用 Azure DevOps。
根据微软的说法,Azure DevOps 是一个基于云的协作平台,帮助团队共享代码、跟踪工作并发布软件。Azure DevOps 是一个新名称,之前被称为Visual Studio Team Services(VSTS)。Azure DevOps 是一个企业级软件开发工具和服务,使组织能够为其端到端的应用生命周期管理过程提供自动化功能,从规划到部署应用程序,并从软件系统中获取实时反馈。这提高了组织交付高质量软件系统给客户的成熟度和能力。
成功的软件交付涉及高效地将多个流程和活动结合在一起。这包括执行和实施各种敏捷流程、增加团队之间的协作、从一个 ALM 阶段到另一个阶段的无缝自动过渡,以及向多个环境的部署。跟踪和报告这些活动非常重要,以便衡量和改进交付流程。Azure DevOps 使这一切变得简单而易行。它提供了一整套服务,支持以下内容:
-
通过提供整个应用生命周期管理的单一界面,促进每个团队成员之间的协作
-
使用源代码管理服务促进开发团队之间的协作
-
使用测试管理服务促进测试团队之间的协作
-
通过构建管理服务,使用持续集成自动验证代码和打包
-
通过发布管理服务,使用持续部署和交付自动验证应用程序功能、部署和多个环境的配置
-
使用工作管理服务跟踪和管理工作项
以下表格显示了从Azure DevOps左侧导航栏中获取的典型项目可用的所有服务:
表 13.1:Azure DevOps 服务列表
Azure DevOps 中的组织作为一个安全边界和逻辑容器,提供实现 DevOps 策略所需的所有服务。Azure DevOps 允许在一个组织内创建多个项目。默认情况下,项目创建时会创建一个代码库;不过,Azure DevOps 也允许在同一个项目内创建额外的代码库。Azure DevOps 组织、项目和代码库之间的关系如图 13.5所示:
图 13.5:Azure DevOps 组织、项目和代码库之间的关系
Azure DevOps 提供两种类型的代码库:
-
Git
-
Team Foundation 版本控制(TFVC)
它还提供了在 Git 或 TFVC 源代码管理库之间进行选择的灵活性。在一个项目内,可能会有 TFS 和 TFVC 代码库的组合。
TFVC
TFVC 是传统的集中式版本控制实现方式,采用中央仓库,开发人员直接在连接模式下对其进行操作,提交更改。如果中央仓库处于离线状态或无法访问,开发人员无法提交代码,只能等待仓库恢复在线并可用。其他开发人员只能看到已提交的代码。开发人员可以将多个更改组合成一个单独的变更集,用于提交逻辑上归为一类的代码更改。TFVC 会锁定正在编辑的代码文件。其他开发人员可以读取已锁定的文件,但无法编辑。必须等待前一个编辑完成并释放锁,才能进行编辑。提交和更改的历史记录保存在中央仓库中,而开发人员拥有文件的工作副本,但没有历史记录。
TFVC 非常适合大团队在同一项目中协作工作。这能够在中央位置控制源代码。它也特别适用于长期项目,因为历史记录可以在中央位置进行管理。TFVC 在处理大文件和二进制文件时没有问题。
Git
另一方面,Git 是一种现代的分布式版本控制实现方式,开发人员可以在离线模式下使用自己的本地代码副本和历史记录。开发人员可以在本地克隆的代码上离线工作。每个开发人员都拥有代码和整个历史记录的本地副本,他们在此本地仓库上进行更改。开发人员可以将代码提交到本地仓库。根据需要,他们可以连接到中央仓库,同步本地仓库。这使得每个开发人员都可以在任何文件上工作,因为他们是在本地副本上工作。Git 中的分支不会创建代码的另一个副本,且创建速度极快。
Git 对于小团队和大团队都非常适用。Git 提供的高级选项使得分支和合并变得轻松。
Git 是推荐的源代码控制方式,因为它提供了丰富的功能。在本书中,我们将使用 Git 作为示例应用程序的仓库。在下一节中,我们将详细概述如何通过 DevOps 实现自动化。
准备 DevOps
展望未来,我们将重点关注通过不同模式在 Azure 中实现过程和部署自动化。这些模式包括以下内容:
-
DevOps 适用于 IaaS 解决方案
-
DevOps 适用于 PaaS 解决方案
-
DevOps 适用于基于容器的解决方案
通常,存在一些共享服务,这些服务并不特定于某一个应用程序。这些服务由来自不同环境(如开发、测试和生产)的多个应用程序使用。每个应用程序中这些共享服务的生命周期不同。因此,它们有不同的版本控制库、不同的代码库以及构建和发布管理。它们有自己的一套计划、设计、构建、测试和发布的周期。
该组的资源是使用 ARM 模板、PowerShell 和 DSC 配置进行配置的。
构建这些公共组件的整体流程如图所示:
图 13.6:构建公共组件的整体流程
发布过程如图 13.7所示:
图 13.7:发布过程
在 DevOps 之旅中,理解并在开始任何软件开发、产品或服务之前配置共享组件和服务非常重要。
开始使用 Azure DevOps 的第一步是配置一个组织。
Azure DevOps 组织
需要一个版本控制系统来进行代码级的协作。Azure DevOps 提供了集中式和分散式版本控制系统。Azure DevOps 还提供了用于构建和执行构建与发布流水线的编排服务。这是一个成熟的平台,组织了所有与 DevOps 相关的版本控制以及构建和发布工作项相关的工件。在 Azure DevOps 中配置一个组织后,应该创建一个 Azure DevOps 项目来存储所有与项目相关的工件。
可以通过访问dev.azure.com
来创建 Azure DevOps 组织。
Azure DevOps 组织是提供安全性、访问权限和组织内团队成员之间协作的顶级管理边界。一个组织可以包含多个项目,每个项目包含多个团队。
配置 Azure Key Vault
不建议将密钥、证书、凭据或其他敏感信息存储在代码配置文件、数据库或任何其他通用存储系统中。建议将这些重要数据存储在专门设计用于存储密钥和凭据的保险库中。Azure Key Vault 提供了这样的服务。Azure Key Vault 作为 Azure 提供的资源和服务是可用的。现在,让我们继续探索配置的存储选项。
配置管理服务器/服务的配置
提供配置存储并将这些配置应用于不同环境的配置管理服务器/服务始终是自动化部署的好策略。自定义虚拟机上的 DSC 和来自 Azure 自动化、Chef、Puppet 以及 Ansible 的 DSC 是一些选项,并且可以在 Azure 上无缝使用,适用于 Windows 和 Linux 环境。本书将 DSC 作为配置管理工具,适用于所有目的,并提供一个拉取服务器,用于存放所有示例应用程序的配置文档(MOF 文件)。它还维护着所有配置并与拉取服务器注册的虚拟机和容器的数据库,以便从中拉取配置文档。目标虚拟机和容器上的本地配置管理器会定期检查新配置的可用性,以及当前配置中的漂移,并向拉取服务器报告。它还具有内置的报告功能,提供有关虚拟机内合规节点以及不合规节点的信息。拉取服务器是一个托管 DSC 拉取服务器端点的通用 Web 应用程序。在下一个主题中,我们将讨论一种实时监控进程的技术,使用日志分析。
日志分析
日志分析是 Azure 提供的一个审计和监控服务,用于获取虚拟机和容器中发生的所有更改、漂移和事件的实时信息。它为 IT 管理员提供了一个集中式工作区和仪表板,用于查看、搜索并深入分析所有发生在这些虚拟机上的更改、漂移和事件。它还提供了可以部署在目标虚拟机和容器上的代理。一旦部署,这些代理就会开始将所有更改、事件和漂移信息发送到集中式工作区。接下来,让我们来看看部署多个应用程序的存储选项。
Azure 存储帐户
Azure 存储是 Azure 提供的一项服务,用于将文件存储为 Blob。用于自动化基础设施和示例应用程序的预配、部署和配置的所有脚本和代码都存储在 Azure DevOps Git 仓库中,并打包后部署到 Azure 存储帐户中。Azure 提供了 PowerShell 脚本扩展资源,可以在执行 ARM 模板时自动下载 DSC 和 PowerShell 脚本并在虚拟机上执行。此存储作为多个应用程序部署中所有部署的公共存储。将脚本和模板存储在存储帐户中,可以确保它们可以跨 Azure DevOps 中的项目使用。接下来,让我们探讨一下镜像在下一节中的重要性。
Docker 和操作系统镜像
虚拟机和容器镜像应作为公共服务的构建和发布流水线的一部分来构建。可以使用 Packer 和 Docker Build 等工具来生成这些镜像。
管理工具
所有管理工具,如 Kubernetes、DC/OS、Docker Swarm 和 ITIL 工具,应该在构建和部署解决方案之前进行配置。
我们将在本节 DevOps 准备中以管理工具做总结。DevOps 生态系统中每项活动都有多种选择,我们应该在 DevOps 旅程中启用它们——这不应是事后的考虑,而是 DevOps 规划的一部分。
PaaS 解决方案的 DevOps
Azure PaaS 应用服务的典型架构基于图 13.8:
图 13.8:典型的 Azure PaaS 应用服务架构
该架构展示了参与 Azure 应用服务基础的云解决方案架构的一些重要组件——例如 Azure SQL、存储帐户和版本控制系统。这些工件应该通过 ARM 模板创建。ARM 模板应该是整体配置管理策略的一部分。它可以拥有自己的构建和发布管理管道,类似于图 13.9所示的管道:
图 13.9:为应用服务选择部署选项
现在我们已经探索了各种部署源选项,让我们继续深入了解如何在 Azure 上部署云解决方案。
Azure 应用服务
Azure 应用服务提供了云解决方案的托管服务。它是一个完全托管的平台,负责云解决方案的配置和部署。Azure 应用服务消除了创建和管理基础设施的负担,并为托管您的云解决方案提供了最低限度的服务级别协议(SLA)。
部署槽
Azure 应用服务提供了部署槽,使得部署变得无缝和简单。提供了多个槽,并且在槽之间的切换是通过 DNS 层面完成的。这意味着任何生产槽中的内容都可以通过切换 DNS 条目与暂存槽互换。这有助于将定制的云解决方案部署到暂存环境中,并在所有检查和测试完成后,如果确认没有问题,可以切换到生产环境。然而,在切换后如果生产环境出现任何问题,可以通过再次切换恢复先前在生产环境中的良好值。接下来让我们深入了解 Azure 的数据库服务及其一些关键特性。
Azure SQL
Azure SQL 是 Azure 提供的 SQL PaaS 服务,用于托管数据库。Azure 提供了一个安全的平台来托管数据库,并全面负责管理服务的可用性、可靠性和可扩展性。使用 Azure SQL,无需配置自定义虚拟机、部署 SQL 服务器并进行配置。相反,Azure 团队会在幕后完成这些操作并代表您进行管理。它还提供了防火墙服务,增强了安全性;只有防火墙允许的 IP 地址才能连接服务器并访问数据库。为托管 Web 应用程序而配置的虚拟机有各自的公共 IP 地址,并会动态添加到 Azure SQL 防火墙规则中。Azure SQL 服务器及其数据库将在执行 ARM 模板时创建。接下来,我们将介绍构建和发布管道。
构建和发布管道
在本节中,创建了一个新的构建管道,该管道编译并验证 ASP.NET MVC 应用程序,然后生成部署包。在生成包之后,发布定义确保在持续部署的过程中,首次部署发生在应用服务和 Azure SQL 环境中。
有两种方式可以编写构建和发布管道:
-
使用经典编辑器
-
使用 YAML 文件
YAML 文件为编写构建和发布管道提供了更大的灵活性。
示例应用程序的项目结构如 图 13.10 所示:
图 13.10:示例应用程序的项目结构
在此项目中,有一个 ASP.NET MVC 应用程序——主应用程序——它由多个应用程序页面组成。Web Deploy 包将通过构建管道从该项目生成,并最终部署到 Web 应用程序中。该解决方案中还包含其他项目,如下所述:
-
单元测试项目:用于对 ASP.NET MVC 应用程序进行单元测试的代码。此项目生成的程序集将在构建执行中生成并执行。
-
DacPac
文件将通过构建定义从该项目中生成。 -
Azure 资源组项目:ARM 模板和参数代码,用于配置 ASP.NET MVC 应用程序和 SQL 表格所在的整个 Azure 环境。
构建管道如 图 13.11 所示:
图 13.11:ASP.NET MVC 应用程序的构建管道
每个任务的配置如 表 13.2 所示:
表 13.2:构建管道任务的配置
构建管道已配置为在持续集成过程中自动执行,如 图 13.12 所示:
图 13.12:在构建管道中启用持续集成
发布定义包含多个环境,如开发、测试、系统集成测试(SIT)、用户验收测试(UAT)、预生产和生产。各个环境中的任务非常相似,但会增加一些特定环境的任务。例如,测试环境会有更多与 UI 相关的任务,以及功能性和集成测试任务,而这些在开发环境中是没有的。
该应用程序的发布定义如图 13.13所示:
图 13.13:发布定义
单个环境的发布任务如图 13.14所示:
图 13.14:单个环境的发布任务
这里列出了每个任务的配置:
表 13.3:发布管道任务的配置
本节介绍了如何在 Azure DevOps 中配置构建和发布管道。从下一节开始,将重点介绍不同的架构,如 IaaS、容器以及不同的场景。
IaaS 的 DevOps
IaaS 涉及基础设施和应用程序的管理与维护,这需要在多个环境中配置、部署多个资源和组件。在继续之前,理解架构是非常重要的。
这里展示了典型的基于 IaaS 虚拟机的解决方案架构:
图 13.15:基于 IaaS 虚拟机的解决方案架构
架构中列出的每个组件将在下一节及之后的内容中进行讨论。
Azure 虚拟机
托管网页应用、应用服务器、数据库和其他服务的 Azure 虚拟机器是通过 ARM 模板进行配置的。它们附加到一个虚拟网络,并拥有来自同一网络的私有 IP 地址。虚拟机器的公共 IP 地址是可选的,因为它们已附加到公共负载均衡器。操作洞察代理被安装到虚拟机器上,用于监控这些虚拟机器。PowerShell 脚本也会在这些虚拟机器上执行,这些脚本是从另一个资源组中的存储帐户下载的,用于打开相关防火墙端口、下载适当的包并安装本地证书,以通过 PowerShell 安全访问。这些虚拟机器上的网页应用配置为在提供的端口上运行。网页应用的端口号和所有配置都从 DSC 拉取服务器中获取,并动态分配。
Azure 公共负载均衡器
公共负载均衡器被附加到一些虚拟机器上,以便以轮询的方式向它们发送请求。这通常需要用于前端网页应用和 API。可以为负载均衡器分配公共 IP 地址和 DNS 名称,这样它就可以处理来自互联网的请求。它在不同的端口上接受 HTTP 网页请求,并将其路由到虚拟机器。它还会通过提供的应用路径探测 HTTP 协议的某些端口。网络地址转换(NAT)规则也可以应用,这样就可以通过远程桌面登录到虚拟机器。
Azure 公共负载均衡器的替代资源是 Azure 应用程序网关。应用程序网关是七层负载均衡器,提供 SSL 终止、会话亲和力和基于 URL 的路由等功能。我们将在下一节讨论构建流水线。
构建流水线
以下是基于 IaaS 虚拟机解决方案的典型构建流水线。发布流水线在开发人员将代码推送到仓库时开始。构建流水线会作为持续集成的一部分自动启动。它编译并构建代码,执行单元测试,检查代码质量,并从代码注释生成文档。它将新的二进制文件部署到开发环境中(注意,开发环境并不是新创建的),更改配置,执行集成测试,并生成构建标签以便于识别。然后,它将生成的工件放入发布流水线可以访问的位置。如果在流水线的任何步骤执行过程中出现问题,会作为构建流水线反馈传达给开发人员,以便他们重新修改并重新提交更改。构建流水线应根据问题的严重性判断失败或成功,而这在不同组织之间可能有所不同。一个典型的构建流水线如图 13.16所示:
图 13.16:典型的 IaaS 构建流水线
类似于构建流水线,让我们来了解一下发布流水线的实现。
发布流水线
下一部分展示了基于 IaaS 虚拟机部署的典型发布流水线。发布流水线在构建流水线完成后开始。发布流水线的第一步是收集构建流水线生成的工件,通常是可部署的程序集、二进制文件和配置文档。发布流水线执行并创建或更新第一个环境,通常是测试环境。它使用 ARM 模板来配置 Azure 上的所有 IaaS 和 PaaS 服务和资源,并对其进行配置。它们还帮助在创建虚拟机后执行脚本和 DSC 配置作为后创建步骤。这有助于配置虚拟机内的环境和操作系统。在这一阶段,构建流水线中的应用程序二进制文件将被部署和配置。执行各种自动化测试以检查解决方案,若测试结果令人满意,流水线将在获得必要的批准后将部署转移到下一个环境。相同的步骤将在下一个环境中执行,包括生产环境。最后,在生产环境中执行操作验证测试,以确保应用程序按预期工作,并且没有任何偏差。
在这一阶段,如果出现任何问题或错误,应该予以修复,并且整个周期需要重新执行;但是,如果在规定的时间内没有完成,应该在生产环境中恢复最后已知的快照,以尽量减少停机时间。典型的发布流水线如图 13.17所示:
图 13.17:典型的 IaaS 发布流水线
本节总结了 IaaS 解决方案的 DevOps 流程,下一章将重点介绍虚拟机上的容器。请注意,容器也可以在像 App Service 和 Azure Functions 这样的 PaaS 上运行。
DevOps 与容器
在典型的架构中,容器运行时被部署在虚拟机上,容器在其中运行。基于 IaaS 容器解决方案的典型架构如图所示:
图 13.18:基于 IaaS 的容器解决方案架构
这些容器由容器编排器(如 Kubernetes)管理。监控服务由 Log Analytics 提供,所有的密钥和机密存储在 Azure Key Vault 中。此外,还有一个拉取服务器,可以是虚拟机或 Azure Automation,它向虚拟机提供配置信息。
容器
容器是一种虚拟化技术;然而,它们并不虚拟化物理服务器。相反,容器是一种操作系统级的虚拟化。这意味着容器共享其主机提供的操作系统内核,并且彼此以及与主机共享该内核。在主机(无论是物理的还是虚拟的)上运行多个容器时,容器共享主机的操作系统内核。主机提供一个操作系统内核,所有在其上运行的容器共享这个内核。
容器与其主机和其他容器完全隔离,类似于虚拟机。容器使用操作系统命名空间(在 Linux 上使用控制组)来提供一个新的操作系统环境的感知,并在 Windows 上使用特定的操作系统虚拟化技术。每个容器都拥有自己的一份操作系统资源。
Docker
Docker 提供了容器的管理功能。它包含两个可执行文件:
-
Docker 守护进程
-
Docker 客户端
Docker 守护进程是管理容器的主力军。它是一个管理服务,负责管理与容器相关的所有主机活动。Docker 客户端与 Docker 守护进程进行交互,负责捕获输入并将其发送给 Docker 守护进程。Docker 守护进程提供运行时、库、图形驱动程序、用于创建、管理和监控容器的引擎,以及主机服务器上的镜像。它还可以创建自定义镜像,用于构建和交付应用程序到多个环境。
Dockerfile
Dockerfile
是创建容器镜像的主要构建模块。它是一个简单的基于文本的、可读性强的文件,没有扩展名,甚至被命名为 Dockerfile
。尽管有一种机制可以将其命名为其他名字,但通常它被命名为 Dockerfile
。Dockerfile 包含了使用基础镜像创建自定义镜像的指令。这些指令会从上到下由 Docker 守护进程依次执行。指令包括命令及其参数,如 COPY
、ADD
、RUN
和 ENTRYPOINT
。Dockerfile 通过将应用程序部署和配置转化为可以版本化并存储在源代码库中的指令,支持 IaC(基础设施即代码)实践。接下来让我们查看构建步骤。
构建管道
从构建的角度来看,容器和基于虚拟机的解决方案没有区别。构建步骤保持不变。一个典型的 IaaS 容器部署发布管道如下所示。
发布管道
IaaS 容器部署的典型发布流水线与发布流水线之间的唯一区别是容器镜像管理以及使用 Dockerfile 和 Docker Compose 创建容器。像 Docker Swarm、DC/OS 和 Kubernetes 这样的高级容器管理工具,也可以作为发布管理的一部分进行部署和配置。不过,值得注意的是,这些容器管理工具应该是共享服务发布流水线的一部分,如前面所讨论的那样。图 13.19展示了一个基于容器的解决方案的典型发布流水线:
图 13.19:基于容器的发布流水线
下一部分的重点是与其他工具集的集成,如 Jenkins。
Azure DevOps 与 Jenkins
Azure DevOps 是一个开放的平台编排器,可以无缝集成其他编排工具。它提供了与 Jenkins 良好集成所需的所有基础设施和功能。已经建立了基于 Jenkins 的 CI/CD 流水线的组织,可以利用 Azure DevOps 的先进但简单的功能来编排这些流水线。
Jenkins 可以用作存储库,并且可以在 Azure DevOps 中执行 CI/CD 流水线,同时也可以在 Azure DevOps 中拥有一个存储库,并在 Jenkins 中执行 CI/CD 流水线。
Jenkins 配置可以作为服务钩子添加到 Azure DevOps 中,每当任何代码更改被提交到 Azure DevOps 存储库时,它可以触发 Jenkins 中的流水线。图 13.20展示了来自 Azure DevOps 服务钩子配置部分的 Jenkins 配置:
图 13.20:Jenkins 配置
在 Jenkins 中有多种触发器可以执行流水线;其中之一是代码推送,如图 13.21所示:
图 13.21:执行的代码推送触发器
也可以将其部署到 Azure 虚拟机并执行 Azure DevOps 发布流水线,具体说明见:docs.microsoft.com/azure/virtual-machines/linux/tutorial-build-deploy-jenkins
。
在任何场景中使用 Jenkins 之前,应该先进行部署。Linux 上的部署过程可以在docs.microsoft.com/azure/virtual-machines/linux/tutorial-jenkins-github-docker-cicd
找到。
下一部分将更加关注与配置管理相关的工具和服务。Azure 自动化提供与 DSC 相关的服务,如拉取服务器。
Azure 自动化
Azure Automation 是微软的自动化平台,适用于云端、本地和混合部署的所有自动化实现。Azure Automation 是一个成熟的自动化平台,提供了以下方面的丰富功能:
-
定义资产,如变量、连接、凭据、证书和模块
-
使用 Python、PowerShell 脚本和 PowerShell 工作流实现运行手册
-
提供创建运行手册的用户界面
-
管理完整的运行手册生命周期,包括构建、测试和发布
-
调度运行手册
-
在任何地方运行运行手册的能力——无论是在云端还是本地
-
DSC 作为配置管理平台
-
管理和配置环境——Windows 和 Linux、应用程序以及部署
-
通过导入自定义模块扩展 Azure Automation 的能力
Azure Automation 提供一个 DSC 拉取服务器,帮助创建一个集中式配置管理服务器,包含节点/虚拟机及其组成部分的配置。
它实现了中心和分支模式,其中节点可以连接到 DSC 拉取服务器,下载分配给它们的配置,并重新配置自己以反映其期望状态。节点中的任何变化或偏差将在下一次运行时由 DSC 代理自动修正。这确保了管理员无需主动监控环境,以便发现任何偏差。
DSC 提供了一种声明性语言,您在其中定义意图和配置,而不是如何运行和应用这些配置。这些配置基于 PowerShell 语言,简化了配置管理的过程。
在本节中,我们将介绍如何使用 Azure Automation DSC 配置虚拟机,安装并配置 Web 服务器 (IIS),并创建一个 index.htm
文件,告知用户网站正在维护中。
接下来,您将学习如何配置 Azure Automation 帐户。
配置 Azure Automation 帐户
在 Azure 门户或 PowerShell 中,从现有或新资源组创建一个新的 Azure Automation 帐户。您可能会注意到在图 13.22中,Azure Automation 提供了有关 DSC 的菜单项:
图 13.22:Azure Automation 帐户中的 DSC
它提供了以下功能:
-
DSC 节点:这些列出了当前 Azure Automation DSC 拉取服务器所注册的所有虚拟机和容器。通过当前的 DSC 拉取服务器的配置来管理这些虚拟机和容器。
-
DSC 配置:这些列出了所有导入并上传到 DSC 拉取服务器的原始 PowerShell 配置。它们是人类可读格式,并未编译。
-
DSC 节点配置:这些列出了所有可以分配给节点(虚拟机和容器)的 DSC 配置的编译版本,节点可以从拉取服务器获取。DSC 配置经过编译后会生成 MOF 文件,最终用于配置节点。
在配置 Azure Automation 账户后,我们可以创建一个示例 DSC 配置,如下一部分所示。
创建 DSC 配置
下一步是使用任意 PowerShell 编辑器编写 DSC 配置,以反映配置的意图。对于此示例,创建了一个名为 ConfigureSiteOnIIS
的配置。它导入了基本的 DSC 模块 PSDesiredStateConfiguration
,该模块包含配置中使用的资源。它还声明了一个节点 web 服务器。当这个配置被上传并编译后,它将生成一个名为 ConfigureSiteOnIISwebserver
的 DSC 配置。该配置随后可以应用于节点。
该配置包含几个资源。这些资源配置目标节点。资源安装了 web 服务器、ASP.NET 和框架,并在 inetpub\wwwroot
目录中创建了一个 index.htm
文件,文件内容用于显示网站正在维护中。有关编写 DSC 配置的更多信息,请参阅 docs.microsoft.com/powershell/scripting/dsc/getting-started/wingettingstarted?view=powershell-7
。
下一段代码列出了前述配置的完整内容。该配置将被上传到 Azure Automation 账户:
Configuration ConfigureSiteOnIIS {
Import-DscResource -ModuleName 'PSDesiredStateConfiguration'
Node WebServer {
WindowsFeature IIS
{
Name = "Web-Server"
Ensure = "Present"
}
WindowsFeature AspDotNet
{
Name = "net-framework-45-Core"
Ensure = "Present"
DependsOn = "[WindowsFeature]IIS"
}
WindowsFeature AspNet45
{
Ensure = "Present"
Name = "Web-Asp-Net45"
DependsOn = "[WindowsFeature]AspDotNet"
}
File IndexFile
{
DestinationPath = "C:\inetpub\wwwroot\index.htm"
Ensure = "Present"
Type = "File"
Force = $true
Contents = "<HTML><HEAD><Title> Website under construction.</Title></HEAD><BODY> '
<h1>If you are seeing this page, it means the website is under maintenance and DSC Rocks !!!!!</h1></BODY></HTML>"
}
}
}
在创建了一个示例 DSC 配置后,应将其导入到 Azure Automation 中,如下一部分所示。
导入 DSC 配置
该 DSC 配置仍未为 Azure Automation 所知。它目前存在于一些本地机器上。应将其上传到 Azure Automation 的 DSC 配置中。Azure Automation 提供了 Import-AzureRMAutomationDscConfiguration
cmdlet 来将配置导入到 Azure Automation:
Import-AzureRmAutomationDscConfiguration -SourcePath "C:\DSC\AA\DSCfiles\ConfigureSiteOnIIS.ps1" -ResourceGroupName "omsauto" -AutomationAccountName "datacenterautomation" -Published -Verbose
这些命令将会在 Azure Automation 中导入配置。导入后,DSC 配置应被编译,以便可以分配给服务器进行合规性检查和自动修复。
编译 DSC 配置
在 Azure Automation 中可用 DSC 配置后,可以请求编译。Azure Automation 提供了另一个 cmdlet 用于此操作。使用 Start-AzureRmAutomationDscCompilationJob
cmdlet 来编译已导入的配置。配置名称应与上传的配置名称匹配。编译会创建一个名为配置和节点名称组合的 MOF 文件,在此案例中是 ConfigureSiteOnIIS
web 服务器。命令执行过程如下所示:
Start-AzureRmAutomationDscCompilationJob -ConfigurationName ConfigureSiteOnIIS -ResourceGroupName "omsauto" -AutomationAccountName "datacenterautomation" -Verbose
现在你已经完成了 DSC 节点配置。在接下来的部分中,你将学习如何将配置分配给节点。
将配置分配给节点
编译后的 DSC 配置可以应用于节点。使用 Register-AzureRmAutomationDscNode
将配置分配给节点。NodeConfigurationName
参数标识应应用于节点的配置名称。这是一个强大的 cmdlet,它还可以在节点下载配置并应用之前,配置 DSC 代理,即 localconfigurationmanager
。有多个可以配置的 localconfigurationmanager
参数,详细信息可查看 devblogs.microsoft.com/powershell/understanding-meta-configuration-in-windows-powershell-desired-state-configuration
。
让我们看看下面的配置:
Register-AzureRmAutomationDscNode -ResourceGroupName "omsauto" -AutomationAccountName "datacenterautomation" -AzureVMName testtwo -ConfigurationMode ApplyAndAutocorrect -ActionAfterReboot ContinueConfiguration -AllowModuleOverwrite $true -AzureVMResourceGroup testone -AzureVMLocation "West Central US" -NodeConfigurationName "ConfigureSiteOnIIS.WebServer" -Verbose
现在,我们可以通过使用浏览器浏览新部署的网站来测试配置是否已应用到服务器上。在测试成功完成后,我们继续验证连接。
验证
如果适当,网络安全组和防火墙应为端口 80 开放并启用,并且为虚拟机分配公共 IP。可以通过该 IP 地址浏览默认网站。否则,登录到用于应用 DSC 配置的虚拟机,并导航至 http://localhost
。
它应该显示以下页面:
图 13.23:本地主机
这就是配置管理的力量:无需编写任何复杂的代码,编写一次配置后,可以多次应用于相同或多个服务器,并且可以确保它们会在所需状态下运行,无需人工干预。在下一节中,我们将查看适用于 Azure DevOps 的各种工具。
DevOps 工具
如前所述,Azure 是一个功能丰富且成熟的平台,支持以下内容:
-
多种语言选择
-
多种操作系统选择
-
多种工具和实用程序的选择
-
多种部署解决方案的模式(例如虚拟机、应用服务、容器和微服务)
在如此众多的选项和选择中,Azure 提供了以下内容:
-
开放云:它对开源、微软以及非微软的产品、工具和服务都是开放的。
-
灵活云:它足够简单,既适合终端用户,也适合开发人员,能够利用现有的技能和知识进行使用。
-
统一管理:它提供无缝的监控和管理功能。
这里提到的所有服务和功能对于 DevOps 的成功实施至关重要。图 13.24 展示了可以用于管理应用生命周期和 DevOps 各个阶段的开源工具和实用程序:
图 13.24:开源工具和实用程序
图 13.24 显示了可以用于管理应用生命周期和 DevOps 各个阶段的 Microsoft 工具和实用程序。再次强调,这只是所有工具和实用程序的一小部分——实际上有许多其他选项,例如以下内容:
-
Azure DevOps 构建编排,用于构建构建管道
-
Microsoft 测试管理器和 Pester 用于测试
-
DSC、PowerShell 和 ARM 模板用于部署或配置管理
-
日志分析、应用洞察以及系统中心操作管理器 (SCOM) 用于警报和监控
-
Azure DevOps 和系统中心服务管理器用于管理流程:
图 13.25:Microsoft 工具和实用程序
每个 DevOps 实践都有许多可用的工具,在本节中,您已经了解了一些工具及其配置方式。
小结
DevOps 在行业中获得了极大的关注和势头。大多数组织已经意识到其好处,并希望实施 DevOps。与此同时,他们中的大多数正在向云迁移。作为云平台,Azure 提供了丰富且成熟的 DevOps 服务,使组织更容易实现 DevOps。
在本章中,我们讨论了 DevOps 及其核心实践,如配置管理、持续集成、持续交付和部署。我们还讨论了基于 PaaS 的不同云解决方案、虚拟机 IaaS 和容器 IaaS,以及它们各自的 Azure 资源、构建和发布管道。
本章还解释了配置管理,以及如何使用来自 Azure 自动化的 DSC 服务和拉取服务器自动配置虚拟机。最后,我们讨论了 Azure 在语言、工具和操作系统选择方面的开放性和灵活性。
在下一章中,我们将详细讲解 Kubernetes 及其组件和交互,此外还将讨论 Kubernetes 上的应用设计和部署注意事项。
第十四章:14. 设计 Azure Kubernetes 解决方案
容器是过去十年中最受讨论的基础设施组件之一。容器并不是新技术,它们已经存在了一段时间。它们在 Linux 世界中已经流行了超过二十年。由于其复杂性以及相关文档的匮乏,容器曾在开发者社区中不太为人知。然而,在本世纪初,即 2013 年,一家名为 Docker 的公司推出了改变开发者世界对容器认知和采纳的局面。
Docker 在现有的 Linux LXC 容器之上编写了一个强大的 API 封装,简化了开发者从命令行界面创建、管理和销毁容器的过程。当容器化应用时,容器的数量会随着时间大幅增加,可能达到需要管理数百个甚至数千个容器的程度。这时,容器编排工具就发挥了作用,而 Kubernetes 就是其中之一。使用 Kubernetes,我们可以自动化容器的部署、扩展、网络配置和管理。
本章将讨论:
-
容器的基本概念
-
Kubernetes 的概念
-
使 Kubernetes 能够正常工作的关键要素
-
使用 Azure Kubernetes 服务构建解决方案
现在你已经知道 Kubernetes 的用途,我们从头开始讨论容器是什么,如何使用 Kubernetes 对它们进行编排等内容。
容器简介
容器被称为操作系统级虚拟化系统。它们托管在运行于物理服务器或虚拟服务器上的操作系统中。实现的性质取决于宿主操作系统。例如,Linux 容器受 cgroups 启发;而 Windows 容器几乎是轻量级虚拟机,具有小巧的占用空间。
容器真正实现了跨平台。容器化应用可以在任何平台上运行,如 Linux、Windows 或 Mac,且无需任何修改,这使得它们具有高度的可移植性。这使得它们成为组织采用的完美技术,因为它们与平台无关。
此外,容器可以在任何云环境或本地环境中运行,无需修改。这意味着如果组织将容器作为其云托管平台,它们也不会被束缚于单一云提供商。它们可以将环境从本地迁移并直接迁移到云端。
容器提供了虚拟机通常具备的所有优势。它们有自己的 IP 地址、DNS 名称、身份、网络堆栈、文件系统以及其他组件,这些都使得用户有使用全新操作系统环境的错觉。在后台,Docker 运行时通过虚拟化多个操作系统内核级别的组件来提供这种错觉。
所有这些优势为采用容器技术的组织提供了巨大的好处,而 Docker 在这方面是先行者之一。还有其他容器运行时选项可供选择,如 CoreOS Rkt(发音为 Rocket,已停产)、Mesos Containerizer 和 LXC 容器。组织可以选择他们感到舒适的技术。
容器在 Windows 系统中之前是不可用的,仅在 Windows 10 和 Windows Server 2016 中才开始支持。然而,现在容器已经成为 Windows 系统中的一等公民。
如介绍中所述,容器应像生态系统中的任何其他基础设施组件一样,进行监控、治理和管理。必须部署一个编排工具,如 Kubernetes,帮助你轻松实现这一点。在接下来的章节中,你将了解 Kubernetes 的基础知识,包括它的优势。
Kubernetes 基础知识
许多组织仍然问,“我们需要 Kubernetes,还是需要任何容器编排工具?” 当我们考虑大规模容器管理时,我们需要考虑多个方面,比如扩展、负载均衡、生命周期管理、持续交付、日志记录和监控等。
你可能会问,“容器不应该完成这些工作吗?” 答案是,容器只是这一拼图的低级组成部分。真正的好处是通过那些位于容器之上的工具获得的。最终,我们需要一些工具来帮助我们进行编排。
Kubernetes 是一个希腊词,κυβερνήτης,意思是“舵手”或“船长”。延续 Docker 容器的海洋主题,Kubernetes 就是这艘船的船长。Kubernetes 通常缩写为 K8s,其中 8 代表单词 "Kubernetes" 中 "K" 和 "s" 之间的八个字母。
如前所述,容器比虚拟机更具灵活性。它们可以在几秒钟内创建,并且同样可以快速销毁。它们的生命周期与虚拟机类似;然而,它们需要在环境中主动进行监控、治理和管理。
使用你现有的工具集来管理容器是可行的;尽管如此,像 Kubernetes 这样的专用工具能够提供宝贵的好处:
-
Kubernetes 本质上是自愈的。当 Kubernetes 环境中的一个 Pod(现在可以理解为“容器”)故障时,Kubernetes 会确保在同一节点或另一个节点上创建一个新的 Pod 来响应应用程序的请求。
-
Kubernetes 还简化了应用程序升级的过程。它提供了开箱即用的功能,帮助你在保留原始配置的情况下执行多种类型的升级。
-
它有助于实现蓝绿部署。在这种部署方式中,Kubernetes 会将新版本的应用程序与旧版本一起部署,一旦确认新应用程序按预期工作,就会进行 DNS 切换,切换到新版本的应用程序。旧的应用程序部署可以继续存在,以便回滚使用。
-
Kubernetes 还帮助实施滚动升级部署策略。在这种策略中,Kubernetes 会逐个服务器地部署新版本的应用程序,并逐个服务器地拆除旧版本部署。它会一直执行此操作,直到旧版本的部署没有服务器为止。
-
Kubernetes 可以通过 基础设施即服务(IaaS)模式在本地数据中心或云上进行部署。这意味着开发人员首先创建一组虚拟机并在其上部署 Kubernetes。还有一种替代方法是将 Kubernetes 用作 平台即服务(PaaS)提供。Azure 提供了一项名为 Azure Kubernetes 服务(AKS)的 PaaS 服务,提供了一个开箱即用的 Kubernetes 环境,供开发人员使用。
在部署方面,Kubernetes 可以通过两种方式进行部署:
-
非托管集群:非托管集群可以通过在裸机或虚拟机上安装 Kubernetes 及其他相关软件包来创建。在非托管集群中,将有主节点和工作节点,前身叫做从节点。主节点和工作节点共同协作管理容器。如果你想知道这是如何实现的,接下来我们将在本章中探索 Kubernetes 的完整架构。现在,你只需要知道有主节点和工作节点即可。
-
托管集群:托管集群通常由云服务提供商提供;云服务提供商为你管理基础设施。在 Azure 中,这项服务被称为 AKS。Azure 将提供关于补丁和基础设施管理的主动支持。使用 IaaS 时,组织必须自行确保节点和基础设施的可用性和可扩展性。在 AKS 中,主组件不可见,因为它由 Azure 管理。然而,工作节点(从节点)是可见的,并且会被部署到单独的资源组中,因此你可以在需要时访问这些节点。
使用 AKS 而不是非托管集群的一些关键好处包括:
-
如果你使用的是非托管集群,你需要努力使解决方案具有高可用性和可扩展性。除此之外,你还需要有合适的更新管理机制来安装更新和补丁。另一方面,在 AKS 中,Azure 完全管理这一切,使得开发人员可以节省时间,更加高效。
-
与其他服务的原生集成,例如 Azure 容器注册表用于安全存储容器镜像,Azure DevOps 用于集成 CI/CD 管道,Azure Monitor 用于日志记录,Azure Active Directory 用于安全性。
-
可扩展性和更快的启动速度。
-
支持虚拟机规模集。
尽管这两种部署方式在基本功能上没有差异,但 IaaS 部署形式提供了灵活性,可以立即添加新的插件和配置,而这可能需要 Azure 团队在 AKS 中推出一段时间才能实现。此外,Kubernetes 的新版本在 AKS 中发布也相对迅速,几乎没有延迟。
我们已经涵盖了 Kubernetes 的基础内容。此时,您可能会想,Kubernetes 是如何实现这一切的。在接下来的章节中,我们将探讨 Kubernetes 的组件以及它们是如何协同工作的。
Kubernetes 架构
理解 Kubernetes 的第一步是了解它的架构。我们将在下一节详细讲解每个组件,但先了解架构的高级概览将有助于您理解各个组件之间的互动。
Kubernetes 集群
Kubernetes 需要物理或虚拟节点来安装两种类型的组件:
-
Kubernetes 控制平面组件,或主控组件
-
Kubernetes 工作节点(从属节点),或非主控组件
图 14.1 是一个提供 Kubernetes 架构高级概览的图表。稍后我们将详细介绍各个组件:
图 14.1:Kubernetes 集群概览
控制平面组件负责管理和治理 Kubernetes 环境以及 Kubernetes 从属节点。
所有节点——包括主控节点和从属节点——共同构成了集群。换句话说,集群是节点的集合。它们可以是虚拟的或物理的,彼此连接,并通过 TCP 网络栈相互访问。外部世界无法得知您的集群的大小、能力,甚至工作节点的名称。节点唯一知道的是与集群互动的 API 服务器的地址。对它们来说,集群就是运行其应用程序的一台大计算机。
正是 Kubernetes 内部决定了一个合适的策略,通过控制器来选择一个有效、健康的节点,以便平稳地运行应用程序。
控制平面组件可以安装在高可用配置中。到目前为止,我们已经讨论了集群及其工作原理。在接下来的章节中,我们将深入了解集群的组件。
Kubernetes 组件
Kubernetes 组件分为两类:主组件和节点组件。主组件也被称为集群的控制平面。控制平面负责管理集群中的工作节点和 Pod。集群的决策权由控制平面掌控,它还负责集群事件的检测和响应。图 14.2 描述了 Kubernetes 集群的完整架构:
图 14.2:Kubernetes 架构
你需要理解每一个组件,才能正确地管理一个集群。接下来,让我们讨论一下主组件:
-
API 服务器:API 服务器无疑是 Kubernetes 的大脑。它是启用 Kubernetes 内部所有活动的核心组件。每个客户端请求(少数例外)最终都会由 API 服务器处理,API 服务器决定请求的流向。它唯一负责与 etcd 服务器进行交互。
-
etcd:etcd 是 Kubernetes 的数据存储。只有 API 服务器被允许与 etcd 进行通信,API 服务器可以对 etcd 执行 创建、读取、更新 和 删除(CRUD)操作。当请求最终到达 API 服务器时,经过验证后,API 服务器可以根据 etcd 请求执行任何 CRUD 操作。etcd 是一个分布式、高可用的数据存储。可以有多个 etcd 实例,每个实例都有一份数据副本,它们中的任何一个都可以为 API 服务器的请求提供服务。在 图 14.3 中,你可以看到在控制平面中运行多个实例来提供高可用性:
图 14.3:使控制平面高度可用
-
控制器管理器:控制器管理器是 Kubernetes 的工作马车。API 服务器接收请求时,Kubernetes 中的实际工作由控制器管理器完成。顾名思义,控制器管理器是控制器的管理者。Kubernetes 主节点中有多个控制器,每个控制器负责管理一个单一的资源。
控制器的主要职责是管理 Kubernetes 环境中的单一资源。例如,有一个用于管理副本控制器资源的副本控制器管理器,以及一个用于管理 Kubernetes 环境中 ReplicaSets 的 ReplicaSet 控制器。控制器监控 API 服务器,当它收到一个请求来管理某个资源时,控制器就会执行相应的操作。
控制器的主要职责之一是保持循环运行,并确保 Kubernetes 处于所需状态。如果与所需状态出现任何偏差,控制器应该将其恢复到所需状态。部署控制器监视 API 服务器创建的任何新的部署资源。如果发现新的部署资源,部署控制器将创建一个新的 ReplicaSet 资源,并确保 ReplicaSet 始终处于所需状态。复制控制器会一直运行,并检查环境中实际的 Pods 数量是否与所需的 Pods 数量匹配。如果某个 Pod 因为某种原因死亡,复制控制器会发现实际数量减少了一个,并会在相同或其他节点上调度一个新的 Pod。
-
调度器:调度器的工作是将 Pods 调度到 Kubernetes 工作节点上。它不负责创建 Pods,仅负责将 Pods 分配到 Kubernetes 工作节点。它会根据节点的当前状态、节点的繁忙程度、可用资源以及 Pod 的定义来进行调度。Pod 可能会对特定节点有偏好,调度器在将 Pods 调度到节点时会考虑这些请求。
我们现在将探索在集群中每个工作节点上部署的节点组件:
-
Kubelet:API 服务器、调度器、控制器和 etcd 部署在主节点上,而 kubelet 部署在工作节点上。它们充当 Kubernetes 主组件的代理,并负责在节点上本地管理 Pods。每个节点上都有一个 kubelet。kubelet 接收来自主组件的命令,同时还向主组件(如 API 服务器和控制器管理器)提供有关节点和 Pods 的健康状况、监控信息和更新信息。它们是主节点与工作节点之间管理通信的中介。
-
kube-proxy:kube-proxy 就像 kubelet 一样,部署在工作节点上。它负责监控 Pods 和 Services,并在 Pods 和 Services 的可用性发生变化时更新本地的 iptables 和 netfilter 防火墙规则。这确保了节点上的路由信息在创建新的 Pods 和 Services 或删除现有 Pods 和 Services 时能够及时更新。
-
容器运行时:如今,生态系统中有许多容器供应商和提供商。Docker 是其中最著名的,尽管其他容器运行时也在逐渐获得人气。因此,在我们的架构中,我们用 Docker 的标志来表示容器运行时。Kubernetes 是一个通用的容器调度器,它不能与任何单一的容器供应商(如 Docker)紧密耦合。它应该能够在工作节点上使用任何容器运行时来管理容器的生命周期。
为了在 Pod 中运行容器,已经开发了一种基于行业标准的 容器运行时接口 (CRI),并被所有领先公司使用。该标准提供了与 Kubernetes 等调度器互操作时应遵循的规则。Kubelet 不知道节点上安装了哪些容器二进制文件。它们可以是 Docker 二进制文件,也可以是任何其他二进制文件。
由于这些容器运行时是基于行业标准开发的,无论你使用的是哪种运行时,kubelet 都能与容器运行时进行通信。这将容器管理与 Kubernetes 集群管理解耦。容器运行时的职责包括创建容器、管理容器的网络栈以及管理桥接网络。由于容器管理与集群管理是分离的,Kubernetes 不会干扰容器运行时的职责。
我们讨论的组件适用于无管理的集群以及 AKS 管理的集群。然而,主组件不会暴露给最终用户,因为在 AKS 的情况下,Azure 会管理所有这些内容。本章稍后将介绍 AKS 的架构。你将了解无管理集群,并更清晰地理解这些系统之间的区别。
接下来,你将学习一些最重要的 Kubernetes 资源,也称为原语,这些知识适用于无管理的集群和 AKS 集群。
Kubernetes 原语
你已经了解 Kubernetes 是一个用于部署和管理容器的调度系统。Kubernetes 定义了一组构建块,也称为原语。这些原语一起可以帮助我们部署、维护和扩展容器化应用程序。让我们逐一了解这些原语及其角色。
Pod
Pod 是 Kubernetes 中最基本的部署单元。一个好奇的心灵自然会产生一个问题:Pod 和容器有什么区别?Pod 是容器的封装。换句话说,容器是包含在 Pod 内的。一个 Pod 内可以包含多个容器;然而,最佳实践是保持一个 Pod 对应一个容器。这并不意味着一个 Pod 里不能有多个容器。一个 Pod 中有多个容器也是可以的,只要有一个主容器,其他都是辅助容器。也有一些模式,比如 sidecar 模式,可以在多容器 Pod 中实现。
每个 Pod 都有自己的 IP 地址和网络栈。所有容器共享同一网络接口和栈。Pod 内的所有容器可以通过主机名在本地访问。
以下是 YAML 格式的一个简单 Pod 定义示例:
---
apiVersion: v1
kind: Pod
metadata:
name: tappdeployment
labels:
appname: tapp
ostype: linux
spec:
containers:
- name: mynewcontainer
image: "tacracr.azurecr.io/tapp:latest"
ports:
- containerPort: 80
protocol: TCP
name: http
显示的 Pod 定义有一个名称,并定义了几个标签,这些标签可以由服务资源用来暴露给其他 Pods、节点和外部自定义资源。它还定义了一个基于 Azure 容器注册表中存储的自定义镜像的单个容器,并为该容器打开端口 80
。
服务
Kubernetes 允许创建多个实例的 Pods。这些 Pods 应该可以从集群中的任何 Pod 或节点访问。可以直接使用 Pod 的 IP 地址访问 Pod。然而,这远非理想做法。Pods 是短暂的,如果先前的 Pod 已经崩溃,它们可能会获得一个新的 IP 地址。在这种情况下,应用程序容易出现故障。Kubernetes 提供了 Services,将 Pod 实例与其客户端解耦。Pods 可以创建或销毁,但 Kubernetes 服务的 IP 地址保持不变和稳定。客户端可以连接到服务的 IP 地址,该服务为每个 Pod 提供一个端点,用于发送请求。如果有多个 Pod 实例,每个 Pod 的 IP 地址都将作为端点对象提供给服务。当 Pod 崩溃时,端点会更新,以反映当前的 Pod 实例及其 IP 地址。
服务与 Pods 之间有很高的解耦。服务的主要目的是为那些在其服务选择器定义中具有标签的 Pods 排队。服务定义了标签选择器,根据标签选择器,Pod 的 IP 地址被添加到服务资源中。Pods 和服务可以独立管理。
服务提供多种类型的 IP 地址方案。有四种类型的服务:ClusterIP、NodePort、LoadBalancer 和使用应用程序网关的 Ingress Controller。
最基本的方案称为 ClusterIP,它是一个只能从集群内部访问的内部 IP 地址。ClusterIP 方案如 图 14.4 所示:
图 14.4:ClusterIP 的工作原理
ClusterIP 还允许创建 NodePort,通过 NodePort,它会获得一个 ClusterIP。然而,它也可以在集群中的每个节点上打开一个端口。Pods 可以通过 ClusterIP 地址访问,也可以通过节点 IP 和节点端口的组合来访问:
图 14.5:NodePort 的工作原理
服务不仅可以指向 Pods,还可以指向外部端点。最后,服务还允许创建基于负载均衡器的服务,能够接收外部请求并通过 ClusterIP 和 NodePort 内部将请求重定向到 Pod 实例:
图 14.6:负载均衡器的工作原理
有一种最终类型的服务被称为 Ingress 控制器,它提供了诸如基于 URL 的路由等高级功能,如图 14.7所示:
图 14.7:Ingress 控制器的工作原理
这里展示了一个 YAML 格式的服务定义:
apiVersion: v1
kind: Service
metadata:
name: tappservice
labels:
appname: tapp
ostype: linux
spec:
type: LoadBalancer
selector:
appname: myappnew
ports:
- name: http
port: 8080
targetPort: 80
protocol: TCP
此服务定义使用标签选择器创建基于负载均衡器的服务。
部署
与 ReplicaSets 和 Pods 相比,Kubernetes 的 Deployment 是更高级的资源。Deployment 提供了与应用程序升级和发布相关的功能。Deployment 资源会创建一个 ReplicaSet,而 ReplicaSet 管理 Pods。理解当 ReplicaSets 已经存在时,为什么还需要 Deployment 资源是非常重要的。
部署在应用程序升级中起着重要作用。如果应用程序已经投入生产并且需要部署新版本的应用程序,你有几种选择:
-
删除现有的 Pods 并创建新的 Pods——这种方法会导致应用程序的停机,因此只有在可以接受停机的情况下才应使用此方法。如果 Deployment 中存在错误并且需要回滚到先前的版本,则停机时间可能会增加。
-
蓝绿部署——在此方法中,现有的 Pods 继续运行,并且创建一组新版本的 Pods。这些新 Pods 对外不可访问。一旦测试成功完成,Kubernetes 开始指向这一组新的 Pods。旧的 Pods 可以保持不变,或者可以随后删除。
-
滚动升级——在此方法中,现有的 Pods 会逐个删除,同时为新应用版本创建新的 Pods。新 Pods 会逐步部署,而旧 Pods 会逐步减少,直到它们的数量为零。
如果没有 Deployment 资源,所有这些方法都必须手动执行。Deployment 资源自动化了整个发布和升级过程。如果当前的 Deployment 出现问题,它还可以帮助自动回滚到先前的版本。
以下代码列出了 Deployment 定义:
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: tappdeployment
labels:
appname: tapp
ostype: linux
spec:
replicas: 3
selector:
matchLabels:
appname: myappnew
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
template:
metadata:
name: mypod
labels:
appname: myappnew
spec:
containers:
- name: mynewcontainer
image: "tacracr.azurecr.io/tapp:latest"
ports:
- containerPort: 80
protocol: TCP
name: http
需要注意的是,Deployment 具有一个 strategy
属性,该属性决定是使用 recreate
还是 RollingUpdate
策略。recreate
会删除所有现有的 Pods 并创建新的 Pods。它还通过提供一次执行中可以创建和销毁的最大 Pods 数量,包含与 RollingUpdate
相关的配置细节。
副本控制器和 ReplicaSet
Kubernetes 的复制控制器资源确保集群内始终有指定数量的 Pod 实例在运行。复制控制器监控任何与期望状态的偏差,并创建新的 Pod 实例以满足期望状态。
ReplicaSets 是复制控制器的新版本。ReplicaSets 提供与复制控制器相同的功能,并增加了一些高级功能。其中最主要的功能是可以丰富地定义与 Pod 相关的选择器。使用 ReplicaSets,可以定义复制控制器中没有的动态表达式。
推荐使用 ReplicaSets 而不是复制控制器。
下一个代码示例展示了如何定义一个 ReplicaSet
资源:
---
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: tappdeployment
labels:
appname: tapp
ostype: linux
spec:
replicas: 3
selector:
matchLabels:
appname: myappnew
template:
metadata:
name: mypod
labels:
appname: myappnew
spec:
containers:
- name: mynewcontainer
image: "tacracr.azurecr.io/tapp:latest"
ports:
- containerPort: 80
protocol: TCP
name: http
需要注意的是,ReplicaSets 有一个 replicas
属性,决定 Pod 实例的数量,selector
属性,定义哪些 Pods 应该由 ReplicaSet 管理,最后是 template
属性,定义 Pod 本身。
ConfigMaps 和 Secrets
Kubernetes 提供了两种重要的资源来存储配置信息。ConfigMaps 用于存储不涉及安全的普通配置信息。诸如文件夹名、卷名和 DNS 名称等通用应用配置数据可以存储在 ConfigMaps 中。另一方面,敏感数据,如凭证、证书和机密,应存储在 Secrets 资源中。这些 Secrets 数据会加密并存储在 Kubernetes 的 etcd 数据存储中。
ConfigMaps 和 Secrets 数据可以作为环境变量或在 Pods 中的卷提供。
想要使用这些资源的 Pod 定义应该包括对它们的引用。我们现在已经介绍了 Kubernetes 的基本构件以及每个构件的角色。接下来,你将学习 AKS 的架构。
AKS 架构
在上一节中,我们讨论了无管理集群的架构。现在,我们将探讨 AKS 的架构。当你阅读完这一节后,你将能够指出无管理集群与管理集群(在此案例中为 AKS)架构之间的主要区别。
当创建 AKS 实例时,只会创建工作节点。主控组件由 Azure 管理。主控组件包括 API 服务器、调度器、etcd 和控制器管理器,这些我们之前已经讨论过。kubelets 和 kube-proxy 部署在工作节点上。节点与主控组件之间的通信通过 kubelets 实现,kubelets 充当 Kubernetes 集群的代理:
图 14.8:AKS 架构
当用户请求一个 Pod 实例时,用户请求会到达 API 服务器。API 服务器检查并验证请求的详细信息,将其存储在 etcd(集群的数据存储)中,并且还会创建部署资源(如果 Pod 请求是围绕部署资源包装的)。部署控制器监视任何新部署资源的创建。如果它发现新资源,它会根据用户请求中提供的定义创建一个 ReplicaSet 资源。
ReplicaSet 控制器监视任何新 ReplicaSet 资源的创建,并在看到资源被创建时,要求调度器调度 Pods。调度器有自己的过程和规则,用于找到合适的节点来托管 Pods。调度器将节点信息通知 kubelet,kubelet 然后获取 Pod 的定义并使用节点上安装的容器运行时创建 Pods。最终,Pod 在其定义中创建容器。
kube-proxy 帮助维护本地节点上 Pod 和 Service 信息的 IP 地址列表,并更新本地防火墙和路由规则。为了快速回顾我们到目前为止讨论的内容,我们从 Kubernetes 架构开始,然后转向基本组件,接着讨论了 AKS 的架构。既然你已经清楚这些概念,我们接下来在下一部分创建 AKS 集群。
部署 AKS 集群
AKS 可以通过 Azure 门户、Azure CLI(命令行界面)、Azure PowerShell cmdlets、ARM 模板、支持语言的 SDKs(软件开发工具包)甚至 Azure ARM REST API 来进行配置。
Azure 门户是创建 AKS 实例最简单的方法;然而,为了启用 DevOps,最好使用 ARM 模板、CLI 或 PowerShell 来创建 AKS 实例。
创建 AKS 集群
让我们创建一个资源组来部署我们的 AKS 集群。从 Azure CLI 使用 az group create
命令:
az group create -n AzureForArchitects -l southeastasia
这里,-n
表示资源组的名称,-l
表示位置。如果请求成功,你将看到类似下面的响应:
图 14.9:资源组创建
现在我们已经准备好了资源组,我们将使用 az aks create
命令继续创建 AKS 集群。以下命令将在 AzureForArchitects
资源组中创建一个名为 AzureForArchitects-AKS
的集群,节点数为 2
。--generate-ssh-keys
参数将允许创建 RSA(Rivest–Shamir–Adleman)密钥对,这是一个公钥加密系统:
az aks create --resource-group AzureForArchitects \
--name AzureForArchitects-AKS \
--node-count 2 \
--generate-ssh-keys
如果命令成功,你将能够看到类似的输出:
图 14.10:创建集群
在查看集群时,你会看到一行项,内容是 "nodeResourceGroup": "MC_AzureForArchitects_AzureForArchitects-AKS_southeastasia"
。创建 AKS 集群时,会自动创建第二个资源来存储节点资源。
我们的集群已经配置好。现在我们需要连接到集群并与其互动。为了控制 Kubernetes 集群管理器,我们将使用 kubectl。在接下来的章节中,我们将快速了解一下 kubectl。
Kubectl
Kubectl 是开发人员和基础设施顾问与 AKS 互动的主要工具。Kubectl 帮助创建一个包含 HTTP 头和正文的 REST 请求,并将其提交到 API 服务器。头部包含认证信息,如令牌或用户名/密码组合。正文包含实际的 JSON 格式有效负载。
kubectl 命令提供了丰富的日志细节,当与详细开关一起使用时,开关会接受一个从 0 到 9 的整数输入,可以从详细日志中查看。
连接到集群
若要本地连接到集群,我们需要安装 kubectl。Azure Cloud Shell 已经预装了 kubectl。如果你想在本地连接,请使用 az aks install-cli
来安装 kubectl。
为了配置 kubectl 连接到我们的 Kubernetes 集群,我们需要下载凭证并用它们配置 CLI。可以使用 az aks get-credentials
命令来完成。使用如下命令:
az aks get-credentials \
--resource-group AzureForArchitects \
--name AzureForArchitects-AKS
现在,我们需要验证是否已连接到集群。如前所述,我们将使用 kubectl 与集群通信,kubectl get nodes
将显示集群中节点的列表。在创建时,我们将节点数量设置为 2
,所以输出应该有两个节点。同时,我们需要确保节点的状态为 Ready
。输出应类似于图 14.11:
图 14.11:获取节点列表
由于我们的节点处于 Ready
状态,让我们继续创建一个 Pod。在 Kubernetes 中创建资源有两种方法。它们是:
-
使用
kubectl run
和kubectl expose
命令来创建资源。 -
使用
kubectl apply
命令来创建资源,文件中声明的资源将被创建。
让我们首先采用命令式方法,创建一个名为 webserver
的 Pod,运行一个暴露 80
端口的 NGINX 容器:
kubectl run webserver --restart=Never --image nginx --port 80
命令成功完成后,CLI 将告知你状态:
图 14.12:创建一个 Pod
既然我们已经尝试了命令式方法,现在让我们采用声明式方法。你可以使用我们在 Kubernetes 原语 部分的 Pod 小节中讨论的 YAML 文件结构,并根据需求进行修改。
我们将使用 NGINX 镜像,Pod 将命名为webserver-2
。
你可以使用任何文本编辑器创建这个文件。最终的文件将类似于这样:
apiVersion: v1
kind: Pod
metadata:
name: webserver-2
labels:
appname: nginx
ostype: linux
spec:
containers:
- name: wenserver-2-container
image: nginx
ports:
- containerPort: 80
protocol: TCP
name: http
在kubectl apply
命令中,我们将把文件名传递给-f
参数,如图 14.13所示,你可以看到 Pod 已经创建:
图 14.13:使用声明式方法创建 Pod。
由于我们已经创建了 Pods,我们可以使用kubectl get pods
命令列出所有的 Pods。Kubernetes 使用命名空间的概念来逻辑隔离资源。默认情况下,所有命令都指向default
命名空间。如果你想对特定命名空间执行操作,可以通过-n
参数传递命名空间的名称。在图 14.14中,你可以看到kubectl get pods
返回的是我们在前一个示例中创建的 Pods,它们位于默认命名空间中。此外,当我们使用--all-namespaces
时,输出会返回所有命名空间中的 Pods:
图 14.14:列出所有 Pods
现在我们将创建一个简单的 Deployment,运行 NGINX,并通过负载均衡器将其暴露到互联网。YAML
文件将如下所示:
#Creating a deployment that runs six replicas of nginx
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-server
spec:
replicas: 6
selector:
matchLabels:
app: nginx-server
template:
metadata:
labels:
app: nginx-server
spec:
containers:
- name: nginx-server
image: nginx
ports:
- containerPort: 80
name: http
---
#Creating Service
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
ports:
- port: 80
selector:
app: nginx-server
---
apiVersion: v1
kind: Service
metadata:
name: nginx-lb
spec:
type: LoadBalancer
ports:
- port: 80
selector:
app: nginx-server
我们将使用kubectl apply
命令并将YAML
文件传递给-f
参数。
成功后,将创建所有三个服务,如果你执行kubectl get deployment nginx-server
命令,你将看到六个副本在运行,如图 14.15所示,从而使服务具有高可用性:
图 14.15:检查 Deployment
由于我们的 Deployment 已经配置好,我们需要检查我们创建的负载均衡器的公共 IP。我们可以使用kubectl get service nginx-lb --watch
命令。当负载均衡器初始化时,EXTERNAL-IP
将显示为<pending>
,--wait
参数将使命令在前台运行,当公共 IP 分配完毕时,我们将看到一行新的信息,如下所示:
图 14.16:查找负载均衡器的公共 IP
现在我们有了公共 IP,我们可以打开浏览器,应该能看到 NGINX 登录页面,如图 14.17所示:
图 14.17:NGINX 登录页面
同样,你可以使用我们在Kubernetes 基础组件部分讨论的YAML
文件来创建不同类型的资源。
有许多命令,如 logs
、describe
、exec
和 delete
,管理员需要在 kubectl
命令中使用。本节的目标是帮助你创建一个 AKS 集群,连接到集群,并部署一个简单的 web 应用。
在接下来的部分,我们将讨论 AKS 网络。
AKS 网络
网络是 Kubernetes 集群中的核心组件。主组件应该能够访问从属节点及其上运行的 Pods,而工作节点则应该能够相互通信并与主组件进行通信。
可能会让你感到惊讶的是,核心 Kubernetes 并不管理网络栈。这是节点上容器运行时的工作。
Kubernetes 制定了三个重要原则,任何容器运行时都应遵守。这些原则如下:
-
Pods 应该能够与其他 Pods 进行通信,而无需改变其源地址或目标地址,这是通过使用网络地址转换(NAT)来实现的。
-
像 kubelet 这样的代理应该能够直接与节点上的 Pods 进行通信。
-
直接托管在主机网络上的 Pods 仍然应该能够与集群中的所有 Pods 进行通信。
每个 Pod 在 Kubernetes 集群中都会获得一个唯一的 IP 地址,并拥有一个完整的网络栈,类似于虚拟机。它们都连接到由容器网络接口(CNI)组件创建的本地桥接网络。CNI 组件还会创建 Pod 的网络栈。然后,桥接网络与主机网络进行通信,并成为 Pods 与网络之间流量传输的通道,反之亦然。
CNI 是由云原生计算基金会(CNCF)管理和维护的标准,有许多提供商提供其自定义实现。Docker 就是其中之一。还有其他提供商,例如 rkt(读作 rocket)、weave、calico 等。每个提供商都有自己的能力,并独立决定网络功能,同时确保完全遵循 Kubernetes 网络的主要原则。
AKS 提供两种不同的网络模型:
-
Kubenet
-
Azure CNI
Kubenet
Kubenet 是 AKS 中的默认网络框架。在 Kubenet 模式下,每个节点从它们所连接的虚拟网络的子网中获取一个 IP 地址。Pods 不会从子网中获取 IP 地址。相反,使用一个独立的寻址方案为 Pods 和 Kubernetes 服务提供 IP 地址。在创建 AKS 实例时,重要的是为 Pods 和服务设置 IP 地址范围。由于 Pods 不在与节点相同的网络中,因此来自 Pods 或指向 Pods 的请求总是会通过 NAT 转换或路由,将源 Pod 的 IP 地址替换为节点的 IP 地址,反之亦然。
在用户定义的路由中,Azure 可以支持最多 400 条路由,且集群中的节点数不能超过 400 个。图 14.18 显示了 AKS 节点如何从虚拟网络获取 IP 地址,但不包括在节点中创建的 Pods:
图 14.18:AKS 中的网络
默认情况下,这个 Kubenet 配置为每个节点 110 个 Pods。这意味着默认情况下,在 Kubernetes 集群中最多可以有 110 * 400 个 Pods。每个节点的最大 Pods 数量是 250。
当 IP 地址的可用性和用户定义的路由不是限制条件时,应该使用此方案。
在 Azure CLI 中,你可以执行以下命令来使用此网络堆栈创建 AKS 实例:
az aks create \
--resource-group myResourceGroup \
--name myAKSCluster \
--node-count 3 \
--network-plugin kubenet \
--service-cidr 10.0.0.0/16 \
--dns-service-ip 10.0.0.10 \
--pod-cidr 10.244.0.0/16 \
--docker-bridge-address 172.17.0.1/16 \
--vnet-subnet-id $SUBNET_ID \
--service-principal <appId> \
--client-secret <password>
请注意,所有的 IP 地址都明确地为服务资源、Pods、节点和 Docker 桥接提供。这些是非重叠的 IP 地址范围。同时请注意,Kubenet 被用作网络插件。
Azure CNI(高级网络)
使用 Azure CNI 时,每个节点和 Pod 会直接从网络子网分配一个 IP 地址。这意味着,可以根据子网中可用的唯一 IP 地址数量来拥有尽可能多的 Pods。这使得在这种网络策略下,IP 地址范围规划变得更加重要。
需要注意的是,Windows 主机仅能使用 Azure CNI 网络堆栈。此外,某些 AKS 组件,如虚拟节点和虚拟 kubelet,也依赖于 Azure CNI 堆栈。根据将要创建的 Pods 数量,可能需要提前预留 IP 地址。子网中应该始终有额外的 IP 地址,以避免 IP 地址耗尽,或者避免因应用需求而需要重新构建集群来支持更大的子网。
默认情况下,此网络堆栈配置为每个节点 30 个 Pods,并且可以配置为每个节点最多支持 250 个 Pods。
用于创建 AKS 实例的命令如下所示:
az aks create \
--resource-group myResourceGroup \
--name myAKSCluster \
--network-plugin azure \
--vnet-subnet-id <subnet-id> \
--docker-bridge-address 172.17.0.1/16 \
--dns-service-ip 10.2.0.10 \
--service-cidr 10.2.0.0/24 \
--generate-ssh-keys
请注意,所有的 IP 地址都明确地为服务资源、Pods、节点和 Docker 桥接提供。这些是非重叠的 IP 地址范围。同时,注意 Azure 被用作网络插件。
到目前为止,你已经学习了如何部署解决方案并管理 AKS 集群的网络。安全性是另一个需要解决的重要因素。在下一部分,我们将重点介绍 AKS 的访问和身份验证选项。
AKS 的访问和身份验证
Kubernetes 集群可以通过多种方式进行安全保护。
服务账户是 Kubernetes 中的主要用户类型之一。Kubernetes API 管理服务账户。授权的 Pod 可以使用服务账户的凭证与 API 服务器通信,这些凭证作为 Kubernetes Secrets 存储。Kubernetes 没有自己的数据存储或身份提供者,它将认证的责任委托给外部软件。它提供了一个认证插件,用于检查给定的凭证并将其映射到可用的组。如果认证成功,请求会传递给另一组授权插件,以检查用户在集群上的权限级别,以及命名空间范围内的资源。
对于 Azure,最佳的安全集成方式是使用 Azure AD。使用 Azure AD,您还可以将本地身份带入 AKS,以提供账户和安全的集中管理。Azure AD 集成的基本工作流程如 图 14.19 所示:
图 14.19:Azure AD 集成的基本工作流程
用户或组可以被授予访问命名空间内或跨集群的资源的权限。在上一节中,我们使用了 az aks get-credential
命令来获取凭证和 kubectl 配置上下文。当用户尝试与 kubectl 交互时,系统会提示他们使用 Azure AD 凭证进行登录。Azure AD 验证凭证并为用户发放令牌。根据他们的访问级别,他们可以访问集群或命名空间中的资源。
此外,您可以利用 Azure 基于角色的访问控制 (RBAC) 来限制对资源组内资源的访问。
在下一节中,我们将讨论虚拟 kubelet,它是扩展集群的最快方式之一。
虚拟 kubelet
虚拟 kubelet 目前处于预览阶段,由 CNCF 组织管理。它是 AKS 用于扩展性目的的一种创新方法。虚拟 kubelet 作为一个 Pod 部署在 Kubernetes 集群中。运行在 Pod 内的容器使用 Kubernetes SDK 创建一个新的节点资源,并将自己作为节点呈现给整个集群。集群组件,包括 API 服务器、调度器和控制器,认为它是一个节点,并在其上调度 Pods。
然而,当一个 Pod 被调度到这个伪装成节点的节点上时,它会与其后端组件(称为提供者)进行通信,以创建、删除和更新 Pods。Azure 上的一个主要提供者是 Azure 容器实例。Azure 批量处理也可以作为提供者使用。这意味着容器实际上是在容器实例或 Azure 批量处理上创建的,而不是在集群本身上;然而,它们仍由集群管理。虚拟 kubelet 的架构如 图 14.20 所示:
图 14.20:虚拟 kubelet 架构
请注意,虚拟 kubelet 在集群内表现为一个节点,并且能够像普通的 kubelet 一样帮助托管和管理 Pods。然而,虚拟 kubelet 有一个局限性;这就是我们将在下一节中讨论的内容。
虚拟节点
虚拟 kubelet 的一个局限性是,部署在虚拟 kubelet 提供者上的 Pods 是隔离的,无法与集群中的其他 Pods 通信。如果这些提供者上的 Pods 需要与集群中的其他 Pods 和节点进行通信,反之亦然,则应该创建虚拟节点。虚拟节点会在与 Kubernetes 集群节点所在虚拟网络的同一虚拟网络上,使用不同的子网创建,这样可以启用 Pods 之间的通信。到目前为止,仅支持 Linux 操作系统与虚拟节点协作。
虚拟节点提供了一个节点的感知;然而,节点并不存在。任何在这样的节点上调度的任务实际上会在 Azure 容器实例中创建。虚拟节点基于虚拟 kubelet,但具有额外的功能,即集群与 Azure 容器实例之间的无缝双向通信。
在虚拟节点上部署 Pods 时,Pod 定义应该包含适当的节点选择器,以引用虚拟节点,并且还应包含容忍设置,如下一个代码片段所示:
nodeSelector:
kubernetes.io/role: agent
beta.kubernetes.io/os: linux
type: virtual-kubelet
tolerations:
- key: virtual-kubelet.io/provider
operator: Exists
- key: azure.com/aci
effect: NoSchedule
在这里,节点选择器使用 type
属性引用虚拟 kubelet,而 tolerations
属性则通知 Kubernetes,带有污点 virtual-kubelet.io/provider
的节点应允许这些 Pods 的部署。
概述
Kubernetes 是最广泛使用的容器编排工具,并与不同的容器和网络运行时一起工作。在本章中,您了解了 Kubernetes 的基础知识、其架构以及一些重要的基础设施组件,如 etcd、API 服务器、控制器管理器和调度器,以及它们的作用。此外,我们还介绍了可以用于管理应用程序的重要资源,如 Pods、复制控制器、ReplicaSets、Deployments 和 Services。
AKS 提供了几种不同的网络栈——Azure CNI 和 Kubenet。它们为 Pods 分配 IP 地址提供了不同的策略。Azure CNI 从底层子网为 Pods 提供 IP 地址,而 Kubenet 仅使用虚拟 IP 地址。
我们还介绍了 Azure 独有的一些功能,如虚拟节点,以及虚拟 kubelet 的相关概念。在下一章中,我们将学习如何通过 ARM 模板配置和管理资源。
第十五章:15. 使用 ARM 模板进行跨订阅部署
Azure 资源管理器(ARM)模板是配置和管理 Azure 上资源的首选机制。
ARM 模板有助于实现一种相对较新的范式,称为 基础设施即代码(IaC)。ARM 模板将基础设施及其配置转化为代码,具有众多优势。IaC 为跨环境的部署带来了高度一致性和可预测性。它还确保在投入生产之前可以对环境进行测试,最终,它使得部署过程、维护和治理更具信心。
本章将涵盖以下主题:
-
ARM 模板
-
使用 ARM 模板部署资源组
-
跨订阅和资源组部署资源
-
使用链接模板进行跨订阅和资源组部署
-
为 PaaS、数据和 IaaS 解决方案创建 ARM 模板
ARM 模板
IaC 的一个显著优势是它可以进行版本控制。它还可以跨环境复用,这在部署中提供了高度的一致性和可预测性,并确保无论模板部署多少次,部署 ARM 模板的影响和结果都是相同的。这个特性被称为 幂等性。
ARM 模板随着 ARM 规范的引入而首次亮相,并且自那时以来功能逐渐丰富,成熟度也在不断提高。需要理解的是,实际资源配置与 ARM 模板中配置的可用性之间通常存在几周到几个月的功能差距。
每个资源都有自己的配置。此配置可以通过多种方式进行更改,包括使用 Azure PowerShell、Azure CLI、Azure SDK、REST API 和 ARM 模板。
每种技术都有其独立的开发和发布生命周期,这与实际资源的开发不同。让我们通过一个例子来理解这一点。
Azure Databricks 资源有其自身的发布周期和开发生命周期。使用该资源的消费者也有自己的开发生命周期,这与实际资源的开发周期不同。如果 Databricks 在 12 月 31 日首次发布,那么针对它的 Azure PowerShell cmdlet 可能在同一天无法使用,甚至可能在次年的 1 月 31 日才发布;同样,这些功能在 REST API 和 ARM 模板中的可用性可能是在 1 月 15 日左右。
ARM 模板是基于 JSON 的文档,执行时会调用 Azure 管理平面上的 REST API 并提交整个文档。REST API 有自己的开发生命周期,而资源的 JSON 架构也有自己的生命周期。
这意味着,资源中的功能开发至少需要在三个不同的组件中进行,才能从 ARM 模板中使用。包括:
-
该资源本身
-
该资源的 REST API
-
ARM 模板资源架构
每个 ARM 模板中的资源都有apiVersion
属性。该属性帮助确定应使用的 REST API 版本,以便配置和部署该资源。图 15.1 显示了从 ARM 模板到负责创建、更新和删除资源的资源 API 请求流:
图 15.1:请求流
资源配置,例如 ARM 模板中的存储帐户,格式如下:
{ "type": "Microsoft.Storage/storageAccounts", "apiVersion": "2019-04-01", "name": "[variables('storage2')]", "location": "[resourceGroup().location]", "kind": "Storage", "sku": { "name": "Standard_LRS" }}
在前面的代码中,定义 sku
的架构可用性基于 ARM 模板架构的开发。REST API 的可用性及其版本号由 apiVersion
决定,版本为2019-04-01
。实际资源由 type
属性决定,该属性包括以下两个部分:
-
资源提供者命名空间:Azure 中的资源托管在命名空间内,相关的资源也托管在相同的命名空间内。
-
资源类型:资源通过其类型名称进行引用。
在这种情况下,资源通过其提供者名称和类型来识别,类型为Microsoft.Storage/storageaccounts
。
以前,ARM 模板要求在部署之前资源组必须已存在。它们也仅限于在单一订阅的单一资源组中进行部署。
这意味着,直到最近,ARM 模板只能在单一资源组内部署所有资源。现在,Azure ARM 模板增加了将资源部署到同一订阅内的多个资源组或多个订阅的功能。现在可以在 ARM 模板中创建资源组,这意味着现在可以将资源部署到多个区域的不同资源组中。
我们为什么需要在 ARM 模板中创建资源组?为什么需要同时进行跨订阅和跨资源组的部署?
为了理解创建资源组和跨订阅部署的价值,我们需要了解这些功能可用之前是如何进行部署的。
部署 ARM 模板之前,资源组是一个前提条件。资源组应该在模板部署之前创建。开发人员可以使用 PowerShell、Azure CLI 或 REST API 创建资源组,然后启动 ARM 模板的部署。这意味着任何端到端的部署都包括多个步骤。第一步是创建资源组,接下来的步骤是将 ARM 模板部署到这个新创建的资源组。这些步骤可以通过单个 PowerShell 脚本执行,或者通过 PowerShell 命令行中的独立步骤执行。PowerShell 脚本应该包含与异常处理相关的代码,考虑到边缘情况,并确保在脚本可以被称为企业级之前没有任何错误。需要注意的是,资源组可以从 Azure 中删除,下次脚本运行时可能会假设资源组已经存在并失败。简而言之,部署 ARM 模板到资源组应该是一个原子步骤,而不是多个步骤。
将这一点与能够在相同的 ARM 模板中创建资源组及其组成资源进行比较。每次部署模板时,它都会确保如果资源组尚未存在,则创建它,并在创建后继续向其中部署资源。
我们还来看看这些新功能如何帮助消除与灾难恢复站点相关的一些技术限制。
在这些新功能之前,如果你需要部署一个以灾难恢复为设计目标的解决方案,会有两个独立的部署:一个是主区域的部署,另一个是备用区域的部署。例如,如果你使用 App Service 部署一个 ASP.NET MVC 应用程序,你会创建一个应用服务并为主区域配置它,然后使用相同的模板在另一个区域进行另一个部署,并使用不同的parameters
文件。当在另一个区域部署一组资源时,如前所述,模板使用的参数应该有所不同,以反映两个环境之间的差异。这些参数包括像 SQL 连接字符串、域名和 IP 地址以及其他特定于环境的配置项。
随着跨订阅和资源组部署功能的引入,您可以在创建主站点的同时创建灾难恢复站点。这消除了两个部署的需要,并确保相同的配置可以在多个站点上使用。
使用 ARM 模板部署资源组
在本节中,将编写并部署一个 ARM 模板,该模板将在同一订阅内创建几个资源组。
要使用 PowerShell 部署包含资源组和跨订阅资源的模板,应使用最新版本的 PowerShell。编写时,使用的是 Azure 模块版本 3.3.0:
图 15.2:验证最新的 Azure 模块版本
如果没有安装最新的 Azure 模块,可以使用以下命令进行安装:
install-module -Name az -Force
现在是创建一个 ARM 模板的时机,该模板将在同一订阅内创建多个资源组。ARM 模板的代码如下:
{ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "resourceGroupInfo": { "type": "array" }, "multiLocation": { "type": "array" } }, "resources": [ { "type": "Microsoft.Resources/resourceGroups", "location": "[parameters('multiLocation')[copyIndex()]]", "name": "[parameters('resourceGroupInfo')[copyIndex()]]", "apiVersion": "2019-10-01", "copy": { "name": "allResourceGroups", "count": "[length(parameters('resourceGroupInfo'))]" }, "properties": {} } ], "outputs": {}}
代码的第一部分是 ARM 模板所期望的参数。这些是必需的参数,任何部署这些模板的人都应提供相应的值。必须为这两个参数提供数组值。
第二个主要部分是 resources
JSON 数组,它可以包含多个资源。在此示例中,我们正在创建资源组,因此它声明在 resources
部分内。由于使用了 copy
元素,资源组在循环中被创建。copy
元素确保资源运行指定次数,并在每次迭代中创建新的资源。如果我们为 resourceGroupInfo
数组参数传递两个值,则数组长度为二,copy
元素将确保 resourceGroup
资源执行两次。
模板中的所有资源名称在同一资源类型内应唯一。copyIndex
函数用于将当前迭代编号分配给资源的整体名称,并确保其唯一性。此外,我们希望资源组在不同区域中创建,使用作为参数传递的不同区域名称。每个资源组的名称和位置分配是通过 copyIndex
函数完成的。
parameters
文件的代码如下所示。该代码相当简单,并为之前模板中预期的两个参数提供了数组值。此文件中的值应根据你的环境更改所有参数:
{ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "resourceGroupInfo": { "value": [ "firstResourceGroup", "SeocndResourceGroup" ] }, "multiLocation": { "value": [ "West Europe", "East US" ] } }}
部署 ARM 模板
要使用 PowerShell 部署此模板,使用以下命令登录 Azure 并提供有效的凭据:
Login-AzAccount
有效的凭据可以是用户帐户或服务主体。然后,使用新发布的 New-AzDeployment
cmdlet 来部署模板。部署脚本可在 multipleResourceGroups.ps1
文件中找到:
New-AzDeployment -Location "West Europe" -TemplateFile "c:\users\rites\source\repos\CrossSubscription\CrossSubscription\multipleResourceGroups.json" -TemplateParameterFile "c:\users\rites\source\repos\CrossSubscription\CrossSubscription\multipleResourceGroups.parameters.json" -Verbose
需要注意的是,不能使用 New-AzResourceGroupDeployment
cmdlet,因为 New-AzResourceGroupDeployment
cmdlet 的作用范围是资源组,并且它期望资源组已经存在作为前提条件。为了在订阅级别部署资源,Azure 发布了一个新的 cmdlet,可以超越资源组范围进行操作。这个新的 cmdlet new-AzDeployment
是在订阅级别运行的。同时,也可以在管理组级别进行部署。管理组处于比订阅更高的层级,使用 New-AzManagementGroupDeployment
cmdlet 进行部署。
使用 Azure CLI 部署模板
同一个模板也可以使用 Azure CLI 进行部署。以下是使用 Azure CLI 部署模板的步骤:
-
使用最新版本的 Azure CLI,通过 ARM 模板创建资源组。在撰写本文时,部署时使用的是版本 2.0.75,如下所示:
图 15.3:检查 Azure CLI 版本
-
使用以下命令登录 Azure,并选择正确的订阅进行使用:
az login
-
如果登录用户有多个订阅的访问权限,可以使用以下命令选择合适的订阅:
az account set –subscription xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
-
使用以下命令执行部署。部署脚本可以在
multipleResourceGroupsCLI.txt
文件中找到:C:\Users\Ritesh>az deployment create—location westus—template-file "C:\users\rites\source\repos\CrossSubscription\CrossSubscription\azuredeploy.json—parameters @"C:\users\rites\source\repos\CrossSubscription\CrossSubscription\azuredeploy.parameters.json"—verbose
一旦命令执行完成,ARM 模板中定义的资源应该会在 Azure 门户中显示出来。
在不同订阅和资源组之间部署资源
在上一节中,资源组是作为 ARM 模板的一部分创建的。Azure 还有一个功能,可以通过单个部署从单一 ARM 模板同时在多个订阅中提供资源。在本节中,我们将为两个不同的订阅和资源组提供一个新的存储帐户。部署 ARM 模板的人将选择其中一个订阅作为基础订阅,利用该订阅发起部署,并将存储帐户同时提供到当前订阅和另一个订阅。部署此模板的前提条件是,部署者必须至少拥有对两个订阅的访问权限,并且在这些订阅中拥有贡献者权限。以下是代码清单,代码也可以在随附代码中的 CrossSubscriptionStorageAccount.json
文件中找到:
{ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "storagePrefix1": { "type": "string", "defaultValue": "st01" ... "type": "string", "defaultValue": "rg01" }, "remoteSub": { "type": "string", "defaultValue": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" } ... } } ], "outputs": {} } } } ], "outputs": {}}
需要注意的是,代码中使用的资源组名称应已在各自的订阅中存在。如果资源组不存在,代码将抛出错误。此外,资源组的名称必须与 ARM 模板中的名称完全匹配。
部署此模板的代码如下所示。在这种情况下,我们使用 New-AzResourceGroupDeployment
,因为部署的范围是一个资源组。部署脚本可以在代码包中的 CrossSubscriptionStorageAccount.ps1
文件中找到:
New-AzResourceGroupDeployment -TemplateFile "<< path to your CrossSubscriptionStorageAccount.json file >>" -ResourceGroupName "<<provide your base subscription resource group name>>" -storagePrefix1 <<provide prefix for first storage account>> -storagePrefix2 <<provide prefix for first storage account>> -verbose
一旦命令执行完成,ARM 模板中定义的资源应在 Azure 门户中反映出来。
跨订阅和资源组部署的另一个示例
在本节中,我们将在一个 ARM 模板和单次部署中,从两个不同的订阅、资源组和区域创建两个存储帐户。我们将使用嵌套模板方法,并结合 copy
元素为这些资源组提供不同的名称和位置,部署到不同的订阅中。
然而,在执行下一组 ARM 模板之前,应先配置一个 Azure Key Vault 实例,并向其中添加一个密钥。这是因为存储帐户的名称是从 Azure Key Vault 中获取的,并作为参数传递给 ARM 模板,以便部署存储帐户。
要使用 Azure PowerShell 配置 Azure Key Vault,可以执行以下一组命令。以下命令的代码可以在 CreateKeyVaultandSetSecret.ps1
文件中找到:
New-AzResourceGroup -Location <<replace with location of your key vault>> -Name <<replace with name of your resource group for key vault>> -verbose New-AzureRmKeyVault -Name <<replace with name of your key vault>> -ResourceGroupName <<replace with name of your resource group for key vault>> -Location <<replace with location of your key vault>> -EnabledForDeployment -EnabledForTemplateDeployment -EnabledForDiskEncryption -EnableSoftDelete -EnablePurgeProtection -Sku Standard -Verbose
你应该注意,从 New-AzKeyVault
cmdlet 的结果中记录下 ResourceID
值。这个值需要在 parameters
文件中进行替换。有关详细信息,请参见 图 15.4:
图 15.4:创建 Key Vault 实例
执行以下命令,将新密钥添加到新创建的 Azure Key Vault 实例中:
Set-AzKeyVaultSecret -VaultName <<replace with name of your key vault>> -Name <<replace with name of yoursecret>> -SecretValue $(ConvertTo-SecureString -String <<replace with value of your secret>> -AsPlainText -Force ) -Verbose
代码列表可以在代码包中的 CrossSubscriptionNestedStorageAccount.json
文件中找到:
{ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "hostingPlanNames": { "type": "array", "minLength": 1 }, ... "type": "Microsoft.Resources/deployments", "name": "deployment01", "apiVersion": "2019-10-01", "subscriptionId": "[parameters('subscriptions')[copyIndex()]]", "resourceGroup": "[parameters('resourceGroups')[copyIndex()]]", "copy": { "count": "[length(parameters('hostingPlanNames'))]", "name": "mywebsites", "mode": "Parallel" }, ... "kind": "Storage", "properties": { } } ]...
这是 parameters
文件的代码。它可以在 CrossSubscriptionNestedStorageAccount.parameters.json
文件中找到:
{ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "hostingPlanNames": { ... "storageKey": { "reference": { "keyVault": { "id": "<<replace it with the value of Key vault ResourceId noted before>>" }, "secretName": "<<replace with the name of the secret available in Key vault>>" } } }}
这是部署前面模板的 PowerShell 代码。部署脚本可以在 CrossSubscriptionNestedStorageAccount.ps1
文件中找到:
New-AzResourceGroupDeployment -TemplateFile "c:\users\rites\source\repos\CrossSubscription\CrossSubscription\CrossSubscriptionNestedStorageAccount.json" -ResourceGroupName rg01 -TemplateParameterFile "c:\users\rites\source\repos\CrossSubscription\CrossSubscription\CrossSubscriptionNestedStorageAccount.parameters.json" -Verbose
一旦命令执行完成,ARM 模板中定义的资源应在 Azure 门户中反映出来。
使用链接模板部署跨订阅和资源组的部署
前面的示例使用了嵌套模板进行多订阅和资源组的部署。在下一个示例中,我们将使用链接模板在不同的订阅和资源组中部署多个应用服务计划。链接模板存储在 Azure Blob 存储中,并通过策略进行保护。这意味着只有存储账户密钥的持有者或有效的共享访问签名(SAS)才能访问此模板。访问密钥存储在 Azure 密钥保管库中,并通过parameters
文件中的storageKey
元素引用进行访问。你应该将website.json
文件上传到 Azure Blob 存储中的一个容器。website.json
文件是一个链接模板,负责为应用服务计划和应用服务提供配置。该文件通过armtemplates
进行保护,并设置为使用私有策略:
图 15.5:为容器设置私有策略
该文件只能使用共享访问签名(SAS)密钥访问。可以从 Azure 门户的存储账户中使用左侧菜单中的共享访问签名项生成 SAS 密钥。你应该点击生成 SAS 和连接字符串按钮以生成 SAS 令牌。需要注意的是,SAS 令牌只会显示一次,并且不会存储在 Azure 中。因此,必须复制并将其存储在其他地方,以便可以上传到 Azure 密钥保管库中。图 15.6展示了生成 SAS 令牌的过程:
图 15.6:在 Azure 门户中生成 SAS 令牌
我们将使用在上一节中创建的相同密钥保管库实例。只需确保密钥保管库实例中有两个密钥可用。第一个密钥是StorageName
,另一个是StorageKey
。在密钥保管库实例中创建这些密钥的命令如下:
Set-AzKeyVaultSecret -VaultName "testkeyvaultbook" -Name "storageName" -SecretValue $(ConvertTo-SecureString -String "uniquename" -AsPlainText -Force ) -Verbose Set-AzKeyVaultSecret -VaultName "testkeyvaultbook" -Name "storageKey" -SecretValue $(ConvertTo-SecureString -String "?sv=2020-03-28&ss=bfqt&srt=sco&sp=rwdlacup&se=2020-03-30T21:51:03Z&st=2020-03-30T14:51:03Z&spr=https&sig=gTynGhj20er6pDl7Ab%2Bpc29WO3%2BJhvi%2BfF%2F6rHYWp4g%3D" -AsPlainText -Force ) -Verbose
建议根据你的存储账户更改密钥保管库实例和密钥值的名称。
在确保密钥保管库实例具有必要的密钥后,可以使用 ARM 模板文件代码在多个订阅和资源组中部署嵌套模板。
ARM 模板代码可以在CrossSubscriptionLinkedStorageAccount.json
文件中找到,并且在这里也有展示。建议你更改该文件中templateUrl
变量的值。它应该更新为有效的 Azure Blob 存储文件位置:
{ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "hostingPlanNames": { "type": "array", "minLength": 1 ... "type": "Microsoft.Resources/deployments", "name": "fsdfsdf", "apiVersion": "2019-10-01", "subscriptionId": "[parameters('subscriptions')[copyIndex()]]", "resourceGroup": "[parameters('resourceGroups')[copyIndex()]]", "copy": { "count": "[length(parameters('hostingPlanNames'))]", "name": "mywebsites", "mode": "Parallel" ... ]}
parameters
文件的代码如下所示。建议您更改参数的值,包括 Key Vault 实例的 resourceid
和密钥名称。应用服务的名称应该是唯一的,否则模板将无法部署。parameters
文件的代码可以在 CrossSubscriptionLinkedStorageAccount.parameters.json
代码文件中找到:
{ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "hostingPlanNames": { "value": [ "firstappservice", "secondappservice" ] ... "storageKey": { "reference": { "keyVault": { "id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/keyvaluedemo/providers/Microsoft.KeyVault/vaults/forsqlvault1" }, "secretName": "storageKey" } } }}
这是部署模板的命令。部署脚本可以在 CrossSubscriptionLinkedStorageAccount.ps1
文件中找到:
New-AzureRmResourceGroupDeployment -TemplateFile "c:\users\rites\source\repos\CrossSubscription\CrossSubscription\CrossSubscriptionLinkedStorageAccount.json" -ResourceGroupName <<replace with the base subscription resource group name >> -TemplateParameterFile "c:\users\rites\source\repos\CrossSubscription\CrossSubscription\CrossSubscriptionLinkedStorageAccount.parameters.json" -Verbose
一旦命令执行,ARM 模板中定义的资源应该会在 Azure 门户中反映出来。
现在您已经知道如何跨资源组和订阅配置资源,接下来我们将了解使用 ARM 模板创建的一些解决方案。
使用 ARM 模板的虚拟机解决方案
基础设施即服务(IaaS)资源和解决方案可以通过 ARM 模板进行部署和配置。与 IaaS 相关的主要资源是虚拟机资源。
创建虚拟机资源依赖于 Azure 中的多个其他资源。创建虚拟机所需的一些资源包括:
-
存储账户或用于托管操作系统和数据磁盘的托管磁盘
-
虚拟网络以及子网
-
网络接口卡
还有其他可选的资源,包括:
-
Azure 负载均衡器
-
网络安全组
-
公共 IP 地址
-
路由表等
本节将讲解如何使用 ARM 模板创建虚拟机。正如本节前面提到的,我们需要在创建虚拟机资源之前,先创建一些虚拟机资源所依赖的其他资源。
需要注意的是,并非总是需要创建依赖资源。只有在依赖资源不存在时,才应该创建它们。如果它们已经存在于 Azure 订阅中,可以通过引用这些依赖资源来配置虚拟机资源。
模板依赖于几个参数,这些参数应该在执行模板时提供。这些变量与资源的位置以及某些配置值有关。由于这些值可能会在不同的部署中发生变化,因此使用参数可以使模板保持通用。
第一步是创建一个存储账户,如以下代码所示:
{
"type": "Microsoft.Storage/storageAccounts", "name": "[variables('storageAccountName')]", "apiVersion": "2019-04-01", "location": "[parameters('location')]", "sku": { "name": "Standard_LRS" }, "kind": "Storage", "properties": {} },
创建存储账户后,应该在 ARM 模板中定义一个虚拟网络。需要注意的是,存储账户和虚拟网络之间没有依赖关系,它们可以并行创建。虚拟网络资源具有一个子网作为其子资源。它们都配置了自己的 IP 范围;子网通常比虚拟网络的 IP 范围小:
{
"apiVersion": "2019-09-01",
"type": "Microsoft.Network/virtualNetworks",
"name": "[variables('virtualNetworkName')]",
"location": "[parameters('location')]",
"properties": {
"addressSpace": {
"addressPrefixes": [
"[variables('addressPrefix')]"
]
},
"subnets": [
{
"name": "[variables('subnetName')]",
"properties": {
"addressPrefix": "[variables('subnetPrefix')]"
}
}
]
}
},
如果虚拟机需要通过公共互联网访问,还可以创建公共 IP 地址,如以下代码所示。同样,它是一个完全独立的资源,并可以与存储帐户和虚拟网络并行创建:
{
"apiVersion": "2019-11-01",
"type": "Microsoft.Network/publicIPAddresses",
"name": "[variables('publicIPAddressName')]",
"location": "[parameters('location')]",
"properties": {
"publicIPAllocationMethod": "Dynamic",
"dnsSettings": {
"domainNameLabel": "[parameters('dnsLabelPrefix')]"
}
}
},
在创建虚拟网络、存储帐户和公共 IP 地址后,可以创建网络接口。网络接口依赖于虚拟网络和子网资源。它也可以选择性地与公共 IP 地址关联。如下代码所示:
{
"apiVersion": "2019-11-01",
"type": "Microsoft.Network/networkInterfaces",
"name": "[variables('nicName')]",
"location": "[parameters('location')]",
"dependsOn": [
"[resourceId('Microsoft.Network/publicIPAddresses/', variables('publicIPAddressName'))]",
"[resourceId('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]"
],
"properties": {
"ipConfigurations": [
{
"name": "ipconfig1",
"properties": {
"privateIPAllocationMethod": "Dynamic",
"publicIPAddress": {
"id": "[resourceId('Microsoft.Network/publicIPAddresses',variables('publicIPAddressName'))]"
},
"subnet": {
"id": "[variables('subnetRef')]"
}
}
}
]
}
},
需要注意的是,公共 IP 地址和子网通过其独特的 Azure 标识符来引用。
在创建网络接口后,我们就拥有了创建虚拟机所需的所有资源。接下来的代码块展示了如何使用 ARM 模板创建虚拟机。它依赖于网络卡和存储帐户,这间接地创建了对虚拟网络、子网和公共 IP 地址的依赖。
对于虚拟机,我们配置必需的资源配置,包括type
、apiVersion
、location
和name
,以及任何依赖项,如以下代码所示:
{
"apiVersion": "2019-07-01",
"type": "Microsoft.Compute/virtualMachines",
"name": "[variables('vmName')]",
"location": "[resourceGroup().location]",
"tags": {
"displayName": "VirtualMachine"
},
"dependsOn": [
"[concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName'))]",
"[concat('Microsoft.Network/networkInterfaces/', variables('nicName'))]"
],
"properties": {
"hardwareProfile": { "vmSize": "[variables('vmSize')]" },
"availabilitySet": {
"id": "[resourceId('Microsoft.Compute/availabilitySets', parameters('adAvailabilitySetName'))]"
},
"osProfile": {
"computerName": "[variables('vmName')]",
"adminUsername": "[parameters('adminUsername')]",
"adminPassword": "[parameters('adminPassword')]"
},
"storageProfile": {
"imageReference": {
"publisher": "[variables('imagePublisher')]",
"offer": "[variables('imageOffer')]",
"sku": "[parameters('windowsOSVersion')]",
"version": "latest"
},
"osDisk": { "createOption": "FromImage" },
"copy": [
{
"name": "dataDisks",
"count": 3,
"input": {
"lun": "[copyIndex('dataDisks')]",
"createOption": "Empty",
"diskSizeGB": "1023",
"name": "[concat(variables('vmName'), '-datadisk', copyIndex('dataDisks'))]"
}
}
]
},
"networkProfile": {
"networkInterfaces": [
{
"id": "[resourceId('Microsoft.Network/networkInterfaces', variables('nicName'))]"
}
]
}
}
}
在前面的代码中,虚拟机被配置为:
-
硬件配置——虚拟机的大小。
-
操作系统配置——用于登录虚拟机的名称和凭据。
-
存储配置——存储虚拟机的虚拟硬盘(VHD)文件的存储帐户,包括数据磁盘。
-
网络配置——指向网络接口卡的引用。
接下来的部分将展示如何使用 ARM 模板配置一个平台即服务解决方案的示例。
使用 ARM 模板的 PaaS 解决方案
平台即服务(PaaS)资源和解决方案可以通过 ARM 模板进行部署。与 PaaS 相关的主要资源之一是 Azure Web 应用程序,在本节中,我们将重点介绍如何使用 ARM 模板在 Azure 上创建 Web 应用程序。
模板执行时需要提供一些参数。所需的参数包括应用服务计划的 SKU、托管资源的 Azure 区域和应用服务计划的 SKU 容量。
模板中声明了一些变量,以使其更加通用和可维护。第一个变量hostingPlanName
是应用服务计划的名称,第二个变量webSiteName
是应用服务本身的名称。
至少有两个资源应该被声明并配置,以便在 Azure 中创建一个可用的 Web 应用程序。它们是:
-
Azure 应用服务计划
-
Azure 应用服务
在 Azure 上创建 Web 应用的第一步是定义 Azure 应用服务计划的配置。以下代码定义了一个新的应用服务计划。值得注意的是,资源类型是 Microsoft.Web/serverfarms
。计划的多数配置值,如 location
、name
和 capacity
,都作为参数传递给 ARM 模板:
{
"apiVersion": "2019-08-01",
"name": "[variables('hostingPlanName')]",
"type": "Microsoft.Web/serverfarms",
"location": "[parameters('location')]",
"tags": {
"displayName": "HostingPlan"
},
"sku": {
"name": "[parameters('skuName')]",
"capacity": "[parameters('skuCapacity')]"
},
"properties": {
"name": "[variables('hostingPlanName')]"
}
},
在计划之后,应该预配的下一个资源是应用服务本身。重要的是要在这两个资源之间创建一个依赖关系,以确保在创建应用服务之前,计划已经创建:
{
"apiVersion": "2019-08-01",
"name": "[variables('webSiteName')]",
"type": "Microsoft.Web/sites",
"location": "[parameters('location')]",
"dependsOn": [
"[variables('hostingPlanName')]"
],
"properties": {
"name": "[variables('webSiteName')]",
"serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]"
},
"resources": [
{
"apiVersion": "2019-08-01",
"type": "config",
"name": "connectionstrings",
"dependsOn": [
"[variables('webSiteName')]"
],
"properties": {
"DefaultConnection": {
"value": "[concat( 'sql connection string here')]",
"type": "SQLAzure"
}
}
}
]
}
在上面的代码中,定义了一个类型为 Microsoft.Web/sites
的资源,并且它依赖于计划。它还使用了应用服务计划,并通过 serverFarmId
与之关联。它进一步声明了一个连接字符串,可用于连接到 SQL Server。
本节展示了如何使用 ARM 模板在 Azure 上创建 PaaS 解决方案的示例。同样,其他 PaaS 解决方案,包括 Azure Function 应用、Kubernetes 服务和 Service Fabric 等,均可使用 ARM 模板创建。
使用 ARM 模板的数据相关解决方案
在 Azure 中,有许多与数据管理和存储相关的资源。一些重要的与数据相关的资源包括 Azure SQL、Azure Cosmos DB、Azure Data Lake 存储、Data Lake Analytics、Azure Synapse、Databricks 和 Data Factory。
所有这些资源都可以通过 ARM 模板进行预配和配置。在本节中,我们将创建一个 ARM 模板,以预配一个数据工厂资源,负责通过存储过程将数据从 Azure Blob 存储迁移到 Azure SQL 数据库。
你将会找到参数文件与模板一起提供。这些值可能会在每次部署之间发生变化;我们将保持模板的通用性,以便你可以轻松地自定义并在其他部署中使用。
本节的完整代码可以在 github.com/Azure/azure-quickstart-templates/blob/master/101-data-factory-blob-to-sql-copy-stored-proc
找到。
第一步是声明 ARM 模板中数据工厂的配置,如下代码所示:
"name": "[variables('dataFactoryName')]",
"apiVersion": "2018-06-01",
"type": "Microsoft.DataFactory/datafactories",
"location": "[parameters('location')]",
每个数据工厂都有多个连接的服务。这些连接的服务充当连接器,将数据引入数据工厂,或者数据工厂可以将数据发送到它们。以下代码列出了为 Azure 存储账户创建的一个连接服务,从中读取 Blob 数据进入数据工厂,以及为 Azure SQL 数据库创建的另一个连接服务:
{
"type": "linkedservices",
"name": "[variables('storageLinkedServiceName')]",
"apiVersion": "2018-06-01",
"dependsOn": [
"[variables('dataFactoryName')]"
],
"properties": {
"type": "AzureStorage",
"description": "Azure Storage Linked Service",
"typeProperties": {
"connectionString":
"[concat('DefaultEndpointsProtocol=https; AccountName=',parameters('storageAccountName'),'; AccountKey=',parameters('storageAccountKey'))]"
}
}
},
{
"type": "linkedservices",
"name": "[variables('sqlLinkedServiceName')]",
"apiVersion": "2018-06-01",
"dependsOn": [
"[variables('dataFactoryName')]"
],
"properties": {
"type": "AzureSqlDatabase",
"description": "Azure SQL linked service",
"typeProperties": {
"connectionString": "[concat('Data Source=tcp:', parameters('sqlServerName'), '.database.windows.net,1433;Initial Catalog=', parameters('sqlDatabaseName'), ';Integrated Security=False;User ID=', parameters('sqlUserId'), ';Password=', parameters('sqlPassword'), ';Connect Timeout=30;Encrypt=True')]"
}
}
},
在链接服务之后,是时候为 Azure 数据工厂定义数据集了。数据集有助于识别应读取并放入数据工厂的数据。它们还可以表示在转换过程中需要由数据工厂存储的临时数据,甚至是数据将写入的目标位置。接下来的代码块创建了三个数据集——分别代表刚才提到的各个数据集方面。
读取数据集在以下代码块中显示:
{
"type": "datasets",
"name": "[variables('storageDataset')]",
"dependsOn": [
"[variables('dataFactoryName')]",
"[variables('storageLinkedServiceName')]"
],
"apiVersion": "2018-06-01",
"properties": {
"type": "AzureBlob",
"linkedServiceName": "[variables('storageLinkedServiceName')]",
"typeProperties": {
"folderPath": "[concat(parameters('sourceBlobContainer'), '/')]",
"fileName": "[parameters('sourceBlobName')]",
"format": {
"type": "TextFormat"
}
},
"availability": {
"frequency": "Hour",
"interval": 1
},
"external": true
}
},
中间数据集在以下代码行中显示:
{
"type": "datasets",
"name": "[variables('intermediateDataset')]",
"dependsOn": [
"[variables('dataFactoryName')]",
"[variables('sqlLinkedServiceName')]"
],
"apiVersion": "2018-06-01",
"properties": {
"type": "AzureSqlTable",
"linkedServiceName": "[variables('sqlLinkedServiceName')]",
"typeProperties": {
"tableName": "[variables('intermediateDataset')]"
},
"availability": {
"frequency": "Hour",
"interval": 1
}
}
},
最终,用于目标的数据集在这里显示:
{
"type": "datasets",
"name": "[variables('sqlDataset')]",
"dependsOn": [
"[variables('dataFactoryName')]",
"[variables('sqlLinkedServiceName')]"
],
"apiVersion": "2018-06-01",
"properties": {
"type": "AzureSqlTable",
"linkedServiceName": "[variables('sqlLinkedServiceName')]",
"typeProperties": {
"tableName": "[parameters('sqlTargetTable')]"
},
"availability": {
"frequency": "Hour",
"interval": 1
}
}
},
最后,我们需要在数据工厂中创建一个管道,能够将所有数据集和链接服务汇集在一起,帮助创建提取-转换-加载(ETL)数据解决方案。管道由多个活动组成,每个活动完成特定任务。所有这些活动都可以在 ARM 模板中定义,正如你接下来看到的。第一个活动将存储帐户中的 Blob 复制到一个中间 SQL 服务器,如下所示的代码:
{
"type": "dataPipelines",
"name": "[variables('pipelineName')]",
"dependsOn": [
"[variables('dataFactoryName')]",
"[variables('storageLinkedServiceName')]",
"[variables('sqlLinkedServiceName')]",
"[variables('storageDataset')]",
"[variables('sqlDataset')]"
],
"apiVersion": "2018-06-01",
"properties": {
"description": "Copies data from Azure Blob to Sql DB while invoking stored procedure",
"activities": [
{
"name": "BlobtoSqlTableCopyActivity",
"type": "Copy",
"typeProperties": {
"source": {
"type": "BlobSource"
},
"sink": {
"type": "SqlSink",
"writeBatchSize": 0,
"writeBatchTimeout": "00:00:00"
}
},
"inputs": [
{
"name": "[variables('storageDataset')]"
}
],
"outputs": [
{
"name": "[variables('intermediateDataset')]"
}
]
},
{
"name": "SqlTabletoSqlDbSprocActivity",
"type": "SqlServerStoredProcedure",
"inputs": [
{
"name": "[variables('intermediateDataset')]"
}
],
"outputs": [
{
"name": "[variables('sqlDataset')]"
}
],
"typeProperties": {
"storedProcedureName": "[parameters('sqlWriterStoredProcedureName')]"
},
"scheduler": {
"frequency": "Hour",
"interval": 1
},
"policy": {
"timeout": "02:00:00",
"concurrency": 1,
"executionPriorityOrder": "NewestFirst",
"retry": 3
}
}
],
"start": "2020-10-01T00:00:00Z",
"end": "2020-10-02T00:00:00Z"
}
}
]
}
最后一个活动将数据从中间数据集复制到最终目标数据集。
还有管道运行期间的开始和结束时间。
本节重点介绍了为数据相关解决方案创建 ARM 模板。在下一节中,我们将讨论用于在 Azure 上创建数据中心的 ARM 模板,涉及 Active Directory 和 DNS。
在 Azure 上创建带有 Active Directory 和 DNS 的 IaaS 解决方案
在 Azure 上创建 IaaS 解决方案意味着创建多个虚拟机,将虚拟机提升为域控制器,并使其他虚拟机加入该域控制器,成为域连接节点。还意味着安装一个用于名称解析的 DNS 服务器,并可以选择安装一个跳板服务器,以安全访问这些虚拟机。
模板在虚拟机上创建一个 Active Directory 林。它根据提供的参数创建多个虚拟机。
模板创建:
-
一些可用性集
-
一个虚拟网络
-
网络安全组用于定义允许和不允许的端口及 IP 地址
模板执行以下操作:
-
配置一个或两个域。默认情况下创建根域;子域是可选的
-
为每个域配置两个域控制器
-
执行所需的状态配置脚本,将虚拟机提升为域控制器
我们可以使用在 使用 ARM 模板的虚拟机解决方案 部分讨论的方法创建多个虚拟机。但是,如果这些虚拟机需要高可用性,它们应当是可用性集的一部分。需要注意的是,可用性集为部署在这些虚拟机上的应用程序提供 99.95% 的可用性,而可用性区域则提供 99.99% 的可用性。
可以按照以下代码配置可用性集:
{
"name": "[variables('adAvailabilitySetNameRoot')]",
"type": "Microsoft.Compute/availabilitySets",
"apiVersion": "2019-07-01",
"location": "[parameters('location')]",
"sku": {
"name": "Aligned"
},
"properties": {
"PlatformUpdateDomainCount": 3,
"PlatformFaultDomainCount": 2
}
},
一旦可用性集创建完成,就需要在虚拟机配置中添加一个附加配置文件,以将虚拟机与可用性集关联,具体代码如下所示:
"availabilitySet" : {
"id": "[resourceId('Microsoft.Compute/availabilitySets', parameters('adAvailabilitySetName'))]"
}
你应该注意,使用负载均衡器与虚拟机配合时,可用性集是强制性的。
虚拟网络配置中需要的另一个更改是添加 DNS 信息,如下所示的代码所示:
{
"name": "[parameters('virtualNetworkName')]",
"type": "Microsoft.Network/virtualNetworks",
"location": "[parameters('location')]",
"apiVersion": "2019-09-01",
"properties": {
"addressSpace": {
"addressPrefixes": [
"[parameters('virtualNetworkAddressRange')]"
]
},
"dhcpOptions": {
"dnsServers": "[parameters('DNSServerAddress')]"
},
"subnets": [
{
"name": "[parameters('subnetName')]",
"properties": {
"addressPrefix": "[parameters('subnetRange')]"
}
}
]
}
},
最后,要将虚拟机转换为 Active Directory,应该在虚拟机上执行 PowerShell 脚本或 期望状态配置(DSC)脚本。即使是将其他虚拟机加入域,也应该在那些虚拟机上执行另一组脚本。
可以使用 CustomScriptExtension
资源在虚拟机上执行脚本,具体代码如下所示:
{
"type": "Microsoft.Compute/virtualMachines/extensions",
"name": "[concat(parameters('adNextDCVMName'),'/PrepareNextDC')]",
"apiVersion": "2018-06-01",
"location": "[parameters('location')]",
"properties": {
"publisher": "Microsoft.Powershell",
"type": "DSC",
"typeHandlerVersion": "2.21",
"autoUpgradeMinorVersion": true,
"settings": {
"modulesURL": "[parameters('adNextDCConfigurationModulesURL')]",
"configurationFunction": "[parameters('adNextDCConfigurationFunction')]",
"properties": {
"domainName": "[parameters('domainName')]",
"DNSServer": "[parameters('DNSServer')]",
"DNSForwarder": "[parameters('DNSServer')]",
"adminCreds": {
"userName": "[parameters('adminUserName')]",
"password": "privateSettingsRef:adminPassword"
}
}
},
"protectedSettings": {
"items": {
"adminPassword": "[parameters('adminPassword')]"
}
}
}
},
在本节中,我们使用 IaaS 模式在 Azure 上创建了一个数据中心。我们创建了多个虚拟机,并将其中一台转换为域控制器,安装了 DNS,并为其分配了域。现在,网络上的其他虚拟机可以加入该域,并可以在 Azure 上形成一个完整的数据中心。
请参考 github.com/Azure/azure-quickstart-templates/tree/master/301-create-ad-forest-with-subdomain
获取在 Azure 上创建数据中心的完整代码清单。
总结
使用单一部署将资源部署到多个订阅、资源组和区域的选项,提供了增强的部署能力,减少了部署中的错误,并能访问高级功能,如创建灾难恢复站点和实现高可用性。
在本章中,你了解了如何使用 ARM 模板创建几种不同类型的解决方案。这包括创建一个基于基础架构的解决方案,其中包含虚拟机;使用 Azure App Service 创建的基于平台的解决方案;使用数据工厂资源(及其配置)创建的数据相关解决方案;以及在 Azure 上创建的一个数据中心,其中虚拟机上安装了 Active Directory 和 DNS。
在下一章,我们将专注于创建模块化 ARM 模板,这是架构师们希望将 ARM 模板提升到更高水平时必须掌握的关键技能。本章还将向你展示设计 ARM 模板的各种方式,并教你如何创建可重用和模块化的 ARM 模板。
第十六章:16. ARM 模板的模块化设计与实现
我们知道,有多种方法可以编写Azure 资源管理器(ARM)模板。使用 Visual Studio 和 Visual Studio Code 编写一个能够在 Azure 中配置所有必要资源的模板是相当容易的。一个单独的 ARM 模板可以包含 Azure 上解决方案所需的所有资源。这个单一的 ARM 模板可以小到仅几个资源,或者大到包含许多资源的模板。
尽管编写一个包含所有资源的单一模板非常具有诱惑力,但建议事先规划将 ARM 模板实现分成多个较小的 ARM 模板,以便避免未来与之相关的麻烦。
在本章中,我们将学习如何以模块化的方式编写 ARM 模板,以便它们能够随着时间的推移不断演进,且在变更、测试和部署时所需的参与和努力最小化。
然而,在编写模块化模板之前,最好先了解通过模块化编写模板所解决的问题。
本章将涵盖以下话题:
-
单模板的问题
-
理解嵌套和链接部署
-
链接模板
-
嵌套模板
-
自由流配置
-
已知配置
现在,让我们详细探讨上述话题,这将帮助您使用行业最佳实践编写模块化模板。
单模板方法的问题
表面上看,单个包含所有资源的大模板似乎不会有什么问题,但将来可能会出现一些问题。让我们讨论使用单个大模板时可能会遇到的问题。
更改模板时灵活性降低
使用包含所有资源的单个大模板使得将来进行更改变得困难。将所有依赖项、参数和变量都放在一个模板中,与较小的模板相比,更改模板可能需要花费大量时间。这些更改可能会影响模板的其他部分,且可能会被忽视,甚至引入错误。
排查大模板问题
大模板难以排查。这是一个已知的事实。模板中的资源数量越多,排查模板的问题就越困难。一个模板部署了所有资源,找到错误通常需要反复部署模板。开发人员在等待模板部署完成时会降低生产力。
此外,部署单个模板比部署较小的模板更加耗时。开发人员必须等待包含错误的资源部署完成后,才能采取任何行动。
依赖滥用
在较大的模板中,资源之间的依赖关系也往往变得更加复杂。由于 ARM 模板的工作方式,滥用 dependsOn
功能是很容易的。模板中的每个资源可以引用它之前的所有资源,而不是构建依赖关系树。ARM 模板在一个资源依赖于所有其他资源时并不会报错,尽管这些其他资源之间可能有相互依赖关系。这使得更改 ARM 模板容易引入 bug,有时甚至无法进行更改。
降低敏捷性
通常,一个项目中有多个团队,每个团队负责其在 Azure 中的资源。这些团队会发现很难使用单一 ARM 模板,因为应该由单个开发人员来更新这些模板。多个团队同时更新一个模板可能会导致冲突和难以解决的合并问题。拥有多个小模板可以使每个团队独立编写自己的 ARM 模板部分。
无法重用
如果你只有一个模板,那么你只能使用这个模板,并且使用这个模板意味着部署所有资源。没有办法直接选择单个资源,除非进行一些额外操作,比如添加条件资源。单一的大模板失去了重用性,因为你只能选择所有资源或没有资源。
了解单一大模板存在的诸多问题后,编写模块化模板是一种好习惯,这样我们可以获得以下好处:
-
多个团队可以在隔离的环境中独立工作各自的模板。
-
模板可以跨项目和解决方案重复使用。
-
模板易于调试和故障排除。
既然我们已经讨论了单一大模板的一些问题,接下来我们将探讨模块化模板的核心,并且它们如何帮助开发人员实现高效部署。
理解单一职责原则
单一职责原则是 SOLID 设计原则中的核心原则之一。它指出,一个类或代码段应该只负责单一功能,并且应完全拥有该功能。代码只有在当前功能发生功能变化或出现 bug 时才应发生更改或演变,而不是因为与当前组件无关的其他组件或代码的变化而改变。
将相同的原则应用于 ARM 模板有助于我们创建仅负责部署单一资源或功能的模板,而不是部署所有资源和完整解决方案。
使用这一原则将帮助你创建多个模板,每个模板负责一个单一资源或一小部分资源,而不是所有资源。
更快的故障排除和调试
每个模板的部署在 Azure 中都是一个独立的活动,是由输入、输出和日志组成的单独实例。当多个模板被部署来实现一个解决方案时,每个模板的部署都有独立的日志条目以及其输入和输出描述。与单个大型模板相比,使用来自多个部署的独立日志来隔离错误和排除故障要容易得多。
模块化模板
当一个单一的大型模板被拆解成多个模板,每个小模板负责自己的资源,而这些资源仅由包含它的模板拥有、维护并负责时,我们可以说这是模块化模板。每个模板都遵循单一职责原则。
在学习如何将一个大型模板拆分为多个小型可重用模板之前,理解创建小型模板背后的技术以及如何组合它们来部署完整解决方案是非常重要的。
部署资源
ARM 提供了一种链接模板的功能。尽管我们已经详细讲解了链接模板,但我还是在这里提一下,以帮助你理解链接模板如何帮助我们实现模块化、组合和重用。
ARM 模板提供了专门的资源,称为 Microsoft.Resources
命名空间。ARM 模板中的部署资源看起来非常类似于以下的代码片段:
"resources": [ { "apiVersion": "2019-10-01", "name": "linkedTemplate", "type": "Microsoft.Resources/deployments", "properties": { "mode": "Incremental", <nested-template-or-external-template> } }]
这个模板不言自明,模板资源中最重要的两个配置项是类型和属性。这里的类型指的是部署资源,而不是任何特定的 Azure 资源(如存储、虚拟机等),属性则指定了部署配置,包括链接模板部署或嵌套模板部署。
然而,部署资源的作用是什么呢?部署资源的工作是部署另一个模板。另一个模板可以是一个独立的外部模板,位于一个单独的 ARM 模板文件中,也可以是一个嵌套模板。这意味着可以像函数调用一样,从一个模板中调用其他模板。
ARM 模板中可以有嵌套级别的部署。这意味着一个模板可以调用另一个模板,而被调用的模板又可以调用另一个模板,这样的嵌套调用最多可以有五个级别:
图 16.1:模板拆分成更小的模板
现在我们已经理解了大型模板可以通过将资源分布在不同的模板中实现模块化,我们需要将它们链接在一起,以便在 Azure 上部署资源。链接模板和嵌套模板是将多个模板组合在一起的方式。
链接模板
链接模板是调用外部模板的模板。外部模板存储在不同的 ARM 模板文件中。以下是链接模板的示例:
"resources": [ { "apiVersion": "2019-10-01", "name": "linkedTemplate", "type": "Microsoft.Resources/deployments", "properties": { "mode": "Incremental", "templateLink": { "uri":"https://mystorageaccount.blob.core.windows.net/AzureTemplates/newStorageAccount.json", "contentVersion":"1.0.0.0" }, "parametersLink": { "uri":"https://mystorageaccount.blob.core.windows.net/AzureTemplates/newStorageAccount.parameters.json", "contentVersion":"1.0.0.0" } } }]
相较于前一个模板,这个模板中重要的额外属性是templateLink
和parametersLink
。现在,templateLink
指向外部模板文件的实际 URL,而parametersLink
是相应parameters
文件的 URL 位置。需要注意的是,调用模板应该有访问被调用模板位置的权限。例如,如果外部模板存储在 Azure Blob 存储中,并且该存储受到密钥保护,则调用模板必须能够使用适当的安全访问签名(SAS)密钥才能访问链接的模板。
也可以提供显式的内联参数,而不是parametersLink
值,如下所示:
"resources": [ { "apiVersion": "2019-10-01", "name": "linkedTemplate", "type": "Microsoft.Resources/deployments", "properties": { "mode": "Incremental", "templateLink": { "uri":"https://mystorageaccount.blob.core.windows.net/AzureTemplates/newStorageAccount.json", "contentVersion":"1.0.0.0" }, "parameters": { "StorageAccountName":{"value": " [parameters('StorageAccountName')]"} } } }]
现在你对链接模板有了较好的理解。一个紧密相关的话题是嵌套模板,下一节将详细讨论这一点。
嵌套模板
相较于外部链接模板,嵌套模板是 ARM 模板中的一个相对较新的功能。
嵌套模板不会在外部文件中定义资源。资源是在调用模板本身和部署资源中定义的,如下所示:
"resources": [ { "apiVersion": "2019-10-01", "name": "nestedTemplate", "type": "Microsoft.Resources/deployments", "properties": { "mode": "Incremental", "template": { "$schema": "https://schema.management.azure.com/schemas/2015- 01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "resources": [ { "type": "Microsoft.Storage/storageAccounts", "name": "[variables('storageName')]", "apiVersion": "2019-04-01", "location": "West US", "properties": { "accountType": "Standard_LRS" } } ] } } }]
在这个代码段中,我们可以看到存储账户资源被嵌套在原始模板内,作为部署资源的一部分。与使用templateLink
和parametersLink
属性不同,这里使用resources
数组作为单个部署的一部分来创建多个资源。使用嵌套部署的优势是,可以通过使用资源的名称来重新配置父级内的资源。通常,一个带有名称的资源在模板中只能存在一次。嵌套模板允许我们在同一个模板内使用它们,并确保所有模板都是自给自足的,而不是分别存储,并且这些模板可能或可能无法访问外部文件。
现在我们了解了模块化 ARM 模板背后的技术,应该如何将一个大型模板分解为更小的模板呢?
有多种方式可以将一个大型模板分解成更小的模板。微软推荐以下模式用于 ARM 模板的分解:
图 16.2:模板分解策略
当我们将一个大型模板分解成更小的模板时,总是会有一个主模板,用于部署解决方案。这个主模板或母模板内部调用其他嵌套或链接的模板,这些模板又会调用其他模板,最终,包含 Azure 资源的模板会被部署。
主模板可以调用已知配置资源模板,后者又会调用包含 Azure 资源的模板。已知配置资源模板是特定于项目或解决方案的,且与之相关的可重用因素较少。成员资源模板是由已知配置资源模板调用的可重用模板。
如果需要,主模板可以调用共享资源模板和其他资源模板(如果它们存在)。
理解已知配置非常重要。模板可以作为已知配置或自由流配置来编写。
自由流配置
ARM 模板可以作为通用模板进行编写,其中大多数(如果不是全部)分配给变量的值都作为参数获取。这允许使用该模板的人传递他们认为必要的任何值来在 Azure 中部署资源。例如,部署模板的人可以选择任何大小的虚拟机、任何数量的虚拟机以及任何存储和网络配置。这被称为自由流配置,其中大多数配置是允许的,模板中的配置来自用户,而不是声明在模板内部。
这种配置方式有其挑战性。最大的问题是,并非所有配置都能在每个 Azure 区域和数据中心中得到支持。如果某些资源不允许在特定位置或区域创建,那么模板将无法创建这些资源。自由流配置的另一个问题是,用户可以提供他们认为必要的任何值,模板会尊重这些值,从而增加了成本和部署的负担,即使这些值并不是完全必需的。
已知配置
另一方面,已知配置是通过 ARM 模板部署环境的特定预设配置。这些预设配置被称为T 恤尺码配置。类似于 T 恤有小号、中号和大号等预设尺码,ARM 模板也可以预配置为部署小型、中型或大型环境,具体取决于需求。这意味着用户不能为环境选择任何随机的自定义尺寸,但可以从提供的选项中进行选择,并且在运行时执行的 ARM 模板将确保提供合适的环境配置。
因此,创建模块化 ARM 模板的第一步是决定环境的已知配置。
例如,以下是 Azure 上数据中心部署的配置:
表 16.1:Azure 上数据中心部署的配置
现在我们了解了这些配置,就可以创建模块化 ARM 模板了。
编写模块化 ARM 模板有两种方法:
-
组合模板:组合模板链接到其他模板。组合模板的示例包括主模板和中间模板。
-
叶级模板:叶级模板是包含单一 Azure 资源的模板。
ARM 模板可以根据以下内容分为模块化模板:
-
技术
-
功能
决定如何编写 ARM 模板的模块化方法的理想方式如下:
-
定义资源级或叶级模板,这些模板由单一资源组成。在接下来的图示中,最右侧的模板是叶级模板。在图中,虚拟机、虚拟网络、存储等位于同一列中,表示叶级模板。
-
使用叶级模板组合特定于环境的模板。这些特定于环境的模板提供了一个 Azure 环境,例如 SQL Server 环境、App Service 环境或数据中心环境。我们进一步探讨一下这个话题。以 Azure SQL 环境为例。要创建一个 Azure SQL 环境,需要多个资源。至少需要一个逻辑 SQL Server,一个 SQL 数据库和一些 SQL 防火墙资源。所有这些资源都在叶级模板中定义。这些资源可以组合在一起,形成一个单一的模板,从而能够创建 Azure SQL 环境。任何想要创建 SQL 环境的人都可以使用这个组合模板。图 16.3中有数据中心、消息传递和App Service作为特定于环境的模板。
-
创建具有更高抽象层次的模板,将多个特定于环境的模板组合成解决方案。这些模板是由前一步创建的特定于环境的模板组成的。例如,要创建一个需要 App Service 环境和 SQL 环境的电子商务库存解决方案,可以将两个环境模板——App Service 和 SQL Server 组合在一起。图 16.3中包含了功能 1和功能 2模板,这些模板是由子模板组成的。
-
最后,应该创建一个主模板,它由多个模板组成,每个模板都能够部署一个解决方案。
上述创建模块化设计模板的步骤,可以通过图 16.3轻松理解:
图 16.3:模板和资源映射
现在,我们将实现上图所示的部分功能。在此实现中,我们将通过模块化的方法为虚拟机提供脚本扩展。自定义脚本扩展部署 Docker 二进制文件,并在 Windows Server 2016 虚拟机上准备一个容器环境。
现在,我们将使用模块化方法通过 ARM 模板创建一个解决方案。如前所述,第一步是创建单独的资源模板。这些单独的资源模板将用于组合成能够创建环境的其他模板。这些模板将用于创建虚拟机。所有此处展示的 ARM 模板都可以在随书章节代码中找到。这些模板的名称和代码如下:
-
Storage.json
-
virtualNetwork.json
-
PublicIPAddress.json
-
NIC.json
-
VirtualMachine.json
-
CustomScriptExtension.json
首先,让我们看看 Storage.json
模板的代码。此模板提供了一个存储帐户,每个虚拟机都需要它来存储操作系统和数据磁盘文件:
{ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "storageAccountName": { "type": "string", "minLength": 1 }, "storageType": { "type": "string", "minLength": 1 }, ... "outputs": { "resourceDetails": { "type": "object", "value": "[reference(parameters('storageAccountName'))]" } }}
接下来,让我们看看公共 IP 地址模板的代码。一个需要通过互联网访问的虚拟机需要将公共 IP 地址资源分配给其网络接口卡。尽管将虚拟机暴露到互联网是可选的,但该资源可能会在创建虚拟机时使用。以下代码位于 PublicIPAddress.json
文件中:
{ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "publicIPAddressName": { "type": "string", "minLength": 1 }, "publicIPAddressType": { "type": "string", "minLength": 1 ... } } ], "outputs": { "resourceDetails": { "type": "object", "value": "[reference(parameters('publicIPAddressName'))]" } }}
接下来,让我们看看虚拟网络的代码。Azure 上的虚拟机需要虚拟网络进行通信。此模板将用于在 Azure 上创建一个虚拟网络,具有预定义的地址范围和子网。以下代码位于 virtualNetwork.json
文件中:
{ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "virtualNetworkName": { "type": "string", "minLength": 1 ... }, "subnetPrefix": { "type": "string", "minLength": 1 }, "resourceLocation": { "type": "string", "minLength": 1 } ... "subnets": [ { "name": "[parameters('subnetName')]", "properties": { "addressPrefix": "[parameters('subnetPrefix')]" } } ] } } ], "outputs": { "resourceDetails": { "type": "object", "value": "[reference(parameters('virtualNetworkName'))]" } }}
接下来,让我们看看网络接口卡的代码。虚拟机需要一个虚拟网络卡来连接虚拟网络,并接收和发送来自互联网的请求。以下代码位于 NIC.json
文件中:
{ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "nicName": { "type": "string", "minLength": 1 }, "publicIpReference": { "type": "string", "minLength": 1 ...[resourceId(subscription().subscriptionId,resourceGroup().name, 'Microsoft.Network/publicIPAddresses', parameters('publicIpReference'))]", "vnetRef": "[resourceId(subscription().subscriptionId,resourceGroup().name, 'Microsoft.Network/virtualNetworks', parameters('virtualNetworkReference'))]", "subnet1Ref": "[concat(variables('vnetRef'),'/subnets/', parameters('subnetReference'))]" }, ... "id": "[variables('subnet1Ref')]" } } } ] } } ], "outputs": { "resourceDetails": { "type": "object", "value": "[reference(parameters('nicName'))]" } }}
接下来,让我们看看创建虚拟机的代码。每个虚拟机都是 Azure 中的一个资源,并且请注意,此模板与存储、网络、公共 IP 地址或之前创建的其他资源没有关联。这个引用和组合将在本节稍后通过另一个模板完成。以下代码位于 VirtualMachine.json
文件中:
{ "$schema": "https://schema.management.azure.com/schemas/2015-01 01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "vmName": { "type": "string", "minLength": 1 ... }, "imageOffer": { "type": "string", "minLength": 1 }, "windowsOSVersion": { "type": "string", "minLength": 1 }, ... "outputs": { "resourceDetails": { "type": "object", "value": "[reference(parameters('vmName'))]" } }
}
接下来,让我们看看创建自定义脚本扩展的代码。此资源在虚拟机配置后执行 PowerShell 脚本。此资源提供了在 Azure 虚拟机中执行后配置任务的机会。以下代码位于 CustomScriptExtension.json
文件中:
{ "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "VMName": { "type": "string", "defaultValue": "sqldock", "metadata": {... "commandToExecute": "[concat('powershell -ExecutionPolicy Unrestricted -file docker.ps1')]" }, "protectedSettings": { } } } ], "outputs": { }}
接下来,我们将查看准备 Docker 环境的自定义脚本扩展 PowerShell 代码。请注意,在执行 PowerShell 脚本时,可能会发生虚拟机重启,具体取决于 Windows 容器功能是否已经安装。以下脚本安装了 NuGet 包、DockerMsftProvider
提供程序和 Docker 可执行文件。docker.ps1
文件随章节代码提供:
## docker.ps1 #Install-PackageProvider -Name Nuget -Force -ForceBootstrap -Confirm:$false Install-Module -Name DockerMsftProvider -Repository PSGallery -Force -Confirm:$false -verboseInstall-Package -Name docker -ProviderName DockerMsftProvider -Force -ForceBootstrap -Confirm:$false
所有之前看到的链接模板应上传到 Azure Blob 存储帐户中的一个容器内。该容器可以应用私有访问策略,正如你在上一章中看到的那样;然而,在此示例中,我们将访问策略设置为 container
。这意味着这些链接模板可以在没有 SAS 令牌的情况下访问。
最后,让我们集中讨论编写主模板。在主模板中,所有的链接模板将被组合在一起,创建一个解决方案——部署虚拟机并在其中执行脚本。相同的方法也可以用于创建其他解决方案,比如提供一个由多个相互连接的虚拟机组成的数据中心。以下代码可以在 Master.json
文件中找到:
{ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "storageAccountName": { "type": "string", "minLength": 1 ... }, "subnetName": { "type": "string", "minLength": 1 }, "subnetPrefix": { "type": "string", "minLength": 1 ... "windowsOSVersion": { "type": "string", "minLength": 1 }, "vhdStorageName": { "type": "string", "minLength": 1 }, "vhdStorageContainerName": { "type": "string", "minLength": 1 ...[concat('https://',parameters('storageAccountName'),'armtfiles.blob.core.windows.net/',variables('containerName'),'/Storage.json')]", "contentVersion": "1.0.0.0" }, "parameters": { "storageAccountName": { "value": "[parameters('storageAccountName')]" }, "storageType": { "value": "[parameters('storageType')]" }, "resourceLocation": { "value": "[resourceGroup().location]" ... "outputs": { "resourceDetails": { "type": "object", "value": "[reference('GetVM').outputs.resourceDetails.value]" } }}
主模板调用外部模板,并协调它们之间的相互依赖关系。
外部模板应存放在一个众所周知的位置,以便主模板可以访问并调用它们。在此示例中,外部模板存储在 Azure Blob 存储容器中,并通过参数将此信息传递给 ARM 模板。
存储在 Azure Blob 存储中的外部模板可以通过设置访问策略来进行访问保护。用于部署主模板的命令如下所示。它可能看起来是一个复杂的命令,但大多数值是作为参数使用的。在运行命令之前,建议你更改这些参数的值。已将链接模板上传到名为 st02gvwldcxm5suwe
的存储帐户中的 armtemplates
容器。如果资源组当前不存在,应先创建资源组。第一个命令用于在 West Europe
区域创建一个新的资源组:
New-AzResourceGroup -Name "testvmrg" -Location "West Europe" -Verbose
剩余的参数值是配置每个资源所需的。存储帐户名称和 dnsNameForPublicIP
值在 Azure 中应是唯一的:
New-AzResourceGroupDeployment -Name "testdeploy1" -ResourceGroupName testvmrg -Mode Incremental -TemplateFile "C:\chapter 05\Master.json" -storageAccountName "st02gvwldcxm5suwe" -storageType "Standard_LRS" -publicIPAddressName "uniipaddname" -publicIPAddressType "Dynamic" -dnsNameForPublicIP "azureforarchitectsbook" -virtualNetworkName vnetwork01 -addressPrefix "10.0.1.0/16" -subnetName "subnet01" -subnetPrefix "10.0.1.0/24" -nicName nic02 -vmSize "Standard_DS1" -adminUsername "sysadmin" -adminPassword $(ConvertTo-SecureString -String sysadmin@123 -AsPlainText -Force) -vhdStorageName oddnewuniqueacc -vhdStorageContainerName vhds -OSDiskName mynewvm -vmName vm10 -windowsOSVersion 2012-R2-Datacenter -imagePublisher MicrosoftWindowsServer -imageOffer WindowsServer -containerName armtemplates -Verbose
本节中,我们介绍了将大型模板拆分为较小的可重用模板的最佳实践,并在运行时将它们组合在一起,以便在 Azure 上部署完整的解决方案。在书中的后续章节中,我们将逐步修改 ARM 模板,直到探索其核心部分。我们使用了 Azure PowerShell cmdlet 来启动模板在 Azure 上的部署。
让我们继续讨论 copy
和 copyIndex
的话题。
理解 copy
和 copyIndex
有许多情况下需要多个实例的特定资源或资源组。例如,你可能需要配置 10 个相同类型的虚拟机。在这种情况下,反复部署模板来创建这些实例并不可取。更好的替代方法是使用 ARM 模板中的 copy
和 copyIndex
功能。
copy
是每个资源定义的一个属性。这意味着它可以用于创建某种资源类型的多个实例。
让我们通过一个在单个 ARM 模板部署中创建多个存储帐户的示例来理解这一点。
下一个代码片段按顺序创建了 10 个存储帐户。它们本可以通过将 mode
属性设置为 Parallel
来并行创建,而不是 Serial
:
"resources": [
{
"apiVersion": "2019-06-01",
"type": "Microsoft.Storage/storageAccounts",
"location": "[resourceGroup().location]",
"name": "[concat(variables('storageAccountName'), copyIndex())]",
"tags":{
"displayName": "[variables('storageAccountName')]"
},
"sku":{
"name":"Premium_ZRS"
},
"kind": "StorageV2",
"copy":{
"name": "storageInstances",
"count": 10,
"mode": "Serial"
}
}
],
在前面的代码中,copy
用于按顺序创建 10 个存储帐户实例,即一个接一个地创建。所有 10 个实例的存储帐户名称必须是唯一的,copyIndex
被用来通过将原始存储名称与索引值连接起来使它们唯一。copyIndex
函数返回的值在每次迭代时都会变化;它从 0 开始,并持续 10 次迭代。这意味着它在最后一次迭代时会返回 9
。
现在我们已经了解了如何创建多个 ARM 模板实例,接下来我们将深入探讨如何保护这些模板免受已知的安全漏洞。
保护 ARM 模板
与创建企业 ARM 模板相关的另一个重要方面是对其进行适当的安全保护。ARM 模板包含资源配置和基础设施的关键信息,因此它们不应被破坏或被未经授权的人访问。
保护 ARM 模板的第一步是将它们存储在存储帐户中,并停止对存储帐户容器的任何匿名访问。此外,应该为存储帐户生成 SAS 令牌,并在 ARM 模板中使用这些令牌来调用链接的模板。这将确保只有持有 SAS 令牌的人才能访问这些模板。此外,这些 SAS 令牌应该存储在 Azure Key Vault 中,而不是硬编码到 ARM 模板中。这样可以确保即使是负责部署的人也无法访问 SAS 令牌。
保护 ARM 模板的另一个步骤是确保任何敏感信息和机密,如数据库连接字符串、Azure 订阅和租户标识符、服务主体标识符、IP 地址等,不应硬编码到 ARM 模板中。它们应全部作为参数,并且值应在运行时从 Azure Key Vault 中提取。然而,在使用这种方法之前,确保这些机密已经在 Key Vault 中存储好,是非常重要的。
以下代码展示了在运行时使用参数文件从 Azure Key Vault 中提取值的方式之一:
{ "$schema": https://schema.management.azure.com/schemas/2016-01-01/deploymentParameters.json#, "contentVersion": "1.0.0.0", "parameters": { "storageAccountName": { "reference": { "keyVault": { "id": "/subscriptions/--subscription id --/resourceGroups/rgname/providers/Microsoft.KeyVault/vaults/keyvaultbook"), "secretName": "StorageAccountName" } } } }}
在这个代码示例中,定义了一个参数,用于引用 Azure Key Vault,以便在部署过程中运行时获取值。Azure Key Vault 的标识符和秘密名称已作为输入值提供。
现在您已经了解了如何保护 ARM 模板,接下来我们来看看如何识别它们之间的各种依赖关系,以及如何启用多个模板之间的通信。
在 ARM 模板之间使用输出
使用链接模板时,一个容易被忽视的重要方面是可能会存在资源依赖性。例如,SQL Server 资源可能位于与虚拟机资源不同的链接模板中。如果我们希望为虚拟机 IP 地址打开 SQL Server 防火墙,那么在配置虚拟机后,我们应该能够将此信息动态传递给 SQL Server 防火墙资源。
如果 SQL Server 和虚拟机资源在同一个模板中,可以通过使用REFERENCES
函数简单地引用 IP 地址资源来实现此功能。
如果我们希望在不同模板之间共享运行时属性值,那么在链接模板的情况下,情况会稍微复杂一些。
ARM 模板提供了outputs
配置,它负责从当前模板部署生成输出并将其返回给用户。例如,我们可以使用reference
函数输出一个完整的对象,如下所示,或者我们也可以仅输出一个 IP 地址作为字符串值:
"outputs": {
"storageAccountDetails": {
"type": "object",
"value": "[reference(resourceid ('Microsoft.Storage/storageAccounts', variables('storageAccountName')))]",
"virtualMachineIPAddress": {
"type": "string",
"value": "[reference(variables ('publicIPAddressName')).properties.ipAddress]"
}
}
}
链接模板中的参数可以被主模板利用。当调用链接模板时,输出将可供主模板使用,并可以作为参数传递给下一个链接模板或嵌套模板。通过这种方式,能够将资源的运行时配置值从一个模板传递到另一个模板。
主模板中的代码将类似于这里所展示的代码;这是用于调用第一个模板的代码:
{ "type": "Microsoft.Resources/deployments", "apiVersion": "2017-05-10", "name": "createvm", "resoureceGroup": "myrg", "dependsOn": [ "allResourceGroups" ], "properties":{ "mode": "Incremental", "templateLink":{ "uri": "[variables( 'templateRefSharedServicesTemplateUri')]", "contentVersion": "1.0.0.0" }, "parameters": { "VMName": { "value": "[variables('VmName')]" } } }}
前面的代码片段来自主模板,它调用了一个负责配置虚拟机的嵌套模板。该嵌套模板有一个输出部分,提供虚拟机的 IP 地址。主模板将在其模板中包含另一个部署资源,该资源将获取输出值并在运行时将其作为参数传递给下一个嵌套模板,从而传递 IP 地址。如下所示:
{ "type": "Microsoft,Resources/deployments", "apiVersion": "2017-05-10", "name": "createSQLServer", "resourceGroup": "myrg", "dependsOn": [ "createvm" ], "properties": { "mode": "Incremental", "templateLink": { "uri": "[variables('templateRefsql')]", "contentVersion": "1.0.0.0" }, "parameters": { "VMName": { "value": "[reference ('createvm').outputs.virtualMachineIPAddress.value]" } } }}
在前面的代码列表中,调用了一个嵌套模板,并且一个参数被传递给它。这个参数的值来自前一个链接模板的输出,该输出被命名为virtualMachineIPAddress
。现在,嵌套模板将动态获取虚拟机的 IP 地址,并可以将其用作白名单中的 IP 地址。
使用这种方法,我们可以将运行时值从一个嵌套模板传递到另一个嵌套模板。
总结
ARM 模板是 Azure 中首选的资源配置方式。它们具有幂等性,为环境创建带来了一致性、可预测性和可重用性。在本章中,我们探讨了如何创建一个模块化的 ARM 模板。对于团队来说,花时间以适当的方式设计 ARM 模板非常重要,这样多个团队可以共同协作。ARM 模板具有高度的可重用性,并且只需最小的修改即可发展。在本章中,我们学习了如何创建具有安全设计的模板,如何在单次部署中配置多个资源实例,以及如何通过 ARM 模板的 outputs 部分将输出从一个嵌套模板传递到另一个模板。
下一章将转向 Azure 中另一种非常流行的技术——无服务器架构。Azure Functions 是 Azure 的主要无服务器资源之一,接下来我们将对其进行深入探讨,包括 Durable Functions(持久化函数)。
在上一章中,你学习了 ARM 模板,到目前为止,我们一直在处理 Azure 中的架构问题及其解决方案。然而,本章并非基于通用的架构。事实上,它探讨了本世纪最具颠覆性的技术之一。本章将讨论物联网(IoT)和 Azure 的细节。
Azure 物联网指的是一组由微软管理的云服务,这些服务可以连接、监控和控制数十亿个物联网资产。换句话说,物联网解决方案包括一个或多个物联网设备,这些设备会不断与云端的一台或多台后端服务器进行通信。
本章将涵盖以下主题:
-
Azure 与物联网
-
Azure 物联网概述
-
设备管理
-
注册设备
-
设备与物联网中心的通信
-
扩展物联网解决方案
-
IoT 解决方案的高可用性
-
物联网协议
-
使用消息属性路由消息
第十七章:物联网(IoT)
互联网是在 1980 年代发明的,随后逐渐变得普及。几乎每个人都开始在互联网上建立自己的存在,并开始创建自己的静态网页。最终,静态内容变得动态,可以根据上下文即时生成。在几乎所有的情况下,都需要一个浏览器才能访问互联网。当时有大量的浏览器可供选择,没有它们,使用互联网将变得困难重重。
在本世纪的第一个十年中,出现了一个有趣的发展——手持设备的兴起,如手机和平板电脑。手机开始变得更加便宜,并且无处不在。这些手持设备的硬件和软件能力得到了显著提高,甚至人们开始使用手机浏览器而非桌面浏览器。但一个特别明显的变化是移动应用的兴起。这些移动应用从商店下载,并通过互联网连接到后端系统。在上个十年末期,市场上涌现了数百万个应用,几乎每一种可想象的功能都被内置其中。这些应用的后端系统建立在云上,以便快速扩展。这是应用程序与服务器连接的时代。
但这就是创新的巅峰吗?互联网的下一个发展是什么?实际上,另一个范式现在正逐步成为主流:物联网。与仅有移动设备和平板设备连接互联网不同,为什么其他设备不能连接互联网呢?过去,这类设备仅在特定市场中可用;它们昂贵,难以普及,且硬件和软件功能有限。然而,自本十年初以来,这些设备的商业化正在大规模发展。这些设备变得越来越小,硬件和软件能力更强,存储和计算能力更大,可以通过多种协议连接互联网,并且几乎可以附加到任何物体上。这是连接设备到服务器、应用程序和其他设备的时代。
这促使了一个观点的形成,即物联网应用可以改变各行业的运作方式。以前闻所未闻的全新解决方案现在开始得以实现。现在,这些设备可以连接到任何东西;它们可以获取信息并将其发送到后端系统,后端系统能够从所有设备中整合信息,并对其采取行动或报告事件。
物联网传感器和控制设备可以在许多商业应用场景中得到利用。例如,它们可以用于车辆追踪系统,这些系统可以追踪车辆的所有重要参数,并将这些数据发送到集中式数据存储进行分析。智能城市计划也可以利用各种传感器来追踪污染水平、温度和街道拥堵情况。物联网还在农业相关活动中找到了应用,比如测量土壤肥力、湿度等。你可以访问 microsoft.github.io/techcasestudies/#technology=IoT&sortBy=featured
了解关于组织如何利用 Azure IoT 的真实案例。
在我们探索与物联网相关的工具和服务之前,我们将首先详细介绍物联网架构。
物联网架构
在深入了解与物联网相关的 Azure 及其功能和服务之前,了解构建端到端物联网解决方案所需的各种组件非常重要。
想象一下,全球范围内的物联网设备每秒都在向集中数据库发送数百万条消息。为什么要收集这些数据呢?答案是为了提取关于事件、异常和离群值的丰富信息,这些都与这些设备监控的内容相关。
让我们更详细地理解这一点。
物联网架构可以分为以下几个不同的阶段:
-
连接性:此阶段涉及设备与物联网服务之间的连接。
-
身份: 连接到物联网服务后,首先进行设备的识别,并确保它被允许向物联网服务发送设备遥测数据。这通过认证过程完成。
-
捕获: 在这个阶段,设备遥测数据被捕获并被物联网服务接收。
-
摄入: 在这个阶段,物联网服务摄取设备遥测数据。
-
存储: 设备遥测数据被存储。它可以是临时存储或永久存储。
-
转换: 遥测数据被转换以供进一步处理。这包括增加现有数据和推断数据。
-
分析: 转换后的数据用于发现模式、异常和洞见。
-
呈现: 洞见以仪表板和报告的形式展示。此外,还可以生成新的警报,可能会调用自动化脚本和流程。
图 17.1展示了一个通用的基于物联网的架构。数据由设备生成或收集,并发送到云网关。云网关将数据发送到多个后端服务进行处理。云网关是可选组件;当设备本身由于资源限制或缺乏可靠网络而无法向后端服务发送请求时,应使用它们。这些云网关可以整合多个设备的数据并将其发送到后端服务。然后,后端服务可以处理数据并向用户显示为洞察或仪表板:
图 17.1:一个通用的物联网应用架构
现在我们清楚了架构,让我们继续了解物联网设备如何与其他设备通信。
连通性
物联网设备需要通信以连接到其他设备。有各种各样的连接类型;例如,设备之间可以在一个区域内连接,设备与集中网关之间可以连接,设备与物联网平台之间也可以连接。
在所有这些情况下,物联网设备需要连接能力。这种能力可以是互联网连接、蓝牙、红外线或任何其他近设备通信形式。
然而,一些物联网设备可能无法连接到互联网。在这些情况下,它们可以连接到一个有能力连接到互联网的网关。
物联网设备使用协议发送消息。主要协议包括高级消息队列协议(AMQP)和消息队列遥测传输协议(MQTT)。
设备数据应发送到 IT 基础设施。MQTT 协议是一种设备到服务器的协议,设备可以使用它将遥测数据和其他信息发送到服务器。一旦服务器通过 MQTT 协议接收到消息,它需要使用基于消息和队列的可靠技术将消息传输到其他服务器。AMQP 是将消息可靠且可预测地传输到 IT 基础设施中其他服务器的首选协议:
图 17.2:MQTT 和 AMQP 协议的工作原理
接收来自物联网设备初始消息的服务器应将这些消息发送到其他服务器进行必要的处理,如保存日志、评估、分析和展示。
一些设备无法连接到互联网,或者不支持与其他服务器技术兼容的协议。为了使这些设备能够与物联网平台和云端协同工作,可以使用中间网关。网关有助于接入那些连接性差、网络能力不稳定的设备;这些设备可能使用非标准的协议,或者它们在资源和功率方面可能有局限。
在这种情况下,当设备需要额外的基础设施来连接到后端服务时,可以部署客户端网关。这些网关接收来自接近设备的消息,并将其转发(或推送)到 IT 基础设施和物联网平台进行进一步处理。这些网关在需要时能够进行协议转换。
在本节中,你了解了如何与其他设备进行通信以及网关在通信中扮演的角色。在下一节中,我们将讨论身份。
身份
物联网设备应在云平台上注册。未注册的设备不应允许连接到云平台。设备应注册并分配一个身份。设备在连接云时应发送其身份信息。如果设备未能发送此身份信息,则连接应失败。在本章后面的内容中,你将看到如何使用模拟应用为设备生成身份。正如你已经知道的,物联网设备用于捕获信息,在下一节中,我们将简要讨论捕获过程。
捕获
IoT 设备应能够捕捉信息。例如,它们应该能够读取或监控空气或土壤中的水分含量。此类信息可以基于频率进行捕捉——也许甚至每秒一次。信息捕获后,设备应能够将其发送到 IoT 平台进行处理。如果设备无法直接连接到 IoT 平台,它可以连接到中介云网关,并通过该网关将捕获的信息推送出去。
捕获数据的大小和捕获频率是设备最重要的因素。设备是否应该具备本地存储,以便暂时存储捕获的数据,是另一个需要考虑的重要方面。例如,如果设备有足够的本地存储,它可以在离线模式下工作。即使是移动设备,有时也作为连接到各种仪器的 IoT 设备,并且具备存储数据的能力。一旦我们捕获了数据,我们需要将其注入到 IoT 平台进行进一步分析,在下一节中,我们将探索注入。
注入
设备捕获和生成的数据应当发送到能够摄取和消费这些数据的 IoT 平台,以从中提取有意义的信息和见解。注入服务是至关重要的服务,因为其可用性和可扩展性会影响传入数据的吞吐量。如果由于可扩展性问题而导致数据被限制,或由于可用性问题无法摄取数据,那么数据将会丢失,数据集可能会受到偏倚或失真。我们已经捕获了数据,需要一个地方来存储这些数据。在下一节中,你将了解存储。
存储
IoT 解决方案通常处理数百万甚至数十亿条记录,涉及数 TB 甚至 PB 级别的数据。这些数据是有价值的,可以提供有关运营及其健康状况的见解。必须以这样的方式存储这些数据,以便能够对其进行分析。存储应当能随时供分析、应用程序和服务使用。存储解决方案应该从性能角度提供足够的吞吐量和延迟,并且要具有高可用性、可扩展性和安全性。下一节将讨论数据转换,这是存储和分析数据所必需的。
转换
IoT 解决方案通常是数据驱动的,并且需要处理大量数据。假设每辆车都有一个设备,并且每个设备每五秒钟发送一次消息。如果有一百万辆车发送消息,这相当于每天 2.88 亿条消息,每月 80 亿条消息。所有这些数据中都隐藏着大量信息和见解;然而,仅仅通过查看这些数据来理解它是非常困难的。
物联网设备捕获并存储的数据可以用来解决业务问题,但并非所有捕获的数据都很重要。只需要一部分数据就能解决问题。此外,物联网设备收集的数据可能也不一致。为了确保数据的一致性,并避免偏差或失真,应该对其进行适当的转换,使其准备好进行分析。在转换过程中,数据会被过滤、排序、删除、丰富并转化为结构化格式,以便下游的组件和应用能够使用。我们需要对转换后的数据进行一些分析,然后再进行呈现。作为工作流程中的下一步,我们将讨论分析。
分析
在前一步骤中转换的数据成为分析步骤的输入。根据手头的问题,可以对转换后的数据执行不同类型的分析。
以下是可以执行的不同类型的分析:
-
描述性分析:这种分析有助于发现物联网设备的状态和整体健康状况的模式和细节。此阶段识别并总结数据,以供更高级的分析阶段进一步使用。它有助于数据总结、与概率相关的统计分析、偏差识别以及其他统计任务。
-
诊断性分析:这种分析比描述性分析更为先进。它在描述性分析的基础上,尝试回答为什么某些事情会发生的问题。也就是说,它试图找出事件的根本原因。它使用高级概念,如假设和相关性,来寻找答案。
-
预测性分析:这种分析尝试预测未来发生的高概率事件。它基于过去的数据生成预测;回归分析是基于过去数据的一个例子。例如,预测汽车的价格、股市中的股票行为、汽车轮胎何时会爆裂等。
-
规范性分析:这种分析是最先进的。此阶段帮助识别应采取的行动,以确保设备和解决方案的健康状况不会恶化,并识别需要采取的预防措施。此阶段的分析结果有助于避免未来的问题并从根本上消除问题。
在最后阶段,分析结果以人类可读的方式呈现,供更广泛的受众理解和解读。在接下来的部分,我们将讨论呈现。
呈现
分析有助于基于数据识别答案、模式和见解。这些见解还需要以相关方能够理解的格式呈现给所有利益相关者。为此,仪表板和报告可以以统计或动态的方式生成,并展示给利益相关者。利益相关方可以利用这些报告采取进一步行动,并不断改进他们的解决方案。
为了快速回顾前面的步骤,我们首先从连接性开始,介绍了用于将数据从不支持标准协议的设备发送到网关的方法。接着,我们讨论了身份验证和数据捕获。捕获的数据随后会被摄取并存储,以便进一步转换。转换后,数据将进行分析,最后呈现给所有相关方。由于我们正在使用 Azure,在下一节中,我们将介绍什么是 Azure IoT,并从 Azure 的角度回顾我们至今所学的基本概念。
Azure IoT
现在,您已经了解了端到端物联网解决方案的各个阶段;每个阶段都至关重要,正确的实施对于任何解决方案的成功都是必须的。Azure 为这些阶段提供了大量服务。除了这些服务,Azure 还提供了 Azure IoT Hub,这是 Azure 的核心物联网服务和平台。它能够托管复杂、高可用、可扩展的物联网解决方案。我们将在深入了解其他服务后,进一步探讨 IoT Hub:
图 17.3:物联网解决方案的设备和服务列表
在下一节中,我们将遵循与之前讨论物联网架构时相似的模式,学习如何通过 Azure IoT 进行通信、身份验证、数据捕获、数据摄取、存储、转换、分析和呈现。
连接性
IoT Hub 提供了所有重要的协议套件,使设备能够连接到 IoT 中心。它提供:
-
HTTPS:超文本传输安全协议(HTTPS)方法使用由一对密钥组成的证书,称为私钥和公钥,用于加密和解密设备与 IoT Hub 之间的数据。它提供从设备到云的一种单向通信。
-
AMQP:AMQP 是一种行业标准,用于在应用程序之间发送和接收消息。它提供了丰富的基础设施来确保消息的安全性和可靠性,这也是它在物联网领域广泛使用的原因之一。它提供设备到 IoT Hub 和 IoT Hub 到设备的双向通信能力,设备可以使用 基于声明的安全性(CBS)或 简单身份验证和安全层(SASL)进行身份验证。它主要用于存在现场网关的场景,在这些场景中,多个设备关联的单一身份可以将遥测数据传输到云端。
-
MQTT:MQTT 是用于在应用程序之间发送和接收消息的行业标准。它提供设备到 Hub 以及 Hub 到设备的功能。它主要用于每个设备都有自己身份并直接与云进行身份验证的场景。
在下一部分,我们将讨论身份和设备如何进行身份验证。
身份
IoT Hub 提供设备身份验证服务。它提供一个接口,用于为每个设备生成唯一的身份哈希。当设备发送包含哈希的消息时,IoT Hub 可以通过检查其数据库中是否存在该哈希来进行身份验证。接下来,我们将了解数据是如何被捕获的。
捕获
Azure 提供 IoT 网关,使得不符合 IoT Hub 标准的设备能够适配并推送数据。可以在设备附近部署本地或中介网关,使多个设备能够连接到单一网关以捕获并发送它们的信息。同样,可以部署多个设备集群及其本地网关。还可以在云端部署云网关,能够从多个来源捕获和接收数据,并将其摄取到 IoT Hub。正如前面讨论的那样,我们需要摄取我们捕获的数据。在下一部分,你将学习如何使用 IoT Hub 进行数据摄取。
摄取
IoT 中心可以作为设备和其他应用程序的单一接入点。换句话说,IoT 消息的摄取是 IoT Hub 服务的责任。还有其他服务,例如事件中心和服务总线消息传递基础设施,也可以摄取传入的消息;然而,使用 IoT Hub 来摄取 IoT 数据的好处远大于使用事件中心和服务总线消息传递的好处。事实上,IoT Hub 的设计就是为了在 Azure 生态系统内摄取 IoT 消息,以便其他服务和组件可以对其进行处理。摄取的数据被存储到存储中。在进行任何形式的转换或分析之前,我们将在下一部分探讨存储在工作流中的作用。
存储
Azure 提供多种存储 IoT 设备消息的方式。这些方式包括存储关系数据、无模式的 NoSQL 数据和 Blob:
-
SQL 数据库:SQL 数据库提供关系型数据、JSON 和 XML 文档的存储。它提供丰富的 SQL 查询语言,并且使用完整的 SQL 服务器作为服务。如果设备数据定义明确且模式不需要频繁更改,它可以存储在 SQL 数据库中。
-
Azure 存储:Azure 存储提供表格存储和 Blob 存储。表格存储帮助以实体的形式存储数据,其中模式不重要。Blob 存储帮助将文件以 Blob 的形式存储在容器中。
-
Cosmos DB:Cosmos DB 是一个完整的企业级 NoSQL 数据库。它作为一项服务提供,能够存储无模式的数据。它是一个全球分布式数据库,可以跨洲提供数据的高可用性和可扩展性。
-
外部数据源:除了 Azure 服务外,客户还可以使用自己的数据存储,如在 Azure 虚拟机上的 SQL 服务器,并将其用于以关系格式存储数据。
下一部分将讲解转换与分析。
转换与分析
Azure 提供多个资源来执行对输入数据的作业和活动。以下是其中的一些:
-
数据工厂:Azure 数据工厂是一个基于云的数据集成服务,允许我们在云中创建基于数据的工作流,用于协调和自动化数据移动和数据转换。Azure 数据工厂帮助创建和安排基于数据的工作流(称为管道),这些工作流可以从不同的数据存储中提取数据;通过使用计算服务(如 Azure HDInsight、Hadoop、Spark、Azure 数据湖分析、Azure Synapse Analytics 和 Azure 机器学习)处理和转换数据;并将输出数据发布到数据仓库,用于 商业智能 (BI) 应用,而不是传统的 提取-转换-加载 (ETL) 平台。
-
Azure Databricks:Databricks 提供一个完整的、托管的端到端 Spark 环境。它可以通过 Scala 和 Python 帮助进行数据转换。它还提供了一个 SQL 库,使用传统的 SQL 语法来操作数据。它比 Hadoop 环境更具性能。
-
Azure HDInsight:微软和 Hortonworks 联手为公司提供一个大数据分析平台与 Azure 结合使用。HDInsight 是一个由 Apache Hadoop 和 Apache Spark 提供支持的强大、完全托管的云服务环境,利用 Microsoft Azure HDInsight。它帮助通过 Microsoft 和 Hortonworks 的行业领先的大数据云服务无缝加速工作负载。
-
Azure Stream Analytics:这是一个完全托管的实时数据分析服务,帮助对流数据进行计算和转换。Stream Analytics 可以检查来自设备或流程的海量数据,提取数据流中的信息,并寻找模式、趋势和关系。
-
机器学习:机器学习是一种数据科学技术,允许计算机使用现有数据预测未来的行为、结果和趋势。通过机器学习,计算机根据我们创建的模型学习行为。Azure 机器学习是一个基于云的预测分析服务,使得快速创建和部署预测模型成为可能。它提供了一个现成的算法库,可以在连接互联网的 PC 上创建模型并快速部署预测解决方案。
-
Azure Synapse Analytics:前身为 Azure 数据仓库。Azure Synapse Analytics 提供适用于企业数据仓库和大数据分析的分析服务。它支持直接流式数据摄取,并可以与 Azure IoT Hub 集成。
现在,您已经熟悉了 Azure 中用于处理 IoT 设备摄取数据的转换和分析工具,接下来我们来学习如何呈现这些数据。
演示
在对数据进行适当分析后,数据应该以可供利益相关者消费的格式呈现。有多种方式可以呈现数据洞察,包括通过使用 Azure App Service 部署的 Web 应用程序呈现数据,向通知中心发送数据,然后通知移动应用程序等。然而,展示和消费洞察的理想方法是使用 Power BI 报告和仪表板。Power BI 是微软的可视化工具,用于在互联网上呈现动态报告和仪表板。
总结来说,Azure IoT 与物联网架构的基本概念紧密契合。它遵循相同的流程;然而,Azure 赋予我们根据需求选择不同服务和依赖项的自由。在下一节中,我们将重点介绍 Azure IoT Hub,这是一个托管在云中的服务,由 Azure 完全管理。
Azure IoT Hub
物联网项目通常具有较高的复杂性。这种复杂性源于设备和数据的庞大数量。设备遍布全球,例如用于存储数据的监控和审计设备,处理和分析 PB 级数据,并最终根据洞察采取行动。此外,这些项目通常周期长,其需求因时间表的变化而不断变化。
如果企业希望尽早开始物联网项目,它将很快意识到我们提到的问题并非易于解决。这些项目需要足够的计算和存储硬件来应对,并且需要能够处理大量数据的服务。
IoT Hub 是一个旨在实现更快速、更优质、更简便的物联网项目交付的平台。它提供了所有必要的功能和服务,包括以下内容:
-
设备注册
-
设备连接
-
现场网关
-
云网关
-
实现行业协议,如 AMQP 和 MQTT 协议
-
存储传入消息的中心
-
基于消息属性和内容的消息路由
-
用于不同类型处理的多个端点
-
与 Azure 上其他服务的连接,用于实时分析等
我们已经概述了 Azure IoT Hub,现在让我们深入了解协议以及设备如何在 Azure IoT Hub 中注册。
协议
Azure IoT Hub 原生支持通过 MQTT、AMQP 和 HTTP 协议进行通信。在某些情况下,设备或现场网关可能无法使用这些标准协议之一,并需要协议适配。在这种情况下,可以部署自定义网关。Azure IoT 协议网关可以通过桥接流量到 IoT Hub,启用 IoT Hub 端点的协议适配。下一部分将讨论设备如何注册到 Azure IoT Hub。
设备注册
设备在向 IoT Hub 发送消息之前需要进行注册。设备注册可以通过 Azure 门户手动完成,也可以通过 IoT Hub SDK 自动完成。Azure 还提供了示例模拟应用程序,通过这些应用程序,可以轻松地为开发和测试目的注册虚拟设备。此外,还有一个可以作为虚拟设备使用的树莓派在线模拟器,当然,其他可以连接到 IoT Hub 的物理设备也可以进行配置。
如果你想模拟一个通常用于开发和测试目的的本地 PC 设备,可以在 Azure 文档中找到多种语言的教程。这些教程可在docs.microsoft.com/azure/iot-hub/iot-hub-get-started-simulated
访问。
树莓派在线模拟器可在docs.microsoft.com/azure/iot-hub/iot-hub-raspberry-pi-web-simulator-get-started
访问,对于需要在 IoT Hub 注册的物理设备,应使用docs.microsoft.com/azure/iot-hub/iot-hub-get-started-physical
中给出的步骤。
要通过 Azure 门户手动添加设备,IoT Hub 提供了IoT 设备菜单,可以用来配置新设备。选择新建选项将允许你创建一个新设备,如图 17.4所示:
图 17.4:通过 Azure 门户添加设备
创建设备身份后,应使用 IoT Hub 的主密钥连接字符串将每个设备连接到 IoT Hub:
图 17.5:为每个设备创建连接字符串
在此阶段,设备已成功注册到 IoT Hub,我们的下一个任务是实现设备与 IoT Hub 之间的通信。下一部分将详细介绍如何进行消息管理。
消息管理
设备注册到 IoT Hub 后,就可以开始与其进行交互。消息管理指的是 IoT 设备与 IoT Hub 之间如何进行通信或交互。这种交互可以是设备向云端发送数据,也可以是云端向设备发送数据。
设备到云端消息传递
在这种通信中必须遵循的最佳实践之一是,尽管设备可能会捕获大量信息,但只有那些重要的数据应传输到云端。消息的大小在物联网解决方案中非常重要,因为物联网解决方案通常有非常大的数据量。即使是多出的 1 KB 数据流动,也可能导致浪费 GB 级的存储和处理能力。每条消息都有属性和有效负载;属性定义了消息的元数据。此元数据包含关于设备、标识、标签以及其他有助于路由和识别消息的属性的数据。
设备或云网关应连接到 IoT Hub 以传输数据。IoT Hub 提供可以供设备使用的公共端点,设备可以连接并发送数据。IoT Hub 应作为后端处理的第一个接触点。IoT Hub 能够将这些消息进一步传输并路由到多个服务。默认情况下,消息存储在事件中心中。可以为不同类型的消息创建多个事件中心。设备用来发送和接收数据的内置端点可以在 IoT Hub 中的内置端点选项卡中查看。图 17.6 展示了如何找到内置端点:
图 17.6:创建多个事件中心
消息可以根据消息头和正文属性路由到不同的端点,如图 17.7所示:
图 17.7:向不同的端点添加新路由
IoT Hub 中的消息默认保存七天,消息的大小可以达到 256 KB。
微软提供了一个示例模拟器,用于模拟将消息发送到云端。它支持多种语言;可以在 docs.microsoft.com/azure/iot-hub/iot-hub-csharp-csharp-c2d
查看 C# 版本。
云端到设备消息传递
IoT Hub 是一个托管服务,提供双向消息传递基础设施。消息可以从云端发送到设备,然后设备根据消息执行相应操作。
有三种类型的云端到设备消息传递模式:
-
直接方法需要立即确认结果。直接方法通常用于设备的互动控制,例如开关车库百叶窗。它们遵循请求-响应模式。
-
使用 Azure 物联网设置设备属性时,提供 设备双胞胎 属性。例如,您可以将遥测发送间隔设置为 30 分钟。设备双胞胎是存储设备状态信息的 JSON 文档(例如元数据、配置和条件)。物联网中心为每个设备在物联网中心中持久化一个设备双胞胎。
-
云到设备的消息用于单向通知设备应用程序。此模式遵循“发送后忘记”模式。
在每个组织中,安全性都是一个重要问题,即使是在物联网设备和数据的情况下,这个问题依然存在。我们将在下一部分讨论安全性。
安全性
安全性是基于物联网的应用程序中的一个重要方面。基于物联网的应用程序包括使用公共互联网进行连接的设备,这些设备连接到后端应用程序。保护设备、后端应用程序及连接免受恶意用户和黑客攻击应被视为这些应用程序成功的首要任务。
物联网中的安全性
物联网应用程序主要围绕互联网构建,安全性在确保解决方案不被妥协方面起着至关重要的作用。影响物联网架构的一些重要安全决策列举如下:
-
关于使用 HTTP 和 HTTPS REST 端点的设备,受到证书保护的 REST 端点可确保从设备到云端及其反向传输的消息得到良好的加密和签名。这些消息对于入侵者来说应该毫无意义,并且极难破解。
-
如果设备连接到本地网关,则本地网关应使用安全的 HTTP 协议连接到云端。
-
设备必须先注册到物联网中心,才能发送任何消息。
-
传递到云端的信息应存储在受保护和安全的存储中。应使用存储在 Azure Key Vault 中的适当 SAS 令牌或连接字符串进行连接。
-
应使用 Azure Key Vault 存储所有的机密、密码和凭证,包括证书。
-
Azure 安全中心 for IoT 提供针对每个设备、IoT Edge 和 IoT Hub 的威胁防护和分析,涵盖您的物联网资产。我们可以根据安全评估在 Azure 安全中心中构建自己的仪表板。一些关键功能包括来自 Azure 安全中心的集中管理、自适应威胁保护和智能威胁检测。在实施安全的物联网解决方案时,考虑使用 Azure 安全中心是一种最佳实践。
接下来,我们将探讨物联网中心(IoT Hub)的可扩展性方面。
可扩展性
物联网中心的可扩展性与其他服务略有不同。在物联网中心,有两种类型的消息:
-
传入:设备到云的消息
-
传出:云到设备的消息
两者在可扩展性方面都需要考虑。
IoT Hub 在配置时提供了一些选项来配置可扩展性。这些选项在配置后也可用,可以更新以更好地满足解决方案的可扩展性要求。
IoT Hub 提供的可扩展性选项如下:
-
库存单位(SKU)版本,即 IoT Hub 的大小
-
单位数量
我们将首先查看 SKU 版本选项。
SKU 版本
IoT Hub 中的 SKU 决定了每个单位每天能处理的消息数量,包括入站和出站消息。共有四个层级,具体如下:
-
免费版:此版本允许每个单位每天处理 8,000 条消息,并支持双向消息(入站和出站)。最多可配置 1 个单位。此版本适用于熟悉和测试 IoT Hub 服务的功能。
-
标准版 (S1):此版本允许每个单位每天处理 400,000 条消息,并支持双向消息(入站和出站)。最多可配置 200 个单位。此版本适用于少量消息。
-
标准版 (S2):此版本允许每个单位每天处理 600 万条消息,并支持双向消息(入站和出站)。最多可配置 200 个单位。此版本适用于大量消息。
-
标准版 (S3):此版本允许每个单位每天处理 3 亿条消息,并支持双向消息(入站和出站)。最多可配置 10 个单位。此版本适用于非常大量的消息。
升级和扩展选项可以在 Azure 门户中的 IoT Hub 定价和规模 页面找到。这些选项将以 图 17.8 所示的形式展示给您:
图 17.8:选择定价和规模层级
您可能会注意到,标准版 S3 层级最多只允许 10 个单位,而其他标准层级则允许 200 个单位。这与为运行 IoT 服务所配置的计算资源的大小直接相关。标准版 S3 的虚拟机的大小和能力远高于其他层级,而其他层级的大小保持不变。
单位
单位定义了每个 SKU 在服务后端运行的实例数量。例如,2 个 标准版 S1 SKU 单位意味着 IoT Hub 每天可以处理 400K * 2 = 800K 消息。
增加单位数量将提高应用程序的可扩展性。图 17.9 来自 IoT Hub 的 定价和规模 页面,您可以在其中看到当前的定价层级和单位数量:
图 17.9:调整或迁移 IoT Hub 单位的选项
目前在 Azure IoT Hub 中蓬勃发展的服务之一是 Azure IoT Edge,它是一个完全托管的服务,建立在 Azure IoT Hub 之上。我们将在下一部分探讨什么是 Azure IoT Edge。
Azure IoT Edge
Microsoft Azure IoT Edge 利用边缘计算实现物联网解决方案。边缘计算是指您本地网络上可用的计算资源,位于网络的末端,公共互联网开始的地方。可以将其部署在您的主网络或具有防火墙隔离的来宾网络上。
Azure IoT Edge 包括 IoT Edge 运行时,需要安装在计算机或设备上。Docker 将安装在计算机上;计算机可以运行 Windows 或 Linux。Docker 的作用是运行 IoT Edge 模块。
Azure IoT Edge 依赖于混合云概念,您可以在本地硬件上部署和管理物联网解决方案,并轻松将其与 Microsoft Azure 集成。
Microsoft 为 Azure IoT Edge 提供了全面的文档,包括快速入门模板和安装模块的指导。文档链接是docs.microsoft.com/azure/iot-edge
。
在下一部分,我们将了解在 Azure IoT Hub 的情况下,如何管理基础设施以及如何为客户提供高可用性。
高可用性
IoT Hub 是 Azure 提供的平台即服务(PaaS)产品。客户和用户不会直接与运行 IoT Hub 服务的虚拟机的数量和大小进行交互。用户决定地区、IoT Hub 的 SKU 和其应用程序所需的单位数量。其余配置由 Azure 在后台确定并执行。Azure 确保每个 PaaS 服务默认是高度可用的。它通过确保多个虚拟机在数据中心内的不同机架上提供服务,从而实现这一点。通过将这些虚拟机放置在可用性集中,并置于单独的故障域和更新域中,Azure 确保了计划内和计划外维护的高可用性。可用性集确保了数据中心级别的高可用性。
在下一部分,我们将讨论 Azure IoT Central。
Azure IoT Central
Azure IoT Central 提供了一个平台,用于构建企业级物联网应用程序,以安全、可靠和可扩展的方式满足您的业务需求。IoT Central 消除了开发、维护和管理物联网解决方案的成本。
IoT Central 提供集中管理,您可以管理和监控设备、设备状态、规则创建和设备数据。在图 17.10中,您可以看到在创建 IoT Central 应用程序时,Azure 门户中可用的一些模板:
图 17.10 创建 Azure IoT Central 应用程序
模板将为您提供一个起点,您可以根据需求进行自定义。这将在开发阶段为您节省大量时间。
IoT Central 在撰写时提供七天的试用期,您可以在这里查看该服务的定价:azure.microsoft.com/pricing/details/iot-central/?rtc=1
。
Azure IoT Central 对于每个开发 IoT 应用程序的组织来说都是一项福音。
总结
IoT 是本十年最大的新兴技术之一,已经开始颠覆各行各业。曾经看似不可能的事情,现在突然变得可能。
本章中,我们探讨了 IoT Hub,并讨论了如何以比其他解决方案更快、更好、更便宜的方式将 IoT 解决方案交付给客户。我们还介绍了 IoT 如何加速整个开发生命周期,帮助公司缩短上市时间。最后,您了解了 Azure IoT Edge 和 Azure IoT Central。
为了帮助您有效分析日益增长的数据量,我们将在下一章讨论 Azure Synapse Analytics。
17. 设计 IoT 解决方案
第十八章:18. Azure Synapse Analytics for architects
Azure Synapse Analytics 是 Azure SQL Data Warehouse 的一个突破性进化。Azure Synapse 是一个完全托管的集成数据分析服务,将数据仓库、数据集成和大数据处理与加速洞察时间结合,形成一个单一的服务。
在本章中,我们将通过以下主题来探索 Azure Synapse Analytics:
-
Azure Synapse Analytics 概述
-
介绍 Synapse 工作区和 Synapse Studio
-
从现有的遗留系统迁移到 Azure Synapse Analytics
-
将现有的数据仓库模式和数据迁移到 Azure Synapse Analytics
-
使用 Azure Data Factory 重新开发可扩展的 ETL 流程
-
常见的迁移问题及解决方案
-
安全性考虑
-
帮助迁移到 Azure Synapse Analytics 的工具
Azure Synapse Analytics
如今,由于存储便宜且具有高弹性存储能力,组织正在比以往任何时候都要积累更多的数据。设计一个解决方案来分析如此庞大的数据量,以提供有关业务的有意义的洞察可能是一个挑战。许多企业面临的一个障碍是需要管理和维护两种类型的分析系统:
-
数据仓库:这些提供了关于业务的重要洞察。
-
数据湖:这些通过各种分析方法提供有关客户、产品、员工和流程的有意义的洞察。
这两个分析系统对企业至关重要,但它们是独立运行的。同时,企业需要从所有组织数据中获得洞察,以保持竞争力并创新流程,以获取更好的结果。
对于需要构建端到端数据管道的架构师,必须采取以下步骤:
-
从各种数据源中摄取数据。
-
将所有这些数据源加载到数据湖中进行进一步处理。
-
对不同数据结构和类型的数据进行清理。
-
准备、转换和建模数据。
-
通过 BI 工具和应用程序将清洗后的数据提供给成千上万的用户。
直到现在,每个步骤都需要不同的工具。不言而喻,市场上有如此多不同的服务、应用程序和工具,选择最适合的工具可能是一个令人畏惧的任务。
有许多可用于摄取、加载、准备和提供数据的服务。有无数基于开发人员所选择的语言的数据清洗服务。此外,一些开发人员可能更倾向于使用 SQL,一些可能希望使用 Spark,而其他人可能更喜欢使用无代码环境来转换数据。
即使选择了看似合适的工具,使用这些工具时仍然常常会面临陡峭的学习曲线。此外,由于不兼容,建筑师可能会遇到在不同平台和语言上维护数据管道时出现的意外后勤挑战。面对如此多的问题,实施和维护基于云的分析平台可能是一个困难的任务。
Azure Synapse Analytics 解决了这些问题及更多问题。它简化了整个现代数据仓库模式,使建筑师能够专注于在统一的环境中构建端到端的分析解决方案。
建筑师常见的场景
建筑师面临的最常见场景之一是制定迁移现有传统数据仓库解决方案到现代企业分析解决方案的计划。凭借无限的可扩展性和统一的体验,Azure Synapse 已成为许多建筑师考虑的首选。稍后在本章中,我们还将讨论从现有传统数据仓库解决方案迁移到 Azure Synapse Analytics 的常见架构考虑因素。
在接下来的部分中,我们将提供 Azure Synapse Analytics 关键特性技术概述。对于新接触 Azure Synapse 生态系统的建筑师来说,阅读本章后他们将获得关于 Synapse 所需的知识。
Azure Synapse Analytics 概述
Azure Synapse Analytics 使数据专业人员能够构建端到端的分析解决方案,同时利用统一的体验。它为 SQL 开发人员提供丰富的功能、无服务器按需查询、机器学习支持、原生嵌入 Spark、协作笔记本和数据集成等功能,且都集中在一个服务中。开发人员可以通过不同的引擎选择多种支持的语言(例如 C#、SQL、Scala 和 Python)。
Azure Synapse Analytics 的主要功能包括:
-
SQL 分析与池(完全配置)和按需(无服务器)。
-
完全支持 Python、Scala、C# 和 SQL 的 Spark。
-
数据流与无需编码的大数据转换体验。
-
数据集成与编排,实现数据集成并使代码开发过程自动化。
-
由 Azure Synapse Link 提供的云原生混合事务/分析处理(HTAP)版本。
为了访问上述所有功能,Azure Synapse Studio 提供了一个统一的网页 UI。
这个单一集成的数据服务对企业非常有利,因为它加速了 BI、AI、机器学习、物联网和智能应用的交付。
Azure Synapse Analytics 可以以极快的速度从数据仓库和大数据分析系统中获取并提供所有数据的洞察。它使数据专业人员能够使用熟悉的语言,如 SQL,来查询关系型和非关系型数据库,支持 PB 级别的数据规模。此外,诸如无限并发、智能工作负载管理和工作负载隔离等高级功能帮助优化所有关键工作负载查询的性能。
什么是工作负载隔离?
在大规模运行企业数据仓库的关键特性之一是工作负载隔离。这是指确保在计算集群中预留资源,使多个团队可以在数据上工作而互不干扰,如图 18.1所示:
图 18.1:工作负载隔离示例
你可以通过设置几个简单的阈值在集群中创建工作负载组。这些阈值会根据工作负载和集群的不同自动调整,但它们始终能确保用户运行工作负载时获得优质的体验。有关在 Azure Synapse Analytics 中配置工作负载隔离的更多信息,请参考techcommunity.microsoft.com/t5/data-architecture-blog/configuring-workload-isolation-in-azure-synapse-analytics/ba-p/1201739
。
为了充分理解 Azure Synapse 的优势,我们首先来看看 Synapse 工作区和 Synapse Studio。
Synapse 工作区和 Synapse Studio 介绍
Azure Synapse 的核心是工作区。工作区是数据仓库中构建分析解决方案的顶级资源。Synapse 工作区同时支持关系型和大数据处理。
Azure Synapse 提供一个统一的 Web UI,供数据准备、数据管理、数据仓库、大数据分析、商业智能(BI)和人工智能(AI)任务使用,这个界面被称为 Synapse Studio。与 Synapse 工作区一起,Synapse Studio 是数据工程师和数据科学家共享和协作分析解决方案的理想环境,如图 18.2所示:
图 18.2:Azure Synapse Studio 中的 Synapse 工作区
以下部分将重点介绍 Synapse 工作区和 Synapse Studio 的功能、关键特性、平台细节和最终用户服务:
功能:
-
一个快速、高度弹性且安全的数据仓库,具备行业领先的性能和安全性
-
使用 SQL 按需(无服务器)和 SQL 查询,能够通过熟悉的 T-SQL 语法来探索 Azure Data Lake 存储和数据仓库
-
Apache Spark 集成 Azure 机器学习
-
混合数据集成,旨在加速数据摄取和分析过程的操作化(摄取、准备、转换和服务)
-
与 Power BI 集成的商业报告生成和提供服务。
关键特性:
-
创建和操作数据摄取与编排的管道。
-
直接通过 Synapse Studio 探索 Azure Data Lake Storage 或数据仓库中的数据,以及任何外部连接到工作区的数据。
-
使用笔记本和 T-SQL 查询编辑器编写代码。
-
无需编写代码的数据转换工具,如果你不想自己编写代码。
-
监控、保护并管理你的工作区,无需离开环境。
-
面向整个分析解决方案的基于 Web 的开发体验。
-
Azure Synapse SQL 池中的备份和恢复功能允许创建恢复点,使得恢复或将数据仓库复制到先前状态变得更加简单。
-
通过 SQL 池在数 PB 的数据上并行运行 T-SQL 查询,以服务 BI 工具和应用程序。
-
按需 SQL 提供无服务器 SQL 查询,方便在 Azure Data Lake Storage 中进行数据探索和分析,无需任何基础设施的设置或维护。
-
满足从数据工程到数据科学的全方位分析需求,支持多种语言,如 Python、Scala、C#和 Spark SQL。
-
Spark 池简化了集群的复杂设置和维护,并简化了 Spark 应用程序的开发和 Spark 笔记本的使用。
-
提供 Spark 和 SQL 之间的深度集成,允许数据工程师在 Spark 中准备数据,将处理结果写入 SQL 池,并结合使用 Spark 和 SQL 进行数据工程和分析,内置支持 Azure Machine Learning。
-
高度可扩展的混合数据集成功能,通过自动化的数据管道加速数据摄取和操作化。
-
提供无摩擦的集成服务,统一的安全性、部署、监控和计费。
平台
-
支持配置计算和无服务器计算。配置计算的示例包括 SQL 计算和 Spark 计算。
-
配置的计算资源允许团队将计算资源分割,以便控制成本和使用情况,更好地与组织结构对齐。
-
另一方面,无服务器计算允许团队按需使用服务,而无需配置或管理任何底层基础设施。
-
Spark 和 SQL 引擎之间的深度集成。
在以下部分,我们将介绍 Azure Synapse 的其他功能,包括 Synapse 的 Apache Spark、Synapse SQL、按需 SQL、Synapse 管道和 Azure Synapse Link for Cosmos DB。
Synapse 的 Apache Spark
对于需要 Apache Spark 的客户,Azure Synapse 通过 Azure Databricks 提供第一方支持,并由 Azure 完全管理。Apache Spark 的最新版本将自动提供给用户,并包含所有安全补丁。你可以快速创建带有你选择的语言的笔记本,如 Python、Scala、Spark SQL 和.NET for Spark。
如果您在 Azure Synapse Analytics 中使用 Spark,它将作为一种软件即服务(SaaS)提供。例如,您可以在不设置或管理自己的服务(如虚拟网络)的情况下使用 Spark。Azure Synapse Analytics 将为您处理底层基础设施。这使您能够立即在 Azure Synapse Analytics 环境中使用 Spark。
在接下来的部分中,我们将探讨 Synapse SQL。
Synapse SQL
Synapse SQL 允许使用 T-SQL 查询和分析数据。有两种模型可供选择:
-
完全配置的模型
-
按需 SQL(无服务器)模型
按需 SQL
按需 SQL 提供无服务器 SQL 查询。这使得在 Azure 数据湖存储中更容易进行探索和数据分析,而无需任何设置或基础设施维护:
表 18.1:不同基础设施的比较
关键特性:
-
分析师可以专注于分析数据,而无需担心管理任何基础设施。
-
客户可以受益于简单灵活的定价模型,因为他们只需为实际使用的部分付费。
-
它使用熟悉的 T-SQL 语言语法和市场上最好的 SQL 查询优化器。SQL 查询优化器是查询引擎背后的大脑。
-
随着需求的增长,您可以独立地扩展计算和存储资源。
-
通过元数据同步和本地连接器与 SQL Analytics Pool 和 Spark 无缝集成。
Synapse 管道
Synapse 管道允许开发人员构建端到端的数据移动和数据处理工作流。Azure Synapse Analytics 使用Azure 数据工厂(ADF)技术提供数据集成功能。ADF 中的关键功能对于现代数据仓库管道至关重要,并且这些功能也在 Azure Synapse Analytics 中可用。所有这些功能都通过 Azure Synapse Analytics 工作区中的统一安全模型基于角色的访问控制(RBAC)进行封装。
图 18.3 展示了一个数据管道的示例以及直接集成在 Azure Synapse Analytics 环境中的 ADF 活动:
图 18.3:Azure Synapse Analytics 中的数据管道
关键特性:
-
用于管理、安全、监控和元数据管理的集成平台服务。
-
Spark 与 SQL 之间的本地集成。使用一行代码从/向 SQL Analytics 读取和写入 Spark 数据。
-
可以创建一个 Spark 表并使用 SQL Analytics 即时查询,而无需定义模式。
-
"免密钥"环境。通过单点登录和 Azure Active Directory 透传,无需密钥或登录即可与Azure 数据湖存储(ADLS)/数据库进行交互。
在接下来的部分中,我们将介绍 Azure Synapse Link for Cosmos DB。
Azure Synapse Link for Cosmos DB
Azure Synapse Link 是 HTAP 的云原生版本。它是 Azure Synapse 的扩展。正如我们之前所了解的,Azure Synapse 是一个用于对数据湖和数据仓库进行分析的单一托管服务,采用无服务器和预配计算方式。通过 Azure Synapse Link,这一覆盖面也可以扩展到操作性数据源。
Azure Synapse Link 消除了传统操作和分析系统中的瓶颈。Azure Synapse 通过在其所有数据服务中将计算与存储分离,使这一切成为可能。在事务处理方面,Cosmos DB 是一个高性能、地理复制的多模型数据库服务。在分析方面,Azure Synapse 提供无限的可扩展性。您可以独立地为事务和分析扩展资源。两者结合起来,使得云原生 HTAP 成为现实。一旦用户指明希望在 Cosmos DB 中提供的分析数据,该数据便会出现在 Synapse 中。它会自动将您希望分析的操作数据转化为面向分析的列式版本。因此,Cosmos DB 中对操作数据的任何更改都会持续更新到 Link 数据和 Synapse 中。
使用 Azure Synapse Link 的最大好处是,它消除了对计划性批处理或需要构建和维护操作管道的需求。
如前所述,Azure Synapse 是架构师在将现有遗留数据仓库解决方案迁移到现代企业分析解决方案时最常选择的平台。在下一节中,我们将讨论从现有遗留数据仓库解决方案迁移到 Azure Synapse Analytics 的常见架构考虑事项。
从现有遗留系统迁移到 Azure Synapse Analytics
如今,许多组织正在将其遗留数据仓库解决方案迁移到 Azure Synapse Analytics,以便获得 Azure Synapse 提供的高可用性、安全性、速度、可扩展性、成本节省和性能等好处。
对于使用遗留数据仓库系统(如 Netezza)的公司来说,情况更加严峻,因为 IBM 已宣布终止对 Netezza 的支持 (www.ibm.com/support/pages/end-support-dates-netezza-5200-netezza-8x50z-series-and-netezza-10000-series-appliances
)。
许多年前,一些公司选择了 Netezza 来管理和分析大量数据。今天,随着技术的进步,基于云的数据仓库解决方案的好处远远超过了本地解决方案。Azure Synapse 是一个无限制的云分析服务,具有无与伦比的洞察时间,能够加速为企业提供商业智能、人工智能和智能应用程序。凭借其多集群和分离的计算与存储架构,Azure Synapse 可以以传统系统(如 Netezza)无法做到的方式即时扩展。
本节涵盖了规划、准备和执行将现有传统数据仓库系统成功迁移到 Azure Synapse Analytics 的架构考虑因素和高层次方法论。适当时,将给出一些具体示例并引用 Netezza。本章并不打算成为一个全面的逐步迁移手册,而是一个实用的概述,帮助你进行迁移规划和项目范围界定。
本章还识别了一些常见的迁移问题及其可能的解决方案。还提供了关于 Netezza 和 Azure Synapse Analytics 之间差异的技术细节。它们应该作为迁移计划的一部分加以考虑。
为什么你应该将传统数据仓库迁移到 Azure Synapse Analytics
通过迁移到 Azure Synapse Analytics,使用传统数据仓库系统的公司可以利用云技术的最新创新,并将基础设施维护和平台升级等任务委托给 Azure。
已经迁移到 Azure Synapse 的客户,已经获得了许多好处,包括以下内容。
性能
Azure Synapse Analytics 通过使用大规模并行处理(MPP)和自动内存缓存等技术,提供了最佳的关系数据库性能。如需更多信息,请查看 Azure Synapse Analytics 架构(docs.microsoft.com/azure/synapse-analytics/sql-data-warehouse/massively-parallel-processing-mpp-architecture
)。
速度
数据仓库是一个处理密集型的过程。它涉及数据摄取、数据转化、数据清洗、数据聚合、数据集成以及数据可视化和报告的生成。将数据从原始来源转移到数据仓库的许多过程是复杂且相互依赖的。单一的瓶颈可能会减缓整个流程,而数据量的突增则加大了对速度的需求。当数据的时效性至关重要时,Azure Synapse Analytics 满足了对快速处理的需求。
提高的安全性和合规性
Azure 是一个全球可用、高度可扩展、安全的云平台。它提供许多安全功能,包括 Azure Active Directory、RBAC、托管身份和托管私有端点。Azure Synapse Analytics 位于 Azure 生态系统内,继承了所有上述的好处。
弹性和成本效率
在数据仓库中,工作负载处理的需求可能会波动。有时,这些波动可能在峰值和谷值之间有很大差异。例如,假期季节时,销售数据量可能会突然激增。云的弹性使得 Azure Synapse 能够根据需求快速增加或减少其容量,而不会影响基础设施的可用性、稳定性、性能和安全性。最棒的是,您只需为实际使用量付费。
托管基础设施
消除数据中心管理和运营的开销,使公司能够将宝贵的资源重新分配到创造价值的地方,专注于使用数据仓库提供最佳的信息和洞察力。这降低了总体拥有成本,并提供了更好的运营费用控制。
可扩展性
数据仓库中的数据量通常随着时间的推移和历史数据的积累而增长。Azure Synapse Analytics 可以通过根据数据和工作负载的增加逐步添加资源来扩展以应对这种增长。
节省成本
运营本地遗留数据中心成本高昂(考虑到服务器和硬件、网络、物理空间、电力、冷却和人员成本)。这些费用可以通过 Azure Synapse Analytics 显著减少。由于计算和存储层的分离,Azure Synapse 提供了非常有吸引力的性价比。
Azure Synapse Analytics 为您提供真正的按需付费云可扩展性,随着数据或工作负载的增长,无需复杂的重新配置。
现在您已经了解了迁移到 Azure Synapse Analytics 的好处,我们将开始讨论迁移过程。
三步迁移过程
一个成功的数据迁移项目始于一个精心设计的计划。有效的计划考虑到需要考虑的众多组件,特别关注架构和数据准备。以下是三步迁移过程计划。
准备工作
-
定义要迁移的范围。
-
创建数据和迁移过程的清单。
-
定义数据模型的变化(如果有的话)。
-
定义源数据提取机制。
-
确定适用的 Azure(和第三方)工具和服务。
-
尽早对员工进行新平台的培训。
-
设置 Azure 目标平台。
迁移
-
从小规模、简单的项目开始。
-
尽可能进行自动化。
-
利用 Azure 内置的工具和功能来减少迁移工作量。
-
迁移表格和视图的元数据。
-
迁移需要维护的历史数据。
-
迁移或重构存储过程和业务流程。
-
迁移或重构 ETL/ELT 增量加载流程。
迁移后
-
监控并记录过程的所有阶段。
-
利用获得的经验为未来的迁移构建模板。
-
如有需要,重新设计数据模型。
-
测试应用程序和查询工具。
-
基准测试和优化查询性能。
接下来,我们将讨论这两种迁移策略。
两种迁移策略
架构师应通过评估现有数据仓库来开始迁移规划,以确定哪种迁移策略最适合他们的情况。需要考虑两种迁移策略。
提升和迁移策略
对于“提升和迁移”策略,现有数据模型不做更改地迁移到新的 Azure Synapse Analytics 平台。这种做法旨在通过将变更的范围缩小到最低限度,最大程度地减少迁移的风险和所需时间。
“提升和迁移”是一种适用于遗留数据仓库环境(如 Netezza)的良好策略,特别是在以下任一条件成立时:
-
一个单独的数据集市需要迁移。
-
数据已经采用了良好的星型或雪花型架构。
-
移动到现代云环境面临着迫切的时间和成本压力。
重新设计策略
在遗留数据仓库经过一段时间的演变后,可能需要重新设计,以维持最佳的性能水平或支持新类型的数据。这可能包括改变底层数据模型。
为了最小化风险,建议首先使用“提升和迁移”策略进行迁移,然后逐步在 Azure Synapse Analytics 上使用重新设计策略现代化数据仓库数据模型。完全改变数据模型会增加风险,因为这会影响源到数据仓库的 ETL 作业以及下游的数据集市。
在下一节中,我们将提供一些关于如何在迁移前减少现有遗留数据仓库复杂性的建议。
在迁移前减少现有遗留数据仓库的复杂性
在上一节中,我们介绍了两种迁移策略。作为最佳实践,在初步评估步骤中,务必留意任何简化现有数据仓库的方法并记录下来。目标是在迁移前减少现有遗留数据仓库系统的复杂性,以便简化迁移过程。
这里是一些关于如何减少现有遗留数据仓库复杂性的建议:
-
迁移前删除并归档未使用的表:避免迁移不再使用的数据。这将有助于减少迁移的数据总量。
-
将物理数据集市转换为虚拟数据集市:最大限度地减少需要迁移的内容,降低总体拥有成本,提高灵活性。
在下一节中,我们将详细讨论为什么你应该考虑将物理数据集市转换为虚拟数据集市。
将物理数据集市转换为虚拟数据集市
在迁移遗留数据仓库之前,考虑将当前的物理数据集市转换为虚拟数据集市。通过使用虚拟数据集市,您可以消除物理数据存储和数据集市的 ETL 作业,而不会在迁移前失去任何功能。这里的目标是减少要迁移的数据存储数量,减少数据副本,降低总拥有成本,并提高灵活性。为此,您需要在迁移数据仓库之前,将物理数据集市转换为虚拟数据集市。我们可以将其视为迁移前的数据仓库现代化步骤。
物理数据集市的缺点
-
相同数据的多个副本
-
更高的总拥有成本
-
难以更改,因为 ETL 作业会受到影响
虚拟数据集市的优点
-
简化数据仓库架构
-
无需存储数据副本
-
更高的灵活性
-
更低的总拥有成本
-
使用下推优化技术,利用 Azure Synapse Analytics 的强大功能
-
易于变更
-
容易隐藏敏感数据
在下一节中,我们将讨论如何将现有数据仓库模式迁移到 Azure Synapse Analytics。
将现有数据仓库模式迁移到 Azure Synapse Analytics
迁移现有遗留数据仓库的模式涉及到现有暂存表、遗留数据仓库和相关数据集市模式的迁移。
为了帮助您理解模式迁移的规模和范围,我们建议您先创建现有遗留数据仓库和数据集市的清单。
以下是帮助您收集必要信息的清单:
-
行数
-
暂存、数据仓库和数据集市的数据大小:表和索引
-
数据压缩比
-
当前硬件配置
-
表(包括分区):识别小的维度表
-
数据类型
-
视图
-
索引
-
对象依赖
-
对象使用情况
-
功能:包括现成的函数和用户自定义函数(UDFs)
-
存储过程
-
可扩展性要求
-
增长预测
-
工作负载要求:并发用户
完成清单后,您可以决定要迁移哪个模式。基本上,对于遗留数据仓库模式迁移,您有四个选择:
-
一次迁移一个数据集市:
图 18.4:一次迁移一个数据集市
-
一次性迁移所有数据集市,然后是数据仓库:
图 18.5:一次迁移所有数据集市,然后是数据仓库
-
同时迁移数据仓库和暂存区:
图 18.6:同时迁移数据仓库和暂存区
-
一次性迁移所有内容:
图 18.7:一次性迁移所有内容
在选择迁移选项时,请记住目标是实现一个物理数据库设计,该设计在性能上能够匹配或超过您当前遗留数据仓库系统的性能,并且最好以更低的成本实现。
总结一下,以下是一些关于模式迁移的建议:
-
避免迁移不必要的对象或过程。
-
考虑使用虚拟数据集市,以减少或消除物理数据集市的数量。
-
尽可能实现自动化。在迁移到 Azure Synapse 时,应考虑实施 DataOps。
-
使用遗留数据仓库系统中的系统目录表元数据来生成 Azure Synapse Analytics 的 数据定义语言(DDL)。
-
在 Azure Synapse Analytics 上执行任何必要的数据模型更改或数据映射优化。
在下一节中,我们将讨论如何将历史数据从遗留数据仓库迁移到 Azure Synapse Analytics。
将历史数据从遗留数据仓库迁移到 Azure Synapse Analytics
一旦确定了模式迁移的范围,我们就可以开始决定如何迁移历史数据。
迁移历史数据的步骤如下:
-
在 Azure Synapse Analytics 上创建目标表。
-
迁移现有的历史数据。
-
根据需要迁移功能和存储过程。
-
迁移增量加载(ETL/ELT)暂存和处理即将到来的数据。
-
根据需要应用任何性能调优选项。
表 18.2 概述了四种数据迁移选项及其优缺点:
表 18.2:数据迁移选项及其优缺点
在下一节中,我们将讨论如何将现有的 ETL 过程迁移到 Azure Synapse Analytics。
将现有 ETL 过程迁移到 Azure Synapse Analytics
有多种选项可用于将现有的 ETL 过程迁移到 Azure Synapse Analytics。表 18.3 概述了一些基于现有 ETL 作业构建方式的 ETL 迁移选项:
表 18.3:ETL 迁移选项
在下一节中,我们将讨论如何使用 ADF 重新开发可扩展的 ETL 过程。
使用 ADF 重新开发可扩展的 ETL 过程
处理现有遗留 ETL 过程的另一种选择是通过使用 ADF 重新开发它们。ADF 是 Azure 的数据集成服务,用于创建数据驱动的工作流(称为管道),以协调和自动化数据移动和数据转换。您可以使用 ADF 创建并安排管道,从不同的数据存储中提取数据。ADF 可以通过使用计算服务(如 Spark、Azure 机器学习、Azure HDInsight Hadoop 和 Azure 数据湖分析)来处理和转换数据:
图 18.8:使用 ADF 重新开发可扩展的 ETL 过程
下一节将提供一些关于迁移查询、BI 报告、仪表板和其他可视化的建议。
关于迁移查询、BI 报告、仪表板和其他可视化的建议
如果旧版系统使用标准 SQL,从旧版数据仓库迁移查询、BI 报告、仪表板和其他可视化到 Azure Synapse Analytics 是直接的。
然而,通常情况下并非如此。在这种情况下,必须采取不同的策略:
-
确定优先迁移的报告。
-
使用使用情况统计数据来识别从未使用的报告。
-
避免迁移任何不再使用的内容。
-
一旦你列出了要迁移的报告、它们的优先级以及要跳过的未使用报告,请与相关方确认该列表。
-
对于正在迁移的报告,及早识别不兼容问题,以评估迁移工作量。
-
考虑使用数据虚拟化,以保护 BI 工具和应用程序免受在迁移过程中可能发生的数据仓库和/或数据集市数据模型结构变化的影响。
常见迁移问题及解决方案
在迁移过程中,你可能会遇到一些需要克服的问题。在本节中,我们将突出一些常见问题,并为你提供可以实施的解决方案。
问题 #1:不支持的数据类型及解决方法
表 18.4 显示了旧版数据仓库系统中不支持的数据类型,以及 Azure Synapse Analytics 的适用解决方法:
表 18.4:Azure Synapse Analytics 中不支持的数据类型及适用的解决方法
问题 #2:Netezza 和 Azure Synapse 之间的数据类型差异
表 18.5 将 Netezza 数据类型映射到其 Azure Synapse 对应的数据类型:
表 18.5:Netezza 数据类型及其 Azure Synapse 对应类型
问题 #3:完整性约束差异
密切关注你的旧版数据仓库或数据集市与 Azure Synapse Analytics 之间的完整性约束差异。在图 18.9中,左侧表示带有主键和外键约束的旧版数据仓库系统,右侧是新的 Azure Synapse Analytics 环境:
图 18.9:完整性约束差异
下一节将全面介绍在从旧版数据仓库迁移到 Azure Synapse Analytics 过程中如何解决其他常见的 SQL 不兼容问题。
常见 SQL 不兼容问题及解决方案
本节将提供有关传统数据仓库系统与 Azure Synapse Analytics 之间常见 SQL 不兼容性及其解决方案的技术细节。本节将解释并比较这些差异,并通过一个快速参考表提供解决方案,供您在开始迁移项目时参考。
我们将涵盖的主题如下:
-
SQL 数据定义语言 (DDL) 差异与解决方案
-
SQL 数据操作语言 (DML) 差异与解决方案
-
SQL 数据控制语言 (DCL) 差异与解决方案
-
扩展 SQL 差异与解决方法
SQL DDL 差异与解决方案
在本节中,我们将讨论传统数据仓库系统与 Azure Synapse Analytics 之间 SQL DDL 的差异与解决方案。
表 18.6:传统系统与 Azure Synapse 之间的 SQL DDL 差异
SQL DML 差异与解决方案
在本节中,我们将讨论传统数据仓库系统与 Azure Synapse Analytics 之间 SQL DML 的差异及其解决方案:
表 18.7:Netezza 与 Azure Synapse 之间的 SQL DML 差异
接下来,我们将讨论传统数据仓库系统与 Azure Synapse Analytics 之间 SQL DCL 的差异与解决方案。
SQL DCL 差异与解决方案
在本节中,我们将讨论传统数据仓库系统与 Azure Synapse Analytics 之间 SQL DCL 的差异与解决方案。Netezza 支持两类访问权限:管理权限和对象权限。表 18.8 映射了 Netezza 访问权限及其对应的 Azure Synapse 权限,供快速参考。
将 Netezza 管理权限映射到 Azure Synapse 对应权限
表 18.8 映射了 Netezza 管理权限与 Azure Synapse 对应权限:
表 18.8:Netezza 管理权限及其 Azure Synapse 对应权限
将 Netezza 对象权限映射到其 Azure Synapse 对应权限
表 18.9 映射了 Netezza 对象权限与 Azure Synapse 对应权限,供快速参考:
表 18.9:Netezza 对象权限及其 Azure Synapse 对应权限
扩展 SQL 差异与解决方法
表 18.10 描述了迁移到 Azure Synapse Analytics 时的扩展 SQL 差异和可能的解决方法:
表 18.10:扩展 SQL 差异与解决方法
在本节中,我们讨论了架构师在迁移项目中可能遇到的常见迁移问题及其解决方案。在下一节中,我们将查看架构师应关注的安全性考虑因素。
安全性考虑因素
保护和安全管理您的数据资产在任何数据仓库系统中都是至关重要的。在规划数据仓库迁移项目时,必须考虑安全性、用户访问管理、备份和恢复等因素。例如,数据加密可能是行业和政府法规(如 HIPAA、PCI 和 FedRAMP)以及非监管行业中的强制要求。
Azure 提供许多标准功能,这些功能在传统的数据仓库产品中通常需要自定义构建。Azure Synapse 标准支持数据静态加密和数据传输加密。
数据静态加密
-
透明数据加密(TDE)可以启用,以动态加密和解密 Azure Synapse 数据、日志及相关备份。
-
Azure 数据存储还可以自动加密非数据库数据。
数据传输中的加密
所有连接到 Azure Synapse Analytics 的连接默认都使用行业标准协议,如 TLS 和 SSH 进行加密。
此外,动态数据屏蔽(DDM)可以基于数据屏蔽规则,为特定类别的用户混淆数据。
作为最佳实践,如果您的传统数据仓库包含复杂的权限层次结构、用户和角色,请考虑在迁移过程中使用自动化技术。您可以使用传统系统中的现有元数据生成必要的 SQL,以便在 Azure Synapse Analytics 上迁移用户、组和权限。
在本章的最后一节,我们将回顾一些架构师可以选择的工具,帮助从传统数据仓库系统迁移到 Azure Synapse Analytics。
帮助迁移到 Azure Synapse Analytics 的工具
现在我们已经讨论了规划与准备工作以及迁移过程的概述,接下来我们来看看你可以用来将传统数据仓库迁移到 Azure Synapse Analytics 的工具。我们将讨论以下工具:
-
ADF
-
Azure 数据仓库迁移工具
-
微软物理数据传输服务
-
微软数据导入服务
让我们开始吧。
ADF
ADF 是一项完全托管、按需付费的混合数据集成服务,用于云规模的 ETL 处理。它提供以下功能:
-
在内存中并行处理和分析数据,以实现规模化并最大化吞吐量
-
创建数据仓库迁移管道,协调和自动化数据迁移、数据转换和数据加载到 Azure Synapse Analytics 中
-
也可以通过将数据导入到 Azure Data Lake、按规模处理和分析数据,并将数据加载到数据仓库中,来现代化您的数据仓库
-
支持基于角色的用户界面,用于 IT 专业人员的数据流映射,以及业务用户的自助数据处理。
-
可以连接多个跨数据中心、云和 SaaS 应用程序的数据存储
-
提供 90 多个原生构建且无需维护的连接器可用(
azure.microsoft.com/services/data-factory
) -
可以在同一管道中混合和匹配数据处理和映射数据流,以大规模准备数据。
-
ADF 编排可以控制数据仓库迁移到 Azure Synapse Analytics。
-
可以执行 SSIS ETL 包
Azure 数据仓库迁移工具
Azure 数据仓库迁移工具可以将数据从本地 SQL Server 数据仓库迁移到 Azure Synapse。它提供以下功能:
-
使用向导式方法执行从本地 SQL Server 数据仓库的模式和数据的“提升和转移”迁移。
-
您可以选择包含要导出到 Azure Synapse 的表格的本地数据库。然后,您可以选择要迁移的表格并迁移模式。
-
自动生成创建 Azure Synapse 中等效空数据库和表所需的 T-SQL 代码。一旦提供了 Azure Synapse 的连接详细信息,您可以运行生成的 T-SQL 代码迁移模式。
-
创建模式后,您可以使用该工具迁移数据。此操作会将数据从本地 SQL Server 数据仓库导出,并生成批量复制程序(BCP)命令,将数据加载到 Azure Synapse 中。
用于物理数据传输的 Microsoft 服务
在本节中,我们将介绍常用的 Microsoft 服务,这些服务可用于物理数据传输,包括 Azure ExpressRoute、AzCopy 和 Azure Databox。
Azure ExpressRoute
Azure ExpressRoute 允许您在数据中心与 Azure 之间建立私人连接,而无需通过公共互联网。它提供以下功能:
-
带宽高达 100 Gbps
-
低延迟
-
直接连接到您的广域网(WAN)
-
私有连接到 Azure
-
提高速度和可靠性
AzCopy
AzCopy 是一个命令行工具,用于将文件和 Blob 复制到/从存储帐户。它提供以下功能:
-
能够通过互联网将数据复制到/从 Azure。
-
将 AzCopy 与所需的 ExpressRoute 带宽结合使用,可能是数据传输到 Azure Synapse 的最佳解决方案。
Azure Data Box
Azure Data Box 允许您快速、可靠且具有成本效益地将大量数据传输到 Azure。它提供以下功能:
-
能够传输大量数据(数十 TB 到数百 TB)
-
没有网络连接限制
-
非常适合一次性迁移和初始大批量传输
用于数据摄取的 Microsoft 服务
在本节中,我们将介绍常用的 Microsoft 服务,这些服务可用于数据摄取,包括:
-
PolyBase
-
BCP
-
SqlBulkCopy API
-
标准 SQL
PolyBase(推荐方法)
PolyBase 提供了最快速且可扩展的大数据批量加载到 Azure Synapse Analytics 的方式。它提供了以下功能:
-
使用并行加载以提供最快的吞吐量
-
可以从 Azure Blob 存储中的平面文件或通过连接器从外部数据源读取
-
与 ADF 紧密集成
-
使用 CREATE TABLE AS 或 INSERT … SELECT
-
可以将临时表定义为 HEAP 类型以加快加载速度
-
支持最多 1 MB 长度的行
BCP
BCP 可用于从任何 SQL Server 环境(包括 Azure Synapse Analytics)导入和导出数据。它提供了以下功能:
-
支持长度超过 1 MB 的行
-
最初为早期版本的 Microsoft SQL Server 开发
请参考docs.microsoft.com/sql/tools/bcp-utility
了解有关 BCP 工具的更多信息。
SqlBulkCopy API
SqlBulkCopy API 是 BCP 功能的 API 等效版本。它提供了以下功能:
-
允许通过编程方式实现加载过程
-
能够批量加载 SQL Server 表格,数据来自选定的来源
请参考docs.microsoft.com/dotnet/api/system.data.sqlclient.sqlbulkcopy
了解有关此 API 的更多信息。
标准 SQL 支持
Azure Synapse Analytics 支持标准 SQL,包括以下功能:
-
将单独的行或
SELECT
语句的结果加载到数据仓库表中。 -
使用
INSERT … SELECT
语句通过 PolyBase 从外部数据源提取数据,并批量插入到数据仓库表中。
本节提供了规划、准备和执行现有遗留数据仓库系统成功迁移到 Azure Synapse Analytics 的架构考虑和高层次方法论。它包含了许多信息,你可以在迁移项目过程中作为参考。
总结
Azure Synapse Analytics 是一个无限制的分析服务,具有无与伦比的洞察力交付时间,能够加速企业 BI、AI 和智能应用的交付。通过将现有的遗留数据仓库迁移到 Azure Synapse Analytics,你将获得许多好处,包括性能、速度、提高的安全性和合规性、弹性、托管基础设施、可扩展性以及成本节约。
通过 Azure Synapse,各种技能水平的数据专业人员可以轻松协作、管理和分析他们最重要的数据——所有操作都在同一服务内进行。从与强大且可信的 SQL 引擎集成的 Apache Spark,到无代码的数据集成和管理,Azure Synapse 为每一位数据专业人员打造。
本章提供了架构考虑和高层次的方法论,以帮助准备和执行将现有遗留数据仓库系统迁移到 Azure Synapse Analytics 的工作。
成功的数据迁移项目始于一个精心设计的计划。一个有效的计划需要考虑多个组件,特别关注架构和数据准备。
成功迁移到 Azure Synapse 后,您可以在丰富的 Azure 分析生态系统中探索更多 Microsoft 技术,进一步现代化您的数据仓库架构。
以下是一些值得思考的想法:
-
将您的暂存区域和 ELT 处理卸载到 Azure Data Lake 和 ADF。
-
一次构建受信任的数据产品,采用统一的数据模型格式,并且可以在任何地方使用——不仅仅是在数据仓库中。
-
通过使用 ADF 映射和数据清洗流,实现业务和 IT 之间的数据准备管道的协作开发。
-
在 ADF 中构建分析管道,以批处理和实时分析数据。
-
构建并部署机器学习模型,为您已有的知识增加更多洞察。
-
将您的数据仓库与实时流数据集成。
-
通过使用 PolyBase 创建逻辑数据仓库,简化对多个 Azure 分析数据存储中数据和洞察的访问。
在下一章中,您将详细了解 Azure 认知服务,重点介绍以智能为核心引擎的解决方案架构。
第十九章:19. 架构智能解决方案
云技术改变了许多事情,包括以灵活、可扩展、按需付费的方式创建智能应用程序。云技术兴起之前的应用程序通常没有内嵌智能,主要是因为:
-
它既耗时又容易出错。
-
持续编写、测试和实验算法是困难的。
-
缺乏足够的数据。
-
这非常昂贵。
在过去的十年里,有两件事发生了变化,导致了比以往更加智能的应用程序的诞生。这两件事是云计算的按需无限可扩展性以及数据在体积、种类和速度上的可用性。
在本章中,我们将探讨能够帮助在 Azure 上构建智能应用程序的架构。本章涵盖的一些主题包括:
-
AI 的演变
-
Azure AI 流程
-
Azure 认知服务
-
构建光学字符识别服务
-
使用 Cognitive Search .NET SDK 构建视觉特征服务
AI 的演变
AI 并不是一个新兴的知识领域。实际上,这项技术是几十年的创新和研究的结果。然而,过去几十年的实施面临以下挑战:
-
成本:AI 实验本质上非常昂贵,而且当时没有云技术。所有基础设施要么是购买的,要么是从第三方租赁的。实验的设置也非常耗时,并且需要大量技能才能入门。大量的存储和计算能力也被要求,而这些在整个社区中通常缺乏,只掌握在少数几个人手中。
-
数据不足:几乎没有智能手持设备和传感器生成数据。数据本质上是有限的,并且需要采购,这再次使得 AI 应用程序成本高昂。数据的可靠性也较差,普遍缺乏对数据本身的信任。
-
难度:AI 算法的文档化程度不足,主要存在于数学家和统计学家的领域。它们难以创建并在应用程序中使用。试想 15 年前创建一个光学字符识别(OCR)系统,当时几乎没有任何库、数据、处理能力或开发 OCR 应用程序所需的技能。
尽管随着时间的推移数据的流入不断增加,但仍缺乏能够以有助于商业价值的方式理解数据的工具。此外,优秀的 AI 模型基于足够准确的数据,并通过算法进行训练,以便解决现实生活中的问题。云技术以及大量的传感器和手持设备重新定义了这一格局。
借助云技术,能够为基于 AI 的应用程序提供按需存储和计算资源。云基础设施提供大量的数据迁移、存储、处理和计算资源,同时生成洞察,并最终提供报告和仪表盘。所有这些都以最低的成本和更快的速度完成,因为没有涉及任何物理设备。让我们深入了解构建基于 AI 的应用程序背后的过程。
Azure AI 处理
每个基于 AI 的项目都需要经过一定的步骤,才能投入使用。让我们来了解这七个阶段:
数据摄取
在这个阶段,数据从多个来源采集并存储,以便在下一阶段使用。数据在存储之前会进行清洗,并且任何偏离常规的数据都会被忽略。这是数据准备的一部分。数据可以具有不同的速度、种类和规模。它可以像关系型数据库一样是结构化的,像 JSON 文档一样是半结构化的,或像图片、Word 文档等一样是非结构化的。
数据转化
所摄取的数据会被转化成另一种格式,因为它可能无法以当前格式使用。数据转化通常包括清洗和过滤数据,去除数据偏差,通过与其他数据集结合来增强数据,基于现有数据创建额外数据等。这也是数据准备的一部分。
分析
最后一阶段的数据会被重新用于分析。分析阶段包括在数据中寻找模式、进行探索性数据分析,并从中生成进一步的洞察。这些洞察与现有数据一起存储,以便在下一阶段使用。这是模型包装过程的一部分。
数据建模
一旦数据被增强和清洗,适当且必要的数据会提供给 AI 算法,以生成有助于实现整体目标的模型。这是一个迭代过程,称为通过使用不同数据组合(特征工程)进行实验,以确保数据模型的健壮性。这也是模型包装过程的一部分。
数据被输入到学习算法中,以识别模式。这个过程称为训练模型。随后,使用测试数据验证模型的有效性和效率。
验证模型
一旦模型创建完成,就会使用一组测试数据来检验其有效性。如果从测试数据中得到的分析结果反映了现实情况,那么该模型是健全且可用的。测试是 AI 过程中的一个重要环节。
部署
模型被部署到生产环境,以便实时数据能够输入模型并获得预测输出。然后,这些输出可以在应用程序中使用。
监控
部署到生产环境中的模型会持续进行监控,用于对所有进入的数据进行未来分析,并重新训练和提升模型的效果。
AI 的各个阶段和过程本质上是耗时且迭代的。因此,基于它们的应用程序具有固有的风险,可能会长时间运行、处于实验阶段、资源密集,并且可能出现成本超支和延期,成功的几率较低。
记住这些要点后,应该有现成的基于 AI 的解决方案,供开发人员在其应用程序中使用,使它们变得更加智能。这些 AI 解决方案应该易于从应用程序中消费,并具备以下特性:
-
跨平台:使用任何平台的开发者都应该能够消费这些服务。它们应该能够在 Linux、Windows 或 Mac 平台上进行部署和使用,而不会出现兼容性问题。
-
跨语言:开发者应该能够使用任何语言来消费这些解决方案。这样,开发者不仅能遇到较短的学习曲线,而且也不需要更改自己偏好的编程语言来使用这些解决方案。
这些解决方案应该作为服务进行部署,使用行业标准和协议。通常,这些服务作为 HTTP REST 端点提供,可以使用任何编程语言和平台进行调用。
有许多此类服务可以被建模并部署以供开发者使用。以下是一些示例:
-
语言翻译:在此类服务中,用户提供一种语言的文本,并获得该文本对应的另一种语言的输出。
-
字符识别:这些服务接受图像并返回其中的文本内容。
-
语音转文本转换:这些服务可以将输入的语音转换为文本。
现在我们已经详细了解了构建基于 AI/ML 的项目,让我们深入探讨一下 Azure 提供的各种认知服务的应用。
Azure 认知服务
Azure 提供了一个名为 Azure 认知服务的总服务。Azure 认知服务是一组服务,开发者可以在他们的应用程序中使用这些服务,将应用程序转变为智能应用程序。
表 19.1:Azure 认知服务
根据服务的性质,这些服务已被分为五大类。这五大类如下:
视觉
这个 API 提供了图像分类的算法,并通过提供有意义的信息来帮助图像处理。计算机视觉可以从图像中提供关于不同物体、人物、字符、情感等的多种信息。
搜索
这些 API 有助于与搜索相关的应用程序。它们可以基于文本、图像、视频进行搜索,并提供自定义搜索选项。
语言
这些 API 基于自然语言处理,帮助提取用户提交文本的意图信息及实体检测。它们还帮助进行文本分析和翻译成不同语言。
语音
这些 API 有助于将语音转换为文本、将文本转换为语音以及语音翻译。它们可以用于接收音频文件并基于内容为用户执行操作。Cortana 是一个使用类似服务,根据语音为用户执行操作的例子。
决策
这些 API 有助于异常检测和内容审核。它们可以检查图像、视频和文本中的内容,并找出需要突出显示的模式。此类应用的一个例子是显示有关成人内容的警告。
现在你已经理解了认知服务的核心内容,接下来我们将详细讨论它们的工作原理。
理解认知服务
Azure 认知服务由接受请求并将响应发送回调用者的 HTTP 端点组成。几乎所有的请求都是 HTTP POST 请求,包含请求头和请求体。
认知服务的配置会生成两个重要的产物,帮助调用者成功调用端点。它生成一个端点 URL 和一个唯一的密钥。
URL 的格式是 https://{azure location}.api.cognitive.microsoft.com/{cognitive type}/{version}/{sub type of service}?{query parameters}
。一个示例 URL 如下:
https://eastus.api.cognitive.microsoft.com/vision/v2.0/ocr?language=en&detectOrientation=true
认知服务在美国东部 Azure 区域配置。服务类型为计算机视觉,使用版本 2,子类型为 OCR。每个顶级类别通常有几个子类型。最后,还有一些查询字符串参数,如 language
和 detectOrientation
。这些查询参数对于每个服务类别和子类别都是不同的。
无论是请求头还是查询参数,都应该提供密钥值,以确保端点调用成功。
密钥值应该与请求一起分配给 Ocp-Apim-Subscription-Key
请求头。
请求体的内容可以是简单字符串、二进制数据或两者的组合。根据值的不同,应该在请求中设置适当的 content-type 头。
可能的头部值包括:
-
Application/octet-stream
-
multipart/form-data
-
application/json
当发送二进制数据时,请使用 octet-stream
,发送字符串值时使用 json
。form-data
可用于发送二进制和文本的多种组合值。
密钥是一个唯一的字符串,用于验证调用者是否被授权调用 URL。这个密钥必须受到保护,确保不应有权限调用端点的人员无法访问它。稍后你将在本章中看到如何保护这些密钥的方法。
使用认知服务
有两种方式可以使用认知服务:
-
直接使用 HTTP 端点:在这种情况下,直接通过构造适当值的标头和请求体来调用端点。然后解析返回值并提取数据。认知服务中的所有 AI 服务都是 REST API。它们接受 JSON 格式的 HTTP 请求及其他格式,并以 JSON 格式回复。
-
使用 SDK:Azure 提供了多个软件开发工具包(SDKs)。.NET、Python、Node.js、Java 和 Go 语言都有可用的 SDK。
在接下来的章节中,我们将探讨如何通过两种方式使用认知服务之一。我们将通过构建一些 AI 服务并使用 HTTP 端点来探索这一点。
构建 OCR 服务
在本节中,我们将使用 C# 和 PowerShell 展示如何使用 HTTP 端点直接调用一些 AI 服务。下一节将重点介绍使用 .NET SDK 完成相同的操作。
在构建使用认知服务的项目之前,第一步是配置 API 本身。
光学字符识别作为视觉 API 提供,并可以通过 Azure 门户进行配置,如下所示。通过导航到认知服务 > 计算视觉 > 创建来创建视觉 API,如图 19.1所示:
图 19.1:创建视觉 API
一旦 API 配置完成,概述页面会提供所有用于使用该 API 的详细信息。它提供基础 URL 和密钥信息。请记下该密钥,后续会用到:
图 19.2:概述页面
它还提供了一个 API 控制台,方便快速测试 API。点击它会打开一个新窗口,显示所有与该服务相关的端点。点击 POST
方法后,URL 会指向位于东美国 Azure 区域的端点。它还与视觉 API 组版本 2 和 OCR 端点相关。
订阅密钥会通过名为ocp-apim-subscription-key
的标头传递。标头还包含 application/json
作为值的 content-type 密钥。这是因为请求体包含 JSON 字符串。请求体是 JSON 格式,包含需要提取文本的图像 URL:
图 19.3:请求 URL
可以通过点击发送按钮将请求发送到端点。如果一切正常,将返回 HTTP 响应 200 OK,如下所示。如果请求值有错误,响应将是一个错误的 HTTP 代码:
图 19.4:HTTP 响应 200 OK
响应包含与计费使用相关的详细信息、由端点生成的内部请求 ID、内容长度、响应内容类型(为 JSON)以及响应的日期和时间。响应的内容是一个 JSON 负载,包含文本的坐标和实际文本。
使用 PowerShell
相同的请求可以通过 PowerShell 创建。以下 PowerShell 代码可以通过 PowerShell ISE 执行。
代码使用 Invoke-WebRequest
cmdlet 通过 POST
方法传递 URL 到 Uri
参数来调用认知服务端点,并添加上一节中讨论的适当头信息,最后是包含 JSON 格式数据的请求体。数据使用 ConvertTo-Json
cmdlet 转换为 JSON 格式:
$ret = Invoke-WebRequest -Uri "https://eastus.api.cognitive.microsoft.com/vision/v2.0/ocr?language=en&detectOrientation=true" -Method Post -Headers @{"Ocp-Apim-Subscription-Key"="ff0cd61f27d8452bbadad36942570c48"; "Content-type"="application/json"} -Body $(ConvertTo-Json -InputObject @{"url"="https://ichef.bbci.co.uk/news/320/cpsprodpb/F944/production/_109321836_oomzonlz.jpg"})
$val = Convertfrom-Json $ret.content
foreach ($region in $val.regions) {
foreach($line in $region.lines) {
foreach($word in $line.words) {
$word.text
}
}
}
来自 cmdlet 的响应被保存在一个变量中,该变量也包含 JSON 格式的数据。使用 Convertfrom-Json
cmdlet 将数据转换为 PowerShell 对象,并循环遍历以查找文本中的单词。
使用 C#
在本节中,我们将构建一个服务,该服务应接受用户请求,提取图像的 URL,构建 HTTP 请求并将其发送到认知服务端点。认知服务端点返回一个 JSON 响应。响应中提取适当的文本内容并返回给用户。
架构与设计
智能应用程序是一个 ASP.NET Core MVC 应用程序。MVC 应用程序由开发人员在开发机上构建,通过持续集成和交付管道,生成 Docker 镜像,并将 Docker 镜像上传到 Azure 容器注册表。在这里,解释了应用程序的主要组件及其使用方法:
图 19.5:智能应用程序的工作流程
Docker
Docker 是容器技术中的重要组成部分,并且支持跨平台,包括 Linux、Windows 和 Mac。以容器化为思路开发应用程序和服务,提供了跨云和不同位置以及本地部署的灵活性。它还消除了对宿主平台的依赖,这样就减少了对平台即服务的依赖。Docker 有助于创建自定义镜像,容器可以从这些镜像中创建。这些镜像包含使应用程序或服务能够运行的所有依赖项、二进制文件和框架,并且它们是完全自给自足的。这使得它们成为微服务等服务的优秀部署目标。
Azure 容器注册表
Azure 容器注册表是一个类似于 Docker Hub 的注册表,用于存储容器镜像。可以创建多个存储库并上传多个镜像。每个镜像都有一个名称和版本号,合起来形成一个完整的名称,用于在 Kubernetes Pod 定义中引用它们。这些镜像可以被任何 Kubernetes 生态系统访问和下载。前提是已经为拉取镜像创建了适当的密钥。容器注册表不需要与 Kubernetes 节点在同一网络中,实际上,创建和使用 Azure 容器注册表时无需网络。
Azure Kubernetes Service
接受图像 URL 并提取其中文本的智能应用程序可以托管在普通虚拟机上,甚至可以在 Azure App Service 中运行。然而,在 Azure Kubernetes Service 中部署提供了许多优势,这些内容在第八章,Azure Kubernetes 解决方案架构中有详细介绍。目前,重要的是要知道,这些应用程序天生具有自愈能力,Kubernetes 主节点会自动维护最小数量的实例,并提供多种方式来更新它们,包括蓝绿部署和金丝雀更新。
Pods、副本集和部署
开发人员还创建了一个与 Kubernetes 部署相关的 YAML 文件,该文件引用了 Pod 规范中的镜像,并提供了副本集的规范。它还提供了与更新策略相关的自定义规范。
运行时设计
架构和设计与前一部分相同;然而,当应用程序或服务已经上线并运行时,它已经从 Azure 容器注册表下载了镜像,并在其中创建了运行容器的 Pod。当用户提供一个图像 URL 以解码其中的文本时,Pod 中的应用程序调用 Azure Cognitive Services 计算机视觉 API,并将 URL 传递给它,等待服务响应:
图 19.6 智能应用的工作流
一旦收到服务返回的 JSON 响应,它就可以提取信息并返回给用户。
开发过程
开发环境可以是 Windows 或 Linux。它可以在 Windows 10 和 Windows 2016/19 服务器上运行。在使用 Windows 时,部署 Docker for Windows 非常有用,这样它会创建 Linux 和 Windows 两种 Docker 环境。
使用 Visual Studio 2019 创建 ASP.NET Core Web 应用程序项目时,Dockerfile
的主要区别是基础镜像名称。它使用不同的镜像来支持 Linux 和 Windows。
安装 Docker for Windows 时,它还会安装一个 Linux 虚拟机,因此启用 Hyper-V 虚拟化程序非常重要。
在此示例中,图像被下载而不是将数据作为 JSON 字符串发送,并且二进制数据被发送到认知服务终结点。
它具有一个接受字符串输入的功能,用于 URL 值。然后,它调用认知服务,并使用适当的头部值和包含 URL 的请求体。头部值应包含认知服务在配置服务时提供的密钥。请求体中的值可以包含以 JSON 形式表示的普通字符串值,也可以包含二进制图像数据。content-type 头部属性应相应设置。
代码声明了与认知服务相关的 URL 和密钥。这里只是为了演示 purposes,URL 和密钥应放在配置文件中。
使用 HttpClient
对象,下载用户提供的 URL 对应的图像并将其存储在 responseMessage
变量中。然后实例化另一个 HttpClient
对象,并用 Ocp-Apim-Subscription-Key
和 content-type
密钥填充其头部。由于传递的是二进制数据,因此 content-type 头部的值应设置为 application/octet-stream
。
提取 responseMessage
变量中的内容后,发出一个 POST 请求,并将其作为请求体传递给认知服务终结点。
控制器操作的代码如下所示:
[HttpPost]
public async Task<string> Post([FromBody] string value)
{
string myurl = " https://eastus.api.cognitive.microsoft.com/vision/v2.0/ocr?language=en&detectOrientation=true
string token = "…………………………";
using (HttpClient httpClient = new HttpClient())
{
var responseMessage = await httpClient.GetAsync(value);
using (var httpClient1 = new HttpClient())
{
httpClient1.BaseAddress = new Uri(myurl);
httpClient1.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", token);
HttpContent content = responseMessage.Content;
content.Headers.ContentType = new MediaTypeWithQualityHeaderValue("application/octet-stream");
var response = await httpClient1.PostAsync(myurl, content);
var responseContent = await response.Content.ReadAsByteArrayAsync();
string ret = Encoding.ASCII.GetString(responseContent, 0, responseContent.Length);
dynamic image = JsonConvert.DeserializeObject<object>(ret);
string temp = "";
foreach (var regs in image.regions)
{
foreach (var lns in regs.lines)
{
foreach (var wds in lns.words)
{
temp += wds.text + " ";
}
}
}
return temp;
}
}
}
在终结点完成处理后,它返回一个带有 JSON 有效负载的响应。上下文被提取并反序列化为 .NET 对象。编写了多个循环来从响应中提取文本。
在本节中,我们创建了一个简单的应用程序,利用认知服务通过 OCR API 提供从特征中提取单词的功能,并将其部署到 Kubernetes Pods 中。此过程和架构可以用于任何想要调用认知服务 API 的应用程序。接下来,我们将了解另一个认知服务 API,称为视觉特征。
使用 Cognitive Search .NET SDK 构建视觉特征服务
上一节介绍了创建一个使用 OCR 认知终结点返回图像中文本的服务。在本节中,将创建一个新的服务,该服务返回图像中的视觉特征,例如描述、标签和对象。
使用 PowerShell
PowerShell 中的代码与之前的 OCR 示例类似,因此在此不再重复。URL 与之前的代码示例不同:
图 19.7:请求 URL
请求使用 POST
方法,并且 URL 指向东部美国 Azure 区域的终结点。它还使用版本 2,并调用视觉 API。
认知服务访问密钥是 HTTP 头部的一部分,名为 ocp-apim-subscription-key
。该头部还包含名为 content-type
的头信息,值为 application/json
。这是因为请求的正文包含 JSON 格式的数据。正文中包含提取文本所需的图像 URL。
响应将以 JSON 格式返回,包含图像内容和描述。
使用 .NET
这个示例再次是一个 ASP.NET Core MVC 应用程序,已安装 Microsoft.Azure.CognitiveServices.Vision.ComputerVision
NuGet 包:
图 19.8:带有 Microsoft.Azure.CognitiveServices.Vision.ComputerVision NuGet 包的 ASP.NET Core MVC 应用程序
控制器操作的代码如下所示。在这段代码中,声明了认知服务和密钥,还声明了 ComputerVisionClient
和 VisionType
对象的变量。它创建了一个 ComputerVisionClient
类型的实例,提供了 URL 和密钥。
VisionTypes
列表包含了从图像中提取的多种数据类型——标签、描述和对象等。只有这些参数会从图像中提取。
创建一个 HttpClient
对象,通过用户提供的 URL 下载图像,并使用 ComputerVisionClient
类型的 AnalyzeImageInStreamAsync
函数将这些二进制数据发送到认知服务端点:
[HttpPost]
public string Post([FromBody] string value)
{
private string visionapiurl = " https://eastus.api.cognitive.microsoft.com/vision/v2.0/analyze?visualFeaure=tags,description,objects&language=en";
private string apikey = "e55d36ac228f4d718d365f1fcddc0851";
private ComputerVisionClient client;
private List<VisualFeatureTypes> visionType = new List<VisualFeatureTypes>();
client = new ComputerVisionClient(new ApiKeyServiceClientCredentials(apikey)) {
Endpoint = visionapiurl
};
visionType.Add(VisualFeatureTypes.Description);
visionType.Add(VisualFeatureTypes.Tags);
visionType.Add(VisualFeatureTypes.Objects);
string tags = "";
string descrip = "";
string objprop = "";
using (HttpClient hc = new HttpClient()) {
var responseMessage = hc.GetAsync(value).GetAwaiter().GetResult();
Stream streamData = responseMessage.Content.ReadAsStreamAsync().GetAwaiter().GetResult();
var result = client.AnalyzeImageInStreamAsync(streamData, visionType).GetAwaiter().GetResult();
foreach (var tag in result.Tags) {
tags += tag.Name + " ";
}
foreach (var caption in result.Description.Captions)
{
descrip += caption.Text + " ";
}
foreach (var obj in result.Objects)
{
objprop += obj.ObjectProperty + " ";
}
}
return tags;
// return descrip or objprop
}
对结果进行循环处理并将标签返回给用户。同样,描述和对象属性也可以返回给用户。现在让我们来看一下如何保护服务密钥的暴露。
保护认知服务密钥
有多种方法可以保护密钥不被其他方暴露。可以通过 Azure 中的 API 管理资源来实现,也可以通过 Azure Functions 代理来实现。
使用 Azure Functions 代理
Azure Functions 代理可以引用任何 URL,无论是内部还是外部。当请求到达 Azure Functions 代理时,它会使用认知服务的 URL 和密钥来调用认知服务端点,并会覆盖请求参数,将传入的图像 URL 作为 POST 数据附加到认知端点 URL 上。当服务返回响应时,它会覆盖响应,移除头信息,并将 JSON 数据传递回用户。
使用认知服务
使用认知服务遵循一致的模式。每个认知服务都可以通过 REST API 提供,每个 API 需要不同的参数集。调用这些 URL 的客户端应查阅相关文档以获取参数,并为它们提供相应的值。直接使用 URL 调用是使用认知服务的一种相对原始的方法。Azure 为每项服务提供了 SDK,并支持多种编程语言。客户端可以使用这些 SDK 来与认知服务进行交互。
https://{luis resource name}-authoring.cognitiveservices.azure.com/
和生产 API 可在此访问
https://{azure region}.api.cognitive.microsoft.com/luis/prediction/v3.0/apps/{application id}/slots/production/predict?subscription-key={cognitive key} &verbose=true&show-all-intents=true&log=true&query=YOUR_QUERY_HERE
。
同样,Face API 可在 https://{endpoint}/face/v1.0/detect[?returnFaceId][&returnFaceLandmarks][&returnFaceAttributes][&recognitionModel][&returnRecognitionModel][&detectionModel]
访问。
有许多认知服务 API,每个 API 在 URL 方面有不同的版本,了解这些 URL 的最佳方式是使用 Azure 文档。
概述
在本章中,您了解了在 Azure 中创建智能应用程序的部署架构和应用程序架构。Azure 提供了大量的认知服务端点——每个端点负责执行与 AI 相关的算法并提供输出。几乎所有的认知服务端点在处理 HTTP 请求和响应方面工作方式相似。这些端点也可以通过 Azure 提供的不同语言 SDK 进行调用,您已看到使用这些 SDK 获取视觉特征的示例。Azure 提供了超过 50 个不同的端点,建议您通过 Azure 提供的 API 控制台功能来了解端点的性质。