设计管道

已完成

在本单元中,你将与 Tailspin Web 团队一起为 Space Game 网站定义发布管道。

计划发布管道时,通常应首先确定该管道的阶段或主要分支。 每个阶段通常映射到一个环境。 例如,在前面的模块中,Andy 和 Mara 的基本管道处于“部署”阶段,该阶段映射到 Azure 应用服务实例。

在此模块中,你可以将更改从一个阶段提升到下一个阶段。 在每个阶段中,你都要将 Space Game 网站部署到与该阶段关联的环境

定义所需的阶段后,请考虑如何将更改从一个阶段提升到下一个阶段。 每个阶段都可以定义在生成可以移动到下一阶段之前必须满足的成功条件。 Azure Pipelines 提供了几种方法来帮助你控制更改在管道中的移动方式和时间。 整体而言,这些方法用于发布管理

本部分的操作:

  • 了解常见管道阶段(如“生成”、“开发”、“测试”和“过渡”)之间的差异。
  • 了解如何使用手动、计划和持续部署触发器来控制项目移到管道中的下一个阶段的时间。
  • 查看发布审批如何暂停管道,直到审批者接受或拒绝相应发布。

会议

整个 Tailspin Web 团队聚集在一起。 在“使用 Azure Pipelines 创建发布管道”中,团队为当前冲刺计划任务。 每个任务都与为 Space Game 网站构建其发布管道相关。

回想一下,团队为冲刺确定了以下五个任务:

  • 创建多阶段管道。
  • 将 Web 应用连接到数据库。
  • 自动执行质量测试。
  • 自动执行性能测试。
  • 改进发布节奏。

团队开会讨论第一个任务,即创建多阶段管道。 在团队定义管道之后,团队可以将其从基本的概念证明阶段移到包括了附加阶段、质量检查和审批的发布管道。

Amita 和 Tim 正在观看 Andy 和 Mara 的第二次发布管道演示。 他们看到在应用服务上生成并安装了项目。

你需要哪些管道阶段?

若要实现发布管道,首先必须确定所需的阶段。 所选阶段取决于你的需求。 接下来,让我们与该团队一起决定他们需要的阶段。

Tim:好的,我了解了自动化管道的概念。 部署到 Azure 十分简单,我很喜欢这一点。 但在这个演示中,我们该做什么呢? 我们需要一些可以在发行版本中实际使用的东西。

Amita:对! 我们需要添加其他阶段。 例如,目前,我们没有地方进行测试阶段。

Tim:此外,我们还需要一个向管理层展示新功能的阶段。 如果没有管理层的审批,我无法将任何东西投入生产。

Andy:当然可以! 现在,我们已经了解了发布管道的功能,那么该如何使该管道满足我们的需求?

Mara:我们来列出我们的需求,帮助我们规划后续步骤。 从我们现有的管道开始。

Mara 走到白板旁,列出现有管道。

Diagram of the whiteboard illustrating build and dev stages. Build stage produces .zip file. Dev stage deploys .zip file to Azure App Service.

Mara:生成”阶段会生成源代码并生成一个包。 在本例中,该包是一个 .zip 文件。 “部署”阶段会在应用服务实例上安装 .zip 文件,即 Space Game 网站。 发布管道中缺少了哪些内容?

添加“开发”阶段

Andy:我可能有些偏颇,但我认为我们需要一个“开发”阶段。 此阶段应是项目生成后的第一站。 开发人员无法始终在其本地开发环境中运行整个服务。 例如,电子商务系统可能需要网站、产品数据库和支付系统。 我们需要一个阶段,其中包括应用所需的一切内容。

在本例中,Space Game 网站的排行榜功能会从外部源读取高分。 目前,它从文件中读取虚拟分数。 设置“开发”阶段将为我们提供一个可以将 Web 应用与真实数据库集成的环境。 该数据库可能仍会有虚拟分数,但这使我们更接近最终的应用。

Mara:我喜欢这个。 我们尚不会与实际的数据库集成。 但在“开发”阶段,我们可以部署到可添加数据库的环境。

Mara 更新了白板上的绘图。 她将“部署”替换为“开发”以显示“开发”阶段。

Diagram that shows the whiteboard illustrating build and dev stages. Build stage produces .zip file. Dev stage deploys .zip file to Azure App Service.

Andy:你提出了一个有趣的观点。 每次将更改推送到 GitHub 时,我们都会生成应用。 这是否意味着每个生成操作完成后都会提升到“开发”阶段?

Mara:生成会不断地向我们提供有关生成和测试运行状况的重要反馈。 但是,我们只想在将代码合并到某个中心分支(主分支或其他发布分支)时才提升到“开发”阶段。 我将更新此绘图以显示该要求。

Diagram that shows whiteboard illustrating build and dev stages. A condition promotes to the Dev stage only when changes happen on a release branch.

Mara:我认为这种提升很容易实现。 我们可以定义一个条件,仅在发布分支发生更改时才提升到“开发”阶段。

什么是条件?

在 Azure Pipelines 中,使用条件可根据管道的状态运行任务或作业。 你在前面的模块中使用了条件。

