使用管道模板处理环境之间的相似性

已完成

将更改部署到多个环境时,部署到每个环境所涉及的步骤相似或完全相同。 本单元将介绍如何使用管道模板以避免重复,并允许重用管道代码。

对多个环境的部署

在与网站团队的同事交谈后,你决定为玩具公司的网站选择以下管道:

显示一系列管道阶段(包括测试和生产部署阶段)的示意图。

  1. 该管道运行 Bicep linter 以检查 Bicep 代码是否有效并遵循最佳做法。

    对 Bicep 代码进行 Lint 分析时无需连接到 Azure,因此部署到多少环境并不重要。 它仅运行一次。

  2. 管道部署到测试环境。 此阶段需要:

    1. 运行 Azure 资源管理器预检验证。
    2. 部署 Bicep 代码。
    3. 针对测试环境运行一些测试。
  3. 如果管道的任何部分出现故障,则整个管道都会停止,以便你可以调查和解决问题。 但如果一切顺利,管道将继续部署到生产环境:

    1. 管道运行预览阶段,该阶段在生产环境中运行 What-if 操作以列出将对生产 Azure 资源进行的更改。 预览阶段还会验证部署,因此无需为生产环境运行单独的验证阶段。
    2. 管道将暂停以便进行手动验证。
    3. 如果收到审批,管道将针对生产环境运行部署和版本验收测试。

其中一些阶段在测试环境和生产环境之间重复,而有些阶段仅针对特定环境运行:

阶段 环境
Lint 两者都不 - Lint 分析不适用于环境
验证 仅测试
预览 仅生产
部署 两种环境
版本验收测试 两种环境

当需要在管道中重复步骤时,可以尝试复制并粘贴步骤定义。 但是,最好避免这种做法。 复制管道的代码时,很容易意外地犯一些细微的错误或使内容不同步。 将来,需要更改步骤时,必须记住在多个位置应用更改。

管道模板

通过管道模板,可创建管道定义的可重用部分。 模板可以定义步骤、作业甚至整个阶段。 可以使用模板在单个管道中多次重复使用管道的各个部分,甚至在多个管道中重复使用。 还可以为想要在多个管道中重复使用的一组变量创建模板。

模板只是一个包含可重用内容的 YAML 文件。 步骤定义的简单模板可能如下所示,并保存在名为 script.yml 的文件中:

steps:
- script: |
    echo Hello world!

通过在通常定义单个步骤的位置使用 template 关键字,可以在管道中使用模板:

jobs:
- job: Job1
  pool:
    vmImage: 'windows-latest'
  steps:
  - template: script.yml

- job: Job2
  pool:
    vmImage: 'ubuntu-latest'
  steps:
  - template: script.yml

嵌套模板

还可以在其他模板中嵌套模板。 假设前面的文件名为 jobs.yml,并且你创建了一个名为 azure-pipelines.yml 的文件,该文件在多个管道阶段重用作业模板:

trigger:
  branches:
    include:
    - main

pool:
  vmImage: ubuntu-latest

stages:

- stage: Stage1
  jobs:
  - template: jobs.yml

- stage: Stage2
  jobs:
  - template: jobs.yml

嵌套模板或在单个管道中多次重用模板时,需要注意不要意外地将同一名称用于多个管道资源。 例如,一个阶段中的每个作业都需要自己的标识符。 因此,如果在模板中定义作业标识符,则不能在同一阶段多次重复使用它。

使用复杂的部署管道集时,为共享管道模板创建专用 Git 存储库会很有帮助。 然后,可以在多个管道中重用同一存储库,即使它们用于不同的项目。 我们在摘要中提供了指向更多详细信息的链接。

管道模板参数

管道模板参数使模板文件更易于重用,因为无论何时使用模板,都不必再为模板中的细微差异而费心。

创建管道模板时,可以在文件顶部指示其参数:

parameters: 
- name: environmentType
  type: string
  default: 'Test'
- name: serviceConnectionName
  type: string

可以根据需要定义任意数量的参数。 但就像 Bicep 参数一样,尽量不要过度使用管道模板参数。 你应该让其他人也可以轻松地重用你的模板,而不必指定过多设置。

每个管道模板参数都有三个属性:

  • 参数的名称,用于引用模板文件中的参数。
  • 参数的类型。 参数支持多种不同类型的数据,包括字符串、数字和布尔值。 还可以定义接受结构化对象的更复杂的模板。
  • 参数的默认值,这是可选的。 如果未指定默认值,则必须在使用管道模板时提供此值。

在该示例中,管道定义了一个名为 environmentType 的字符串参数(其默认值为 Test)以及一个名为 serviceConnectionName 的必需参数。

在管道模板中,使用特殊语法来引用参数的值。 使用 ${{parameters.YOUR_PARAMETER_NAME}} 宏,如下例所示:

steps:
- script: |
    echo Hello ${{parameters.environmentType}}!

可以使用 parameters 关键字将参数的值传递给管道模板,如下例所示:

steps:
- template: script.yml
  parameters:
    environmentType: Test

- template: script.yml
  parameters: 
    environmentType: Production

还可以在为管道模板中的作业和阶段分配标识符时使用参数。 当需要在管道中多次重复使用同一模板时,此方法会有所帮助,如下所示:

parameters:
- name: environmentType
  type: string
  default: 'Test'

jobs:
- job: Job1-${{parameters.environmentType}}
  pool:
    vmImage: 'windows-latest'
  steps:
  - template: script.yml

- job: Job2-${{parameters.environmentType}}
  pool:
    vmImage: 'ubuntu-latest'
  steps:
  - template: script.yml

条件

可以使用管道条件来指定是否应根据你指定的规则运行步骤、作业甚至阶段。 可以组合模板参数和管道条件,以针对许多不同的情况自定义部署过程。

例如,假设你定义了运行脚本步骤的管道模板。 你计划在每个环境中重用该模板。 在部署生产环境时,你希望运行一个其他步骤。 以下是使用 if 宏和 eq(等于)运算符实现这一目标的方法:

parameters: 
- name: environmentType
  type: string
  default: 'Test'

steps:
- script: |
    echo Hello ${{parameters.environmentType}}!

- ${{ if eq(parameters.environmentType, 'Production') }}:
  - script: |
      echo This step only runs for production deployments.

此处的条件转换为:如果 environmentType 参数的值等于“Production”,则运行以下步骤。

提示

使用示例中的条件时,请注意 YAML 文件的缩进。 该条件适用的步骤需要缩进一个额外的级别。

还可以在阶段、作业或步骤上指定 condition 属性。 下面的示例展示了如何使用 ne(不等于)运算符指定条件 - 如果 environmentType 参数的值不等于“Production”,则运行以下步骤:

- script: |
    echo This step only runs for non-production deployments.
  condition: ne('${{ parameters.environmentType }}', 'Production')

尽管条件是增加管道灵活性的一种方式,但尽量不要使用过多的条件。 条件过多会使管道变得复杂,更加难以理解其流。 如果在管道模板中有很多条件,则该模板可能并不是计划运行的工作流的最佳解决方案,你可能需要重新设计管道。

此外,请考虑使用 YAML 注释来解释你使用的条件以及管道中可能需要多加说明的其他方面。 注释有助于使管道易于理解和在将来使用。 在整个模块的练习中存在一些示例 YAML 注释。