设计管道
- 11 分钟
在本单元中,你将跟随 Tailspin 网站团队,为 Space Game 网站定义其发布管道。
规划发布管道时,通常首先确定该管道的各个 阶段或主要部门。 每个阶段通常与一个环境相对应。 例如,在上一模块中,Andy 和 Mara 的基本管道包含一个 部署 阶段,该阶段映射到 Azure 应用服务实例。
在此模块中,你可以将更改从一个阶段提升到下一个阶段。 在每个阶段中,将 Space Game 网站部署到与该阶段关联的环境。
定义所需的阶段后,请考虑如何将更改从一个阶段提升到下一个阶段。 每个阶段都可以定义必须满足的成功标准,然后构建才能进入下一个阶段。 Azure Pipelines 提供多种方法,帮助您控制更改在管道中的传递方式和时机。 总的来说,这些方法用于 发布管理。
在本部分中,你将:
- 了解常见管道阶段之间的差异,例如生成、开发、测试和过渡。
- 了解如何使用手动、计划和持续部署触发器来控制工件何时移动到管道中的下一阶段。
- 查看发布审批如何暂停管道,直到审批者接受或拒绝相应发布。
会议
整个 Tailspin Web 团队聚集在一起。 在 Azure Pipelines 中创建发布管道中,团队计划了当前冲刺的任务。 每个任务都与为 Space Game 网站生成其发布管道相关。
回想一下,团队决定为他们的冲刺执行这五项任务:
- 创建多阶段管道
- 将 Web 应用连接到数据库
- 自动执行质量测试
- 自动执行性能测试
- 改进发布节奏
团队开会讨论第一个任务, 创建多阶段管道。 团队定义管道后,它可以从其基本概念证明迁移到包含更多阶段、质量检查和审批的发布管道。
Amita 和 Tim 正在观看 Andy 和 Mara 的第二次发布管道演示。 他们看到在应用服务上生成并安装了项目。
需要哪些流程阶段?
如果要实现发布管道,请务必首先确定所需的阶段。 你选择的阶段取决于你的要求。 接下来,让我们与该团队一起决定他们需要的阶段。
提姆: 好吧,我了解自动化管道的想法。 我喜欢如何轻松地部署到 Azure。 但在这个演示中,我们该做什么呢? 我们需要一些可以在发行版本中实际使用的东西。
Amita: 对! 我们需要添加其他阶段。 例如,目前,我们没有用于测试阶段的空间。
提姆: 此外,我们需要一个阶段,我们可以向管理显示新功能。 没有管理层的批准,我无法发送任何东西到生产部门。
安 迪: 绝对! 现在,我们已经了解了发布管道的功能,那么该如何使该管道满足我们的需求?
玛拉: 让我们来勾勒出我们的要求,帮助我们规划后续步骤。 让我们从我们所拥有的开始。
Mara 移动到白板并绘制现有管道的草图。
玛拉:生成阶段生成源代码并生成包。 在本例中,该包是 .zip 文件。 部署阶段会在应用服务实例上安装 .zip 文件,该文件是 Space Game 网站。 发布管道中缺少了哪些内容?
添加“开发”阶段
安 迪: 我可能会有偏见,但我认为我们需要一个 开发 阶段。 此阶段应是项目生成后的第一站。 开发人员无法始终从本地开发环境运行整个服务。 例如,电子商务系统可能需要网站、产品数据库和支付系统。 我们需要一个包含应用所需的一切的阶段。
在本例中, Space Game 网站的排行榜功能从外部源读取高分。 现在,它会从文件中读取虚构的分数。 设置 开发 阶段将给我们一个环境,我们可以将 Web 应用与实际数据库集成。 该数据库可能仍然持有虚构的分数,但它使我们离最终应用更近一步。
玛拉: 我喜欢。 我们尚未与实际数据库集成。 但在 开发 阶段,我们可以部署到可以添加数据库的环境。
Mara 更新了她在白板上的绘图。 她将“部署”替换为“开发”以显示 开发 阶段。
安 迪: 你提出一个有趣的点。 每次将更改推送到 GitHub 时,都会生成应用。 这是否意味着每个构建在完成后都会被提升到 开发 阶段?
Mara:生成会不断地向我们提供有关生成和测试运行状况的重要反馈。 但是,仅当我们将代码合并到一些中心分支时,我们才希望提升到 开发 阶段:主分支或其他发布分支。 我将更新绘图以显示该要求。
玛拉: 我认为这次晋升很容易实现。 我们可以定义一个条件,仅在发布分支发生更改时才提升到“开发”阶段。
什么是条件?
在 Azure Pipelines 中, 使用条件 根据管道的状态运行任务或作业。 你在前面的模块中使用了条件。
请记住,可以指定的一些条件包括:
- 仅当以前的所有依赖任务都成功时
- 即使以前的依赖项失败,除非运行已取消
- 即使以前的依赖项失败,即使运行已取消
- 仅当以前的依赖项失败时
- 某些自定义条件
下面是一个基本示例:
steps:
- script: echo Hello!
condition: always()
条件导致此 always()
任务无条件地打印“Hello!”,即使以前的任务失败。
如果未指定条件,则使用此条件:
condition: succeeded()
succeeded()
内置函数检查上一个任务是否成功。 如果上一个任务失败,则会跳过使用相同条件的此任务和后续任务。
在这里,需要生成一个指定条件:
- 上一个任务成功。
- 当前 Git 分支的名称是 release。
若要生成此条件,请使用内置 and()
函数。 此函数检查其每个条件是否为真。 如果任何条件不成立,则总体条件失败。
若要获取 Current Branch 的名称,请使用内置 Build.SourceBranchName
变量。 可以通过多种方式访问条件中的变量。 此处使用 variables[]
语法。
若要测试变量的值,可以使用内置 eq()
函数。 此函数检查其参数是否相等。
考虑到这一点,仅当当前分支名称为“release”时,才应用此条件来运行 开发 阶段:
condition: |
and
(
succeeded(),
eq(variables['Build.SourceBranchName'], 'release')
)
函数中的 and()
第一个条件检查上一个任务是否成功。 第二个条件检查当前分支名称是否等于 释放。
在 YAML 中,使用管道 (|
) 语法定义跨越多行的字符串。 可以在单行上定义条件,但我们以这种方式编写该条件,使其更具可读性。
注释
在本模块中,我们将 发布 分支用作示例。 可以组合条件来定义所需的行为。 例如,你可以生成一个条件,仅在生成由针对主分支的拉取请求触发时才运行该阶段。
在下一个单元中,设置 开发 阶段时,你将使用更完整的示例。
有关 Azure Pipelines 中条件的更完整说明,请参阅 表达式文档。
玛拉: 通过使用条件,可以控制将哪些更改提升到哪些阶段。 我们可以为任何更改生成一个项目,以验证该生成并确认其运行状况良好。 准备就绪后,我们可以将这些更改合并到发行分支,并将该构建提升到 开发 阶段。
添加测试阶段
玛拉: 到目前为止,我们有 “生成 ”和 “开发 ”阶段。 接下来会发生什么?
Amita: 下一步是否可以添加 测试 阶段? 这似乎是测试最新更改的好地方。
Mara 在白板上的绘图中添加了测试阶段。
Amita: 我关心的一个问题是,我需要测试应用的频率。 每当 Mara 或 Andy 进行更改时,电子邮件都通知我。 变化发生在一整天,我从来不知道什么时候跳进来。 我希望每天看一次生成,大概在我到达办公室的时候。 我们能做到这一点吗?
安 迪: 确定。 我们何不部署在非工作时间进行“测试”? 例如,在每天凌晨 3 点向你发送一个生成。
玛拉: 这听起来不错。 如果需要,我们始终可以手动触发该过程。 例如,如果你需要立即验证某个重要错误的修复,我们可以触发它。
Mara 更新了她的绘图,以表明生成在每天 3 点从“开发”阶段移动到了“测试”阶段。
什么是触发器?
Amita: 现在我感觉好多了,我们知道一个阶段是如何移动到另一个阶段的。 但如何控制某个阶段何时运行?
玛拉: 在 Azure Pipelines 中,可以使用触发器。 触发器定义阶段何时运行。 Azure Pipelines 提供了几种类型的触发器。 下面是我们的选择:
- 持续集成 (CI) 触发器
- 拉取请求 (PR) 触发器
- 定时触发
- 生成完成触发器
CI 和 PR 触发器允许你控制哪些分支参与整个过程。 例如,你希望在任何分支中进行了更改时生成项目。 计划的触发器会在特定时间启动部署。 当另一个构建(例如依赖组件的构建)成功完成时,构建完成触发器将运行构建。 我们似乎需要计划的触发器。
什么是计划的触发器?
“计划的触发器”使用 cron 语法来使生成按定义的计划运行。
在 Unix 和 Linux 系统上,cron 是计划作业以在设定的时间间隔或特定时间运行的常用方法。 在 Azure Pipelines 中,计划触发器使用 cron 语法定义阶段运行时。
cron 表达式包括与特定时间参数匹配的字段。 以下是相关字段:
mm HH DD MM DW
\ \ \ \ \__ Days of week
\ \ \ \____ Months
\ \ \______ Days
\ \________ Hours
\__________ Minutes
例如,此 cron 表达式描述“每天凌晨 3 点”: 0 3 * * *
cron 表达式可以包含特殊字符来指定值列表或值范围。 在此示例中,星号 \ 匹配 “天”、“ 月”和 “星期几” 字段的所有值。
换句话说,此 cron 表达式表示为:
- 在整点,
- 在第三个小时,
- 在每月的某一天,
- 在任何月份,
- 在一周中的任何一天,
- 运行作业
如果要指定仅在星期一到星期五的凌晨 3 点运行作业,应使用此表达式:0 3 * * 1-5
注释
cron 计划的时区是协调世界时(UTC),因此在此示例中,3 A.M. 是指 UTC 时间的凌晨 3 点。 在实际操作中,你可能希望调整相对于 UTC 的 cron 调度时间,以确保流水线在你和你的团队预期的时间运行。
若要在 Azure Pipelines 中设置计划触发器,需要在 YAML 文件中设置一个 schedules
部分。 下面是一个示例:
schedules:
- cron: '0 3 * * *'
displayName: 'Deploy every day at 3 A.M.'
branches:
include:
- release
always: false
在本 schedules
部分中:
cron
指定 cron 表达式。branches
指定仅从release
分支进行部署。always
指定是无条件运行部署(true
),还是仅当release
分支自上次运行以来发生更改时(false
)运行。 在此处指定false
,因为只有在release
分支自上次运行以来发生更改时才需要部署。
当 Azure Pipelines 执行计划的触发器时,整个管道将运行。 管道还会在其他条件下运行,例如将更改推送到 GitHub 时。 若要仅响应计划的触发器而运行阶段,可以使用一个条件来检查生成的原因是否为计划的运行。
下面是一个示例:
- stage: 'Test'
displayName: 'Deploy to the Test environment'
condition: and(succeeded(), eq(variables['Build.Reason'], 'Schedule'))
此阶段 Test
仅在上一阶段成功且内置 Build.Reason
管道变量相等 Schedule
时才运行。
在本模块的后面部分,你将看到一个更完整的示例。
Amita: 我喜欢这样。 我甚至不必手动选取版本并安装它。 它已经为我准备好了。
安 迪: 请记住,如果以后我们想自动化更多,我们可以。 没有什么是板上钉钉的。 管道会随着我们的改进和学习而发展。
添加“过渡”阶段
提姆: 轮到我了 我需要一个阶段来运行更多压力测试。 我们还需要一个可以演示给管理层以便获得他们批准的场合。 目前,我们可以将这两个需求组合到一个阶段,我们可以称之为 过渡。
安 迪: 嗯,蒂姆说。 拥有 过渡环境或预生产环境非常重要。 此测试环境通常是新功能或漏洞修复到达用户之前的最后一站。
Mara 在白板上向绘图添加“过渡”。
Amita: 我们使用计划触发器将 开发 阶段的更改提升到 测试 阶段。 但是,我们如何促进从 测试 到 预备环境的更改? 促销是否还必须按计划进行?
玛拉: 我认为最好的处理方法是获得发布审批。 使用发布审批,你可以手动将更改从一个阶段提升到下一个阶段。
Amita: 这听起来就像我需要的! 发布批准将让我有时间在向管理层展示生成版本之前测试最新的更改。 我可以在准备就绪后提升生成。
Mara 更新了她的绘图,以表明仅当 Amita 批准后,生成才会从“测试”移到“过渡”。
Tim:我还可以想象,在管理层签字之后,我们可以使用发布审批从“过渡”提升到“生产”。 我永远无法预测这需要多长时间。 在他们签字后,我可以手动批准发布,并将其提升到生产。 但发布审批是如何工作的?
什么是发布审批?
发布审批是一种暂停管道的方法,直到审批者接受或拒绝发布。 若要定义发布工作流,可以合并审批、条件和触发器。
回想一下,在 Azure Pipelines 中创建发布管道时,你在管道配置中定义了一个环境来表示部署环境。 下面是现有流程中的一个示例:
- stage: 'Deploy'
displayName: 'Deploy the web application'
dependsOn: Build
jobs:
- deployment: Deploy
pool:
vmImage: 'ubuntu-20.04'
environment: dev
variables:
- group: Release
你的环境可以包括发布的特定条件。 此条件可以指定哪些管道可部署到该环境,以及需要哪些人工审批才能将发布从一个阶段提升到另一个阶段。
在本模块的后面部分,你将定义 过渡 环境,并将自己分配为审批者,以便将 Space Game Web 应用从 测试 阶段提升到 过渡。
自动化程度根据你的需要而定
借助 Azure Pipelines,可以灵活地自动执行某些阶段,同时手动控制尚未准备好实现自动化的阶段。
提姆: 我喜欢我们如何设定标准,使更改从一个阶段推进到下一个阶段。 但我们在流程中定义了一些手动标准。 我认为 DevOps 是关于自动执行一切。
玛拉: 你提出了一个很好的观点。 DevOps 实际上是关于自动执行重复且容易出错的任务。 有时需要人工干预。 例如,在发布新功能之前,我们从管理中获得批准。 随着我们对自动化部署的更多体验,我们可以自动执行更多手动步骤来加快该过程。 例如,我们可以在 测试 阶段自动化更多质量检查,这样 Amita 就不必批准每个版本。
提姆: 听起来很棒。 现在让我们来看看这个计划,看看我们以后如何加快系统的速度。
Amita: 谈到我们的计划,我们能否总结后续步骤?
计划
Tailspin 团队即将进行后续操作,我们来回顾一下他们的计划。
玛拉: 下面是我们要生成的发布管道。
Mara 指向白板。
玛拉: 概括而言,我们的步骤是:
- 每次将更改推送到 GitHub 时生成构建工件。 此步骤在 生成 阶段发生。
- 将生成项目提升到 开发 阶段。 当生成阶段成功且更改位于发布分支上时,此步骤会自动执行。
- 每天早上 3 点将生成项目提升到 测试 阶段。我们使用计划的触发器自动升级生成项目。
- 在 Amita 测试并批准生成后,将生成项目提升到“过渡”阶段。 我们使用发布审批来提升生成项目。
管理批准构建后,可以将构建工件部署到生产环境。
Amita: 这是很难做到吗? 这似乎很费事。
玛拉: 我不认为太糟糕了。 每个阶段都与其他每个阶段分开。 阶段是离散的。 每个阶段都有自己的一组任务。 例如, 测试 阶段中发生的情况保留在 测试 阶段。
管道中的每个部署阶段也有自己的环境。 例如,当我们将应用部署到 开发 或 测试时,环境是应用服务实例。
最后,我们一次只测试一个版本。 我们永远不会在管道中途更改版本。 我们在 开发 阶段使用与 过渡 阶段相同的版本,并且每个版本都有自己的版本号。 如果某个阶段中的发布中断,我们将修复它,并使用新的版本号再次生成它。 然后,该新版本从最开始的位置重新通过该管道。
关于质量的几句话
你刚刚看到团队设计了一个流程,该流程将他们的应用从构建一直推进到预部署阶段。 此管道的目的不只是让他们的工作更轻松。 这是为了确保他们向客户交付的软件的质量。
如何衡量发布过程的质量? 无法直接度量它。 可以衡量的是流程的效果。 如果不断更改该过程,则可能表明有问题。 在流水线中的某个特定节点上持续失败的版本发布也可能表明发布过程存在问题。
发布是否始终在特定日期或时间失败? 部署到特定环境后,它们是否始终失败? 查找这些模式和其他模式,以查看发布过程的一些方面是依赖的还是相关的。
跟踪发布过程质量的好方法是创建发布质量的可视化效果。 例如,添加一个显示每个发布状态的仪表板小组件。
当你想要衡量发布本身的质量时,可以在管道内执行各种类型的检查。 例如,可以在运行管道时执行不同类型的测试,例如负载测试和 UI 测试。
使用质量门也是检查发布质量的好方法。 存在许多不同的质量门。 例如,工作项门可以验证需求过程的质量。
还可以添加更多的安全性和符合性检查。 例如,你是否遵守四眼原则,或者是否有适当的可追溯性?
完成此学习路径时,你将看到许多这些技术付诸实践。
最后,在设计质量发布过程时,请考虑需要向用户提供哪种类型的文档或发行说明。 使文档保持最新状态可能很困难。 可能需要考虑使用工具,例如 Azure DevOps 发行说明生成器,它是包含 HTTP 触发函数的函数应用。 通过使用 Azure Blob 存储,每当在 Azure DevOps 中创建新版本时,它都创建 Markdown 文件。