请记住,你可以指定的条件有:

  • 仅当所有以前的相关任务都成功时。
  • 即使以前的依赖项失败,除非运行已取消。
  • 即使以前的依赖项失败,即使运行已取消。
  • 仅当以前的依赖项失败时。
  • 某种自定义条件。

下面是一个基本示例:

steps:
  - script: echo Hello!
    condition: always()

即使以前的任务失败,always() 条件也会导致此任务无条件打印“Hello!”。

如果未指定条件,则使用此条件:

condition: succeeded()

succeeded() 内置函数会检查上一个任务是否成功。 如果上一个任务失败,则会跳过此任务以及使用相同条件的后续任务。

在此处生成一个指定以下内容的条件:

  • 上一个任务成功。
  • 当前 Git 分支的名称为“发布”。

若要生成此条件,可以使用内置 and() 函数。 此函数会检查每个条件是否都为 true。 如果有任何条件不为 true,则整体条件会失败。

若要获取当前分支的名称,请使用内置 Build.SourceBranchName 变量。 可通过几种方法访问某个条件中的变量。 在此处使用 variables[] 语法。

若要测试变量的值,可以使用内置 eq() 函数。 此函数检查其参数是否相等。

记住这一点,仅当当前分支名为“发布”时,才应用此条件来运行“开发”阶段:

condition: |
  and
  (
    succeeded(),
    eq(variables['Build.SourceBranchName'], 'release')
  )

and() 函数中的第一个条件检查上一个任务是否成功。 第二个条件会检查当前分支名称是否为“发布”。

在 YAML 中,使用管道 (|) 语法来定义跨越多行的字符串。 可以在单行上定义条件,但我们以这种方式编写它是为了使它更具可读性。

注意

在此模块中,我们使用发布分支作为示例。 你可以组合条件来定义所需的行为。 例如,你可以生成一个条件,仅在生成由针对主分支的拉取请求触发时才运行该阶段。

在下一个单元中,设置“开发”阶段时,你将使用更完整的示例。

有关 Azure Pipelines 中条件的更完整说明,请参阅《表达式文档》。

Mara:通过使用条件,可以控制哪些更改将提升到哪些阶段。 我们可以为任何更改生成一个项目,以验证该生成并确认其运行状况良好。 准备就绪后,我们可以将这些更改合并到一个发布分支中,并将该生成提升到“开发”阶段。

添加测试阶段

Mara:到目前为止,我们已经有了“生成”和“开发”阶段。 接下来需要做什么?

Amita:接下来是否可以添加“测试”阶段? 这似乎是测试最新更改的好地方。

Mara 将“测试”阶段添加到白板上的绘图中。

Diagram that shows the whiteboard illustrating build, dev and test stages. The Test stage deploys the build to Azure App Service.

Amita:我关心的一个问题是我需要多久测试一次应用。 每当 Mara 或 Andy 做出更改时,我都会收到一封电子邮件通知。 每天都会发生很多变化,我不知道应该什么测试。 我希望每天看一次生成,大概在我到达办公室的时候。 我们能做到吗?

Andy:当然。 我们何不部署在非工作时间进行“测试”? 例如,在每天凌晨 3 点向你发送一个生成。

Mara:听起来不错。 如果需要,也可以手动触发该过程。 例如,如果我们需要你立即验证是否有重要的 bug 修复,可以触发此过程。

Mara 更新了她的绘图,以表明生成在每天早晨 3 点从“开发”阶段移动到了

Diagram that shows the whiteboard showing Build, Dev, and Test stages. The schedule promotes the change from Dev to Test at 3 A.M. each morning.

什么是触发器?

Amita:我现在感觉好多了,因为我们知道了一个阶段是如何移到另一个阶段的。 但如何控制某个阶段何时运行?

Mara:在 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 点指的是协调世界时的凌晨 3 点。 实际上,你可能需要调整 cron 计划中相对于 UTC 的时间,以便管道在你和你的团队的预期时间运行。

若要在 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:我喜欢。 我甚至不必手动选取版本并安装它。 已经为我准备好了。

Andy:请记住,如果我们想以后实现更多自动化,我们可以做到这一点。 没有什么是一成不变的。 管道会随着我们的改进和学习而发展。

添加“过渡”阶段

Tim:轮到我了。 我需要一个阶段来运行更多压力测试。 我们还需要一个阶段,在此阶段,我们可以向管理层演示以获得他们的批准。 现在,我们可以将这两种需求合并到一个阶段,我们称之为“过渡”阶段。

Andy:说得好,Tim。 具有“过渡”或预生产环境非常重要。 此过渡环境通常是向客户发布功能或 bug 修复之前的最后一站。

Mara 在白板上向绘图添加“过渡”。

Diagram where the whiteboard is showing the Build, Dev, Test, and Staging stages. The Staging stage deploys the build to Azure App Service.

Amita:我们使用一个计划的触发器将更改从“开发”阶段提升到“测试”阶段。 但如何将更改从“测试”阶段提升到“过渡”阶段呢? 提升也必须按计划执行吗?

