原文:
annas-archive.org/md5/eb2d156388068d02b11a808e92183ccf
译者:飞龙
前言
每位软件工程专业人员必须熟练掌握其对 DevOps 的理解,以及它为团队带来的积极影响。本书将使您了解一些最重要的 DevOps 实践,如配置管理、发布管理、持续集成、持续部署、基础设施即代码、持续测试以及应用程序监控和反馈。您还将学习使用 Azure DevOps、GitHub 以及其他相关工具来实施各种实践。
通过详细的案例研究和动手实验,本书作为如何实施各种实践的现成参考书。本书还涵盖了其他主题,将帮助您发展深厚的专业知识和面向 DevOps 的思维方式,这将对您的职业生涯产生重要影响。
本书适合人群
本书的目标读者包括以下人群:
-
想要参加 AZ-400 考试的软件开发人员或运维专家
-
想要学习如何使用 Azure DevOps 来实施 DevOps 实践的软件开发人员或运维专家
-
想要提升其 DevOps 技能的技术爱好者
您应该熟悉软件开发以及更广泛的软件开发实践。您必须熟悉瀑布模型、Scrum、敏捷和 DevOps 等术语。任何有至少 2 年团队软件开发经验的严肃从业者都应该能够阅读本书。您还应该对 Azure DevOps 和 GitHub 有基本的了解。
本书涵盖内容
第一章,Introduction to DevOps,概述了 DevOps 运动及其代表的文化。本章介绍了本书的重点实践和习惯。
第二章,Site Reliability Engineering Fundamentals,向您介绍了Site Reliability Engineering(SRE)的原则和实践,以及采纳 SRE 思维方式在确保云应用成功方面的重要性。
第三章,Getting the Best Out of DevOps Tools,提供了各种 DevOps 相关工具在整个应用程序开发生命周期中的高级概述。
第四章,Everything Starts with Source Control,讨论了源代码控制的各种方法,以及如何正确进行源代码控制是持续交付的核心。
第五章,Moving to Continuous Integration,涵盖了持续集成、自动化测试、质量控制、度量、代码覆盖率以及生产高质量产品所需的最低标准。
第六章, 实现持续部署和发布管理,讲解了如何使用 Azure DevOps 发布流水线,以及各种部署模式和策略以实现持续部署。
第七章, 依赖管理,讨论了 Azure Artifacts 如何帮助管理共享组件,并介绍了如何使用 Azure 流水线自动化这些组件的构建、发布,甚至使用。
第八章, 将基础设施和配置视为代码,展示了如何配置应用程序的基础设施,并如何将其创建或更新过程完全自动化,作为发布的一部分。
第九章, 在 DevOps 场景中处理数据库,讨论了将数据库视为应用程序代码、基础设施或配置的几种策略。
第十章, 集成持续测试,探讨了不同类型的测试以及它们如何通过测试金字塔相互关联,并展示了如何在 DevOps 流水线的不同阶段嵌入不同类型的测试。
第十一章, 管理安全性与合规性,展示了如何与安全专家合作,将他们的关注点自动化集成到流水线中,而不是通过后期的检查单手动验证。
第十二章, 应用监控,介绍了应用监控的过程,旨在对应用程序进行仪器化,以理解应用性能和使用模式,并提取关键性能指标。
第十三章, 收集用户反馈,讨论了如何通过假设驱动开发验证你的想法,在付诸实施之前先进行验证。
第十四章, 采纳持续改进文化,重点关注一些对业务成果产生直接影响的组织文化方面。
第十五章, 通过 DevOps 加速云端采用,提供了通过场景和指导来使用 DevOps 的概述,同时帮助制定企业云端采用计划。
第十六章, 容器,概述了容器技术,容器允许你将任何应用程序或工具(使用任何编程语言开发)打包,并在基本主机或集群上进行部署。
第十七章, 规划你的 Azure DevOps 组织,讨论了哪些做法适用于你的组织和团队,以及如何使用 Azure DevOps 实施实践和方法。
第十八章, AZ-400 模拟考试,包含了一份模拟测试,帮助你评估自己的学习成果。
为了最大程度地利用本书
本书涵盖的软件/硬件 | 操作系统要求 |
---|---|
Visual Studio 2019/Visual Studio 2022/VS Code | Windows、macOS 或 Linux |
Azure 订阅 | - |
Azure DevOps 订阅 | - |
如果你正在使用本书的数字版本,我们建议你自己输入代码或从本书的 GitHub 仓库访问代码(下节中提供了链接)。这样做有助于避免与复制和粘贴代码相关的潜在错误。
下载示例代码文件
你可以从 GitHub 下载本书的示例代码文件,链接为 github.com/PacktPublishing/Designing-and-Implementing-Microsoft-DevOps-Solutions-AZ-400-Exam-Guide
。如果代码有更新,它会在 GitHub 仓库中更新。
我们还提供了其他代码包,来自我们丰富的图书和视频目录,访问链接:github.com/PacktPublishing/
。快来看看吧!
下载彩色图像
我们还提供了一份包含本书中截图和图表的彩色图像的 PDF 文件,你可以在这里下载:packt.link/OADjU
。
使用的约定
本书中使用了许多文本约定。
Code in text
:表示文本中的代码单词、数据库表名、文件夹名称、文件名、文件扩展名、路径名、虚拟网址、用户输入和 Twitter 用户名。以下是一个示例:在 GitHub Flow 中,有一个 master 分支,始终应该保持可部署状态。不允许有未完成的更改进入该分支。
代码块的显示方式如下:
{
"appServiceName": {
"type": "string",
"metadata": {
"description": "a free to choose text"
}
}
当我们希望你注意代码块的某个特定部分时,相关的行或项会以粗体显示:
az aks update -n 'packtsbookaci' -g 'az400-dev'
--attach-acr 'packtbookacr'
任何命令行输入或输出如下所示:
git add NewFile.txt
git push
粗体:表示新术语、重要词汇或你在屏幕上看到的词汇。例如,菜单或对话框中的词汇通常以粗体显示。以下是一个示例:“从管理面板中选择系统信息。”
提示或重要注意事项
如此显示。
联系我们
我们始终欢迎读者的反馈。
常见反馈:如果你对本书的任何方面有疑问,请通过电子邮件联系 customercare@packtpub.com,并在邮件主题中提及书名。
勘误表:尽管我们已尽力确保内容的准确性,但错误仍然可能发生。如果你在本书中发现了错误,我们将非常感谢你能向我们报告。请访问 www.packtpub.com/support/errata 并填写表格。
盗版:如果你在互联网上发现任何非法复制的我们作品的形式,请提供该地址或网站名称。请通过 copyright@packt.com 联系我们,并附上材料的链接。
如果你有兴趣成为作者:如果你在某个领域拥有专业知识,并且有意写作或为书籍做贡献,请访问 authors.packtpub.com。
分享你的想法
阅读完 设计与实施 Microsoft DevOps 解决方案 AZ-400 考试指南 后,我们很想听听你的想法!请 点击此处直接前往亚马逊评论页面 为本书分享你的反馈。
你的评论对我们和技术社区都非常重要,并将帮助我们确保提供优质的内容。
第一部分 – 通过 DevOps 实现数字化转型
在这一部分中,你将学习 DevOps 的核心原则和实践,这些是实现软件开发目标的基础,能让你更快速、高效地完成任务。我们将探讨大多数组织如何通过整合 站点可靠性工程(SRE)实践来构建安全可靠的系统。你还将了解可以提高团队生产力的重要 DevOps 工具。
本节为我们的工作奠定了必要的基础,之后可以按任意顺序阅读其余章节,以深入了解各个主题。
本书的这一部分包括以下章节:
-
第一章,DevOps 简介
-
第二章,站点可靠性工程 基础知识
-
第三章,充分利用 DevOps 工具
第一章:DevOps 介绍
DevOps 不是你可以购买或安装的产品或工具。DevOps 是关于文化以及你如何编写、发布和运营软件。DevOps 是关于缩短新想法与最终用户体验其带来的价值之间的时间。在本书中,你将学习如何利用工具和技术将这一理念应用于你的工作方式。本书的目的是帮助你准备 AZ-400 认证考试,因此核心概念和与 DevOps 相关的实践将通过 Azure DevOps 及其相关技术来阐述。
近年来,DevOps 在软件工程领域越来越受欢迎,几乎所有软件工程团队都在适应一个新的工作方式,使用一组新的工具来激发生产力,并在开发和运维之间实现更好的协作。DevOps 常被视为敏捷的延伸,但其范围要广得多,它补充了敏捷方法。
在本章中,你将更多地了解什么是 DevOps,以及如何识别一个成功的 DevOps 团队。到本章结束时,你将熟悉关键术语,并掌握 DevOps 的高层次原则和实践。你还将发现 DevOps 对软件工程团队的益处。
在本章中,我们将涵盖以下主题:
-
什么是 DevOps?
-
创建理想的 DevOps 组织
-
探索 DevOps 实践和习惯
-
DevOps 发展历程的五个阶段
技术要求
本章没有技术要求。
什么是 DevOps?
如果你列出所有关于 DevOps 的不同定义和描述,会有很多。然而,尽管它们可能有所不同,它们最有可能共享几个概念。这些概念是协作、持续交付商业价值和打破孤岛。
在本书其余部分涉及到的技术讨论中,重要的是不要忽视采用 DevOps 的价值主张——即它将帮助你改进持续向最终用户交付价值的方式。为了实现这一点,你必须减少从开始开发新功能到第一个用户在生产环境中使用该功能的时间。这意味着你不仅要编写软件,还要交付并运营它。
在过去的十年里,我们编写软件的方式发生了根本性的变化。越来越多的公司现在采用敏捷工作方式,以提高软件开发的效率。越来越多的团队现在通过短期迭代或冲刺,快速创建产品的新增量。然而,快速创建潜在可发布的增量本身并不能创造任何价值。只有当每个新版本的软件被发布到生产环境并被最终用户使用时,它才开始提供价值。
在传统的组织中,开发人员和运维人员通常位于不同的部门,将软件投入生产往往需要交接,并且通常伴随有正式的仪式。在这样的组织中,加速将软件交付到生产环境,以及开发人员快速创建新版本的速度,可能会变得很困难。
此外,开发和运维部门往往存在目标冲突。开发部门的奖励是尽可能快速地创造许多变化,而运维部门则因减少停机时间和防止问题而获得奖励。后者通常通过尽可能少地做出更改来最佳实现。这里的冲突很明显——两个部门都有各自针对一个子目标的优化,如下图所示:
图 1.1 – 开发与运维之间的目标冲突
这违背了这些子目标的目的,这些子目标源于共同的、宏观的目标,即在保持稳定性的同时快速地引入新版本。正是开发和运维目标之间的冲突,应该成为 DevOps 文化中消失的一个问题。在这种文化中,开发和运维团队应该协同工作,以快速可靠的方式将新版本交付到生产环境,并共同承担这两个子目标的责任。
虽然知道 DevOps 是一个文化运动很重要,但工具和自动化在这种文化中扮演着重要角色。在本书中,我们将重点介绍这些工具以及如何使用它们来实现 DevOps 文化中的许多实践。换句话说,本书主要关注与 DevOps 相关的产品和流程。如果你想了解更多关于文化方面的内容和人群,还有许多其他书籍可以阅读。一本非常值得阅读的书是*《凤凰项目:IT、DevOps 与帮助你的企业获胜的小说》*,作者为 Gene Kim。
本节的其余部分将探讨 DevOps 与敏捷之间的关系,看看它们如何相辅相成。重点将放在敏捷技术和工作管理的价格上。我们还将讨论 DevOps 文化的目标和好处。
DevOps 与敏捷的关系
如果你看看敏捷开发,你可能会注意到它的一部分内容侧重于商业价值和缩短交付新商业价值的时间。从这个角度来看,采用 DevOps 是敏捷开发后的一个合乎逻辑的步骤。敏捷提倡软件开发团队的职责应向前延伸,通过与用户及其他利益相关者互动,更快地交付有价值且可能可以发布的产品。DevOps 不仅仅是指可能发布的东西,而是实际发布它。通过结合敏捷与 DevOps,你可以为用户创造一个端到端的、持续的价值流。
你需要为所有参与者提供一个共同的工作管理方法。在下一节中,你将找到一些关于如何将运维方面的考量纳入你管理工作方式的指引。
敏捷工作管理
当你开始增加开发与运维之间的协作时,你会很快注意到他们必须应对不同类型的工作。在开发中,大部分工作是计划好的:从待办事项中提取的用户故事和 bug。另一方面,对于运维来说,很多工作是未计划的。他们需要响应来自系统的警告和提醒,以及来自用户或开发人员的请求或工单。
将这两者整合在一起,尤其是当开发人员和运维人员位于同一团队时,可能会很具挑战性。为了学习如何应对这一点,我们可以探索以下方法:
-
首先,为开发人员切换到基于流的工作方式。
-
接下来,允许运维团队也通过同步将他们的工作列在与开发人员相同的工作管理系统中。你还可以选择实施快速通道(fastlaning),一种加速处理紧急工作的方式。
-
最后,如果可能的话,你可以选择停用现有的运维工单工具。
快速通道是一种组织工作的方式,它通过可视化两条独立的工作轨道,允许同时处理计划内和未计划的工作。为此,Scrum 看板上方扩展了一个类似 Kanban 的看板,这就是快速通道。在 Kanban 看板上,添加了紧急但未计划的工作。任何添加到此通道的工作将由优先级最高的团队来处理。只有当快速通道中的工作都处理完毕后,才会处理 Scrum 看板上的工作以及计划中的工作。每当有新的工作添加到快速通道时,它将再次优先处理。通常,团队会达成一致,所有正在进行中的工作在切换到快速通道工作之前必须完成。
重要提示
依赖管理也是敏捷工作计划中一个重要方面。因此,团队通常会利用优先级属性来确定短期内更重要的工作。
切换到基于流的工作方法
切换到基于流的工作方法时,首先需要考虑的是将开发人员的工作方式从批量处理转变为基于流的工作方式。批量工作方式的一个例子是 Scrum。如果你正在使用 Scrum 框架,你已经习惯了每 2 到 4 周拾取一批工作,并集中精力在这个时间窗口内完成所有工作。只有当这一批工作完成后,才会交付一个潜在可交付的产品。
在转向基于流程的方法时,你的目标是专注于一个任务,而不是一个批次。你专注于完成这个单一的工作项,直到它完成再开始下一个。这样,就不再有冲刺待办事项列表,只有产品待办事项列表。这种方法的优点在于,你不再需要预先决定执行哪些工作;只要有空,你就可以从待办事项列表中选择下一个任务。在优先级迅速变化的环境中,这让你能够快速应对变化。
开发人员组织工作方式的这些变化使得将操作工作纳入工作管理变得更容易,但也有另一个好处。当开发人员专注于完成单一的工作项而不是一次完成整个冲刺时,你还可以增加向用户交付小部分价值的频率。
将工作项同步到一个系统
一旦开发团队改变了工作组织的方式,开发人员应该能更容易地将他们计划中的工作列在共享的待办事项列表中,并在有空时从该列表中拉取工作。同时,他们现在也有一个地方可以列出他们的未计划工作。
然而,可能仍然存在一个现有的工单系统,其中用户会提交操作请求或监控工具会自动创建请求。虽然 Azure DevOps 有一个强大的 API 可以重新设计该集成,直接在 Azure DevOps 中创建工作项,但你可以首先选择在现有的工单工具和 Azure Boards 之间创建一个同步。这方面有很多集成选项,并且正在持续进行相关工作。通过这种方式,操作人员可以逐步从旧工具迁移到新工具,因为它们现在是同步的。当然,目标是让他们完全转移到与开发人员相同的工具。
快速通道
由于开发人员和操作人员都在使用同一个工作管理工具,你会发现系统中混合了计划和未计划的工作,且这些工作往往是紧急的。为了确保紧急工作能得到应有的关注和优先处理,你可以在冲刺看板中引入一个所谓的快速通道。下面的截图展示了一个 Azure 看板的例子,该看板已为生产问题设置了快速通道:
图 1.2 – 展示快速通道的 Azure 看板设置
该看板中的水平分割线仅在快速通道中没有任务可选时,用于处理常规通道中的任务。
你可以在docs.microsoft.com/en-us/azure/devops/boards/boards/expedite-work?view=azure-devops
找到如何在 Azure(看板)中配置游泳道以加速工作的说明。
停用其他工作管理工具
在创建了一个开发与运维之间的共享工作管理系统后,有机会增加它们之间的协作。当这种协作开始展开时,原本由运维使用的旧票务系统可能会随着时间的推移逐渐被淘汰。监控工具的集成可以迁移到新的共享工具中,开发人员与运维人员之间的票务数量应该会逐渐减少,因为他们找到了新的协作方式。
重要提示
Azure DevOps 允许你自定义工作项模板,并定义生命周期状态。通过这个功能,团队可以根据他们在现有工具中使用的任何现有分类法,轻松地建模他们的工作项模板类型。这大大减少了采用新共享工作管理工具时的学习曲线。欲了解更多信息,请访问docs.microsoft.com/en-us/azure/devops/boards/backlogs/work-item-template?view=azure-devops&tabs=browser#manage-work-item-templates
。
DevOps 文化的目标与好处
此时,你可能会对这一切的意义产生疑问。DevOps 的好处是什么?它对你、你的同事和你的组织有什么影响?采用 DevOps 的最常见目标是减少周期时间。周期时间是从开始开发一个新特性到第一个用户可以使用它的时间。这一目标通过自动化实现,同时也有助于降低更改失败率、降低平均修复时间(MTTR)和减少计划停机时间。
除了这些,还有其他的好处,比如提高员工满意度、减少倦怠和压力、以及更好的员工留存率。这归因于消除了开发人员和运维人员之间的对立目标。
一段时间以来,大家对于 DevOps 是否有效、这些目标是否能实现、以及额外的好处是否能实现产生了疑问,因为这些成果仅通过案例研究来展示。这样做的缺点是,案例研究通常只针对成功的案例,而不包括失败的案例。直到 2018 年,《Accelerate》一书发布,情况才发生了变化。这本书基于多年的定量研究,展示了现代开发实践,如 DevOps,如何有助于实现 IT 目标和组织目标。
测量结果
为了衡量你目前作为一个团队或组织的现状,以及 DevOps 对你的影响,有几个指标可以开始记录。像往常一样,当处理指标或关键绩效指标(KPIs)时,确保不要鼓励人们只看数字,从而操控系统。一些有趣的指标将在以下章节中详细说明,如果你查看这些指标,你会发现它们都是关于鼓励流程的。
周期时间和交付时间
周期时间和交付时间是来自精益和看板的指标,用于衡量实现变更所需的时间。周期时间是从开始工作到用户能够在生产环境中使用某个特性之间的时间。周期时间越短,你对需求变化或洞察的反应就越快。交付时间是从请求一个特性到实现该特性之间的时间。它是从将工作添加到待办事项列表到你开始实施它之间的时间。
当你将周期时间和交付时间加在一起时,你是在计算另一个指标,称为上市时间。这是在开发软件时一个重要的商业指标。因此,最小化周期时间和交付时间会对业务产生影响。
在制工作量
你可以衡量的另一项内容是任何时刻在制工作量。DevOps 专注于价值流向用户。这意味着每个人应尽可能一次只做一件事,并在开始做其他事情之前完成当前任务。这能减少任务切换所花费的时间,以及未完成工作的时间。衡量一个团队并行处理的事务数量,并报告这些内容,可以作为激励的来源。
你甚至可以将实际的工作量限制设定为在制工作量。以下是图 1.2的一小部分,展示了这些在制工作量限制甚至可以在工具中显示:
图 1.3 – Azure Boards 显示每个阶段的限制
目标是尽可能减少同时进行的工作量。
平均恢复时间
第三个指标是平均恢复时间。在发生(部分)故障时,恢复服务需要多长时间?过去,企业专注于减少平均故障间隔时间。这曾是衡量产品稳定性的主要指标。然而,这一指标鼓励限制生产环境中的变更数量。不良的结果往往是,尽管故障可能不常发生,但发生时却持续较长时间且难以修复。
衡量平均恢复时间将注意力转向你能多快修复故障。如果你能快速修复故障,你就能实现同样的目标——即在不牺牲变更速率的情况下,最小化停机时间。目标是最小化恢复时间。
变更率和变更失败率
最后,你可以衡量交付到生产环境的变更数量以及其中未成功的百分比。提高变更速率意味着你更频繁地为用户交付价值,从而实现价值流。同时,通过不仅仅衡量失败的次数,还要衡量失败的百分比,你鼓励许多小规模的成功变更,而不是仅仅鼓励总体变更次数的限制。
你的目标应该是增加变更的速率,同时降低变更失败率。除了本节列出的四个主要 KPI,许多其他度量标准可能对衡量 DevOps 成熟度也有帮助。所有这些度量标准都必须与期望的业务目标和关键结果(OKRs)相关联。你可以在这里找到更多关于 OKR 的信息:docs.microsoft.com/en-us/azure/cloud-adoption-framework/strategy/business-outcomes/okr
。
为了说明,以下表格展示了一个典型的示例:
目标 | 关键结果 |
---|---|
更快的市场上线时间 |
-
部署频率:每周一次
-
部署时间 <= 4 小时
-
交付时间(重大版本):每季度一次
|
提高已实现的业务价值,同时维持或降低成本 |
---|
-
CI/CD 流程:100%自动化
-
资源利用率(95 百分位):80%
-
用于监控健康状况和成本的仪表板
|
可预测的高质量交付和更快速的修正,缺陷更少 |
---|
-
高可用性:> 99.9%
-
RTO < 1 小时,RPO < 15 分钟
|
改进 IT、自动化、团队协作和文化的流程 |
---|
-
MTTR < 1 小时
-
交付时间(Bug):< 8 小时
-
大规模敏捷:特性团队 > 5
-
技术债务 < 1 周
|
提升客户参与度和快速响应市场需求的能力 |
---|
-
CSAT:4 分或以上
-
产品规划:50%的待办事项集中在客户反馈上
|
表 1.1 – 使用 OKR 方法衡量你的 DevOps 成熟度
在这一点上,你可能在想,如何帮助我的组织培养这种文化,并获得这些好处呢?接下来的章节将回答这个问题。
创建你理想的 DevOps 组织
好吧,也许你的组织结构根本不需要改变。DevOps 必须从文化变革开始:开放、同理心和协作是需要鼓励的价值观。但即便如此,改变组织结构可能有助于加速这一进程。
传统上,开发人员和运维人员通常被组织成不同的团队,甚至是不同的部门——这些团队成员拥有相似的技能和职责。组织结构的一个常见变化是通过调整,将团队围绕共同目标、单一产品或一组特性进行组织。
现在,你将需要具有不同技能和职责的团队,这些团队很可能包含开发人员和运维人员。重要的是要意识到,强行对这些人进行这样的变化可能并不是最好的前进方式。通常,最有效的做法是先改变文化,鼓励合作——然后,这种组织变革可能会自然而然地发生。
最后,在这一点上,重要的是要认识到一个反模式。一些公司试图通过招聘专门的 DevOps 工程师并将其置于开发与运维之间,与两者互动,从而实施 DevOps。虽然这开始时可能看起来是一个好主意,但这实际上违背了 DevOps 的价值观。如果你这样做,你并没有打破孤岛,而是增加了第三个孤岛。你没有减少交接次数,很可能是增加了交接次数。此外,将开发人员和运维人员分开,使用另一种组织结构通常并不能促进他们之间的合作,你可能完全看不到对最终用户的任何价值提升。
现在,你已经知道了什么是 DevOps,并且对如何组建 DevOps 团队有了清晰的认识,接下来是时候探索如何开始实现你的目标了。
探索 DevOps 实践和习惯
由于你们不是第一支进行这项旅程的团队,你们可以从前人经验中汲取教训。一个例子是构建 Azure DevOps 的微软团队。由于他们处于一个罕见的位置,可以将自己的产品用于开发另一个产品,因此他们学到了很多关于什么使 DevOps 成功的经验。从中,他们识别出了七个关键的 DevOps 实践和七个 DevOps 习惯,这些习惯是许多成功的 DevOps 团队所共有的:
DevOps 实践 | DevOps 习惯 |
---|---|
配置管理 | 团队自主权与企业对齐 |
发布管理 | 对技术债务的严格管理 |
持续集成 | 专注于客户价值流 |
持续部署 | 假设驱动的开发 |
基础设施即代码 | 在生产环境中收集的证据 |
测试自动化 | 现场文化 |
应用性能监控 | 将基础设施管理为灵活资源 |
表 1.2 – DevOps 实践和习惯
现在,重要的是要意识到,仅仅复制这里描述的动作并不能保证成功。就像敏捷方法一样,你需要花时间去理解这些实践和习惯,它们的来源,以及它们如何为最终用户提供持续的价值流。
重要提示
微软服务推出了一种更为全面的 DevOps Dojo 模型,旨在对你的 DevOps 实践的成熟度进行分类。它为你提供了一个很好的结构,帮助你在团队中优先考虑与 DevOps 相关的投资。你可以在这里阅读更多相关内容:docs.microsoft.com/en-us/learn/paths/devops-dojo-white-belt-foundation/
。
接下来的章节将更详细地探讨所有这些实践和习惯。在阅读本书的其余部分时,请将这些放在心底。虽然本书的其余部分大多数将专注于如何做事的技术手段,但请不要忘记,这些仅仅是手段。真正的价值来自于你的心态,以及创建一个专注于为客户创造持续价值流的文化。
DevOps 实践
本节将依次讨论七项 DevOps 实践。正如你很快会发现的,它们彼此高度相关,要单独实践其中一项几乎是不可能的。例如,测试自动化与持续集成和持续部署密切相关。
重要提示
如果你计划参加 AZ-400 考试,掌握所有这些实践并通过 Azure DevOps 执行它们将对你大有帮助。
配置管理
配置管理是关于对你的应用程序及其依赖的组件进行版本控制,包括你的应用程序本身。配置保存在源代码控制中,通常以 JSON 或 YAML 文件的形式存在,这些文件描述了应用程序所需的配置。这些文件是像 Ansible、Terraform、Puppet 或 PowerShell DSC 等工具的输入,帮助配置你的环境和应用程序。这些工具通常从持续部署流水线中被调用。
即使配置没有变化,所需的状态也可以在一定时间间隔后重新应用。这样,可以确保实际配置保持正确,并且手动更改会自动被撤销。我们称之为防止配置漂移。配置漂移是由于随着时间的推移服务器被添加或移除,或管理员进行手动临时干预而发生的。当然,这意味着预期的配置更新需要在源代码控制中完成,并且只能通过工具应用。
配置管理或配置即代码(CaC)与基础设施即代码(IaC)密切相关。这两者通常交织在一起,在某些平台上,它们之间的差异甚至可能显得人为。CaC 将在第八章中详细讨论,实施基础设施和配置即代码。
发布管理
发布管理是关于控制你的软件的哪个版本被部署到哪个环境。版本通常通过持续集成和交付流水线创建。这些版本以及所需的所有配置将作为不可变的工件存储在一个仓库中。从这里开始,发布管理工具用于规划和控制如何将这些版本部署到一个或多个环境中。此类控制的例子包括手动审批和在允许部署到新环境之前自动查询开放工作项和质量检查。
发布管理与持续部署相关,并更多关注通过持续部署流水线的版本流程控制。第八章,实施基础设施和配置即代码,将作为发布管理的一部分进行讨论。
持续集成
持续集成是一种实践,每个开发人员每天至少一次与团队其他开发人员集成他们的工作,最好更频繁。这意味着每个开发人员应该每天至少将他们的工作推送到代码库中。持续集成构建验证他们的工作是否编译,并且所有单元测试是否运行。重要的是要理解,这种验证不应仅仅运行在开发人员孤立工作的代码上。当工作与他人的工作集成时才能真正体现其价值。
当频繁快速地集成更改时,合并更改的问题较少,并且如果出现问题,解决起来通常较为简单。在第四章,一切始于源代码控制中,你将学习如何设置你的源代码控制库以实现这一点。在第五章,迁移到持续集成中,你将了解如何设置持续集成构建。
持续部署
持续部署是自动将每个新版本的足够质量部署到生产环境的实践。在实践持续部署时,你拥有一个完全自动化的流水线,接收每个应用程序的新版本(每个提交),生成一个新的发布,并开始将其部署到一个或多个环境中。第一个环境通常称为测试,最终环境称为生产。
在这个流水线中,多个步骤会在软件进入下一个环境之前验证其质量。如果质量不足,发布将被中止,并且不会传播到下一个环境。这种方法背后的前提是,在流水线中,你试图证明当前版本无法进入下一个环境。如果你未能证明这一点,那么你就假定它已经准备好进一步进行。
只有当一个发布通过了流水线中的所有环境后,它才会部署到生产环境。每当一个发布无法继续到下一个环境时,该发布将完全取消。虽然你可能倾向于修复失败的原因,然后从失败点重新启动部署,但重要的是不要这样做。此时所做的更改尚未通过版本已经通过的所有控制进行验证。验证新版本作为一个整体的唯一方法是从头开始启动流水线。你可以在下图中清楚地看到这一点:
图 1.4 – 持续部署流程
在第六章《实现持续部署和发布管理》中,您将学习如何使用基础设施即代码设置持续部署。
重要提示
上面的图示可以在en.wikipedia.org/wiki/Continuous_delivery#/media/File:Continuous_Delivery_process_diagram.svg
找到。该图片由 Grégoire Détrez 提供,原图由 Jez Humble 制作,采用 CC BY-SA 4.0 许可,详情见creativecommons.org/licenses/by-sa/4.0/
。
基础设施即代码
在编写应用程序时,您构建的二进制文件必须在某个应用程序主机上运行。此类应用程序主机的示例可以是像 IIS 或 Apache 这样的 Web 服务器。在应用程序主机旁边,我们可能需要一个数据库和一些消息传递解决方案。这就构成了我们应用程序的基础设施。在实践 IaC 时,您会将此基础设施的描述与应用程序代码一起保存在源代码库中。
当发布新版本的应用程序,并且需要对基础设施进行一项或多项更改时,您将使用 Chef、Puppet、Terraform、Azure Bicep、PowerShell DSC 或 Azure ARM 模板等工具执行对期望基础设施的描述。执行此类描述是幂等的,这意味着它可以执行多次,而结果始终相同。这是因为您对基础设施的描述是您希望基础设施处于的期望状态,而不是一系列需要执行的步骤。如果有任何需要执行的步骤,它们会由您选择的工具自动确定。期望状态的应用也可以在持续部署流水线中自动完成,并且通常在应用程序代码更新之前执行。
这样做的一个大优势是,您可以轻松地创建一个新的环境,其中基础设施保证与其他环境中的相同。此外,配置漂移的问题(即不同环境之间的基础设施逐渐发生变化)也不再可能,因为每次您将期望的状态重新应用到每个环境时,都会强制执行。
第八章《实现基础设施和配置即代码》将更详细地讨论 IaC。
测试自动化
为了不断向最终用户交付价值,您必须快速并频繁地发布。这对您测试应用程序的方式有一定影响。当您每隔几分钟就发布一次应用程序时,您无法再执行手动测试。这意味着您必须尽可能地自动化测试。
你很可能希望为不同阶段的应用创建多个测试套件,在你的交付管道中运行。快速的单元测试应该在几分钟内完成,并且每当有新的拉取请求时都会执行,这将为你的团队提供关于他们工作质量的快速反馈,通常也能捕捉到大多数错误。接下来,团队应该在管道后期运行一个或多个较慢的测试套件,以进一步提高你对应用版本质量的信心。
所有这些应该将手动测试的量限制到最少,并让你能够自动部署新版本的应用,且充满信心。
第十章,持续测试集成,将详细讲解测试自动化。
应用性能监控
最后的这一项实践完全是关于了解你的应用在生产环境中的表现。收集诸如响应时间和请求数量等指标将告诉你系统的性能情况。捕获错误也是性能监控的一部分,它能让你在无需等待客户联系我们的情况下,开始解决问题。
除此之外,你还可以收集哪些应用部分被更频繁或不那么频繁使用的信息,以及用户是否在采纳新功能。了解使用模式将为你提供宝贵的见解,帮助你了解客户如何使用你的应用,以及他们常见的场景。
第十一章,安全性与合规管理,以及 第十二章,应用监控,将详细介绍你的应用以及用户在生产环境中的行为。
DevOps 习惯
成功的 DevOps 团队的七大习惯更关注的是文化和开发交付软件过程中的态度,而不是像 DevOps 实践那样关注技术手段。不过,了解和理解这些习惯仍然非常重要,因为它们将帮助你更轻松地进行 DevOps 的采用。
你会发现,培养这些习惯将强化前面列出的实践和你用来实施这些实践的工具。当然,反过来也适用。
团队自主性与企业对齐
在敏捷工作中,一个重要的部分是创建那些在很大程度上由团队自主管理并能够做出决策的团队,团队在做决策时(通常不需要太多)外部依赖。这类团队通常会包括多个角色,其中包括负责一个或多个功能并有权决定前进方向的产品负责人。
然而,这种自主性也意味着团队有责任将工作与整个产品的方向保持一致。开发将数十个或数百个团队的工作协同对齐的方式非常重要,确保每个团队可以按照自己的方向航行,但整体上船队能够保持一致。
最理想的情况是,团队能够主动自发地与更大愿景对齐,而不是时不时接受外部指示。
对技术债务的严格管理
另一个习惯是对技术债务进行严格管理。债务这个词本身就意味着处理问题的延迟会产生成本(利息)。为了保持持续的进展,并防止随着时间的推移逐渐失去速度,保持 bug 数量或架构问题最小化是至关重要的,且只能容忍一定的数量。在一些团队中,这甚至已被正式化为协议。例如,一个团队可以达成一致,规定未解决的 bug 数量永远不能超过团队成员的数量。这意味着,如果一个团队有四名成员并报告了第五个 bug,那么在至少修复一个 bug 之前,团队将不会承担任何新工作。
聚焦于客户价值的流动
重要的是要接受这样的事实:直到用户使用代码之前,他们无法从已编写的代码中获得任何价值。专注于为用户提供价值的流动意味着代码必须编写、测试、交付并且在生产环境中运行,直到完成。专注于这一习惯可以推动学科和团队之间的合作。
假设驱动的开发
在许多现代开发方法论中,通常有一个产品负责人,负责根据业务价值排序所有待办事项。作为专家,这个负责人负责通过根据业务价值(按工作量划分)来排序所有项目,最大化开发团队交付的价值。
然而,最近的研究表明,即使产品负责人是专家,他们也无法正确预测哪些功能将为用户带来最大价值。大约三分之一的团队工作为用户带来了价值,而另三分之一则减少了价值。因此,你可以将待办事项从功能或用户故事转向你希望证明或反驳的假设。你只需创建一个最小的实现,甚至仅仅是功能的一个提示,然后衡量用户是否会接受它。只有当这种情况发生时,你才能扩展该功能的实现。
在生产环境中收集的证据
性能测量应在生产环境中进行,而不是(仅仅)在人工负载测试环境中进行。如果负载测试在投入生产之前能够为你带来价值,那么进行负载测试是没有问题的。然而,真正的性能工作是在生产环境中完成的,应该在那里进行测量,并与之前的测量结果进行比较。
这同样适用于使用统计数据、模式和许多其他性能指标。它们都可以通过生产度量自动收集。
生产环境文化
现场文化倡导这样一种理念:生产环境中发生的任何事情优先于其他任何事情。接下来,任何威胁生产环境、即将进入生产环境,或者在任何时候妨碍生产环境的事情,都要优先处理。只有在这些问题都处理妥当后,才会将注意力转向未来的工作。
现场文化的一个组成部分是确保对任何扰乱服务运行的事件进行彻底分析——并非为了找出谁应该负责或被解雇,而是为了找出如何防止类似事件的再次发生。预防最好通过“左移”来实现;例如,通过在管道中更早地检测到重复事件的指示符。
将基础设施管理作为灵活的资源
最终,一个成功的 DevOps 团队将其服务器和基础设施视为可以持续更改、升级、调整,甚至停用的可变资产,以满足业务需求。实现这一点的能力得益于配置管理和基础设施即代码(IaC)。这甚至可能发展到为每个新部署创建一个新的生产环境,并在将所有流量从旧环境切换到新环境后删除旧生产环境。
除了牢记这些 DevOps 实践和习惯外,你还会经历一些阶段,尝试将 DevOps 文化引入组织中。接下来的部分将带你了解这些阶段。
DevOps 演化的五个阶段
当你尝试将 DevOps 文化引入组织时,这将需要时间。你需要经历一些过程,直到组织中的每个人都接受他们在工作方式上必须做出的改变。那些在你之前走过这条路的人,经历了以下五个步骤或阶段,这可能对你有所帮助。了解这些步骤可以帮助你加快进程。这些步骤首次发布在 2018 年 DevOps 状态报告 中,接下来的部分将对其进行讨论。
标准化技术栈
迈向 DevOps 文化的一个常见第一步是采纳。至少,有好的源代码控制工具,通常会推出公司标准并进行持续集成和交付。团队也会共同合作,规范他们开发软件的技术栈。例如,选择一到两个云供应商,逐步淘汰其他部署平台。其他目的的工具也是如此——它们在可能的情况下进行标准化。自制的解决方案会被行业标准所取代。
标准化并减少变异性
在这个阶段,团队致力于进一步减少应用程序之间以及开发与运维团队之间的差异,共同努力对齐操作系统、库和工具。此外,在这一阶段,部署过程也会被调整,以减少它们之间的差异,配置和基础设施通常会被移入源代码控制。
扩展 DevOps 实践
开发和运维之间的剩余问题被清除,确保开发团队的输出正是运维团队所期望的。同时,两者之间的协作开始增长,他们可以一起工作,不再依赖外部的变更创建和交付。
自动化基础设施交付
在这一阶段,开发人员和运维部门使用的基础设施完全对齐。所有内容都从源代码管理中部署,并且两个团队使用相同的脚本或解决方案。
提供自助服务功能
在 DevOps 之前,虚拟机或托管环境通常由开发人员通过手动方式或通过工单系统向运维部门请求。运维人员手动进行资源配置,这可能需要几天,甚至几周时间。
自助服务功能意味着环境不再由手动创建,而是通过运维团队提供给开发人员的自助 API 来创建。
这样,开发人员可以自行创建和销毁环境。他们可以自己创建并测试更改,然后将其提交或安排自动部署。
总结
本章中,你了解了什么是 DevOps(以及什么不是 DevOps),以及它与敏捷的关系。转向 DevOps 文化有助于打破开发人员和运维人员之间的目标冲突。这使得他们能够协同工作,持续地为最终用户提供价值,将工作组织在同一个待办事项列表中,并在同一个看板上进行操作,同时尊重他们各自的工作方式差异。将开发人员和运维人员组织成以产品为导向的团队,是创建志同道合、目标导向团队的下一个重要步骤。
转向 DevOps 可以带来许多好处,而你现在已经知道如何衡量这些好处,从而不断地进行改进。接下来,你了解了许多成功的 DevOps 团队所展示的 DevOps 习惯和实践。掌握这些习惯和实践,无论是你个人还是你的团队,都将帮助你通过 DevOps 评估。所有这些都能帮助你持续地为用户提供价值。
在下一章中,我们将讨论站点可靠性工程(SRE),以及它如何补充 DevOps,帮助管理应用程序的可靠性和可扩展性。
自我练习
利用本章中介绍的概念完成以下活动:
-
识别对你的团队可能重要的 2-3 个 DevOps 相关指标。
-
对于每个指标,识别出适用的 DevOps 实践。
-
定义这些指标的当前基准,并列出改进领域。
问题
在我们结束时,这里有一份问题列表,帮助你测试自己对本章内容的理解。你可以在评估部分找到答案:
-
判断对错:开发和运维部门经常有冲突的目标。
-
真假:本章讨论的七种 DevOps 实践没有关联性,可以轻松单独实践。
-
以下哪项不属于 DevOps 进化的五个阶段?
-
规范化技术栈
-
自动化基础设施交付
-
标准化和减少变异性
-
招聘专门的自动化团队
-
-
什么是快速通道?
-
用你自己的话简述 DevOps 的核心是什么。
进一步阅读
还有许多其他资源可以帮助您更深入了解 DevOps 文化和 DevOps 思维方式。以下是其中一些:
-
《凤凰项目》,作者吉恩·金、凯文·贝尔和乔治·斯帕福德。
-
《高效 DevOps》,作者詹妮弗·戴维斯和凯瑟琳·丹尼尔斯。
-
《加速》,作者尼科尔·福斯格伦、杰兹·汉布尔和吉恩·金。
-
与 Sam Guckenheimer 的访谈,详情请见
devops.com/11626/
。 -
Microsoft 对其 DevOps 之旅的案例研究,详情请见
stories.visualstudio.com/devops/
。 -
2018 年 DevOps 现状报告,详情请见
info.puppet.com/Eficode-Puppet-State-of-DevOps-Report.xhtml
。 -
更多关于评估现有开发流程的信息,请访问
docs.microsoft.com/zh-cn/learn/modules/assess-your-development-process/index
。 -
关于不同敏捷方法的更多信息以及如何使用 Azure Boards 支持它们,请访问
docs.microsoft.com/zh-cn/learn/modules/choose-an-agile-approach/index
。
第二章:网站可靠性工程基础
在上一章中,您学习了 DevOps 文化、目标和好处。DevOps 的实践和习惯促进了团队之间的协作,并缩短了从创意构思、设计到最终用户部署的交付周期。
网站可靠性工程(SRE)和 DevOps 方法是互为补充而非竞争关系。SRE 并不是 DevOps 之后的下一步。技术上,采用 SRE 实践的团队在使用 DevOps 指标进行衡量时能够实现更好的客户成果。
传统上,组织将团队划分为不同的孤岛单元,如开发(Dev)、质量保证(QA)和运维(Ops)团队。开发团队主要负责完成功能开发,而 QA 团队主要负责执行并完成已开发功能的质量检查。运维团队则主要负责应用程序在生产环境中的部署和维护。此外,他们还需要监控并采取必要的措施,以确保已部署应用程序的可靠性和可扩展性。
SRE 和 DevOps 都有由具备开发和运维专业知识的工程师组成的团队。因此,组织可以防止各团队之间的孤岛效应。
企业或产品的声誉和成功依赖于云解决方案在生产环境中的稳定性。为了提高应用程序的稳定性和可扩展性,SRE 将使用自动化来减少重复和手动的运维任务。将 SRE 实践融入软件开发生命周期,对于在当前 IT 解决方案构建的时代中生存至关重要。
在本章中,我们将涵盖以下主要内容:
-
SRE 简介
-
关键原则与实践
技术要求
本章没有技术要求。
SRE 简介
SRE这一术语最早由 Ben Treynor Sloss 在 Google 提出(sre.google/sre-book/introduction/
)。SRE 使 Google 能够以最有效、可靠、可扩展和可持续的方式管理大型复杂系统和庞大基础设施。
提示
SRE 主要关注服务的可靠性。
为什么可靠性如此重要?
可靠性被定义为在特定操作条件下,服务按预期执行的可能性。最可靠的系统将更易于访问,从而带来更好的客户体验。服务的可靠性是一个重要的质量指标。
可靠性和可用性是相互关联的;然而,它们的区别在于衡量方式。尽管可用性和可靠性是相辅相成的,但所采取的衡量方法可能会产生不同的结果。系统的可用性可以通过数学模型作为其可靠性的一个衡量标准。换句话说,可靠性可以视为可用性的一个子集。
什么是可用性?
系统的可用性可以通过系统可用或完全正常运行的时间百分比来衡量。一个软件系统由多个组件组成,所有这些组件都必须进行评估以确保其可用性。假设我们有一个包含数据库服务器、存储服务器和应用服务器的系统。系统的可用性将由这些组件的组合可用性来定义。
参考uptime.is/
以了解更多关于基于可用性保证的服务停机时间,通常称为服务级别协议 (SLA)的信息。以下表格展示了某些可用性百分比和停机时限(以秒、分钟和小时为单位)。术语可用性或正常运行时间通常以“九”表示(表示九的数量),如表中所示(相应地计算允许的停机时间):
可用性 | 允许停机时间 |
---|---|
百分比 | 每日 |
99.999%(五个 9) | 0 秒 |
99.99%(四个 9) | 8 秒 |
99.95%(三个 9) | 43 秒 |
表 2.1 – 可用性百分比和停机时间容许值
计算基于时间的可用性百分比的公式如下:
可用性百分比 = ((服务正常运行时间 - 服务停机时间) ÷ (服务正常运行时间)) * 100
例如,要计算单日生产服务的可用性,假设约定的服务预计会运行24365,可以使用以下公式*:
-
一天内约定服务预计正常运行的总秒数 = 86,400 秒。
-
特定日期的停机时间总和 = 部署时间 60 秒 + 因部署错误回滚时间 60 秒。
-
使用上述公式计算可用性 = ((86,400 -120) ÷ (86,400)) *100。
-
您当天服务的可用性为 99.86%。
SRE 提倡监控和评估对业务成功至关重要的重要服务的可用性。
您的 IT 部门的目标不应是全面提高服务的可用性。更高的可用性增加了业务成本,因为它需要更多的工作和资源。然而,由于更差的可用性可能导致显著的经济损失(通常,超过运营成本),因此 SRE 团队将采取务实的方法,根据业务需求定义可用性水平。
域名服务(DNS),例如,是互联网的目录。域名通过该服务与 IP 地址匹配。DNS 应该全天候、每周 7 天都可用。因此,DNS 的可用性保持在 100%。
一般来说,追求任何服务或系统的 100%可靠性并不是一个明智的选择。用户很难识别出一个服务是否是 100%可用,和一个 99.999%可用的服务之间的区别。
根据表 2.1,99.999%的可用性意味着每月可以容忍 26 秒的停机时间,每周可以容忍 6 秒的停机时间,在大多数情况下,这个时间是相当少的。
然而,一些任务关键型系统,例如医疗设备和航空器,必须完全可靠,无法承受任何停机时间。
可靠性挑战与 SRE
云架构必须可靠、可扩展并具有良好的性能。云服务将使用自动扩展来动态调整服务规模,以满足变化的需求,并且可观察性将用于支持监控系统性能、可用性、成功率、错误率、依赖错误率、请求失败率、延迟、新鲜度和吞吐量的应用程序。
组织将使用服务的可用性和可靠性指标来确定保持业务活动顺利进行所需的服务水平。您的 SRE 战略的关键决策因素是可靠性和可用性,它们有不同的含义,并且测量方式也不同:
图 2.1 – 可靠性与可用性
如前图所示,可靠性可以视为可用性的一个子集。组织已经意识到,在保持系统可靠性的同时,还需要保持开发速度、期望的可扩展性和操作稳定性,这是一项具有挑战性的任务。
传统的团队模型包括开发、质量保证(QA)和运维(Ops)团队,开发、QA 和运维任务被分开。这种分离导致了组织孤岛或推卸责任的心态,这影响了组织团队实现长期目标并培养学习和无责文化的能力:
图 2.2 – 可靠性挑战
开发团队将他们的代码丢到墙那边,期望运维团队在生产环境中运行和管理它。开发团队希望以快速的节奏将功能发布到生产环境中,而不负责应用程序的稳定性。另一方面,运维团队希望尽量减少对生产服务的更改,以避免任何对业务的干扰,从而保持服务的稳定性。
SRE 帮助团队在交付新功能和确保系统适当有效运行之间找到平衡。这种协作方法弥合了开发责任与日常系统运营、客户服务和支持任务之间的鸿沟。日常的客户支持和运营活动形成了一个反馈循环,这对于提高系统质量至关重要。
尽管客户越来越期望更短的交付时间,但仅仅关注交付速度或更高的产品速度是不够的。今天现代开发中最关键的属性之一就是可靠性。因此,在提高产品速度的同时保持可靠性,是任何 IT 组织的基本前提。SRE 团队负责其服务的可用性、延迟、性能优化、变更管理、监控、警报、应急响应和容量规划。
SRE 的基本目标是提高系统的可靠性和稳定性。团队理解可靠性指标是由业务需求驱动的,并非每个业务功能都需要最高水平的可靠性,因为这会涉及成本权衡。
适当的可靠性
服务的可靠性水平必须与其业务需求相匹配。在线电子商务企业与传统零售商店相比,会有不同的需求。例如,它们需要比传统零售商店更高的可用性,而后者通常只在设定的时间段内运营。
可靠性通过服务级目标(SLOs)来定义和衡量。SRE 实践可以根据需要调整,以实现适当的可靠性水平,SLO 通常被定义为在一段时间内的百分比达成率。SLO 是由关键业务目标驱动的,而服务级指标(SLIs)则是由在实现服务时可以衡量的内容驱动的。
一致的可靠性
产品建立在可靠的系统、服务和人员的基础上。SRE 认为,建立一种文化和实践是至关重要的,这将带来一致和可预测的可靠性。我们与同事建立的联系和信任、可持续的操作程序、以及我们培养的学习文化,为团队提供一个心理安全的工作环境,以实现环境可持续性,这些都是可靠性的一部分。
下一节将介绍 SRE 团队的关键原则和实践。
关键原则和实践
SRE 团队的日常活动包括开发和维护大型分布式服务。成功地运营一个健康的服务需要一系列广泛的活动,例如构建监控系统、规划容量、响应事故、解决故障根本原因等。
本节介绍了影响 SRE 团队日常活动的关键原则和实践。以下图表展示了从最基本到最先进的服务可靠性所需的元素:
图 2.3 – 根据 Google SRE 书籍的服务可靠性层级
从最基本的需求到推出产品或服务的巅峰步骤,Google 描述了为了提高系统可靠性和保持服务健康所需的可靠性层级。每个层级将在下文简要讨论:
- 监控:监控是维持系统可用性最重要的策略,它位于服务可靠性层级的最底层。有效的监控应简单且具有弹性,并且应该提供针对服务中关键故障的警报。这些警报应简单明了,易于理解。
没有监控的情况下,无法判断一个服务是否正常运行、是否离线或是否遇到间歇性的故障。要建立一个可靠的系统,你必须在用户注意到问题之前,就能察觉到服务中的问题和错误。一旦这些问题被发现,SRE 团队应优先处理并管理事故响应。为了减轻影响或恢复服务到先前状态,团队应以最有效的方式协调工作,并保持积极沟通。
Microsoft Azure 是一个非常强大的云平台,具备处理解决方案各个方面的丰富功能。该平台提供管理和部署应用程序的工具。在 Azure 云上开发解决方案时,必须选择适当的服务来满足你的 SRE 需求。
为了监控你的应用程序,你可以使用以下服务:
-
Azure Monitor 提供了一个全面的解决方案,用于收集、分析和处理来自云环境和本地环境的遥测数据,并支持大规模操作,配备了智能警报和自动化操作。
-
Azure Application Insights 是 Azure Monitor 的一个功能,提供强大的应用性能管理(APM)工具,能够轻松地与应用程序集成,发送遥测数据并分析应用程序特定的指标。它还提供现成的仪表板和指标浏览器,可以用来分析数据并探索业务需求。
-
事件响应:一旦你围绕服务建立了有效的监控,你需要配置通知系统,例如 SMS 和事件管理系统(EMS),用于处理未计划的、关键的和紧急的事件。事件和故障在复杂的分布式系统中是不可避免的。需要适当的人为干预来识别根本原因并修复这些故障。
为了最小化业务影响并平稳运行服务,你需要建立一个结构化的过程来缓解和响应这些事件。事件得到缓解后,SRE 团队应按照事件管理响应过程尽快恢复服务。
事件响应框架有三个共同目标,广泛称为事件管理的三大 C(3Cs):
-
协调响应工作。
-
沟通:在事件响应者、组织内部以及外部之间进行沟通。
-
保持对事件响应的控制。
尽管每个组织的事件响应过程可能会根据组织结构、技能和先前的经验有所不同,但可以参考以下一套建议和最佳实践来响应事件:
-
优先级:修复频繁发生的问题,尽快恢复服务,并保留根本原因分析的证据。
-
准备:提前与事件参与者共同制定并记录你的事件管理程序。
-
信任:为所有事件参与者在其分配的角色和责任范围内提供完全的自主权。
在事件发生期间,你必须平衡以下关键点:
-
速度:
- 平衡快速行动以满足利益相关者需求与匆忙决策带来的风险。
-
信息共享:
- 通知调查人员、利益相关者和客户,以减少责任,避免不切实际的期望。
-
事后分析和根本原因分析/无责事后分析:一旦事件得到缓解并处理完毕,SRE 团队会执行事后分析程序。这个事后分析程序为培养无责事后分析文化提供了机会。无责事后分析(或回顾)是一个事后文件,帮助团队弄清楚事件发生的原因、哪些做得好、哪些做得不好,并集思广益,探讨如何防止类似问题的再发生。
无责事后分析是 SRE 文化的一个基本原则。为了建立可持续的文化,我们需要假设所有参与事件的人都抱有良好的意图,并且在他们掌握的信息基础上做出了正确的决定,以最小化业务影响。将责任归咎于个人或团队会打击团队士气,并引发对惩罚的恐惧,这会使得问题更难暴露出来。
无责事后分析是团队从失败或错误中学习的机会。
-
测试和发布流程/可靠性测试:SRE 团队负责建立对其构建和维护的生产系统可靠性的信任。SRE 团队将采用完全自动化的测试策略,并结合传统的软件测试技术,将其部署到生产环境并发布给用户,确保没有问题或停机时间。旨在支持软件可靠性的自动化测试套件可以增强信心,确保软件能够顺利部署到生产环境中。作为其质量保证活动的一部分,SRE 团队必须优先考虑并持续投资于自动化测试实践。客户会更满意,平台的采纳率也会提高,从而带来更高的投资回报率(ROI)。
-
容量规划:作为 SRE 团队的一员,你负责确定你的服务所需的资源,包括必要的硬件、软件和网络资源,并确保即使面对预料之外的需求,服务仍能表现良好。容量管理是确保服务拥有足够资源以实现可扩展性、容错性、高效性和可靠性的过程。例如,SRE 会估算在特定时间间隔内,你将需要多少存储、服务实例或内存。这些数据将帮助你为服务创建可扩展的架构。在基于云的模型中,你可能对所需的容量更为灵活,因为可以动态地增加或减少所需资源。
Azure 应用服务、Azure SQL 数据库、Azure Kubernetes 和 Azure Cache for Redis 是 Azure 云服务的示例,这些服务内置了自动缩放功能。
例如,在Azure 应用服务中,缩放设置在秒级别应用,并影响你应用服务计划中的所有应用。你不需要修改或重新部署应用。你可以扩展并获得更多的 CPU、内存、磁盘空间以及额外的功能,例如专用的虚拟机(VMs)、自定义域名和证书、暂存槽、自动缩放等。你还可以利用自动缩放,依据设定的标准和时间表自动调整实例数量。缩放规则是一个更为可控的扩展或缩减的方法。
例如,每天 21:00,你可以将 Azure 应用服务的实例数缩减到两个,并设置规则,当 CPU 需求的平均值高于 50%时,自动扩展一个实例。扩展或缩减通常需要几分钟才能完成。在设计你的扩展计划时,请考虑这一点,以匹配性能需求并满足 SLA 要求。
- 开发:虽然每个人都期望服务能够顺利运行,但可能会由于某些无法控制的事件而发生中断,如自然灾害、硬盘故障,甚至是系统进程崩溃,这些都可能对您的服务产生不利影响。自然灾害可能会严重损坏某个区域的许多数据中心。为了保持系统 正常运行,SRE 团队必须设计策略来缓解这些故障。这些解决方案可能会采用诸如 地理复制与故障转移、地理冗余、以及 活动-活动、活动-被动 高可用性 等部署模式/策略。
图 2.4 – 多区域架构
例如,如前图所示,多区域架构比单一区域部署提供更高的服务可用性。这里讨论的架构包括以下组件,仅举几例:
-
活动区域与备用区域:两个区域用于实现更高的可用性。一个是主区域,另一个区域用于故障转移。
-
Azure Front Door:一种现代云端 内容分发网络(CDN)服务,提供高性能、可扩展性和安全的用户体验,适用于您的内容和应用程序。该服务提供多种第七层负载均衡能力以及接近实时的故障转移。
-
Azure DNS:用于 DNS 域名托管服务,提供名称解析。
-
Azure 应用服务:Azure 的主要服务,用于 Web 应用程序和基于 Web 的 API,提供与 Azure AD 和 Azure Key Vault 的集成安全性。支持自动扩展。
-
Azure Functions:一种无服务器计算选项,采用事件驱动模型。在此架构中,当新消息推送到队列时,函数会被调用。
-
Azure Redis 缓存:作为解决方案的一部分,应用缓存层服务,提供内存中的托管缓存,以减少延迟并提高客户端性能。
-
Azure 存储、Azure Cosmos DB 和 Azure SQL:可以存储结构化和非结构化内容。
-
在灾难发生的情况下,如果区域中断影响了活动区域,Azure Front Door 将会切换到备用区域。此架构使用两个区域,活动区域和备用区域,以实现更高的可用性。在正常操作期间,网络流量会被路由到主区域。如果活动区域不可用,流量将路由到备用区域。
-
活跃/被动与热备份意味着在备用/待命区域的资源将始终处于运行状态。这些备用区域的资源可以用于 A/B 测试,以提高性价比。
-
产品:公司推出新产品的速度较慢。在云计算和分布式现代化世界中,推出和发布周期需要更快。
团队可以创建清单来记录行动项目和回滚计划。清单在以可复制的可靠性启动新服务中发挥着重要作用。清单需要根据公司的内部服务、流程和基础设施进行定制。
清单需要小心创建,否则它会膨胀到无法管理的规模。此清单可以并且应该被文档化和自动化,以最小化工作量。清单可以涵盖以下主题:
-
架构和依赖关系
-
集成
-
容量规划
-
故障模式
-
流程与自动化
-
开发过程
-
发布规划
-
渐进式和阶段性发布
在下一节中,我们将讨论影响 SRE 操作的模式和原则。
实施 SLOs 和 SLIs
SLOs 定义了您服务可靠性的目标水平。SLOs 是 SRE 实践的核心,因为它们对做出关于可靠性的基于数据的决策至关重要。SLOs 是帮助确定优先处理哪些工程工作的工具。
SLIs 是衡量您提供的服务水平的定量指标。SLOs 和 SLIs 总是并行存在,并通常是迭代定义的。SLOs 由关键业务目标驱动,而 SLIs 则由实施服务时可衡量的内容驱动。
您第一次尝试 SLI 和 SLO 时不必是正确的。最重要的目标是建立并进行测量,并设置反馈回路,以便您可以改进。您可以识别哪些度量指标最符合用户在您的服务中关心的内容。
SRE 团队建议根据关键服务使用有限的度量指标,以提高用户体验,而不是开发无穷无尽的监控指标。您可以从广泛的目标开始,然后随着时间的推移进行调整。这使您能够将警报集中在可以可靠地判断服务将失效并开始影响用户体验的实例上。
假设您正在构建一个外卖应用,用户可以执行以下操作:
-
浏览餐厅和菜单。
-
选择菜单项并下单。
-
支付订单。
对于这个应用,用户能够下单并成功支付对于更好的用户体验和整体业务成功至关重要。在这里,首次尝试的下单并支付场景将成为定义 SLOs 的基础,因为这个服务对业务成功的优先级高于其他任何服务。
下一步是弄清楚哪些度量指标可以作为 SLIs,最准确地跟踪用户体验。您可以从各种指标中选择,例如可用性延迟、吞吐量、正确性和数据新鲜度,接下来会详细介绍。
大多数服务专注于以下四个关键 SLI 指标来进行监控。这些是监控的四个黄金信号:
-
请求延迟:您的服务返回请求响应所需的时间
-
服务可用性:服务可用的时间占比
-
成功率:成功完成的请求数量
-
吞吐量:每秒处理的请求数量
定义 SLO 的测量周期非常重要,可以在不同的时间间隔内进行定义。SLO 和 SLI 需要是能够在监控系统中准确测量和表示的内容。随着时间的推移,你将比较 SLO 目标和 SLI 与实际度量指标。现在,对于下单并支付服务,它是 SLO 的基础,你希望在可接受的时间窗口内收到订单确认。
在我们以外卖应用为例的情况下,你可以为下单并支付服务设置一个响应时间值,比如 700 毫秒,用于在指定的 1 个月时间窗口内成功请求的响应。这些 SLI 目标和时间框架应当是业务可以接受的。所以,如果在一个日历月内有 10,000 个 HTTP 请求,其中 9,990 个请求成功,这意味着该月的可用性为 9,990/10,000,或 99.9%。
如果你的服务未能满足 SLO,SRE 团队将努力在新功能开发/部署和提高服务可靠性之间找到平衡,以避免在给定的测量周期内发生 SLO 违规。
SLA 是商业和客户之间的法律协议,包括可靠性目标以及未能达到目标的后果,而 SLO 是一个衡量客户如何使用服务的内部目标。SLO 不会与外部利益相关者共享,也没有法律约束力或后果。如果服务的可用性违反了 SLO,SRE 团队必须立即响应,以避免组织因未能满足 SLA 而受到处罚。SLO 应始终比相应的 SLA 更严格。SRE 团队通常不参与构建 SLA,因为 SLA 与业务和产品决策密切相关。然而,SRE 团队可以帮助定义 SLI。
为了在可靠性和创新之间找到合适的平衡,最好创建一个衡量 SLO 违规的比率,以及一个可以容忍 SLO 失效的错误预算。在接下来的部分中,我们将深入了解错误预算。
建立错误预算政策
错误预算是指在给定周期内,服务无法正常运行的最大错误数或最大时间,超过此限度会对业务产生负面影响,用户将不满。错误预算适用于服务的多个方面,例如可用性、延迟等。SRE 团队利用错误预算在服务可靠性和创新速度之间找到平衡。
错误预算将帮助你判断自己是否达到了预期目标,并帮助你采取适当的措施来减少服务的可靠性故障。如果服务在四周内收到 1,000,000 个请求,99.9%的成功请求 SLO(服务水平目标)允许我们在这段时间内预算 1,000 个错误。
一个具有 99.95% SLO 的服务,其错误预算为 0.5%,意味着在一年内整体的停机时间为 4 小时 22 分钟 48 秒。SRE 团队应采取适当的行动来恢复服务的稳定性,特别是当服务未达到 SLO,或错误预算已用尽或接近用尽时。
当你的服务在预算范围内时,SRE 实践鼓励你战略性地消耗错误预算,无论是用于新功能还是架构修改。尽管任何新的发布都会在某种程度上使服务变得不那么可靠,例如,如果服务因为部署配置问题而宕机,服务仍然在预算内。错误预算通常是根据一定时间段设定的,例如一个月、一个季度或一年。
错误预算通常用于战略性地为Toil任务(如手动部署、环境设置、配置更改、事件响应等)应用自动化。在下一节中,我们将进一步了解如何减少 Toil。
减少 Toil
在 SRE(站点可靠性工程)上下文中,“Toil” 指的是那些没有长期经济价值并且不会显著推动服务进展的操作。这些操作通常是重复性的,并且大多是手动的(尽管它们可以自动化)。随着服务或系统的增长,系统的手动请求数量可能会按比例增长,进而需要更多的人工劳动。
SRE 工程师最多只能将 50%的时间花费在Ops工作上,如处理工单、值班和手动任务等。
SRE 工程师应该将他们的另一半时间花在以下活动上(这不是一个全面的列表):
-
使用自动化来实现可扩展性
-
发布部署
-
测试套件自动化
-
应用数据库更改
-
自动化响应事件,如密码重置和用户创建
-
审查非关键监控警报
-
为了减少 Toil 并提高系统可靠性,进行工程工作以开发新功能。
为了有效地减少 Toil 工作负担,SRE 团队可以从小处开始,逐步推进。消除 Toil 需要自动化,SRE 团队必须不懈努力,减少或最小化 Toil。自动化工程工作,无论是部分还是完全,都是必要的,但它不应危及系统可靠性。Azure Automation 可以用来自动化人类响应,并诊断和解决问题。自动化将提升团队的动力,使团队能够专注于工程工作。
总结
在这一章中,我们了解了 SRE 的原则和实践。现在我们知道如何计算基于时间的可用性,以及如何根据业务期望和需求定义可用性。
我们还探讨了传统团队模型中常见的可靠性挑战,以及如何通过建立 SRE 团队来帮助你在系统可靠性和开发之间找到合适的平衡。我们强调了适当且一致的可靠性的重要性。
然后,我们学习了从构思到成功将服务部署到生产环境的所有必要方面。我们还重点介绍了关键技术,如应用 SLO 和 SLI、减少繁重工作、事后分析文化,以及高效利用错误预算来提高系统和云服务的可靠性。
在接下来的章节中,我们将探讨 DevOps 工具和能力,看看它们如何帮助你管理软件开发生命周期。
自我实践练习
-
与业务利益相关者和开发团队共同确定 SLO。
-
对你服务在生产环境中最近或假设的生产事件进行无责事后分析:
-
识别与在生产环境中运行服务相关的繁琐、重复性任务/负担。
-
在 Azure 门户中,首先配置应用服务日志记录与应用洞察,以监控应用程序,然后配置电子邮件警报。
问题
在我们总结 SRE 战略时,这里有一份问题清单供你测试你对本章内容的理解。你可以在书本末尾的评估部分找到答案:
-
正确还是错误?SRE 主要关注服务的可靠性。
-
正确还是错误?可用性是以五个 9 来表示的。
-
正确还是错误?SRE 采用自动化来实现应用程序管理。
-
对于一个可用性为 95%的服务,每周、每月和每年的停机容忍时间是多少?
-
最主要的三大可靠性挑战是什么?
-
开发速度
-
质量
-
稳定性
-
DevOps 管理
-
缺陷跟踪
-
-
正确还是错误?服务的适当可靠性水平由关键利益相关者确定。
-
在 SRE 的背景下,什么是负担(toil)?
进一步阅读
-
谷歌的 SRE 书籍:
sre.google/sre-book/part-I-introduction/
-
微软的 SRE 文档:https://docs.microsoft.com/en-us/learn/modules/intro-to-site-reliability-engineering/
-
Azure 监视器:
docs.microsoft.com/zh-cn/azure/azure-monitor/overview
-
Azure 应用程序洞察:
docs.microsoft.com/zh-cn/azure/azure-monitor/app/app-insights-overview
-
Azure 自动化:
docs.microsoft.com/zh-cn/azure/automation/overview
第三章:最大化利用 DevOps 工具
DevOps 可以看作是一种旨在改进整体软件开发生命周期(SDLC)过程的方法,从而增强参与团队之间的合作。因此,使用适当的工具集来支持 DevOps 流程和活动对于推动各个工程团队之间的一致性和可预测性至关重要。目标是通过自动化各个流程,建立创新文化,从而同步团队(或角色)的努力,在开发、测试和部署软件时,以尽可能高的质量实现更快的速度。
Microsoft 提供了诸如 Azure DevOps、GitHub、Azure Monitor 和 Visual Studio Code 等优秀产品,帮助简化在 DevOps 实施的各个生命周期阶段中采用重要实践的过程。这些工具功能丰富,并为开发者社区提供了业界领先的体验。通过其他独立软件供应商(ISVs)和开源社区提供的市场扩展,这些工具的开箱即用体验可以进一步扩展。
到本章结束时,你将熟悉其中一些工具的功能,以及它们在各自的软件开发程序中的应用背景。
在本章中,我们将涵盖以下主要主题:
-
SDLC 和 DevOps 工具
-
Azure DevOps 和 GitHub
-
Azure DevTest Labs
-
Azure Monitor
-
Visual Studio Code
SDLC 和 DevOps 工具
无论是服务还是产品,SDLC 这个术语指的是在构建软件解决方案时所应用的一系列过程和实践,以确保质量并达到为工程团队设定的其他目标。
这些流程通常根据开发生命周期的各个阶段进行分组。随着技术的演进,这些流程的成熟度也得到了提升。由于分布式计算和云技术的使用,工程系统变得相对复杂,开发团队需要保持高度的严谨性和纪律性,同时利用自动化来支持他们的数字化转型之路。
根据你所遵循的软件开发方法论,无论是 瀑布模型、敏捷、Scrum、看板,还是你自己定制的版本,你很可能会以某种形式使用 DevOps 相关的实践。然而,值得一提的是,如果你希望充分发挥 DevOps 投资的真正潜力,瀑布模型已经不再是推荐的方法论。
让我们看看 DevOps 生命周期中执行的一些关键活动。
DevOps 生命周期中的关键活动
从高层次来看,DevOps 相关的活动可以分为四个不同的重点领域,如下图所示:
图 3.1 – DevOps 生命周期中的关注领域和关键活动
这里列出的活动清单旨在作为基本的基础列表。根据您的 DevOps 成熟度,您可能会实施更多的实践来最大化业务成果。您必须利用第一章《DevOps 简介》中与您的上下文相关的 DevOps 度量指标,并识别出有助于实现这一目标的重要实践。
在接下来的几个部分中,我们将详细回顾这些关注点,帮助您更好地理解每个部分。
规划和跟踪
开发团队识别并组织产品积压,并发布工作任务给团队。工作将根据业务优先级和可用容量进行排期。积压梳理和完善是产品生命周期中的持续活动,且将跨多个版本进行。
开发和测试
开发团队开始以源代码或脚本的形式产出工作成果。所有对代码库的更改都会通过静态分析器、单元测试,甚至人工检查来检测质量问题。一旦确认无误,工件将被编译并构建,生成可部署的包,也称为解决方案。
部署和发布
解决方案最初部署在测试环境中,使用自动化测试验证其正确性,然后发布到生产环境中。之后,解决方案将正式上线,并供最终用户访问产品或服务。
监控和学习
一旦解决方案上线,这一阶段开始生效,从产品或服务的实际使用中捕获诊断和健康监控信息。监控工具中捕获的数据会定期分析故障和错误;任何识别出的问题要么通过自动化程序进行缓解,要么记录为待修复的缺陷。此时,客户反馈也可以通过渠道反馈给产品或服务,以提出改进建议。现在,您已经了解了 DevOps 生命周期中的工作内容,我们接下来将回顾一些常用的 DevOps 工具。
您的 DevOps 需求的工具
微软提供了多种工具来支持您的 DevOps 生命周期需求。此外,它还支持与其他第三方工具的集成,为您团队的开发人员提供一个协调一致的体验。因此,无论您是在构建新软件系统还是维护现有系统,您都可以轻松采用 Azure DevOps 服务和 GitHub,以大规模创新。
这里列出了您可以计划用于各种 SDLC 活动的工具:
实践/活动 | 工具选择 |
---|---|
管理产品积压,规划并跟踪工作,准备仪表板和报告。 | Azure Boards |
本地开发代码,构建、调试并测试。 | Visual Studio Code/Visual Studio |
管理和跟踪源代码的更改。 | Azure Repos,Git |
定义持续集成(CI)/持续部署(CD)工作流,以集成更改并将最新发布部署到不同环境。 | Azure PipelinesGitHub ActionsJenkins(第三方) |
提供开发环境。 | Azure DevTest Labs,Azure Virtual Desktop |
部署和管理 Azure 云基础设施和服务(包括 IaaS 和 PaaS)。 | Azure 资源管理器(ARM)和 Azure 命令行界面(CLI)Ansible 和 Terraform(第三方) |
管理资源的配置。 | Ansible,Terraform,Chef,Puppet 和 Azure Automation |
高级分析和报告。 | Power BI |
捕获和分析日志(诊断、审计和健康)。 | Azure Monitor 和 Azure Data Explorer |
准备测试计划并管理执行。 | Azure Test Plans |
存储可重用的软件包和工件。 | Azure Artifacts |
通过使用第三方扩展和插件提高生产力。 | Azure DevOps MarketplaceGitHub Marketplace |
表 3.1 – 用于 SDLC 活动的 DevOps 工具
请访问 https://azure.microsoft.com/en-in/solutions/devops/#practices 了解更多详细信息。
在接下来的几节中,我们将介绍这些工具的一些功能和能力。这些工具的详细使用也将在后续章节中解释,并提供说明性示例,展示如何实现各自的 DevOps 实践。
Azure DevOps 和 GitHub
Azure DevOps 和 GitHub 是微软提供的两款强大的软件即服务(SaaS)产品,构成了完整的 DevOps 工具集。从管理待办事项和团队流程,到基于 Git 的代码库,再到能够执行 CI/CD 流程并进行自动化测试,你会发现 GitHub 和 Azure DevOps 是完美的解决方案。
在接下来的子章节中,我们将探索这两款工具的独特功能。
Azure DevOps
最初,作为 Visual Studio 套件的一部分,现今的 Azure DevOps 可能是工程团队最常用的产品,用于管理他们的源代码和应用程序生命周期过程。它以前被称为Visual Studio Team Services,在此之前还叫做Visual Studio Online。
Azure DevOps 是 Azure 云托管版的 Azure DevOps Server,之前在开发者社区中被称为Team Foundation Server(TFS)。该产品中提供的主要服务如以下图所示:
图 3.2 – Azure DevOps 中可用的服务
您对这些服务的访问权限将取决于您用户帐户的许可类型。有关个人和组织可用的完整许可选项列表,请访问 azure.microsoft.com/en-in/pricing/details/devops/azure-devops-services/
。
让我们简要了解每个服务。
Azure Boards
使用 Azure Boards 管理产品待办事项并跟踪工作变得更加容易。通过使用看板风格的板块,您可以创建自定义的看板来跟踪从想法到实现的所有内容:
图 3.3 – Azure Boards 的功能
您可以在此阅读更多有关 Azure Boards 的信息:docs.microsoft.com/en-in/azure/devops/boards/get-started/what-is-azure-boards?view=azure-devop
s
。
使用 Azure Boards,您可以执行以下操作:
-
管理和组织您的待办事项列表。
-
可视化各个阶段,并在每日站会和团队会议中使用它们来跟踪进度。
-
为各利益相关者创建自定义的仪表板报告。
在下一节中,我们将介绍 Azure Repos,这是您将存储所有工作产品的地方。
Azure Repos
源代码管理(SCM)和版本控制对管理代码库更改的工程团队至关重要。Azure Repos 提供了一个版本控制工具,用于管理各种软件开发项目。
Azure Repos 提供两种类型的版本控制系统:
-
团队基金会版本控制(TFVC):这是一个集中式版本控制系统。尽管近些年使用不广泛,但许多项目团队仍然在出于遗留目的的情况下继续使用这种方法。
-
Git:这是更受欢迎的分布式版本控制系统。如果您刚开始您的 DevOps 之旅,建议仅使用基于 Git 的版本控制系统:
图 3.4 – Azure Repos 的功能
您可以在此阅读更多有关 Azure Repos 的信息:docs.microsoft.com/en-us/azure/devops/repos/get-started/what-is-repos
。
使用 Azure Repos,您可以执行以下操作:
-
使用 Git CLI 或基于 GUI 的工具管理您的源代码更改。
-
配置分支策略和安全性以确保合规性。
-
使用语义搜索快速找到您在代码库中查找的内容。
现在,让我们回顾一下 Azure Pipelines,您将使用它进行 CI/CD 过程。
Azure Pipelines
所有基于代码的工件都遵循某种形式的持续集成(CI)、持续交付(CD)和持续测试(CT),以确保它们的质量,然后才能将其移至生产环境。Azure Pipelines 提供自动化来执行构建、测试和发布工作流。执行任务的顺序通过 YAML 文件进行配置。在构建管道时,您可以选择多个源代码库(如Azure Repos、GitHub、Bitbucket等)。此外,通常会为不同的工作负载创建单独的管道,并根据需要进行门控审批检查:
图 3.5 – Azure Pipelines 中的功能
您可以在此阅读更多关于 Azure Repos 的内容:docs.microsoft.com/en-us/azure/devops/pipelines/get-started/what-is-azure-pipelines?view=azure-devops
。
使用 Azure Pipelines,您可以执行以下操作:
-
创建 CI/CD 管道(基于 YAML),执行各种任务,如构建解决方案、运行自动化测试,然后部署解决方案。
-
管理不同环境的部署。您还可以实施门控检查和批准。
现在,让我们回顾一下如何使用 Azure 测试计划组织您的测试用例。
Azure 测试计划
测试是软件开发生命周期(SDLC)中的一个非常重要的步骤。测试活动有不同的类型,如功能测试(手动或自动化)、性能测试、用户验收测试和探索性测试。Azure 测试计划允许您为任何特定的迭代或版本创建执行计划,包含适用的测试并跟踪执行结果。执行测试计划的报告可以轻松生成,利益相关者可以根据报告推断软件产品或服务的质量:
图 3.6 – Azure 测试计划中的功能
您可以在此阅读更多关于 Azure 测试计划的内容:docs.microsoft.com/en-us/azure/devops/test/overview?view=azure-devops
。
使用 Azure 测试计划,您可以执行以下操作:
-
为各种类型的测试活动创建执行计划。
-
维护测试用例、缺陷和产品待办事项之间的可追溯性。
-
使用现成的图表和小部件分析测试报告。
在下一部分中,我们将回顾您的团队如何利用 Azure Artifacts 作为所有可重用代码组件的存储库。
Azure Artifacts
Azure Artifacts 允许开发人员管理各种类型的可重用包,以满足他们的解决方案开发需求。这些包可以仅供内部使用,也可以分发给外部。实质上,它充当了一个包的仓库,如公开可用的注册表。
您可以在此处了解更多关于 Azure Artifacts 的信息:docs.microsoft.com/en-us/azure/devops/artifacts/start-using-azure-artifacts?view=azure-devops
。
使用 Azure Artifacts,您可以执行以下操作:
-
将包发布到中央私有仓库。支持的包类型包括 NuGet、npm、Maven、Python 和通用包。
-
消费并共享包以供其他解决方案组件重用和参考。
现在,让我们来看看微软的 GitHub 提供的服务。
GitHub
GitHub 于 2018 年 6 月左右被微软收购。在最初几年,GitHub 是开发者社区中非常流行的代码托管平台,主要用于开源项目的代码共享。然而,自从被收购以来,它增加了各种功能,使其在开发者中更受欢迎,帮助他们构建和共享代码,同时通过提供多种其他功能扩大了企业使用范围。
GitHub 是另一款非常流行的工具,用于实现您的 DevOps 实践。产品中提供的主要功能如下图所示:
图 3.7 – GitHub 上可用的功能
您可以在 https://github.com/features 详细了解这些功能。
由于功能列表持续更新(您可以参考公共路线图:github.com/github/roadmap
),请随时查阅产品文档以获取最新信息。
在下一部分中,我们将介绍Azure DevTest Labs,它允许您快速配置非生产类型的环境,以验证您的解决方案是否有效。
Azure DevTest Labs
这是微软 Azure 提供的一项服务,允许开发人员使用已发布的可重用模板和工件快速创建开发和测试环境。您可以在此处找到更多信息:azure.microsoft.com/en-in/services/devtest-lab/
。
虽然该服务可免费使用,但仍要求开发人员拥有付费的 Azure 订阅。不过,根据适用的定价计划,使用已配置的 Azure 资源将按大幅折扣价格收费。您可以在此处查阅与定价相关的详细信息:azure.microsoft.com/en-in/pricing/details/devtest-lab/
。
在下一部分中,我们将查看 Azure 中可用的监控工具。
Azure Monitor
Azure Monitor 提供丰富的仪表板功能,帮助你监控特定应用程序的指标、资源健康状况和利用率,以检测异常并提供及时干预。这是一个综合性服务,允许你收集、分析并处理来自各种来源的监控数据,包括应用程序、基础设施和其他自定义源。
你必须计划使用的 Azure Monitor 的一些关键功能如下:
-
日志分析,深入挖掘监控数据并获取深刻洞察
-
Application Insights,用于端到端事务追踪、异常和性能指标
-
容器洞察,用于微服务的使用情况和健康相关统计
-
自定义仪表板,根据使用案例量身定制,用于跟踪使用情况和可靠性指标
-
警报,用于检测异常并通知团队采取适当的行动,以及执行自动化的操作。
要了解更多关于 Azure Monitor 的信息,请访问 azure.microsoft.com/en-us/services/monitor/
。
来自不同来源的监控数据可以分为两部分,即日志和指标。它们是 Azure Monitor 服务中的两个独立的大数据存储。
Azure Monitor 由一系列产品和服务组成,提供所需的监控和仪表板功能。在以下小节中,我们将回顾三种最常用的服务——即 Azure Monitor 日志、Azure Monitor 指标和 Application Insights。
Azure Monitor 日志
可以收集来自多个来源的通用日志和性能数据,并将其整合到 Azure Monitor 日志的一个工作区中。
更多信息请参见:docs.microsoft.com/en-in/azure/azure-monitor/logs/data-platform-logs
。
Azure Monitor 指标
这是 Azure Monitor 的一项功能,将来自多个来源的数值数据捕获到一个时间序列数据库中。这些值对应于从系统收集的、按定期间隔采样的指标列表。
更多信息请参见:docs.microsoft.com/en-in/azure/azure-monitor/essentials/data-platform-metrics
。
Application Insights
你可以通过 Azure Application Insights 在所有应用程序中集成对丰富遥测数据的捕获支持。使用日志来获取洞察,检测性能问题,诊断常见错误,利用端到端事务流可视化 HTTP 请求,并收集指标以推导出其他各种指标。
你可以在这里了解更多关于 Azure Application Insights 的信息:docs.microsoft.com/en-us/azure/azure-monitor/app/app-insights-overview
。
在下一节中,我们将回顾开发人员常用的工具——Visual Studio Code。
Visual Studio Code
Visual Studio Code 是微软推出的一款免费代码编辑器,允许你快速开发、构建、部署和测试现代云应用。它可以在 Windows、Linux 和 macOS 上使用,并内置支持多种编程语言。此外,它还有一个社区支持的插件和小工具,可以极大提升你的工作效率。
如果你是开发人员,必须尝试 Visual Studio Code。欲了解更多信息,请访问 code.visualstudio.com/
。
总结
本章中,我们回顾了几种可以用于 DevOps 生命周期需求的重要工具。我们将在接下来的章节中通过实例和实践实验详细说明这些工具的具体使用。不论你是开发人员还是 IT 管理员(Ops),你都会在日常工作中使用这些工具中的一种或多种。
继续专注于构建自动化工作流,更多地采用这些工具将有利于你的组织实现 DevOps 目标,这些目标通过各种指标进行跟踪。研究表明,已经转向 DevOps 交付模式的企业,在执行各种数字化转型计划方面比竞争对手更成功。
因此,必须理解,技术的使用在推动 DevOps 成熟度指数方面也发挥着至关重要的作用。在企业中采用 Azure DevOps 和 GitHub,不仅能激发团队更大的生产力和潜力,还能提升你成为 DevOps 采纳者的顶尖表现者的机会。
在下一章中,我们将探讨在 API 平台生命周期流程中实施正确的 DevOps 实践的重要性。
自我练习
利用本章中介绍的概念来完成以下活动:
-
使用你的电子邮件在
github.com/
注册 GitHub。 -
通过访问 https://azure.microsoft.com/en-us/free/ 创建一个免费的 Azure 账户。创建账户时,你需要使用现有的 Microsoft 账户(或 GitHub 凭证)进行注册。
-
通过访问 https://azure.microsoft.com/en-us/services/devops/?nav=min 创建一个免费的 Azure DevOps 组织。这样,你将在 Azure DevOps 目录中创建一个组织。
问题
在本章结束时,以下是一些问题,供你测试自己对本章内容的理解。你可以在附录中的 评估 部分找到答案:
-
判断题:你需要企业用户账户才能创建 Azure DevOps 项目。
-
判断对错:你可以使用 Azure Boards 可视化和跟踪团队的工作。
-
判断对错:Azure Application Insights 提供性能指标,例如所有与其集成的应用程序的响应时间。
-
判断对错:你可以在 Azure Pipelines 中使用 GitHub 存储库。
-
判断对错:GitHub 仅作为开源代码存储库使用。
进一步阅读
要了解本章涉及的主题,请查看以下资源:
-
企业 DevOps 报告: https://azure.microsoft.com/en-us/resources/enterprise-devops-report-20202021/
-
Agile: https://docs.microsoft.com/en-us/devops/plan/what-is-agile
-
Kanban: https://docs.microsoft.com/en-us/devops/plan/what-is-kanban
-
GitHub:
docs.github.com/en
-
Ansible:
docs.ansible.com/
-
Terraform:
www.terraform.io/docs
-
Chef 和 Puppet:
www.chef.io/puppet
第二部分 – 实现持续交付
在本部分中,你将学习源代码控制、持续集成和持续部署的实践。大多数组织首先采用这些 DevOps 实践,因为它使你能够以最有效、可预测的方式持续地生产高质量的解决方案。
本书的这一部分包含以下章节:
-
第四章,一切始于源代码控制
-
第五章,过渡到持续集成
-
第六章,实现持续部署和发布管理
第四章:一切从源代码控制开始
源代码控制是软件开发中最基本的工具之一。因此,可以合理假设你之前已经使用过源代码控制。鉴于此,本章将仅简要介绍源代码控制,并迅速进入更高级的话题,以帮助你设置源代码控制并支持 DevOps 实践。
多种 DevOps 实践依赖于源代码控制,因此,设置你的代码库以持续为用户提供价值是一个很好的起点,并且是后续章节中许多主题的前提条件。
本章将涵盖以下主题:
-
Azure DevOps 源代码控制系统中的源代码控制类型
-
选择分支和合并策略
-
使用分支策略保护源代码控制
-
可用于源代码控制的其他工具
技术要求
为了实践本章所涉及的主题,你可能需要一个 Azure DevOps 组织。此外,请确保在本地计算机上安装了 Git 工具。你可以从这里下载 Git 工具:git-scm.com/downloads
。
Azure DevOps 中的源代码控制类型
虽然存在许多不同的源代码控制系统,但它们可以分为两类:集中式和去中心化,如下所示:
-
在集中式源代码控制系统中,只有服务器拥有完整的历史记录和构成代码库的所有分支。
-
在去中心化源代码控制系统中,每个与代码库协作的人都拥有代码库的完整副本,包括所有分支及其历史记录。
Azure Repos,作为 Azure DevOps 服务的一部分,通过团队基础版本控制(TFVC)和 Git 提供两种类型的源代码控制。接下来的两节将更详细地讨论这两种源代码控制。
集中式源代码控制
在集中式源代码控制系统中,服务器是唯一存储完整代码库(包括所有历史记录)的地方。当你创建内容的本地版本时,你只会获得代码的最新版本。获取这个最新版本的过程称为检出代码库。除了这个最新版本,你的计算机上只有你本地所做的更改。
不检出完整历史记录显然节省了你本地计算机的空间。然而,如今磁盘空间几乎从来不是问题。这样做的缺点是,你需要持续连接到服务器,才能执行诸如查看文件历史记录、其他人最近提交的内容,或是某个文件中的某一行最后由谁修改等操作。
集中式源代码控制系统的一个优点是,它们通常提供对谁可以访问哪些分支、目录,甚至文件的精细控制选项。
去中心化源代码控制
使用去中心化源代码管理系统时,所有文件、历史记录和分支也会存储在服务器上。与集中式源代码管理的不同之处在于,当你克隆仓库时,能够在本地计算机上拥有一份副本。
由于你拥有仓库的完整克隆,现在可以在不需要再次连接到服务器的情况下查看文件的历史记录和其他分支。这显然减轻了服务器的负担,并允许你在断开连接时继续工作,这是去中心化源代码管理的两个优势。
缺点是,去中心化的源代码管理可能比集中式源代码管理更难学习。总体来说,去中心化源代码管理系统的学习曲线更陡峭。此外,基于单独目录和文件的访问控制通常也更为有限。
无论你使用哪种类型的源代码管理,都必须制定分支和合并策略,以便让开发人员能够并行工作在不同的功能上,同时始终保持 master
分支处于可交付的状态。
在 Azure DevOps 的一次更新中,仓库创建时默认创建的分支现在被命名为 main
。Azure DevOps 还提供了将默认分支重命名为其他名称的功能。有关更多信息,请参考:docs.microsoft.com/en-us/azure/devops/repos/git/change-default-branch
。
在下一节中,我们将了解开发者社区中最常用的不同源代码管理系统。
源代码管理系统
目前有许多源代码管理系统被使用,但在本章中,我们将只关注当前最常用的三种,它们如下:
-
TFVC
-
Git
-
Subversion
在 Azure DevOps 中,只有 TFVC 和 Git 可用。Subversion 是由 Apache 基金会创建的集中式源代码管理系统。在接下来的小节中,我们将更详细地了解 TFVC 和 Git,并学习如何在它们之间迁移源代码。Subversion 将在本章最后的 其他源代码管理工具 部分进行讨论。
TFVC
TFVC 是由微软在 2013 年推出的集中式源代码管理系统,作为 Team Foundation Server (TFS) 的一部分,该产品已经发展成了现在的 Azure DevOps。TFVC 在 Azure DevOps 中仍然受到支持,但不建议用于新项目。如果你还没有使用 TFVC,那么学习它没有什么价值,因为微软很可能不会再为它发布新功能,但也不必因为没有其他原因就停止使用它。
在 Azure DevOps 中,每个团队项目最多只能有一个 TFVC 仓库。
Git
除了 TFVC,Azure DevOps 还支持托管 Git 代码库。Git 是一种去中心化的源代码控制方式,目前在开发者社区中是标准做法。Git 并非 Azure DevOps 特有,它是一种通用协议,许多提供源代码托管服务的平台都使用这个协议。Azure DevOps 之外的著名例子有 GitHub 和 GitLab。
要与 Git 代码库一起工作,您必须首先克隆它:
-
打开命令提示符并导航到您希望存储代码库的目录。
-
执行以下命令并将示例 URL 替换为您的 Git 代码库的 URL。示例 URL 展示了 Azure DevOps 中 Git 代码库位置的构建方式:
git clone https://{organization}@dev.azure.com/{organization}/{teamProjec t}/_git/{repository}
现在,您可以开始处理您想要做的更改。在本示例中,添加了一个新文件NewFile.txt
。
-
接下来,必须暂存此文件以便提交。暂存文件是为了区分您想提交的文件和您希望保留的更改:
git add NewFile.txt
-
在将所有希望归为一个提交的更改暂存后,创建实际的
commit
可以通过调用commit
命令并指定更改描述来完成:git commit -m “Added a new file that contains an important text”
-
最后,您可以通过执行以下命令将您的更改推送回中央代码库(也称为远程库):
git push
要进行更多更改,您可以根据需要随时暂存和提交更改。您可以一次提交一个提交,也可以一次推送多个提交。
您也可以通过Visual Studio(VS)或 VS Code 接口来使用 Git。在这里,您执行完全相同的步骤,但可以使用图形界面代替熟悉的命令行界面。
大文件存储
Git 被设计和优化用于处理纯文本文件,并跟踪从版本到版本的变化。然而,您可能希望在源代码管理中存储除了文本文件以外的其他内容。比如,图像或二进制文件,这些文件应该在应用程序运行时与应用一起使用。虽然这些是有效的使用场景,但开箱即用时,它们与 Git 的兼容性并不好。为了解决这个问题,引入了大文件存储(LFS)。
Git LFS 并不直接存储二进制文件本身,而是允许您存储一个小的文本文件,这个文本文件充当二进制文件的指针。该文本文件包含二进制文件的哈希值,以便客户端在克隆或获取更改时下载文件。之后,当您更新二进制文件时,文本文件中的哈希值也会更新。
要使用 Git LFS,您必须在 Git 客户端之外安装 LFS 客户端。这是一个独立的客户端,代码库的每个用户都必须下载。没有这个客户端,其他用户只能看到指针文件,而无法看到实际的二进制文件。安装客户端后,您必须为代码库准备 LFS 的使用。以下示例命令启用了对 MP4 文件的 LFS 支持:
git lfs install
git lfs track “*.mp4”
git add .gitattributes
从现在开始,您可以像处理任何文件一样处理 MP4 文件,在幕后,它们将与您的文本文件更改分开存储。
在控制系统之间迁移
DevOps 旅程中的一步是工具的整合。这意味着在某个时刻,您可能会被要求将源代码从一个源代码控制系统迁移到另一个,并且公司可能决定将所有源代码从 GitLab 或 Subversion 迁移到 Azure Repos。您可以选择多种选项来执行此类迁移。
最可能的情况是您将收到将源移动到一个或多个 Azure Git 存储库的请求。可能的来源包括其他 Git 存储库、TFVC 或 Subversion。有工具和方法可用于在保留原始存储库中变更历史的同时执行此类迁移。
如果没有可用的程序或者必须从另一个系统导入源代码,您还可以回退到创建一个新的空存储库,并使用现有代码库进行初始化。这种方法的缺点是所有历史记录将丢失。
迁移现有 Git 存储库
在迁移源方面,与其他迁移相比,将 Git 存储库迁移到另一个托管位置非常简单。让我们学习如何做到这一点:
-
首先,将现有存储库克隆到您的本地计算机:
git clone https://{organization}@dev.azure.com/{organization}/{teamProjec t}/_git/{repository} .
-
添加另一个引用新的空存储库的远程服务器,您希望将源移动到该存储库:
git remote add migrationTarget https://{organization}@dev.azure.com/{organization}/{teamProjec t}/_git/{newRepository}
-
最后,将更改推送到这个新存储库。您必须对每个要移动到主干旁边的分支单独执行此操作:
git push migrationTarget master
同时,其他开发人员可能会继续使用现有的存储库。
-
要将这些包含在新存储库中,您必须从原始存储库将它们获取到您的本地计算机,然后将它们推送到新存储库。再次为每个分支重复此操作:
git fetch origin master git push migrationTarget master
-
指示所有开发人员开始使用新的远程存储库。随后,计划废弃原始存储库。
-
成功迁移后,最好删除旧存储库。这样可以防止任何人意外继续在那里工作。
前述步骤对任何 Git 到 Git 的迁移都适用。
现在,如果您特别想迁移到 Azure Git 存储库,您还可以使用 Azure DevOps 提供的导入
功能。要执行此操作,请按照以下步骤操作:
-
转到存储库,并可选择创建一个新的 Git 存储库。
-
选择导入现有存储库。
-
提供所请求的信息。
-
单击导入以开始导入存储库。
以下截图展示了这些步骤:
图 4.1 – 导入存储库
这种方法的缺点是您不能继续将更改从源仓库推送到新仓库。这意味着您团队中的所有其他开发人员必须确保他们自己将更改迁移过来,或者在您迁移仓库时没有任何待处理工作。
从 TFVC 迁移到 Azure Git 仓库
要从 TFVC 迁移到 Git,您可以使用与将任何 Git 仓库迁移到 Azure 仓库相同的导入仓库。此向导可以在进行导入时迁移过去 180 天的变更历史。如果这不够,您需要将超过 180 天的历史迁移到新仓库,您可以使用其他方法,但这些方法更加复杂。更多详细建议的链接已包含在本章末尾。
从 Subversion 迁移到 Azure Git 仓库
您可能收到的最后一种请求是将 Subversion 仓库迁移到 Git 仓库。对此,微软没有提供现成的解决方案。但是,Atlassian 创建了一个工具,可以在保持变更历史的同时,将 Subversion 仓库迁移到本地 Git 仓库。
运行此工具后,剩下要做的就是向新的空托管仓库添加远程仓库,并推送所有分支。这些步骤与从 Git 迁移到 Git 的步骤相同,从添加新远程仓库的步骤开始。
不保留历史记录的迁移
如果您被要求进行不保留历史记录的迁移,您可以直接从本地计算机上的源文件夹创建一个新的空仓库,并将现有更改推送到该仓库。
从包含应进入 master
分支的文件的目录执行以下命令:
git init
git add
git commit -m “Initial import of existing sources”
git remote add https://{organization}@dev.azure.com/{organization}/{teamProject}/_git/{repository}
git push
这些命令初始化一个新的仓库,创建所有目录中文件的第一个提交,添加对目标服务器位置的引用,并将新创建的仓库推送到该位置。
如果您想保留多个分支,必须为每个其他分支重复以下步骤:
-
首先,进入该分支的正确目录:
Git checkout {branchName}
-
现在,将需要进入该分支的文件复制到您的工作目录中。然后,继续执行以下命令:
git add . git commit git push
这完成了迁移,您本地计算机上的源文件的最新版本现在可以在 Git 中使用。您的团队其他成员现在可以克隆该仓库并与其合作。接下来,我们将继续学习关于分支和合并的内容。
选择分支和合并策略
源代码管理允许你保留所有文件更改的历史记录,还允许你与团队成员暂时分开工作(如果你愿意的话)。我们称之为分支。当你在源代码管理中进行分支时,你分叉了当前注册的更改路径。我们称这样的分叉为分支。分支使你可以暂时将某些工作与其他工作隔离开来。在任何时候,如果你想将一个分支的更改与另一个分支的更改合并,你可以合并这些更改。分支通常用于开发尚未完成的特性、概念验证或热修复。使用分支允许你稍后决定哪些更改应包含在下一个版本中,哪些不包含。
分支策略
目前有许多分支策略可供选择,但如今最常用的三种策略如下:
-
GitHub 流程
-
GitFlow
-
发布流程
以下小节将更详细地讨论这些内容。
提示
作为分支的替代方法,基于主干的开发如今变得越来越流行。欲了解更多信息,请访问 trunkbaseddevelopment.com/
。
GitHub 流程
GitHub 流程是一种简单但通常足够的分支策略。在 GitHub 流程中,只有一个 master
分支。
如果你想开始开发一个新特性或修复 bug,你需要在 master
分支上创建一个新的主题分支,并在该分支上提交你的工作。只有在你完全完成工作后,才应将该分支合并回 master
分支。一个示例提交流程可能如下所示:
图 4.2 – GitHub 流程
由于这是涉及最少分支的分支方案,它可能是一个很好的起始策略。
了解更多信息,请参见:www.geeksforgeeks.org/git-flow-vs-github-flow/
。
GitFlow
GitFlow 是另一种著名的、复杂的分支方案,几乎可以处理在软件开发过程中可能出现的任何情况。GitFlow 描述了每当你开始开发新版本时,如何从 master
分支创建一个 develop
分支。develop
是集成分支,用于合并新特性并进行集成测试。它应该只包含你认为已准备好发布的工作。
从 develop
分支,你可以创建一个或多个 feature
分支,开始开发新特性。只有当特性完成后,才应将该分支合并回 develop
分支。
当你想发布应用程序的新版本时,你会创建一个release
分支,基于develop
分支。你可以在此分支上进行最终测试,并根据需要进行一个或多个 bug 修复。当你对代码的质量满意时,你可以将此分支合并到master
并标记版本。你还可以将这些 bug 修复合并回develop
,以便它们也能被纳入新的开发中。这个流程可以在下图中看到:
图 4.3 – GitFlow 分支模型
如果有一个紧急的 bug 需要尽快修复,或者你想做一个热修复,也可以使用基于 GitFlow 的分支策略。在这种情况下,你可以创建一个master
分支的新分支,在这个分支上修复 bug。测试完成后,你可以将该分支合并到master
和develop
中——就像处理release
分支一样。
发布流程
master
分支。
区别在于,部署到生产环境的不是位于master
分支上的代码。而是每当需要发布新版本时,会从master
创建一个名为release-{version}
的新分支。该分支中的代码随后被部署到生产环境。一旦新的release
分支被部署,之前的分支就可以被忽略。这导致了以下流程:
图 4.4 – 发布流程分支模型
该模型的优点在于,它允许获取master
分支当前状态的快照并将其推向生产环境。如果生产环境中出现了一个 bug,需要在新的完整发布之前修复,那么必要的提交可以从master
分支合并到当前的release
分支中。
基于主干的开发
在许多公司中,分支和合并操作用于保持发布新版本软件时的灵活性,并且能够在最后一刻为特定版本选择性地挑选更改。这种灵活性以某些时候需要合并或整合你的更改为代价。
这种成本不仅仅是所需的时间,还有合并操作引入的风险。合并来自两个不同分支的变化,即使它们包含完美运行的软件,也可能仍然产生无法工作的代码。
因此,你可能考虑切换到master
分支,仅为准备单一更改创建一个短期存在的分支,然后将其合并到master
分支。
基于主干的开发的好处
主干开发有助于提高开发团队在发布功能到生产环境时的敏捷性。功能团队将使用临时且短生命周期的features
分支来开发功能。更改将在开发环境中进行单元测试和验证,随后通过 Git 的PULL
请求功能推送到master
分支。这将在后续章节中进行详细说明。
你可以在这里阅读更多关于主干开发的信息:trunkbaseddevelopment.com/
。
采用此方法时,你需要另一种方式来确定发布新版本软件时哪些更改对用户可用,哪些不可用。你可以通过使用抽象分支来实现这一点。
抽象分支
在进行抽象分支时,你不会通过分支并排存放代码的两个版本,而是将它们并排保存在代码库中。例如,当你想要更改名为FoodClassifier
的类的实现,而该类实现了IFoodClassifier
接口时,你需要执行以下步骤:
-
将
FoodClassifier
类的名称重构为FoodClassifierToBeRemoved
。 -
创建一个完整的
FoodClassifierToBeRemoved
类的副本。 -
将这个副本的名称改回
FoodClassifier
。
此时,你的更改应该是这样的:
public class FoodClassifier : IFoodClassifier
{
public FoodClassification Classify(Food food)
{
// Unchanged classification algorithm
}
}
public class FoodClassifierToBeRemoved : IFoodClassifer
{
public FoodClassification Classify(Food food)
{
// Unchanged classification algorithm
}
}
请注意,在运行时,你的应用程序行为与之前完全相同。你只是添加了一个新的、尚未使用的类,并且它具有行为变更。现在提交这些更改并将新二进制文件交付给用户是安全的。接下来,你可以开始修改新FoodClassifier
类的实现,进行测试,并建立对其实现的信任。
与此同时,你可以继续提交并推送你的更改,甚至是推送到客户那里。切换到新实现可以通过依赖注入配置、布尔标志或环境变量来完成。只需根据你的场景选择合适的方式。
只有当你完全确认新实现正常工作时,才会移除FoodClassifierToBeRemoved
类,并将任何引用更新回FoodClassifier
。
我们将在第六章《实现持续部署和发布管理》中,讨论特性开关时详细介绍抽象分支。虽然抽象分支是加速交付的推荐方法,但它也是一把双刃剑。如果没有有效的流程来控制并清理并行实现的数量,且在切换实现后进行清理,代码库的质量可能会下降。
合并策略
根据你使用的源代码管理系统,可能有多种方式将你的更改从一个分支合并到另一个分支。
TFVC
当你使用 TFVC 时,你可以通过选择源分支和目标分支,并选择你想要合并的更改列表来准备本地合并。TFVC 将执行合并并将合并的结果显示为本地更改。你可以审查、更正或更改这些更改,并解决任何冲突。之后,你可以像处理常规更改一样提交这些更改。
Git
使用 Git 进行合并时,可以切换到目标分支,然后合并源分支的所有更改。如果分支之间有冲突的更改,你必须像从服务器获取新更改时一样解决这些冲突。合并源分支的更改并解决冲突后,你可以提交这些更改。这将产生一个合并提交,你可以像其他更改一样将其推送到远程仓库。
合并提交可以通过 Visual Studio 或 VS Code 的可视化界面来完成,也可以使用以下命令序列:
git checkout targetBranch
git merge sourceBranch
在合并过程中,如果有任何冲突,你必须在此时解决这些冲突,否则无法继续:
git commit -m “Merged changes from sourceBranch”
git push
正如你将在保护仓库部分中看到的那样,可以通过禁止这种方式的合并来保护某些分支。当涉及到合并更改到master
分支时,你可能希望使用另一种机制,即拉取请求。通过拉取请求,你可以请求其他人从你的本地分支拉取更改到目标分支。这样,其他团队成员可以首先审查你的更改,并在满足所有约定标准时进行合并。其他人可以对你的更改进行评论或请求更新,然后再进行合并。这是强制执行四眼原则的最常见方式,适用于 Git 的源代码管理。四眼原则规定,每个更改或操作都应该至少由两个人审查。
当你批准拉取请求时,你可以使用不同的策略来生成合并提交。最常用的策略有合并提交、压缩提交或变基提交。
合并提交
常规的合并提交是一种保留所有先前提交可见性的提交类型。它引用了两个父提交,展示了更改的两个来源,即源分支和目标分支。这与你可以手动使用 Git 合并执行的合并类型相同。此类型的提交的优点是,它清晰地显示了目标分支的新状态来自哪里。
压缩提交
当执行所谓的压缩提交时,你将源分支中的所有单独提交合并为一个新的提交。这对于源分支上的所有提交都与一个功能相关,并且你希望在目标分支上保持清晰、简洁的更改历史时非常有用。当源分支上有修复 bug 或清理操作的提交时,这种方法最为合适。缺点是,你可能会失去一些源分支上增量更改的理由。
变基
master
分支暂时被搁置。与此同时,master
分支超前于本地分支的所有提交现在会合并到本地分支。最后,所有被搁置的你自己的提交将被重新应用。以下图示展示了变基提交前后的分支状态:
图 4.5 – 变基
在变基源分支后,它现在被合并到master
分支中。这种合并的优点是,你可以在一个提交历史中保留所有单独的更改。
管理仓库
在使用 Azure Repos 时,每个团队项目最多只能有一个 TFVC 仓库。然而,在使用 Git 时,你可以在同一个团队项目中拥有多个仓库。最近越来越受到关注的讨论是,是否应该为所有应用程序使用单一仓库,还是每个应用程序使用一个仓库。管理仓库时,其他重要的话题包括创建和删除仓库、确保仓库安全以及为仓库设置策略。
单仓库或多仓库
你使用单体仓库(monorepo)时,将所有项目和应用程序的代码存储在一个源代码控制仓库中。与此相对,你可能会使用多个仓库,其中每个应用程序、库或项目存储在自己的仓库中。这两种方法各有优缺点,且大小公司都会使用这两种方法。
单仓库的可能优势包括以下几点:
-
更容易重用现有代码:如果所有代码都在一个仓库中,那么每个人都可以访问和查看它。这意味着重用的机会增加。
-
将所有应用程序放在一个仓库中也意味着,任何影响多个应用程序的更改都可以在一个提交中进行,这样可以在一个仓库里完成。一个典型的例子是 API 更改。
-
由于所有代码都可以由每个人访问和维护,因此开发人员或团队声称某个特定仓库是自己的可能性较小。这鼓励大家互相学习。
单仓库的缺点包括以下几点:
-
单仓库可能会变得非常非常大,甚至到达开发人员只检出或克隆单个部分的程度。这实际上会消除单仓库的大部分优势。
-
将所有代码集中在一个仓库中会促使组件或应用之间的紧耦合。如果你有多个仓库,可以更新 API 并以新版本发布,逐个升级客户端。在单一仓库中,你可能会被诱惑在一次提交中升级 API 并更改所有消费者,带来所有相关的风险。
哪种方法最适合你,受到的不仅是已讨论的优缺点的影响,还受到你团队和组织的背景及构成的影响。如果你有一个团队负责内部应用的所有开发,单一仓库可能更有意义。如果你有多个团队为不同客户开发不同的应用,多个仓库更合适。
创建和删除仓库
在 Azure DevOps 中,每个团队项目可以有多个 Git 仓库。试着执行以下操作:
- 首先,访问管理仓库界面。以下截图展示了如何访问此界面:
图 4.6 – 管理仓库
-
打开此界面后,新的界面(如下图所示)会弹出。在这里,你可以通过点击带有加号的**添加…**按钮(请参阅左侧导航菜单旁边的垂直部分)来添加新仓库,并填写仓库名称。
-
也可以通过点击仓库名称,然后选择删除仓库(标记为2;请参阅仓库名称的上下文菜单)来删除仓库:
图 4.7 – 删除仓库
删除仓库并不是常做的事。将不再使用的仓库设置为只读或移除其所有授权,可能更有意义。
现在,让我们学习如何保护我们创建的仓库。
保护仓库
虽然分布式源代码管理的安全选项通常没有集中式源代码管理那么广泛,但 Azure Repos 提供了一些设置仓库或服务器端分支授权的方式。在上一节的最后一张图中,你还可以看到如何在中间列中选择一个组或用户,然后更新仓库的授权。默认情况下,所有授权都是从项目默认设置继承的。
提示
建议尽量减少更改授权的次数,如果确实需要更改,最好通过组进行操作并授权。
你还可以通过在左侧下拉菜单中打开仓库分支,点击你希望覆盖授权的分支来更改特定分支的授权。在之前的截图中,这是标记为HenryBreen.RazorAnalysers
的仓库。
分支策略
最后,您还可以强制对特定分支的拉取请求应用一项或多项策略。分支策略的界面如下所示,可以通过在管理仓库分支的授权时选择分支策略选项来访问:
图 4.8 – 分支策略
前四个复选框与可以启用(或不启用)的默认策略相关。默认情况下,它们都处于禁用状态。
构建验证可以用于禁止合并任何拉取请求,如果选择的一个或多个构建未成功完成。如何设置这样的构建是你将在下一章中学习的内容。
除了构建外,你还可以调用外部服务来检查拉取请求,并允许或拒绝它。这里经常使用的集成是与代码质量工具的集成。你也可以在这里调用自己的 API,以强制执行团队在诸如拉取请求标题、与工作项的关联或更复杂的约束等方面的约定。
最后,你可以强制要求特定的用户或小组必须参与拉取请求的审查。这可能是为了确保特定的质量水平,但也可能成为限制你开发速度和流程的因素。
其他源代码管理工具
除了 Azure Repos 中可用的源代码管理系统外,还有一些其他著名的系统,你应该了解它们:
-
GitHub
-
GitLab
-
Subversion
我们将在接下来的子章节中逐一讲解这些内容。
GitHub
GitHub 是一个托管的源代码管理提供商,提供托管的 Git 仓库。GitHub 允许任何人创建任意数量的公开可见仓库。当你创建需要三名或更多贡献者的私有仓库时,必须切换到付费订阅。
如果是在公共开发中使用,该模型允许平台的无限制免费使用,这使得 GitHub 成为全球最大的开源软件托管平台。
GitHub 于 2018 年被微软收购,从那时起,微软和 GitHub 一起合作,创建了 GitHub 仓库与 Azure DevOps 之间的良好集成体验,特别是在 Azure Boards 和 Azure Pipelines 上。除此之外,微软表示 GitHub 和 Azure Repos 将继续并存,目前没有计划为了一个产品而终止另一个产品。
GitHub 还提供了一个企业版,称为 GitHub Enterprise,提供两种部署选项,即云托管和自托管(或本地部署)。
你可以在这里阅读更多关于各种 GitHub 产品和定价计划的内容:docs.github.com/en/get-started/learning-about-github/githubs-products
。
GitHub 的公共路线图可以在这里查看:github.com/orgs/github/projects/4247/views/1
。
GitLab
GitLab 是另一个提供托管 Git 仓库的平台。像 Azure DevOps 一样,源代码控制托管是它提供的服务之一。
Subversion
Subversion 是一种较早的源代码控制系统。Subversion 开发并首次使用于 2004 年,由 Apache 软件基金会维护。Subversion 是一种集中式源代码控制系统,支持你期望的所有功能。
关于为什么 Subversion 比 Git 更差的论点有很多是错误的;然而,大多数论点对新版 Subversion 并不适用。事实上,Subversion 是一种广泛使用的源代码控制系统,特别适用于非常大的仓库或具有特定授权需求的仓库。
虽然 Azure DevOps 无法托管 Subversion 仓库,但它可以连接并与存储在 Subversion 中的源代码进行协作。
总结
在本章中,你已经了解了源代码控制。你了解到源代码控制有两种类型:集中式和分散式,Azure DevOps 都支持这两种类型。TFVC 不再推荐用于新项目。你应该在开始新项目时使用 Git。
在使用 Git 时,你可以在团队项目中拥有多个仓库。对于每个仓库,你可以分配策略来锁定特定分支,并强制执行四眼原则。你还学习了访问控制,如何为用户提供对一个或多个仓库的访问权限。最后,你了解了替代工具,并学会了如何将源代码从一种工具迁移到另一种工具。
你可以利用所学知识来决定在你的产品中使用哪种类型的源代码控制系统。你现在可以专业地组织你所工作的一个或多个仓库。你现在能够使用不同的分支策略,并使用策略来强制执行安全性或质量要求。
下一章将基于你学到的源代码控制知识,使用这些知识来设置持续集成。
问题
在我们总结之前,这里有一份问题列表,供你测试自己对本章内容的掌握情况。你可以在附录的评估部分找到答案:
-
集中式和分散式源代码控制有什么区别,在哪些情况下哪种方式更合适?
-
判断题:Git 是分散式源代码控制的一个例子,正确还是错误?
-
以下哪一项不是常见的分支策略?
-
发布流程
-
变基
-
GitFlow
-
GitHub Flow
-
-
许多公司希望在代码合并到
master
分支之前进行代码审查。使用 Git 时,应该使用什么方法来完成此操作?如何在 Azure DevOps 中强制执行这一流程? -
以下哪些不是有效的合并策略?
-
变基
-
基于主干的开发
-
合并提交
-
压缩提交
-
练习
-
前提阅读:
docs.microsoft.com/zh-cn/azure/devops/boards/best-practices-agile-project-management
-
创建你的第一个团队项目,并将其命名为
PacktBookLibrary
。按以下截图设置其他配置:
图 4.9 – 创建一个新的团队项目
- 一旦
PacktBookLibrary
团队项目创建完成,使用左侧导航,按照层次结构进入Product-Backlog
,在Product-Backlog
查询中:
图 4.10 – 查询编辑器
- 使用编辑器视图中的列选项部分,选择列(堆栈排名等)并在堆栈排名上进行排序:https://github.com/OpenDocCN/freelearn-devops-pt3-zh/raw/master/docs/dsn-impl-ms-dop-solu-az400-exgd/img/B18655_04_11.jpg
图 4.11 – 添加列并应用排序
- 添加一个初始的产品待办事项(史诗和特性),如以下截图所示:
图 4.12 – DevOps 特性列表
这里的目标是通过相同的产品待办事项跟踪重要的 DevOps 实践的实施,以便在工作规划和优先级设置过程中将其纳入其中。最终,实施这些实践的将是同一组团队成员。
- 你可以配置一个新的 Git 仓库开始添加代码,或者从现有 Git 仓库导入代码。
PacktBookLibrary
解决方案的起始代码可以在这里找到:https://github.com/PacktPublishing/Exam-Guide-AZ-400-Designing-and-Implementing-Microsoft-DevOps-Solutions。
在导入现有仓库时,以下截图中的对话框会显示出来:
图 4.13 – 导入 Git 仓库
-
一旦代码被导入,你应该能够在仓库中查看到代码文件。
-
在以下设置中,为仓库中的
main
分支配置分支策略:-
打开(使用切换按钮)要求最低数量的审阅者。将最低审阅者数量设置为1。
-
打开(使用切换按钮)检查关联工作项,设置为必需。
-
-
打开限制合并类型。从允许的合并类型列表中选择Squash 合并作为唯一选项。
-
将
PacktBookLibrary
仓库(main
分支)克隆到你工作站中的本地文件夹。 -
通过从
main
分支创建一个分支来检出源代码,然后开始使用它进行提交。定期计划发起PULL
请求,以将更改合并到main
分支中。
完成练习列表中的步骤后,你的源代码控制仓库将被设置好。我们将在接下来的章节中通过练习在此基础上进行拓展。
进一步阅读
-
关于 Git 的更多使用信息可以在
docs.microsoft.com/en-us/learn/paths/intro-to-vc-git/
找到。 -
关于 TFVC 与 Git 的原始 Microsoft 建议可以在
docs.microsoft.com/en-us/azure/devops/repos/tfvc/comparison-git-tfvc?view=azure-devopsviewFallbackFrom=vsts
找到。 -
关于 Git LFS 的更多信息可以在
docs.microsoft.com/en-us/azure/devops/repos/git/manage-large-files?view=azure-devops
找到。 -
下载 Git LFS 的说明可以在
git-lfs.github.com/
找到。 -
关于迁移到 Git 的更多信息可以在
docs.microsoft.com/en-us/azure/devops/repos/git/import-from-TFVC?view=azure-devops
找到。 -
一个用于将 SVN 仓库转换为本地 Git 仓库的 Atlassian 工具可以在
www.atlassian.com/git/tutorials/migrating-convert
找到。 -
关于 GitFlow 的更多信息可以在
datasift.github.io/gitflow/IntroducingGitFlow.xhtml
找到。 -
关于 GitHub Flow 的更多信息可以在
guides.github.com/introduction/flow/
找到。 -
Release Flow 的详细描述可以在
docs.microsoft.com/en-us/azure/devops/learn/devops-at-microsoft/release-flow
找到。 -
Trunk-based 开发的讨论可以在
trunkbaseddevelopment.com/
找到。 -
关于 GitLab 的更多信息可以在
about.gitlab.com/
找到。 -
关于 Subversion 的更多信息可以在
subversion.apache.org/docs/
找到。
第五章:转向持续集成
在为你的组织设置了源代码管理并决定了支持并行工作的分支和合并策略后,你就可以继续进行持续集成了。持续集成是一种方法,每个开发人员将自己的工作与其他人的工作集成,然后验证组合后的工作质量。这样做的价值在于在管道早期提高质量。这减少了以后在合并代码更改时出现错误的风险,并减少了在生产中发现的缺陷数量,从而降低了成本并保护了你的声誉。
持续集成只有在你具备必要的工具和适当的配置时才有可能实现。在本章中,你将学习如何使用 Azure DevOps 管道来设置持续集成。
本章将涵盖以下主题:
-
介绍持续集成
-
创建构建定义
-
运行构建
-
使用 YAML 管道
-
代理和代理队列
-
使用 GitHub Actions 自动化持续集成(CI)构建
-
其他工具
技术要求
为了完成本章中涵盖的示例,你将需要以下内容:
-
一个 Azure DevOps 组织
-
Git 命令行工具
-
一个代码编辑器,如 Visual Studio Code
介绍持续集成
持续集成是一种方法,你将自己的更改与项目中所有其他开发人员的更改集成,并测试组合后的代码是否仍按预期工作。通过这种方式,你创建了一个快速的反馈循环,能够为你的工作提供反馈。
在处理用于隔离代码更改的大规模分支策略时,开发人员可能会在一个孤立的分支上工作数天、数周甚至数月。这对于确保他们的更改不会干扰其他人是很有好处的,但持续集成是确保以后不会出现合并问题的好方法。如果你曾经需要将数周或数月的工作合并回主分支,你会知道这涉及多少工作,并且常常会导致错误或其他问题。
为了防止这种情况,开发人员应养成每天至少一次将自己的更改与其他开发人员的更改集成的习惯。在这里,集成意味着至少合并、编译并运行单元测试。这样,开发人员的更改质量就会得到持续的反馈,并且由于这些反馈是综合的,它是防止以后出现合并问题的好方法。
持续集成还使你能够将其他关注点嵌入到管道中,以自动保持代码质量。静态代码分析、单元测试和安全扫描是三个典型的例子。这些主题将在后续章节中讨论,但一个好的持续集成管道是这些实践的基础。
在本章的其余部分,你将了解如何使用 Azure Pipelines 设置持续集成的技术手段。但首先,让我们看一个常见的误解以及持续集成的四大支柱。
重要提示
虽然自动化的持续集成构建是执行持续集成的重要组成部分,但持续集成不仅仅是拥有一个构建管道。需要记住的关键点是,持续集成是一个过程,每个开发者至少每天都会将自己的工作与同事的工作进行整合。然后,整合后的源代码会被编译并进行测试。其价值在于编译和测试整合后的工作,而非孤立的工作。
持续集成的四大支柱
有四个支柱支撑着持续集成的成功实施:
-
版本控制系统:用于存储自系统创建以来所做的所有更改。版本控制系统在上一章中已讨论。
-
包管理系统:用于存储你在自己应用中使用的二进制包以及你创建的包。这将在 第七章 中详细讨论,依赖管理。
-
持续集成系统:一个可以将所有开发者的更改汇总在一起——一天多次——并创建一个集成的源版本的系统。这可以通过 Azure DevOps 管道来实现。
-
自动化构建过程:用于编译和测试合并后的源代码。我们将探讨如何使用 Azure DevOps 管道实现这一过程。
可以在 Azure DevOps 中设置持续集成和自动化构建。下一节将解释如何在 Azure DevOps 中设置这两者。
在 Azure DevOps 中创建构建定义
执行持续集成的主要方法是使用持续集成构建。在 Azure DevOps 中,构建可以作为 Azure Pipelines 的一部分进行配置。目前,创建构建定义有两种方法:
-
通过可视化设计器(也称为经典构建和发布)
-
通过 另一种标记语言 (YAML) 文件(也称为 YAML 管道或多阶段管道)
本节的其余部分将重点讲解可视化设计器。接下来的部分,YAML 构建定义,将详细介绍 YAML 管道。两种方法大致支持相同的功能,尽管也有一些差异。某些在经典构建和发布中可用的功能在 YAML 构建定义中尚不可用。此外,只有 YAML 管道才提供某些新功能。
如果你没有管道经验,经典编辑器是一个很好的方式,可以在转向 YAML 管道之前,先熟悉持续集成/持续开发管道的工作原理。经典构建中的几乎所有概念都可以转化为 YAML 构建。
在接下来的各节中,我们将从构建一个经典的构建管道开始。
连接到源代码管理
要开始创建构建定义,请按照以下简单步骤操作:
-
打开管道菜单。
-
从此菜单中,点击构建。在这里,您将看到一个按钮,用于创建新的构建。点击此按钮后,将打开一个新的视图,用于创建构建,如下图所示:
图 5.1 – 用于管道的源代码仓库选项
- 然后,您将被引导到新的 YAML 体验,但您仍然可以选择通过选择经典编辑器返回。
选择经典编辑器后,您可以配置如何连接到源代码管理。经典编辑器是在以下各节的所有截图中可见的编辑器。
支持多种源代码管理系统。如果您正在使用托管的 Git 仓库,请选择您的具体产品(如果有的话),如果没有可用的产品,则选择其他 Git;目前,支持GitHub、GitHub 企业服务器和Bitbucket Cloud。这样做的原因是,使用其他 Git进行持续集成是通过轮询模型来工作的,所有具体产品使用它们已知的集成 Webhooks。以下示例适用于位于同一 Azure DevOps 组织中的 Git 仓库。
当您选择管道标题时,您可以设置构建定义的名称,并选择作业阶段将默认运行的代理池。代理负责实际执行您的任务,关于代理的更多细节将在本章的代理与代理队列部分中介绍。
在管道标题下,您可以看到构建定义的时间轴布局。首先是下载源代码。在这里,您可以再次选择连接到源代码管理系统。您还可以指定更多与获取源代码相关的高级设置,如是否先清理构建目录、选择一个分支或添加标签。
配置作业
在源节点下,您可以添加一个或多个作业来执行您希望执行的大部分工作。可以通过点击管道标题上的省略号来添加作业。这里有两种类型的作业:
-
无代理作业:无代理作业可以用于运行不需要代理的任务。这些任务在 Azure DevOps 服务器上运行。
-
代理作业:代理作业用于运行需要代理的任务,绝大多数任务都需要代理来运行。
一些无代理任务的示例如下:
-
等待手动批准后继续
-
在继续之前插入延迟
-
调用 REST API
-
调用 Azure 函数
无代理作业的主要优点是它在运行时不会占用代理。这使得代理可以做其他工作,意味着您需要更少的代理,从而节省成本。此外,您可以并行使用的代理数量受限于您在 Azure DevOps 中购买的并行管道数量。限制代理作业的数量也可以在这里节省费用。
让我们来回顾一下配置作业的过程:
- 选择任何作业。您将看到以下截图中显示的视图。在此视图中,您可以更改作业的名称,对于代理作业,可以覆盖执行此作业的代理池:
图 5.2 – 为管道添加/更新作业
-
接下来,指定用于执行作业的代理池。在这里,还指定了您对执行此作业的代理的需求。需求将在本章的代理和代理队列部分中讨论。
-
作为代理执行计划的一部分,您可以指定并行性并选择以下三种选项之一:
-
无:这将仅在同一代理上依次执行您添加到代理作业中的所有任务。
-
多配置:在这里,您可以指定一系列变量,这些变量决定要运行的构建的变体数量。如果您想从同一代码创建例如 x86 和 x64 构建,这会非常有用。
-
多代理:在这里,您可以指定将并行运行相同任务的代理数量。
-
-
接下来,您可以指定一个或多个依赖项。这些是需要在所选作业运行之前完成的其他作业。
-
此外,对于任何作业,您可以通过告诉它继续或停止,来指定如何处理前一个作业中的错误。
作为步骤 3和步骤 4的替代方法,您还可以指定一个自定义表达式来确定是否应执行某个作业。此表达式应评估为布尔值,并支持基本操作,如or()
、and()
或eq()
。以下是一个示例条件:
and(succeeded(), ne(variables['Build.SourceBranch'], 'refs/heads/main'))
此条件指定,只有当所有前置作业成功并且构建未从主分支启动时,作业才会运行。本章末尾附有条件语法的详细描述链接。
无代理作业比代理作业可用的选项更少。例如,无法为多个变量值并行执行相同的构建。
向作业添加任务
添加一个或多个作业后,您可以向作业添加任务。任务定义了在构建执行过程中需要完成的实际工作。以下截图展示了如何添加任务并进行配置:
- 单击您想要添加任务的作业旁边的加号:
图 5.3 – 选择任务并指定作业的配置参数
-
然后,您将看到一个任务选择器,您可以在其中找到与您的搜索输入匹配的任何任务,并通过点击添加按钮添加一个或多个任务。接着会打开一个新屏幕,您可以在其中配置单个任务。此处提供的选项对于每个任务有所不同。
-
一个任务可能有多个版本,您可以在其主要版本之间切换。这意味着维护者可以推送不破坏兼容性的更新,您会自动接收这些更新。重大或破坏性更新可以通过新的主要版本号推送,您可以根据自己的需要进行升级。
可以根据需要向管道作业中添加任意数量的任务。
发布构建工件
构建定义的重要部分是其输出。构建通常用于生成一个或多个工件,这些工件稍后会用于应用程序的部署。工件的示例包括可执行文件或安装程序文件。这些文件需要在构建管道执行完成后提供以供使用。
前面截图中显示的发布构建工件任务是专门设计用于此目的的任务。它允许您选择一个文件或目录,并以工件名称发布它。这样,选定路径中的文件会在每次管道执行时保留,以便稍后手动下载或在发布定义中使用。发布定义将在第六章中讨论,实现持续部署和发布管理。
接下来,我们将学习如何将我们的管道与其他工具集成,并配置我们的服务连接。
调用其他工具
在构建管道时,我们通常需要将其与其他工具集成。对于源代码控制系统,这是创建管道时的一个环节,您仅限于使用内置选项。对于任务,您可以使用服务连接创建对任何工具或位置的引用。以下部分展示了一个使用指向 Azure 应用服务的服务连接的任务示例。
服务连接是指向外部系统的指针,具有名称和一系列属性,针对每种类型的服务连接有所不同。通常,您需要提供一个 URL 来定位其他服务,并提供一个认证机制。以下步骤将帮助您配置您的服务连接:
- 在定义一个或多个服务连接后,您可以从下拉菜单中选择要使用的服务连接:
图 5.4 – 在任务中使用服务连接
- 服务连接在一个中央位置作为项目设置进行管理。你可以通过从当前配置的任务中直接访问管理视图来访问它们,如前面的截图所示。你也可以通过导航到项目设置,然后转到服务连接来访问,如下图所示(参见2):
图 5.5 – 服务连接对话框
- 在此视图中,你可以选择添加一个新的服务连接或更新现有的服务连接(参见前面截图中的2和3)。
默认情况下,服务连接的作用域是项目级别,这意味着它们并非对所有 Azure DevOps 组织中的人都可用。为了鼓励服务连接的重用,Azure 自 2019 年中期以来已经实现了在项目之间共享服务连接的功能。
任务市场
Azure Pipelines 内置了一组常用的任务;然而,使用 Azure DevOps 的 Visual Studio 市场,你还可以找到更多的任务。如果你是 DevOps 组织的管理员,你可以在此找到并安装添加任务的扩展。如果你是普通用户,你也可以在此找到任务;但是,你无法安装它们,只能请求它们。你的 Azure DevOps 管理员会收到通知,并在他们批准后代表你安装扩展。
当然,你也可以编写并分发带有你自己任务的扩展。
创建变量和变量组
在配置构建时,可能会有一些值需要多次使用。通常,提取这些值为变量,而不是在任务中重复使用它们,是明智的做法。
变量可用于记录那些你不希望存储在源代码控制中的值。例如,密码和许可证密钥可以安全地作为不可检索的值存储,当它们被锁定(参见下图中的1)时。保存构建定义后,这些值将被加密,并且只能被属于它们的构建使用。
要学习如何在 Azure Pipelines 中使用变量,请按照以下步骤操作:
- 在 Azure Pipelines 中,你可以通过转到变量 | 管道变量选项卡(参见下图中的3)来将变量添加到你的构建定义中。在这里,你可以输入变量的名称和值,如下图所示:
图 5.6 – 管道变量
-
一旦定义,你就可以在同一构建的所有任务配置中使用这些变量。为此,你可以使用以下表示法:
$(variableName)
-
最后,你可以将变量标记为
system.debug
内置变量。当此变量设置为true
时,构建中将包含详细的调试日志。
除了你自己的变量外,系统变量也会被定义。这些是包含当前正在运行的构建的相关信息的变量,包括版本号、代理名称、构建定义详情和源版本。系统定义变量的完整列表链接将会在本章末尾提供。
变量组
除了为特定构建创建变量外,你还可以创建变量组。这些变量组可以与一个或多个构建关联。这是一种有效的在构建之间共享变量的方式;一些例子可能包括你的公司名称、商标文本和产品名称。我们来看看如何使用变量组:
- 通过点击库(Library)在管道(Pipelines)菜单中,你可以通过菜单访问变量组(参见下图中的1)。这将显示你可以编辑的现有变量组列表,同时你也可以在这里添加一个新的变量组,如下图所示:
图 5.7 – 新的变量组
-
在这里,你可以像使用构建自带的变量一样使用变量。唯一的区别在于以下列表中突出显示的内容:
-
你不能将变量标记为在队列时可设置。
-
你可以允许或拒绝在所有管道中使用该组。如果你拒绝在所有管道中使用它,那么只有你可以使用该变量组。你可以通过安全性(Security)选项授权其他用户或组(参见前述截图中的2)。
-
你可以引用一个 Azure 密钥保管库,该变量组将作为一个占位符。在登录到 Azure 后,你可以选择一个密钥保管库,并指定希望通过变量组访问的存储在密钥保管库中的值。
-
Azure 密钥保管库(Azure Key Vault)是 Azure 提供的一项服务,可用于安全存储密钥。密钥保管库中的机密会自动进行版本控制,因此旧的值不会被覆盖,而是被新版本替代。此外,你可以指定分隔的访问策略,按用户指定他们是否可以读取、写入、更新或删除值。所有这些操作都会在密钥保管库中进行审计,因此你也可以追溯到谁进行了哪些更改。如果你将 Azure DevOps 与密钥保管库链接,则将在你的活动目录中创建一个具有该密钥保管库访问权限的新服务主体。现在,每当 Azure DevOps 需要从变量组中提取变量时,实际的值将从密钥保管库中提取。
变量组可以通过变量组标签与构建的变量关联(参见图 5.7中的截图)。
除了与变量组一起工作外,你还可以与库中的文件一起工作。你可以上传其他用户无法访问的文件,但这些文件可以在构建中使用。这对于包含私钥、许可证密钥和其他机密的文件很有用。欲了解更多信息,请参阅此链接:docs.microsoft.com/en-us/azure/devops/pipelines/library/secure-files?view=azure-devops
。
与变量组一样,你可以指定每个安全文件是否可以被任何构建使用,或仅授权特定用户使用。
触发构建
构建定义中的下一个标签控制着应该启动或触发构建的内容。要实现持续集成,请按照以下步骤操作:
- 点击触发器标签页,选择左侧的第一个标题:
图 5.8 – 为管道定义触发器
-
勾选启用持续集成框。这意味着 Azure DevOps 将监视你仓库中的变化,并在有新的变更时立即排队新的构建。
-
接下来,你可以选择是希望单独构建每个传入的更改,还是在构建某个更改时将多个更改批量处理。如果可行,建议每次都单独构建每个更改。
-
除了持续集成触发器外,还需要指定一个或多个分支和路径过滤器。在这里,你可以指定哪些分支和文件需要排队新构建。你可以根据需要指定包括或排除某些内容。一个常见的例子是将构建限制在主分支。如果你的仓库中有名为
doc
和src
的文件夹,且所有源代码都在后者文件夹中,那么限制触发器仅适用于该路径可能更为合适。 -
除了选择持续集成触发器外,你还可以选择按计划定期执行构建,选择一个或多个工作日和时间。
-
你还可以安排在另一个构建完成时启动构建。这被称为链式构建。
接下来,让我们学习如何更改构建定义的配置。
构建选项
你可以更改构建定义的高级配置选项。这些选项包括描述、构建编号的格式,以及在失败或超时时自动创建工作项。要进行设置,请按照以下步骤操作:
- 点击选项标签页。你应该会看到以下界面:
图 5.9 – 构建选项
-
现在,创建您的构建号格式。如果该字段为空,则您的应用程序的构建号将设为一个不断增加的数字,每次构建都会增加 1。该数字在团队项目中是唯一的,并且跨所有构建定义进行计数。您也可以使用可用的变量来指定您自己的格式。一种常见的方法是手动指定一个主版本号和次版本号,然后使用变量添加一个递增的数字。以下示例指定了版本号为 4.1.xx,其中最后部分会被一个两位数递增的数字替代:
4.1($Rev:.rr)
-
右侧有一些高级(但很少使用)选项,用于指定构建作业超时的授权范围,适用于构建定义中的每个作业。
-
还可以指定代理需求,要求每个代理在构建定义中的每个作业中都必须满足这些需求。我们将在本章的代理与代理队列部分进一步探讨需求。
左侧的其他选项允许您暂时暂停管道。
构建历史
最后一页标签,称为历史记录,显示了构建定义中每一次更改的列表。构建定义以 JSON 格式存储,您可以查看每次更改的并排对比。您在保存构建时所输入的评论也会存储在这里,并可以用来提供更改的理由。您还可以恢复到管道的旧版本。
由于构建是保持质量的重要手段,因此跟踪是谁更改了它们非常重要,以确保自动化质量度量不会被删除。
完成这些操作后,您现在可以运行您的第一个构建。您可以直接使用在本节大多数截图中可见的保存并排队按钮来运行它。本章的运行构建部分将教您如何处理您获得的结果。
任务组
在一个拥有多个管道的团队或组织中,往往不会过多久就会出现多个形态相同的管道。例如,在一些公司中,所有管道都包含安全扫描、运行测试和计算测试覆盖率的任务。
与其在各处重复这些任务,不如将它们从现有的管道中提取到一个任务组中。任务组可以像任务一样在多个管道中使用。这样做可以减少创建新管道或更新所有管道时的工作量。同时,这也确保了所有使用任务组的管道具有相同的任务配置。
要创建一个新的任务组,请打开任何现有的构建定义并按照以下步骤操作:
- 按住 Ctrl 键并单击一个或多个任务,或者使用鼠标悬停在任务上时出现的选择器来选择任务:
图 5.10 – 创建任务组
-
右键点击选项并选择创建任务组。
-
在现在出现的弹窗中(截图未显示),为任务组选择一个名称、描述和类别。如果选定的任务中有指定变量值的任务,你现在可以为这些参数提供默认值和描述。这些参数将在任务组中使用,并且在使用任务组时需要进行配置。
-
在点击创建后(截图未显示),现有的构建定义将通过移除选定的任务并用新的任务组替换它们来进行更新。
将已有任务组添加到构建或发布定义中的方式与添加常规任务完全相同。任务组会出现在同一任务选择列表中。
所有现有任务组的列表可以通过导航到管道菜单,然后选择任务组找到。要编辑现有的任务组,在显示的列表中选择它,然后选择编辑选项。编辑任务组的方式与编辑构建定义完全相同。
本节主要讲解了如何创建构建定义以及如何描述应用程序的构建方式。下一节将介绍如何执行构建。
运行构建
在本节中,您将学习如何处理构建结果,并利用它们报告和生成构建。您还将学习如何在每次拉取请求时运行构建,并将更改的质量报告回该拉取请求,以帮助审阅者。
查看构建结果
在构建运行时,代理将执行所有配置的步骤。Azure Pipelines 会捕获所有这些步骤的详细信息和日志。如以下截图所示,构建会在左侧显示它已执行的所有步骤列表。点击任何一个步骤将打开详细视图,显示该步骤的日志:
图 5.11 – 构建结果
每当构建过程中出现警告或错误时,它们会分别以橙色或红色显示。
构建拉取请求
设置好构建定义并运行第一次构建后,您可能还会看到第一次失败——例如,当有人不小心提交并推送了无法编译的更改或包含无法成功运行的单元测试时。您可以通过设置使构建定义在每次拉取请求到来时自动运行来防止这种情况。要配置此功能,请按照以下步骤操作:
- 在项目设置下点击策略,将打开以下界面。点击添加构建策略:
图 5.12 – 添加构建策略
-
选择一个构建定义,用于验证拉取请求。
-
接下来,您可以配置以下三项内容:
-
触发器:构建定义应该何时开始执行,可以是自动执行或手动执行。当然,真正的价值来自于自动运行验证构建。
-
策略要求:这决定了当构建失败时,是否可以完成拉取请求。换句话说,这决定了你是否可以忽略失败的构建。建议如果可能,避免将此设置为可选。
-
构建过期时间:这决定了一个成功的构建结果有效的时间长度。默认值是12小时,但你应该考虑将其更改为当主分支更新时立即过期。这样做的好处是,必须先执行构建,以检查你将要合并的分支的当前状态和拟议更改的组合,才能进行合并。
-
你可以添加多个构建策略。如果你有很多可以自动验证的内容,并希望将自动验证的时间保持在最小值,那么这是一个很好的方法。
访问构建工件
除了编译、测试和验证源代码外,构建还可以用于生成所谓的工件。工件是构建的输出,可以是任何你想要从构建中保存并发布的内容,比如测试结果和应用程序包。
应用程序包旨在成为你应用程序版本的不可变构建。这个包稍后可以在发布中使用,并部署到一个或多个环境中:
图 5.13 – 查看应用程序包
在前面的截图中,你可以看到,作为已执行构建的总结的一部分,有两个工件被发布。你可以通过屏幕右上角的工件下拉菜单或摘要标签访问这些工件。你可以从此页面下载并查看工件,在下一章中,你将看到如何使用它们来设置持续交付。
很棒!通过这一步,你已经学会了如何使用可视化设计器创建定义。但等等——正如我们之前提到的,还有另一种方法可以做到这一点,那就是使用 YAML 文件。让我们在下一节看看它是如何工作的。
使用 YAML 管道
你已经看到如何使用可视化设计器创建构建定义。自 2019 年初以来,一种新的替代方法是使用 YAML 管道。在使用 YAML 管道时,你需要在 YAML 文件中指定完整的构建定义,并将其存储在源代码管理中,通常与构建所针对的源代码一起存储。
虽然两种管道系统并存,但现在定义管道的首选方法是使用 YAML 管道。这意味着新的功能很可能只会出现在 YAML 管道中。
使用构建定义作为代码的原因
当你第一次开始使用 YAML 构建定义时,你可能会发现学习曲线比使用可视化设计器时更陡峭。这可能会引发一个问题,那就是为什么要使用 YAML 定义的构建。YAML 构建定义相对于可视化设计定义有两个主要优势。
当你在 YAML 中编写定义时,它可以与代码一起托管在源代码控制中。这样做的结果是,所有针对源代码控制的更改策略现在自动应用于你的构建定义。这意味着任何更改都必须经过拉取请求,由同行审核,并且可以提前构建和验证。强制实施四眼原则于你的构建定义以及代码,有助于提高构建过程的稳定性。当然,它也有助于提高安全性和合规性,这些主题将在后面的章节中讨论。
除了增强的安全性外,将构建定义放在源代码控制中还意味着它在每个分支中都是可用的。这意味着它可以在每个分支中进行更改,以便在与主分支合并之前构建该特定分支。使用可视化设计的构建定义时,这个单一的定义不仅负责构建你的主分支,还负责构建你想通过拉取请求合并的所有分支。
这意味着你必须执行以下其中一项操作:
-
更新构建定义以适应你将要合并的更改。然而,这将终止当前主分支的构建。
-
合并更改,这也会导致构建失败,因为构建定义尚未更新。
这两种选项都有允许错误更改流入目标分支的风险,这会破坏持续集成构建的目的。通过每个分支都有一个构建定义,我们消除了这个问题。
编写一个基本的 YAML 管道
要开始使用 YAML 构建,你需要做两件事:
-
首先,你需要编写 YAML 文件。
-
然后,你需要从中创建一个构建定义。
那么,让我们开始吧。
编写 YAML 文件
以下代码示例包含一个用于构建 .NET Core 应用程序并运行单元测试的 YAML 定义。将文件以任何名称保存——例如 pipeline.yaml
——并存储在 Azure DevOps 中的任何 Git 仓库中。然后,可以稍后使用它来创建一个管道:
trigger:
- main
pool:
name: Azure Pipelines
vmImage: windows-2019
steps:
- task: DotNetCoreCLI@2
displayName: 'dotnet build'
inputs:
projects: '**/*.csproj'
- task: DotNetCoreCLI@2
displayName: 'dotnet test'
inputs:
command: test
projects: '**/*.csproj'
这个 YAML 示例定义了一个基本的管道。每个管道都需要以某种方式触发。就像经典的构建一样,可以通过将管道连接到源代码仓库中的更改来实现。此默认仓库是包含 YAML 定义的仓库。trigger 关键字用于指定哪些分支的推送应触发管道。一个好的起点是主分支。由于 trigger 关键字接受列表,可以指定多个分支,并且可以使用通配符。
触发器不是必需的,因为管道也可以手动启动。
提示
还有其他替代触发器关键字的选项,例如在存储库中包含或排除一个或多个分支、标签或路径。这些选项的详细说明可以参见 docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema#triggers
。
每个管道都包含一个或多个任务,和经典构建定义一样,除了触发器外。所有这些任务需要在代理池上执行——同样,和经典构建定义一样。pool
关键字用于指定一组键值对,通过指定池的名称来确定任务将在哪个池上运行。使用 Microsoft 提供的默认代理时,可以使用默认名称 Azure Pipelines
。使用这个特定池时,必须指定虚拟机(VM)镜像。这决定了将执行任务的代理上可用的操作系统和软件。
提示
可通过 docs.microsoft.com/en-us/azure/devops/pipelines/agents/hosted#use-a-microsoft-hosted-agent
查找到所有可用的 VM 镜像的最新列表。
最后,定义包含构成管道本身的步骤列表。这些步骤与您可以拖入经典构建管道中的任务一一对应。添加任务时,指定任务的名称和版本——由 @
符号分隔——然后您可以选择性地为任务指定显示名称。此显示名称稍后将在显示已执行管道结果的视图中可见。最后,为任务指定一个或多个输入。这些输入与您在可视设计器中已经看到的任务特定配置有关。
创建 YAML 管道
在将 YAML 文件保存在存储库中之后,您可以从中创建构建定义。创建新构建定义时(请参阅本章的创建构建定义部分),您应当按照以下步骤进行操作:
-
当向导启动时,选择Azure Repos Git YAML选项。
-
从这里,按照向导的步骤选择并查看您希望构建的 YAML,如下图所示:
图 5.14 – 用于存储库的 YAML 管道
-
然后,找到包含您要用作管道的 YAML 文件的存储库。
-
接下来,通过选择一个示例 YAML 文件作为起点或引用已有的文件来配置管道。
-
最后,您可以查看所选的 YAML 文件并从中启动构建。
你的管道会自动保存。管道保存后,可以启动,并且你可以像操作经典构建管道一样与它交互。
多作业管道
你在前一节中看到的管道没有指定任何作业,正如你可能记得的经典构建部分。相反,它包含了一个 steps
关键字下的任务列表。这意味着它隐式地只包含一个作业。在 YAML 管道中,也可以创建包含多个作业的定义。为此,可以使用以下结构:
trigger:
- main
pool:
name: Azure Pipelines
vmImage: windows-2019
jobs:
- job: job1
displayName: A pretty name for job1
steps:
- task: DotNetCoreCLI@2
...
- job: job2
displayName: My second job
pool:
name: Azure Pipelines
vmImage: ubuntu-18.04
...
不直接将 steps
关键字添加到管道中,而是先创建一个作业列表。在该列表中,添加一个或多个 job
关键字,后跟该作业的名称。在该技术名称旁,还可以为每个作业指定一个显示名称 (displayName
)。
如前例中的第二个作业所示,也可以为每个作业指定使用的代理池。当没有为作业指定代理池时,将使用文件顶部指定的默认池。
提示
本节讨论的作业称为代理作业。除了代理作业,还有服务器作业、容器作业和部署作业。有关这些类型作业的更多信息,请访问 docs.microsoft.com/en-us/azure/devops/pipelines/process/phases#types-of-jobs
。
默认情况下,管道中的所有作业都是并行运行的,但有可用的控制选项可以更改这一点。
控制选项
要控制作业的顺序,可以在作业的定义中使用 dependsOn
关键字。这表明该作业只能在一个或多个作业完成后开始。除此之外,condition
关键字可以用于指定作业运行的条件。可以结合这两个关键字来实现更复杂的场景,如下所示:
jobs:
- job: compile
steps:
...
- job: test
dependsOn: compile
steps:
...
- job: build_schema
dependsOn: compile
steps:
..
- job: report
dependsOn:
- test
- build_schema
condition: or(succeeded('test'), succeeded('build_schema'))
steps:
..
该管道将通过运行名为 compile
的作业开始。一旦该作业完成,接下来的两个作业 test
和 build_schema
将并行运行,因为它们都依赖于 compile
任务。在这两个任务都完成后,report
任务将运行,因为它声明依赖于 test
和 build_schema
作业。在该作业实际开始之前,会评估条件,以确定该作业是否应该运行或被跳过。
条件可以使用类似于许多编程语言的语法来构建。它通过 succeeded()
和 failed()
函数检查作业是否成功完成。同时还支持布尔运算符,如 or()
、and()
和 ne()
。
你可以根据需要以任何方式结合 dependsOn
和 condition
关键字。唯一的要求是,至少应有一个作业不依赖于任何其他作业。
变量
与经典构建管道一样,YAML 管道支持使用变量。变量可以在 YAML 管道的每一层级(任务内部除外)使用以下语法进行定义:
variables:
name: value
anotherName: otherValue
以后可以使用你从经典构建管道中熟悉的语法来检索变量——$(name)
和$(anotherName)
。
也可以在 YAML 管道中引用现有的变量组。这是通过使用group
关键字来完成的,而不是指定变量的名称。若要从名为myVariableGroup
的变量组中检索所有变量,可以按照以下方式扩展前面的 YAML:
variables:
name: value
anotherName: otherValue
group: myVariableGroup
可以在 YAML 管道的每一层级中设置变量,但只有在根级别设置的变量才能在手动排队新执行时被覆盖。你可以在这里了解更多:docs.microsoft.com/en-us/azure/devops/pipelines/process/variables
。
管道工件
与经典构建一样,YAML 管道可以用于构建和发布工件。由于用于此目的的任务与其他任务一样,它可以直接添加到作业中的步骤列表中。
然而,随着 YAML 管道的引入,一种新的工件类型——所谓的管道工件——已经可用。这种工件带来了提高大规模工件上传和下载速度的优势。当使用经典发布时,管道工件不会自动下载,而构建工件则会。
要发布管道工件,可以在作业的steps
关键字中使用以下 YAML:
steps:
- publish: folder/to/publish
artifact: artifactName
管道工件主要用于在多阶段 YAML 管道中下载,相关内容将在下一章中介绍。
写 YAML 管道的技巧
从头开始编写 YAML 管道可能会比较复杂,尤其是对于刚入门的人。有两个工具可以帮助你。
首先,有一个选项可以从可视化设计器导出 YAML。对于每个任务,都会有一个查看 YAML的链接。点击该链接会打开一个小弹出框,显示当前打开的任务和配置对应的 YAML。对于作业也可以执行相同操作,并且在特定条件下,可以对完整的构建定义进行相同操作。
写 YAML 的另一个工具是内置的 YAML 编辑器:
图 5.15 – YAML 编辑器
每次打开 YAML 构建定义时,有两个工具可供你帮助。首先,在 YAML 文件的每个位置都有自动完成功能。它会显示该位置可用的选项。此外,右侧的任务选择器中也有代码片段。当选择右侧的任何任务时,你可以通过可视化界面配置它们,然后点击添加按钮将生成的 YAML 添加到定义中。
这两种工具旨在将可视化设计器的便捷性引入到 YAML 构建体验中,结合了两者的优点。
请参考这些文档,获取完整的 YAML 模式参考:docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema/?view=azure-pipelines
。
代理和代理队列
到目前为止,你创建的构建定义可以包含代理作业,而代理作业又包含任务。这些任务不会直接在你的 Azure DevOps 组织中执行,而是由在虚拟机或容器中运行的代理来执行。代理又被分组到代理池中。你可以使用两种类型的代理池:
-
内建代理池
-
自托管代理池
让我们一一来了解它们。
内建代理池
内建代理池由微软管理,并作为 Azure DevOps 产品的一部分提供给你。根据你的需求,提供了不同的代理池。池运行不同版本的 Windows 和 Visual Studio,还有运行 Linux(Ubuntu)和 macOS 的池。
这些托管池的缺点是,如果你需要的话,你不能在托管代理的机器或容器上安装额外的软件。这意味着,在这种情况下,你必须创建自己的私有代理池。
创建私有代理池
私有池在你的 Azure DevOps 组织中定义,并从那里提供到一个或多个团队项目。不过,如果在一次操作中创建并配置这些池,你也可以在团队项目级别创建私有池。为此,请进入项目设置 | 代理池。你应该会看到以下添加代理池选项:
图 5.16 – 代理池设置
在为池命名并确定是否希望自动为所有管道提供访问权限后,你可以保存该池。创建池之后,你可以添加或移除代理。
添加和移除代理
添加代理分为两个步骤:
- 下载并提取代理运行时。你可以通过进入包含代理池概览的部分并打开任何私有代理池的详细信息来找到代理运行时。打开池的详细信息后,点击右上角的新建代理:
图 5.17 – 添加新代理
- 在弹出的对话框中,你可以下载一个包含代理程序和提取及安装代理程序的说明的 ZIP 文件。
重要提示
在配置阶段,你将被提示使用你的 Azure DevOps 组织进行身份验证,并提供你希望安装代理的代理池的名称。虽然有 x86 和 x64 版本的代理可供选择,但建议你使用 x64 代理,除非有特殊原因不这么做。
要从代理池中移除代理,可以使用以下两种方法之一:
-
你可以像安装时那样返回到 PowerShell 命令行,并使用以下命令:
.\remove.cmd
-
另外,你也可以通过代理标签从代理池概览中移除代理。前往项目设置 | 代理池(见下方截图中的1) | 代理(见下方截图中的2),然后选择你想要移除的代理旁边的选项按钮(见下方截图中的3)。接着,点击删除(见下方截图中的4):
图 5.18 – 删除代理
在前面的截图中,你可以看到使用界面移除代理的步骤。请注意,这不会清理主机上的二进制文件和任何文件;然而,如果承载代理的机器故障或虚拟机被移除,这将是唯一可以移除代理的方法。
代理选择
每当构建任务开始运行时,都会从池中选择一个代理来执行你在管道中定义的任务。代理的选择分为两个步骤:
-
只有属于选定代理池的代理才有资格执行任务。这意味着,在使用私有代理池时,最好在池中拥有多个代理。如果你将某个代理下线进行维护,那么依赖该代理池的代理任务可以继续运行。
-
在代理任务运行之前,来自每个任务及其包含的任务的需求会被收集。如你在变量组部分中学到的那样,代理任务可以指定它对所使用的代理的需求。任务也是如此——它们也可以指定需求。要运行一个任务,只有满足所有这些需求的代理才会被使用。需求和能力是键/值对,其中值为整数。有关需求的示例,请参考以下文档:
docs.microsoft.com/en-us/azure/devops/pipelines/process/demands
。
当没有符合条件的代理可用于构建定义时,构建会在超时后最终失败。
查找代理能力
要查找各个代理上可用的能力,请按照以下步骤操作:
- 导航到组织设置 | 代理池:
图 5.19 – 查看代理设置
-
导航到正确的代理池(托管或私有),然后选择代理,接着打开代理详细信息(在前面的截图中未显示)。
-
打开能力标签。
在这里,你可以使用顶部的块来为代理指定一个或多个自定义能力,称为用户定义的能力。对于自托管(私有)代理,安装代理时在机器上发现的所有能力也会显示出来。
自托管代理池的好处
使用微软(云)托管代理是一种相当常见的做法,可以节省大量时间来管理和配置构建基础设施。自托管代理在许多场合已被证明非常有益。由于有大量优秀的文档,管理员已能轻松地为其管道配置和设置自托管代理。
使用自托管代理的主要好处如下:
-
优化构建代理的成本。
-
根据需要安装特定构建任务所需的附加软件。
-
通过缓存资源并启用增量构建来提高构建性能,使其运行更快。
-
构建问题的调试和故障排除变得更容易。
-
支持 虚拟网络(Vnet)集成,您可以在防火墙后安全地运行构建。
-
使用白名单 IP 地址安全地访问其他企业资源。
在下一节中,我们将探讨如何自动化托管在 GitHub 上的仓库的 CI 构建。
使用 GitHub Actions 自动化 CI 构建
如果您使用的是 GitHub 仓库,您还可以通过 GitHub Actions(作为仓库顶部导航菜单中的一个标签)自动化 CI 构建。您可以从现有的模板工作流中选择(提供超过 50 个工作流)或创建自己的自定义工作流:
图 5.20 – GitHub Actions 中的可用选项
编写工作流的体验类似于创建一个 YAML 文件并将其保存在您的 GitHub 仓库中:
图 5.21 – 在 GitHub 仓库中编辑 YAML 文件
在接下来的章节中,我们将介绍可用于管理 CI 流程的其他工具。
其他工具
除了 Azure DevOps 外,还有许多其他工具可供选择。两个其他知名工具是 GitLab CI 和 Jenkins。了解这些工具的一些基础知识有助于您理解如何与它们集成,万一需要时也能更好地应对。此外,对其他工具的有限了解将帮助您快速理解概念,并推广您如何与这些工具协作的知识。
为了突出这些工具如何在相同的概念下工作,本节中的两个示例与 编写 YAML 构建定义 一节中的 Azure DevOps YAML 管道是等效的。
GitLab CI
GitLab 提供了使用 GitLab CI 功能的构建管道。GitLab CI 通过将一个名为 .gitlab-ci.yml
的文件放置在仓库的根目录中进行配置。在此文件中,您可以定义一个或多个阶段和任务,并指定它们应该执行的任务。以下是 GitLab CI 示例 YAML 文件的样式:
stages:
- build
- test
build:
stage: build
script: dotnet build **/*.csproj
test:
stage: test
script: dotnet test **/*.csproj
就像 Azure DevOps 使用代理池与代理一样,GitLab CI 依赖于运行器来执行实际的工作。在 GitLab CI 中,目前不支持直观地创建或编辑管道。
Jenkins
Jenkins 是另一个用于运行构建管道的工具。可以使用 Jenkins 管道运行复杂的构建,Jenkins 管道从 Jenkinsfile 中获取工作。Jenkinsfile 使用 Jenkins 特定的符号编写,如下所示:
pipeline {
agent any
stages {
stage('build') {
agent any
steps {
dotnet build **/*.csproj
}
}
stage('test') {
agent any
steps {
dotnet test **/*.csproj
}
}
}
}
Jenkins 对直观地创建和编辑管道的支持有限。这被称为自由风格项目。
总结
在本章中,我们探讨了持续集成,并了解它是开发团队使用的心态、过程和工具的结合。你学会了如何使用 Azure Pipelines 创建构建定义,既可以使用图形设计器,也可以使用 YAML,还学会了如何运行构建。你学到可以使用构建管道来编译和测试代码,并将结果反馈给拉取请求。
你学到了构建可以产生输出,这些输出称为工件(Artifacts)。工件存储并保留在 Azure 管道中,可以用于存储报告,但它们也是部署管道的起点,你将在下一章学习到这一点。你还了解了运行构建所需的基础设施——即代理和代理池。最后,你看到了两个简短的示例,展示了如何使用 GitLab CI 和 Jenkins 运行持续集成构建,它们是你可以用于构建管道的另外两个工具。
拥有这些知识后,你现在能够为你的项目创建构建管道。你可以连接到源代码管理,并生成将在下一章中用于部署应用程序的构建。通过深入了解任务、作业、阶段和管道的底层结构,你能够解决复杂的应用构建问题。
在下一章,你将继续学习管道,但这次是关于发布管道。你将学习如何获取构建并将其发布到一个或多个环境中。
问题
在我们总结时,以下是一些问题,供你测试对本章内容的掌握情况。你可以在附录的评估部分找到答案:
-
对还是错?如果你每天至少编译一次项目的所有分支,就能实现持续集成。
-
对还是错?经典构建定义始终与源代码库连接。
-
对还是错?YAML 管道定义始终与源代码库连接。
-
以下哪项是从 Azure 管道调用外部工具所需的?
-
一个外部服务定义
-
一个 Azure 服务连接
-
一个服务连接
-
一个服务定位器
-
-
使用自托管代理的常见原因有哪些?从以下选项中选择所有正确答案:
-
需要访问封闭网络。
-
需要将特定的扩展任务提供给代理。
-
并行管道执行的数量需要大于 10。
-
必须安装特定软件才能让代理使用它。
-
练习
-
在
PacktBookLibrary
仓库的根目录下添加一个名为pipelines
的文件夹。 -
在
pipelines
目录下创建一个名为build
的子文件夹。 -
添加名为
main-ci-build.yml
的构建文件。 -
将以下代码块插入到文件中:
trigger: - main pool: vmImage: ubuntu-latest variables: buildConfiguration: 'Release' steps: - script: dotnet build --configuration $(buildConfiguration) displayName: 'dotnet build $(buildConfiguration)'
-
保存文件并将更改提交到分支。推送更改后,发起拉取请求以将更改合并到主分支。
-
在你的团队项目中创建一个新的管道。在配置管道步骤中,选择现有的 Azure Pipelines YAML 文件选项:
图 5.22 – 使用现有管道选项
-
在提示选择构建管道时,指定
main-ci-build.yml
文件。点击继续完成构建管道的创建。 -
运行管道作业以验证构建管道是否正常工作。在管道状态页面上,检查是否有任何错误并确认管道作业成功执行。
重要提示
该管道由构建 .NET Core 项目的任务组成。要构建其他类型的代码组件,请使用适当的任务库。
启动包的源代码仓库可以在这里找到:github.com/PacktPublishing/Designing-and-Implementing-Microsoft-DevOps-Solutions-AZ-400-Exam-Guide
进一步阅读
-
Martin Fowler 对持续集成的深入定义可以在
martinfowler.com/articles/continuousIntegration.xhtml
查看。 -
条件语法的详细描述可以在
docs.microsoft.com/en-us/azure/devops/pipelines/process/conditions?view=azure-devopstabs=classic
找到。 -
关于 Azure DevOps 构建练习的更多信息可以在
docs.microsoft.com/en-us/learn/modules/create-a-build-pipeline/index
找到。 -
你可以在
marketplace.visualstudio.com/azuredevops
找到 Azure DevOps 的 Visual Studio 市场。 -
你可以在
docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=azure-devopstabs=schema
找到关于 Azure Pipelines YAML 语法的详细描述。 -
Azure Pipelines 托管和自托管代理池的定价详情可在
azure.microsoft.com/en-us/pricing/details/devops/azure-pipelines/
找到。 -
有关 GitLab CI 的更多信息,请访问
about.gitlab.com/product/continuous-integration/
。 -
有关 Jenkins 的更多信息,请访问
jenkins.io/
。 -
.NET Core 项目的构建任务:
docs.microsoft.com/en-us/azure/devops/pipelines/ecosystems/dotnet-core?view=azure-devops&tabs=dotnetfive.
-
开发一个网页扩展:
docs.microsoft.com/en-us/azure/devops/extend/get-started/node?view=azure-devops
。