在我的职业生涯中,有人曾对我说过,“CI/CD 已死,CI/CD 万岁”。当然,这句话并不意味着它已经完全消亡。它只是意味着 CI/CD 现在正成为软件开发的标准,是开发人员在软件开发生命周期中应采用和学习的常见做法。它现在被视为开发过程的一部分,而不是一个崭新的过程。
在本章中,我们将回顾持续集成/持续部署(CI/CD)的含义以及如何为管道准备代码。在介绍了代码中需要包含的必要更改后,我们将讨论构建软件的常见管道是什么样的。理解管道过程后,我们将研究从不成功的部署中恢复的两种方法以及如何部署数据库。我们还将介绍三种不同类型的云服务(内部和外部以及混合),并查看互联网上顶级 CI/CD 提供商的列表。最后,我们将引导您完成为示例应用程序以及其他类型的项目创建构建的过程。
在本章中,我们将介绍以下主题:
- 什么是 CI/CD?
- 准备代码
- 理解管道
- 两种“失败”方法
- 部署数据库
- 三种类型的构建提供程序
- CI/CD 提供程序
- Azure Pipelines 演练
完成本章后,您将能够在准备软件部署代码时识别软件中的缺陷,理解常见管道在生产高质量软件时包含的内容,确定从不成功的部署中恢复的两种方法,理解如何通过管道部署数据库,理解不同类型的 CI/CD 提供程序,并理解 CI/CD 提供程序领域的一些关键参与者。
最后,我们将介绍 Azure Pipelines 中的常见管道,以涵盖我们在本章中学到的所有内容。
技术要求
对于本章,唯一的技术要求包括拥有一台笔记本电脑和一个在 CI/CD 提供商 部分中提到的云提供商之一的帐户(最好是 Microsoft 的 Azure Pipelines - 不用担心,它是免费的)。
理解了管道的创建方式后,您将能够将相同的概念应用于其他云提供商及其管道策略。
什么是 CI/CD?
在本节中,我们将理解持续集成和持续部署对开发人员的意义。
持续集成 (CI) 是将所有开发人员的代码合并到主线中以触发自动构建过程的过程,以便您可以使用单元测试和代码分析快速识别代码库的问题。
当开发人员将他们的代码签入分支时,同行开发人员会对其进行审查。一旦被接受,它就会合并到主线中并自动启动构建过程。这个构建过程将很快介绍。
持续部署 (CD) 是持续创建软件以随时部署的过程。
通过自动化流程构建完所有内容后,构建将准备编译后的代码并创建工件。这些工件用于在各种环境(如开发、准备和生产)中进行一致部署。
实施 CI/CD 管道的好处大于没有管道的好处:
- 自动化测试:触发提交后,您的测试将与构建一起自动执行。可以将其视为有人始终在提交时检查您的代码。
- 更快的反馈循环:作为开发人员,立即收到反馈以理解某些东西是否有效总是一件好事。如果您收到一封电子邮件,告知您构建失败,则需要您自己处理。
- 一致的构建:在构建服务器上构建项目后,您可以按需创建构建 - 并持续进行测试。
- 团队之间的协作:我们齐心协力,CI/CD 包括开发人员、系统管理员、项目经理/SCRUM 主管和 QA 测试人员等,共同实现创建出色软件的目标。
在本节中,我们回顾了以自动化方式开发软件时持续集成和持续部署的定义以及实施 CI/CD 管道的好处。
在下一节中,我们将理解在自动化软件构建时应避免的某些代码实践。
准备代码
在本节中,我们将介绍代码的某些方面以及它们如何影响软件的部署。此类软件问题可能包括代码无法编译(构建失败)、避免使用相对路径名以及确保编写了正确的单元测试。这些是我多年来遇到的几个常见错误;在本节中,我还将提供如何修复它们的解决方案。
在审查 CI 管道之前,我们应该事先解决一些问题。尽管我们在上一章中介绍了很多有关版本控制的内容,但您的代码需要处于特定状态才能实现“一键式”构建。
在以下部分中,您将学习如何准备代码以使其“为 CI/CD 做好准备”,并检查部署软件时可能遇到的问题以及如何避免这些问题。
完美构建
如果雇用了新人并立即开始工作,您希望他们能够立即开始工作并立即开始开发软件。这意味着能够将它们指向存储库并提取代码,以便您可以立即以* 最小设置运行代码。
我说“最小设置”是因为可能涉及访问公司中某些资源的权限,以便它们可以在本地运行。
尽管如此,代码应该处于可运行状态,将您发送到某种简单的屏幕,并通知用户跟进权限问题或提供一些通知以解决问题。
在上一章中,我们提到了代码应如何始终编译。 这意味着以下内容:
- 代码应始终在克隆或签出后编译
- 单元测试应包含在构建中,而不是单独的项目中
- 您对版本控制的提交消息应该有意义(它们可用于发行说明)
这些标准使您的管道陷入成功的陷阱。 当您的代码处于干净状态时,它们可以帮助您更快、更轻松地创建构建。
在基于文件的操作中避免使用相对路径名
多年来,在涉及 Web 应用程序时,我见过的一个麻烦问题是如何在 Web 应用程序中访问文件。
我还见过通过网页进行基于文件的操作,其中使用相对路径移动文件,但出了问题。它涉及删除目录,结果并不好。
例如,假设您有一个图像的相对路径,如下所示:
../images/myimage.jpg
现在,假设您正在浏览一个网页,例如 https://localhost/kitchen/chairs。
如果您返回一个目录,您将位于缺少图片的厨房,而不是网站的根目录。根据您的相对路径,您正在寻找位于 https://localhost/kitchen/images/myimage.jpg 的图片目录。
更糟糕的是,如果您使用自定义路由,这甚至可能不是正常路径,谁知道它在哪里寻找图片。
准备代码时的最佳方法是在 URL 开头使用单个斜杠 (/),因为它被视为“绝对”:
/images/myimage.jpg
这样,无论您处于什么环境,在网站上查找文件时,都可以更轻松地导航到根目录。无论您在 https://www.myfakewebsite.com/ 还是 http://localhost/,根目录都是根目录,在源开头使用单个斜杠时,您总能找到文件。
确认您的单元测试是单元测试
代码中的测试旨在提供制衡,以便您的代码按预期工作。每个测试都需要仔细检查,以确认它没有做任何异常的事情。
单元测试被视为针对内存中代码的测试,而集成测试是需要 ANY 外部资源的测试:
- 您的测试是否访问任何文件?集成测试。
- 您是否连接到数据库来测试某些东西?集成测试。
- 您是否在测试业务逻辑?单元测试。
正如您开始猜测的那样,当您在另一台机器上构建应用程序时,云服务无法访问您的数据库服务器,也可能没有每个测试通过所需的其他文件。
如果您正在访问外部资源,将测试重构为更受内存驱动的内容可能是一种更好的方法。我将在 [第 7 章]中解释原因,届时我们将介绍 单元测试。
创建环境设置
无论您是在项目中期还是首次单击 创建新项目…,您都需要一种方法来为您的 Web 应用程序创建环境设置。
在 ASP.NET Core 应用程序中,我们开箱即用地提供了 appsettings.json 和 appsettings.Development.json 配置文件。appsettings.json 文件旨在作为基本配置文件,根据环境,每个 appsettings 文件都会应用,并且只有现有属性会覆盖到 appsettings.json 文件中。
一个常见示例是连接字符串和应用程序路径。根据环境,每个文件都有自己的设置。
还需要预先定义环境。始终会有一个开发和发布环境。可能有一个选项可以在另一台机器上创建另一个名为 QA 的环境,因此需要一个 appsettings.qa.json 文件,其中包含自己的环境特定设置。
确认已为每个相关环境保存了这些设置,因为它们在 CI/CD 管道中很重要。这些环境设置应始终与您的解决方案/项目一起签入版本控制,以帮助管道将正确的设置部署到正确的环境。
在本节中,我们介绍了为 CI/CD 管道准备代码的方法,即确保我们可以在克隆或本地拉取存储库后立即进行构建,为什么我们应该避免使用基于相对的文件路径,并确认我们正在使用特定于环境的应用程序设置,从而轻松构建和部署我们的应用程序。
签入代码后,我们现在可以继续并描述通用管道的所有阶段。
理解管道
在本节中,我们将介绍使用 CI/CD 服务构建软件时通用管道所包含的步骤。当您读完本节时,您将理解通用管道中流程的每个步骤,以便您可以制作出高质量的软件。
CI 管道是编码、构建、测试和部署软件所需的步骤集合。每个步骤都不属于某个人,而是由一个团队共同完成,专注于生产出卓越软件的目标。好消息是,如果您遵循了上一章的建议,那么您已经领先了。
每个公司的管道可能因产品而异,但 CI 流程始终会有一组通用步骤。这取决于您的管道根据您的需求变得多么详细。管道中的阶段可能会受到流程中涉及的每个利益相关者的影响。当然,开发人员需要提取代码、构建和测试,但 QA 团队需要将成品(工件)发送到另一台服务器进行测试。
图 2.1 显示了一个通用管道:
图 2.1 – 构建管道的一个示例
如图 2.1 所示,创建软件部署时,该过程是连续的。以下是步骤摘要:
- 从单个存储库中提取代码。
- 构建应用程序。
- 针对在步骤 2中构建的代码运行单元测试/代码分析。
- 创建工件。
- 创建容器(可选)。
- 将工件部署到服务器(开发/QA/登台/生产)。
现在我们已经定义了一个通用管道,让我们深入研究每个步骤,理解构建软件时每个流程包含的内容。
在以下小节中,我们将根据此处定义的步骤详细检查每个流程。
提取代码
在构建应用程序之前,我们需要确定我们在管道中构建的项目。管道服务需要存储库位置。提供存储库 URL 后,服务就可以准备存储库以在其服务器上进行编译。
在上一节中,我们提到了为什么您的代码在克隆后需要完美编译。代码是在与您的完全不同的机器上克隆和构建的。如果应用程序只能在您的计算机上运行,而不能在其他任何人的计算机上运行,那么俗话说,“我们必须将您的计算机发送给我们所有的用户。”虽然这是业内一句幽默的话,但在现实世界中编写和部署软件时,人们通常会皱眉头。
每种 DevOps 服务都有其优势。例如,Azure Pipelines 可以检查您的存储库并根据项目结构做出假设。
在分析项目后,它使用一种名为 YAML(发音为 Ya-mel)的文件格式来定义项目的构建方式。虽然 YAML 现在被认为是行业标准,但我们不会深入研究 YAML 所包含的所有内容。YAML 功能本身就可以写成一本书。
Azure 会根据您项目的假设创建一个 YAML 模板,说明如何构建您的应用程序。
它知道如何编译应用程序、确定容器是否包含在项目中,以及在执行构建之前检索 NuGet 包。
最后要提到的是,大多数 DevOp 服务允许每个项目一个存储库。这种方法的好处包括:
- 简单:管理和构建一个应用程序比在一个项目中编排数百个应用程序更简单。
- 协作:与多个团队专注于一个大型项目相比,让一两个较小的团队在一个更易于管理的项目上工作更容易。
- 更快的构建:CI/CD 管道旨在提供快速反馈和更快的改进。项目越小,构建、测试和部署的速度就越快。
话虽如此,我们现在已准备好构建应用程序。
构建应用程序
如前所述,YAML 文件定义了服务如何构建应用程序。
在构建之前,确认 YAML 文件包含您需要的所有内容始终是一种很好的做法。如果您有一个简单的项目,向导中包含的样板可能就是您所需要的,但它允许您在需要其他文件或其他应用程序检查时进行更新。
可能需要几次尝试才能修改 YAML 文件,但是一旦文件处于稳定状态,看到一切都按预期工作就很棒了。
在构建应用程序之前,请确保您已检索所有代码。如果此步骤失败,则该过程将退出管道。
如果您签入了错误的代码并且构建失败,则将根据警报级别通知适当的权限(开发人员或管理员),并且您将因破坏构建而受到惩罚,直到其他人破坏它。
接下来,我们将重点介绍针对应用程序运行单元测试和其他测试。
运行单元测试/代码分析
构建完成后,我们可以继续进行单元测试和/或代码分析。
单元测试应针对已编译的应用程序运行。这包括单元测试和集成测试,但正如我们前面提到的,要警惕集成测试。管道服务可能无法访问某些资源,从而导致测试失败。
单元测试本质上应该非常快。为什么?因为您不想等待 30 分钟运行单元测试(这很痛苦)。如果您的单元测试花费了这么长时间,请确定运行时间最长的单元测试并重构它们。
编译和加载代码后,单元测试应每 10-30 秒运行一次,这是一般准则,因为它们是基于内存的。
虽然单元测试和集成测试在大多数测试场景中很常见,但您可以向管道添加其他检查,包括识别安全问题和代码指标以在构建结束时生成报告。
接下来,我们的构建将创建用于部署的工件。
创建工件
构建成功且所有测试通过后,下一步是创建构建的工件并将其存储在中心位置。
一般来说,最好只创建一次二进制文件。构建完成后,它们随时可用。这些工件可以随时将版本部署到服务器,而无需再次经历整个构建过程。
工件应该是防篡改的,永远不会被任何人修改。如果工件有问题,管道应该从头开始并创建一个新的工件。
让我们继续讨论容器。
创建容器
创建自包含工件后,一个可选步骤是围绕它构建一个容器或将工件安装在容器中。虽然大多数企业使用各种平台和环境,例如 Linux 或 Windows,但使用 Docker 等工具“容器化”应用程序允许它在任何平台上运行,同时隔离应用程序。
由于容器被视为行业标准,因此创建一个容器以便轻松部署到任何平台(例如 Azure、Amazon Web Services (AWS) 或 Google Cloud Provider)是有意义的。同样,这是一个可选步骤,但它正在成为行业中不可避免的步骤。
使用 Visual Studio 创建新项目时,您会通过生成的 Docker 文件自动获得容器包装器。此 Dockerfile 定义了容器将如何允许访问您的应用程序。
将 Dockerfile 添加到项目后,Azure 会将其识别为容器项目并使用包含的项目创建容器。
部署软件
生成所有内容后,我们需要做的就是部署软件。
还记得 appsettings.json 文件中的环境设置吗?这就是它们在部署中派上用场的地方。
根据您的环境,您可以分配一项任务,在部署时将适当的环境 JSON 文件合并到 appsettings.json 文件中。
整理好环境设置后,您可以按照自己喜欢的任何方式定义部署的目标。
部署范围包括 FTP 或 WebDeploy 工件或将容器推送到某个服务器。所有这些选项都是现成的。
但是,您必须以相同的方式部署到每个环境。唯一改变的是 appsettings 文件。
部署成功(或失败)后,应向参与部署结果的每个人发送报告或通知。
在本节中,我们理解了常见管道包含的内容以及每个步骤如何依赖于成功的上一步。如果整个管道中有一个步骤失败,则该过程将立即停止。这种“传送带”软件开发方法提供了可重复的步骤、质量驱动的软件和可部署的软件。
两种“失败”方法
在本节中,我们将理解两种从失败的软件部署中恢复的方法。完成本节后,您将知道如何使用这两种方法做出从糟糕的部署中恢复的合理决策。
在标准管道中,公司在部署到 Web 服务器时有时会遇到软件故障。用户在网站上执行操作时可能会看到错误消息。
当软件无法按预期工作时,您会怎么做?这在 DevOps 管道中如何工作?
每次构建软件时,总有可能出错。在部署软件之前,您始终需要一个备份计划。
让我们介绍一下当软件部署不成功时可以使用的两种恢复方法。
回退(或回退)
如果产品中引入了各种错误,而以前的版本似乎没有这些错误,则恢复软件或回退到以前的版本是有意义的。
在管道中,最后的流程会创建工件,这些工件是产品的独立可部署版本。
以下是回退的示例:
- 您的软件部署上周成功,并被标记为版本 1.1(v1.1)。
- 在 2 周内,开发人员为该软件创建了两个新功能,并希望尽快发布它们。
- 创建并发布了一个名为版本 1.3(v1.3)的新版本。
- 当用户使用最新版本(v1.3)时,他们遇到了新功能之一的问题,导致网站显示错误。
- 由于之前的版本 (v1.1) 没有这个问题,影响也不严重,因此开发人员可以将 v1.1 重新部署到服务器,以便用户能够继续工作。
这种发布方式称为回退。
如果您必须用之前的版本 (v1.1) 替换当前版本 (v1.3)(数据库除外,稍后我会介绍),您可以轻松识别和部署最后一个已知工件。
向前倒退
如果回退方法不是一种可行的恢复策略,那么另一种选择就是向前倒退。
在向前倒退时,产品团队接受有错误的部署(包括所有缺陷),并继续推进更新的版本,同时高度重视这些错误,并承认这些错误将在下一个或 未来版本中修复。
以下是向前倒退的类似示例:
- 同样,上周软件部署成功,并被标记为版本 1.5 (v1.5)。
- 在接下来的 2 周内,开发人员为该软件创建了另一个新的大型功能。
- 创建并发布了新版本,称为版本 1.6 (v1.6)。
- 当用户使用最新版本 (v1.6) 时,他们遇到了新功能之一的问题,导致网站显示错误。
- 经过分析,开发人员意识到这是一个“快速修复”,创建了适当的单元测试来表明它已修复,通过管道推送了新版本,并立即在新版本(v1.7)中部署了修复后的代码。
这种类型的发布称为向前回滚。
产品团队可能必须检查每个错误,并决定哪种恢复方法是维护产品声誉的最佳方法。
例如,如果问题出在业务逻辑或用户界面更新等产品功能上,则最佳恢复方法可能是向前回滚,因为这对系统的影响很小,并且用户的工作流程不会中断且富有成效。
但是,如果涉及代码和数据库更新,则更好的方法是回滚 - 即恢复数据库并使用工件的先前版本。
如果这是一项关键功能并且无法恢复,则可能需要使用“修补程序”方法(如上一章所述)来修补软件。
同样,哪种恢复策略是最佳方法取决于每个问题对系统的影响。
在本节中,我们理解了两种从不成功的软件部署中恢复的方法:向后回退和向前回退。虽然这两种选择都不是强制性的选择,但每种方法都应根据错误类型、修复的恢复时间和软件的部署计划进行权衡。
部署数据库
部署应用程序代码是一回事,但如果做得不好,部署数据库可能是一项艰巨的任务。部署数据库时有两个痛点:结构和记录。
对于数据库的结构,您需要添加、更新和删除表中的列/字段,以及更新相应的存储过程、视图和其他与表相关的函数以反映表更新。
对于记录,这个过程并不像更改表的结构那么棘手。更新记录的频率并不那么规律,但当它发生时,您要么想要用默认记录播种数据库,要么用新值更新这些种子记录。
以下部分将介绍在 CI/CD 管道中部署数据库时的一些常见做法。
部署前备份
由于公司数据对企业至关重要,因此在对数据库进行任何修改或更新之前必须备份数据。
一项建议是让整个数据库部署分为两个步骤:备份数据库,然后应用数据库更新。
DevOps 团队可以包含一个部署前脚本,以在应用数据库更新之前自动备份数据库。如果备份成功,您可以继续将更改部署到数据库。如果没有,您可以立即停止部署并确定失败的原因。
如上一节所述,这对于“后退”方法而不是“前进”策略是必要的。
创建表结构策略
更新表的一种策略是采用非破坏性方法:
- 添加列:添加列时,在创建记录时为列设置默认值。这将防止应用程序在添加记录时出错,通知用户字段没有值或必填。
- 更新/重命名列:更新列略有不同,因为您可能正在更改数据库中的数据类型或值。如果您要将列名和/或类型更改为其他内容,请添加具有新列类型的新列,确保将值设为默认值,然后继续在应用程序代码中使用它。一旦代码稳定并按预期运行,请从表中删除旧列,然后从代码中删除。
- 删除列:有几种不同的方法来处理此过程。如果字段是使用默认值创建的,请在应用程序代码中进行适当的更改以停止使用该列。当记录添加到表中时,默认值不会产生错误。更新应用程序代码后,重命名表中的列,而不是删除它。如果您的代码仍在使用它,您将能够识别代码问题并修复它。一旦您的代码运行无误,就可以安全地从表中删除该列。
在对表结构进行适当更改时,不要忘记更新其他数据库代码以反映表更改,包括存储过程、视图和函数。
创建数据库项目
如果您的 Visual Studio 解决方案连接到数据库,则需要将另一种项目类型添加到您的解决方案中,称为数据库项目类型。将此项目添加到解决方案时,它会获取数据库的快照并将其作为代码添加到项目中。
为什么要将其包含在您的解决方案中?有三个原因将其包含在您的解决方案中:
- 当您从头开始创建数据库时,它会以 T-SQL 的形式提供数据库架构。
- 它允许您对数据库进行版本控制,以符合基础架构即代码 (IaC) 范式。
- 当您在 Visual Studio 中构建解决方案时,它会自动从数据库项目生成一个 DAC 文件以供部署,并可选择附加自定义脚本。在您的解决方案中包含 DAC 后,管道可以首先使用 DAC 文件部署和更新数据库。数据库部署(和备份)完成后,管道可以部署工件。
如您所见,将其包含在您的解决方案中非常方便。
使用 Entity Framework Core 的迁移
Entity Framework 自诞生以来已经取得了长足的进步。迁移是通过 C# 而不是 T-SQL 包含数据库更改的另一种方式。
创建迁移后,Entity Framework Core 会获取数据库和 DbContext 的快照,并使用 C# 创建数据库架构和 DbContext 之间的增量。
在初始迁移中,整个 C# 代码都是使用 Up() 方法生成的。
任何后续迁移都将包含 Up() 方法和 Down() 方法,分别用于升级和降级数据库。这允许开发人员保存他们的数据库增量更改以及他们的代码更改。
Entity Framework Core 的迁移是使用 DAC 和自定义脚本的替代方案。这些迁移可以根据 C# 代码执行数据库更改。
如果需要种子记录,则可以使用 Entity Framework Core 的 .HasData() 方法轻松创建表的种子记录。
在本节中,我们学习了如何通过始终创建备份来准备数据库部署,理解了添加、更新和删除表字段的常用策略,并学习了如何使用 DAC 或 Entity Framework Core 的迁移在 CI/CD 管道中部署数据库。
三种类型的构建提供程序
现在我们已经理解了标准管道的工作原理,在本节中,我们将介绍不同类型的管道提供程序。
三种类型的提供程序是本地、非本地和混合。
本地(意味着现场或本地)与您拥有的软件有关,您可以使用它在公司所在地构建产品。本地构建服务的一个优点是,一旦您购买了软件,您就拥有了它;没有订阅费。因此,如果构建服务器出现问题,您可以轻松地在本地查看软件以识别和修复问题。
非本地(或云)提供商是当今更常用的服务。由于每个人都希望昨天就能获得所有东西,因此设置起来更快,而且通常是创建软件管道的直接方法。
正如您所猜测的,混合服务是本地服务和外部服务的混合。一些公司喜欢控制软件开发的某些方面,并将工件发送到远程服务器以进行部署。
虽然混合服务是一种选择,但使用外部服务进行自动化软件构建更有意义。
在本节中,我们理解了三种类型的提供商:本地、外部和混合服务。虽然这些服务在各种公司中使用,但大多数公司倾向于使用外部(或云)服务来自动化其软件构建。
CI/CD 提供商
在本节中,我们将查看互联网上当前的提供商列表,以帮助您自动化构建。虽然还有其他提供商可用,但这些提供商被视为开发人员在行业中用作标准。
由于我们的目标是 ASP.NET Core,请放心,这些提供商中的每一个都在其构建流程和部署中支持 ASP.NET Core。
Microsoft Azure Pipelines
由于 Microsoft 创建了 ASP.NET Core,因此提及其非本地云产品是有意义的。它确实也提供本地和混合支持。Azure Pipelines 为 ASP.NET Core 应用程序和部署机制提供了迄今为止最自动化的支持。
虽然 Azure 被认为是世界上最大的云提供商之一,但我认为 Azure Pipelines 只是 Azure 名称下的一个小组件。
重要提示
您可以在此处理解有关 Azure Pipelines 的更多信息:https://azure.microsoft.com/en-us/products/devops/pipelines/。
GitHub Actions
当微软于 2018 年 6 月收购 GitHub 时,GitHub 于同年 10 月推出了带有 GitHub Actions 的自动化管道。
由于 GitHub 是所有源代码相关内容的提供商,因此 GitHub Actions 被认为是实现代码可部署的必然步骤。
注册 Actions 后,您会注意到屏幕非常“Azure-ish”,并且在您构建软件管道时提供非常相似的界面。
Amazon CodePipeline
亚马逊在电子商务领域占据领先地位,并且凭借其 Amazon Web Services(AWS 产品),它还为开发人员提供了自动化管道。
其管道分为以下几类:
- CodeCommit:用于识别源代码存储库
- CodeArtifact:构建工件的集中位置
- CodeBuild:一种专用服务,用于根据存储库中的更新构建产品,这些更新在 CodeCommit 中定义
- CodeDeploy:用于管理部署软件的环境
- CodePipelne:将所有内容粘合在一起的粘合剂
您可以根据自己的需求选择所需的服务。Amazon CodePipeline 与大多数云服务类似,您可以使用一项服务或所有服务。
Google CI
最终的云提供商就是 Google CI。 Google CI 还提供了执行自动构建和部署所需的工具。
Google CI 提供了类似的工具,例如 Artifact Registry、源存储库、Cloud Build 甚至私有容器注册表。
如前所述,一旦您理解一个云提供商的工作原理,您就会开始在其他云提供商中看到类似的产品。
在本节中,我们研究了四个 CI/CD 云提供商:Microsoft 的 Azure Pipelines、GitHub Actions、Amazon 的 CodePipeline 和 Google 的 CI。这些提供商中的任何一个都是创建 ASP.NET Core 管道的合适候选者。
Azure Pipelines 演练
通过我们到目前为止讨论的所有内容,本节将带我们理解每个开发人员都应该熟悉的 Web 应用程序的标准管道:ASP.NET Core Web 应用程序。
如果您有自己的 Web 应用程序,您将能够按照说明操作,并对您的 Web 应用程序进行修改。
在本节中,我们将通过考虑示例应用程序并逐步介绍使其成功构建的所有组件来演示管道的组成。
准备应用程序
在继续之前,我们需要确认版本控制中的应用程序是否已准备好用于管道:
- 应用程序是否编译和克隆时没有错误?
- 应用程序附带的所有单元测试是否都通过?
- 您的应用程序中是否有正确的环境设置?(例如,appsettings.json、appsettings.qa.json 等等。)
- 您是否会将此应用程序部署到 Docker 容器?如果是,请确认您的应用程序根目录中有一个 Dockerfile。
同样,Dockerfile 是可选的,但大多数公司都包含一个,因为他们有多个在不同的操作系统上运行的环境。我们将在我们的 Web 应用程序中包含 Dockerfile 以完成演练。
一旦我们的清单中确认了所有内容,我们就可以继续创建管道。
介绍 Azure Pipelines
Azure Pipelines 是一项免费服务,开发人员可以使用它来自动化、测试和部署他们的软件到任何平台。
由于 Azure 是用户专用的,因此您必须登录 Azure Pipelines 帐户或在 https://azure.microsoft.com/en-us/products/devops/pipelines/ 创建一个新帐户。不用担心 - 注册和创建管道都是免费的:
- 要继续本演练,请单击 使用 GitHub 免费开始 按钮,如图 2.2 所示:
图 2.2 – Azure Pipelines 网页
登录 Azure Pipelines 后,即可创建项目。
-
单击右上角的 新建项目。输入 项目名称 和 描述 的详细信息,并确定它是 私有 还是 公共。
-
单击 创建 后,我们需要定义在管道中使用哪个存储库。
识别存储库
我们尚未指定 Azure Pipelines 使用的存储库。因此,我们需要导入现有存储库:
-
如果单击 文件 下的任何选项,您将看到一条消息,提示 为空。添加一些代码!。听起来是个不错的建议。
-
单击 导入存储库 部分下的 导入 按钮,如图 2.3 所示:
图 2.3 – 导入存储库
- 单击 导入 按钮将弹出一个侧面板,询问您的源代码位于何处。目前,只有 Git 和 Team Foundation Version Control (TFVC)。
- 由于 DefaultWebApp 的代码在 Git 中,我复制了克隆 URL 并将其粘贴到文本框中,然后单击侧面板底部的 导入 按钮,如图 2.4 所示:
图 2.4 – 识别 Azure Pipelines 将使用的存储库
Azure Pipelines 将继续导入存储库。下一个屏幕将是每个人都习惯看到的标准 Explorer 视图,存储库左侧是树形视图,右侧是当前目录中的详细文件列表。
这样,我们就完成了将存储库导入 Azure Pipelines 的过程。
创建构建
现在我们已经导入了我们的存储库,Azure Pipelines 通过添加一个名为“设置构建”的按钮,使这个过程变得非常简单,如图 2.5 所示:
图 2.5 – 导入的存储库,下一步是“设置构建”按钮
尽管 Azure Pipelines 的功能非常广泛,但有几种预设模板可用于您的构建。每个模板都属于 .NET 生态系统中的特定项目,以及不太常见的项目:
-
出于我们的目的,我们将选择 ASP.NET Core (.NET Framework) 选项。
-
在我们的向导中的 配置 步骤之后(看到顶部了吗?),我们将进入 审查 步骤,我们可以在其中检查 YAML 文件。
-
话虽如此,您随时都可以添加任务。有 显示助手 可以帮助您将新任务添加到现有的 YAML 文件中。
对于 DefaultWebApp 示例,我们不需要更新 YAML 文件,因为我们没有任何更改;这是因为我们想要一些非常简单的东西来创建我们的构建。默认 YAML 文件如下所示:
# ASP.NET Core (.NET Framework)
# Build and test ASP.NET Core projects targeting the full .NET Framework.
# Add steps that publish symbols, save build artifacts, and more:
# https://docs.microsoft.com/azure/devops/pipelines/languages/dotnet-core
trigger:
- master
pool:
vmImage: 'windows-latest'
variables:
solution: '**/*.sln'
buildPlatform: 'Any CPU'
buildConfiguration: 'Release'
steps:
- task: NuGetToolInstaller@1
- task: NuGetCommand@2
inputs:
restoreSolution: '$(solution)'
- task: VSBuild@1
inputs:
solution: '$(solution)'
msbuildArgs: '/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:DesktopBuildPackageLocation="$(build.artifactStagingDirectory)\WebApp.zip" /p:DeployIisAppPath="Default Web Site"'
platform: '$(buildPlatform)'
configuration: '$(buildConfiguration)'
- task: VSTest@2
inputs:
platform: '$(buildPlatform)'
configuration: '$(buildConfiguration)'
Azure Pipelines 创建的这个新文件名为 azure-pipelines.yml。那么,这个新的 azure-pipelines.yml 文件在创建后位于何处?它被提交到存储库的根目录。一旦我们确认 YAML 文件中的所有内容都正常,我们就可以单击 保存并 运行 按钮。
完成此操作后,将出现一个侧面板,要求您提供提交消息和可选描述,以及指定是否直接提交到主分支或为此提交创建新分支的选项。单击侧面板底部的 保存并 按钮后,它会将您的新 YAML 文件提交到您的存储库并立即执行管道。
创建工件
构建运行后,您将看到类似于图 2.6 的内容:
图 2.6 – 将我们的 DefaultWebApp 构建过程排队
如上图底部所示,我的作业状态为 已排队。一旦它退出队列并开始执行,您可以通过单击底部蓝色时钟旁边的 作业 来查看构建进度。
就 DefaultWebApp 而言,构建过程如下所示,如 图 2*.7* 所示:
图 2.7 – DefaultWebApp 的构建进度
恭喜!您已成功创建管道和工件。
为了不写一整本关于 Azure Pipelines 的书,接下来,我们将继续创建版本。
创建版本
构建完成并成功后,我们现在可以专注于发布我们的软件。请按照以下步骤操作:
-
如果您单击“发布”,您将看到我们需要创建一个新的发布管道。单击“新建”按钮。
-
您将立即看到一个侧面板,其中列出了您可以选择的模板。选择侧面板顶部的“空作业”,如图 2.8 所示:
图 2.8 – 选择空作业模板
“发布”中有一个术语称为“阶段”,您的软件在进入最终阶段之前可以经历几个阶段。这些阶段也可以与环境同义。这些阶段包括开发、QA、准备和生产。一旦一个阶段(开发)获得批准,它就会进入下一个阶段(QA),直到最后一个阶段,通常是生产阶段。但是,这些阶段可能会变得非常复杂。
- 单击“应用”按钮后,您将看到另一个侧面板,您可以在其中定义您的阶段。由于我们只是部署网站,因此我们将其称为“推送到站点”阶段。
- 输入您的“阶段”名称(听起来不太对),单击“X”按钮关闭侧面板并检查管道。
如图 2.9 所示,我们需要添加一个工件:
图 2.9 – 已定义“推送到站点”阶段,但没有工件
- 单击“添加工件”时,另一个侧面板将滑开并要求您添加工件。由于我们在上一小节中创建了一个工件,因此我们可以使用“DefaultWebApp”项目和源填充所有输入,如图 2.10 所示:
图 2.10 – 将 DefaultWebApp 工件添加到我们的发布管道
- 单击“添加”将您的工件添加到管道。
部署构建
一旦我们定义了阶段,我们就可以在每个阶段之前和之后附加某些部署条件。可以定义部署后批准、门控和自动重新部署触发器,但每个阶段默认禁用这些功能。
在任何阶段,您都可以通过单击每个阶段名称下的“x 作业,x 任务”链接来添加、编辑或删除所需的任何任务,如图 2.11 所示:
图 2.11 – 阶段允许您添加任意数量的任务
每个阶段都有一个代理作业,可以执行任意数量的任务。可供选择的任务列表令人眼花缭乱。只要您能想到,就会有相应的任务。
例如,我们可以使用 Azure、IIS Web Deploy 或甚至只是从一个目录复制到另一个目录的文件来部署网站。想要将文件通过 FTP 传输到服务器吗?单击 Utility 选项卡并找到 FTP Upload。
您添加的每个任务都有针对每个主题的参数,并且可以轻松修改以满足开发人员的要求。
在本节中,我们介绍了如何通过准备应用程序来满足某些要求来创建管道。我们通过登录并添加示例项目、识别我们将在管道中使用的存储库以及创建构建来介绍 Azure Pipelines。完成此操作后,我们找到了我们的工件、创建了一个版本,并找到了部署构建的方法。