我所在的公司拥有许多 Azure Devops YAML 管道,分布在多个 Git 存储库中。这些多阶段管道用于构建 .NET 应用程序并将其部署到四个不同的阶段(dev/test/accp/prod)。
为了减少从一个管道复制到下一个管道的文件量,我创建了一个单独的 Git 存储库,其中包含各种管道可以引用的可重用模板。
其中一个模板在部署应用程序时执行一些横切关注点,我想扩展此模板以为每个jobs.deployment注入一个预部署步骤。为了说明这个问题,我构建了一个由 3 个文件组成的非常人为的示例。第一个是包含部署作业的模板;基于参数 includePredeployStep
将包含一个硬编码 预部署步骤:
# File: deployJob.yaml
parameters:
- name: deploymentName
type: string
- name: environment
type: string
- name: includePredeployStep
type: boolean
jobs:
- deployment: ${{parameters.deploymentName}}
environment:
name: ${{parameters.environment}}
resourceType: virtualMachine
strategy:
runOnce:
deploy:
steps:
- powershell: |
Write-Host "Inside job deploy step"
${{if eq(parameters.includePredeployStep, 'true')}}:
preDeploy:
steps:
- powershell: |
Write-Host "Inside job preDeploy step"
为了注入预部署步骤,我创建了另一个模板,该模板深受 Microsoft 有关如何使用每个步骤的示例的启发,这是我无法使用的文件:
# File: execute-deployment-jobs.yaml
parameters:
- name: deployJobs
type: jobList
jobs:
- ${{ each job in parameters.deployJobs }}:
- ${{ each deployJobProperty in job }}:
${{ if and(ne(deployJobProperty.key, 'dependsOn'), ne(deployJobProperty.key,'strategy')) }}:
${{ deployJobProperty.key }}: ${{ deployJobProperty.value }}
${{ if eq(deployJobProperty.key, 'strategy')}}:
strategy:
${{if deployJobProperty.value.runOnce}}:
runOnce:
${{each runOnceProperty in deployJobProperty.value.runOnce}}:
${{if ne(runOnceProperty.key, 'preDeploy')}}:
${{runOnceProperty.key}}: ${{runOnceProperty.value}}
preDeploy:
steps:
- powershell: |
Write-Host "Inside injected preDeploy step"
displayName: Injected preDeploy step
- ${{each preDeployStep in runOnceProperty.predeploy.steps}}:
- ${{preDeployStep}}
最后,我在管道中使用文件“execute-deployment-jobs”:
# File: pipeline.yaml
pool:
name: Development
stages:
- stage: Test
jobs:
- template: execute-deployment-jobs.yaml
parameters:
deployJobs:
- template: deployJob.yaml
parameters:
deploymentName: MyApplication
environment: Test
includePredeployStep: false # <--- Value 'false' does not cause a problem
- template: deployJob.yaml
parameters:
deploymentName: MyOtherApplication
environment: Test
includePredeployStep: true # <--- Value 'true' causes the problem
当我验证模板时,收到一条错误消息“'preDeploy' 已定义”。 仅当管道最后一行上的
includePredeployStep
设置为
true
时,才会出现问题;如果我将值更改为 false
,模板验证会成功,编译后的模板将显示注入的 preDeploy 步骤。关于如何修改文件“execute-deployment-jobs.yaml”,使其适用于具有或不具有内置预部署步骤的作业,有什么建议吗?
顺便说一句,“execute-deployment-jobs”中的大部分代码必须针对策略
canary
和
rolling
进行复制。不知道有没有快速解决办法。考虑这个示例管道:
trigger: none
pool:
vmImage: 'ubuntu-latest'
jobs:
- template: /pipelines/jobs/deployJob.yaml
parameters:
strategy: runOnce
deploymentName: 'Dev'
environment: 'Dev'
- template: /pipelines/jobs/deployJob.yaml
parameters:
strategy: runOnce
deploymentName: 'QA'
environment: 'QA'
includePredeployStep: true
deployJob.yaml
可以实现如下:
parameters:
- name: strategy
type: string
default: runOnce
values:
- runOnce
- rolling
- canary
- name: deploymentName
type: string
- name: environment
type: string
- name: includePredeployStep
type: boolean
default: false
jobs:
# based on the chosen strategy, include the corresponding template
# e.g. runOnce-strategy-deploy-job.yaml
- template: ${{ parameters.strategy }}-strategy-deploy-job.yaml
parameters:
deploymentName: ${{ parameters.deploymentName }}
environment: ${{ parameters.environment }}
# Using hard-coded steps for demonstration purposes only.
# Use templates instead to reuse steps in multiple jobs/pipelines.
preDeploySteps:
- ${{ if parameters.includePredeployStep }}:
# hard-coded preDeploy step to include
- powershell: |
Write-Host "This is the hard-coded step"
displayName: 'Hard-coded predeploy step'
# other preDeploy steps to include
- powershell: |
Write-Host "This is preDeploy step 1"
displayName: 'Predeploy step 1'
- powershell: |
Write-Host "This is preDeploy step 2"
displayName: 'Predeploy step 2'
我假设在这种情况下
predeploySteps
将始终相同。
每个策略都有其相应的工作 - 例如runOnce-strategy-deploy-job.yaml
:
parameters:
- name: deploymentName
type: string
- name: environment
type: string
- name: preDeploySteps
type: stepList
jobs:
- deployment: ${{ parameters.deploymentName }}
environment:
name: ${{ parameters.environment }}
resourceType: virtualMachine
strategy:
runOnce:
deploy:
steps:
# Using hard-coded steps for demonstration purposes only.
# Use templates instead to reuse steps in multiple jobs/pipelines.
# Example:
# - template: /pipelines/steps/deploy-steps.yaml
- script: echo "This is a run-once deployment to ${{ parameters.environment }}"
displayName: 'Run-once deployment to ${{ parameters.environment }}'
${{ if parameters.preDeploySteps }}:
preDeploy:
steps:
- ${{ parameters.preDeploySteps }}
我还没有测试其他策略,但实施与上述工作非常相似 - 例如
rolling-strategy-deploy-job.yaml
:
parameters:
- name: deploymentName
type: string
- name: environment
type: string
- name: preDeploySteps
type: stepList
jobs:
- deployment: ${{ parameters.deploymentName }}
environment:
name: ${{ parameters.environment }}
resourceType: virtualMachine
strategy:
rolling:
maxParallel: 1
deploy:
steps:
# Using hard-coded steps for demonstration purposes only.
# Use templates instead to reuse steps in multiple jobs/pipelines.
# Example:
# - template: /pipelines/steps/deploy-steps.yaml
- script: echo "This is a rolling deployment to ${{ parameters.environment }}"
displayName: 'Rolling deployment to ${{ parameters.environment }}'
${{ if parameters.preDeploySteps }}:
preDeploy:
steps:
- ${{ parameters.preDeploySteps }}