Mara:我认为处理此问题最好的方法是使用“发布审批”。 使用发布审批,你可以手动将更改从一个阶段提升到下一个阶段。

Amita:听起来正是我所需要的! 使用发布审批,我就有时间在向管理层展示生成之前测试最新更改。 我可以在准备就绪后提升生成。

Mara 更新了她的绘图,以表明仅当 Amita 批准后,生成才会从“测试”移到“过渡”。

Diagram where the whiteboard shows the Build, Dev, Test, and Staging stages. Changes move from Test to Staging only after approval.

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,你可以灵活地自动化某些阶段,同时手动控制尚未准备好进行自动化的阶段。

Tim:我们可以定义一个条件,将更改从一个阶段提升到下一个阶段,我喜欢这种方式。 但我们已经在管道中定义了一些手动条件。 我认为 DevOps 是要将一切都自动化。

Mara:你提出了一个很好的观点。 DevOps 实际上是指自动化重复且容易出错的任务。 有时需要人工干预。 例如,我们会在发布新功能之前获得管理层的审批。 随着我们在自动化部署方面获得了更多经验,我们可以自动化更多的手动步骤来加快这个过程。 例如,我们可以在“测试”阶段自动执行其他质量检查,这样 Amita 就不必审批每个生成。

Tim:听起来不错。 现在,让我们来了解一下这一计划,并看看如何在以后加快系统速度。

Amita:说到我们的计划,我们是否可以总结一下我们的后续步骤?

计划

Tailspin 团队即将进行后续操作,我们来回顾一下他们的计划。

Mara:下面是我们要生成的发布管道。

Mara 指向白板。

Diagram of the final whiteboard showing the Build, Dev, Test, and Staging stages.

Mara:概括而言,我们的步骤如下:

  1. 每次将更改推送到 GitHub 时生成一个生成项目。 此步骤在“生成”阶段进行。
  2. 将生成项目提升到“开发”阶段。 如果生成阶段成功并且更改位于发布分支上,则会自动执行此步骤。
  3. 将生成工件提升到测试阶段每天早晨 3 点。我们使用计划的触发器来自动提升生成工件。
  4. 在 Amita 测试并批准生成后,将生成项目提升到“过渡”阶段。 我们使用发布审批来提升生成项目。

管理层批准生成后,我们就可以将生成项目部署到生产环境。

Amita:这会很难吗? 工作量好像很大。

Mara:我认为不太糟糕。 每个阶段都是独立的。 各个阶段都是离散的。 每个阶段都有自己的一组任务。 例如,在“测试”阶段发生的事件会停留在“测试”阶段

管道中的每个部署阶段也有自己的环境。 例如,当我们将应用部署到“开发”或“测试”时,环境就是应用服务实例。

最后,我们每次只测试一个版本。 我们永远不会在管道中途更改版本。 我们在“开发”阶段使用与“过渡”阶段相同的发布,每个发布都有自己的版本号。 如果发布在某个阶段中断,我们将对其进行修复,然后使用新的版本号重新生成它。 然后,该新发布会从最开始的位置重新通过该管道。

有关质量的几个事项

你刚刚看到团队设计了一个管道,该管道伴随应用经历从生成到过渡的整个过程。 此管道的目的不只是为了使他们的工作更轻松。 这是为了确保他们交付给客户的软件的质量。

如何衡量发布过程的质量? 我们无法直接衡量发布过程的质量。 你可以衡量的是过程的运行状况。 如果你常常更改此过程,则可能表示出现了问题。 在管道中的某个特定点持续失败的发布也可能表示发布过程存在问题。

发布是否始终在特定日期或时间失败? 部署到特定环境后,它们是否始终失败? 查找这些模式和其他模式,查看发布过程的某些方面是否依赖或相关。

跟踪发布过程质量的一个好方法是创建发布质量的可视化效果。 例如,添加一个显示每个发布状态的仪表板小组件。

当你想要衡量发布本身的质量时,可以在管道内执行各种类型的检查。 例如,你可以在运行管道时执行不同类型的测试,例如负载测试和 UI 测试。

使用质量门也是检查发布质量的好方法。 有很多不同的质量门。 例如,工作项门可以验证需求过程的质量。 你还可以添加其他安全性和合规性检查。 例如,你是否符合四眼原则,或者你是否有适当的可追溯性?

在学习本学习路径的过程中,你将看到这些技巧中的许多都被应用到实践中。

最后,在设计质量发布过程时,请考虑需要向用户提供何种类型的文档或发行说明。 使文档保持最新可能很困难。 你可能需要考虑使用工具,如 Azure DevOps 发行说明生成器。 该生成器是包含 HTTP 触发的函数的函数应用。 通过使用 Azure Blob 存储,每当在 Azure DevOps 中创建新版本时,它都会创建一个 Markdown 文件。

知识检查

1.

管道包含多个测试和质量检查,需要几分钟才能完成。 哪种类型的触发器最适合用于仅在同级评审过的代码上运行测试?

2.

在审批者签署更改之前,暂停管道的最佳方式是什么?

3.

你希望在每次生成完成后,将 Web 应用部署到测试环境。 设置此过程的最简单方法是什么?