部署作业

Azure DevOps Services | Azure DevOps Server 2020

重要

  • 作业和阶段名称不能包含关键字 (例如: deployment) 。
  • 阶段中的每个作业都必须具有唯一的名称。

在 YAML 管道中,我们建议你将部署步骤放在一种特殊类型的 作业 中,称为部署作业。 部署作业是针对环境按顺序运行的步骤集合。 部署作业和 传统作业 可以在同一阶段中存在。

部署作业具有以下优势:

  • 部署历史记录:通过管道获取部署历史记录,降低到特定资源以及用于审核的部署状态。

  • 应用部署策略:定义应用程序的推出方式。

    注意

    目前仅支持runOnce滚动和不成的策略。

部署作业不会自动克隆源存储库。 您可以通过 checkout: self 在作业中签出源存储库。 部署作业仅支持一个结帐步骤。

架构

下面是用于指定部署作业的完整语法:

jobs:
- deployment: string   # name of the deployment job, A-Z, a-z, 0-9, and underscore. The word "deploy" is a keyword and is unsupported as the deployment name.
  displayName: string  # friendly name to display in the UI
  pool:                # not required for virtual machine resources
    name: string       # Use only global level variables for defining a pool name. Stage/job level variables are not supported to define pool name.
    demands: string | [ string ]
  workspace:
    clean: outputs | resources | all # what to clean up before the job runs
  dependsOn: string
  condition: string
  continueOnError: boolean                # 'true' if future jobs should run even if this job fails; defaults to 'false'
  container: containerReference # container to run this job inside
  services: { string: string | container } # container resources to run as a service container
  timeoutInMinutes: nonEmptyString        # how long to run the job before automatically cancelling
  cancelTimeoutInMinutes: nonEmptyString  # how much time to give 'run always even if cancelled tasks' before killing them
  variables: # several syntaxes, see specific section
  environment: string  # target environment name and optionally a resource name to record the deployment history; format: <environment-name>.<resource-name>
  strategy:
    runOnce:    #rolling, canary are the other strategies that are supported
      deploy:
        steps: [ script | bash | pwsh | powershell | checkout | task | templateReference ]

还有一个更详细的替代语法,还 environment 可用于属性。

environment:
    name: string # Name of environment.
    resourceName: string # Name of resource.
    resourceId: string # Id of resource.
    resourceType: string # Type of environment resource.
    tags: string # List of tag filters.

对于虚拟机,无需定义池。 在部署作业中使用虚拟机资源定义的任何步骤将针对该虚拟机运行,而不是针对池中的代理运行。 对于其他资源类型(例如 Kubernetes),需要定义一个池,以便任务可以在该计算机上运行。

部署策略

在部署应用程序更新时,重要的是,你用来提供更新的技术将:

  • 启用初始化。
  • 部署更新。
  • 将流量路由到更新的版本。
  • 在路由流量后测试更新的版本。
  • 如果出现故障,请运行步骤还原到上一次已知的正确版本。

在部署过程中,我们将使用可运行步骤的生命周期挂钩来实现此目的。 每个生命周期挂钩都可解析为代理作业或 服务器作业 (或将来) 中的容器或验证作业,具体取决 pool 于属性。 默认情况下,生命周期挂钩将继承作业指定 deploymentpool

部署作业使用 $(Pipeline.Workspace) 系统变量。

生命周期挂钩说明

preDeploy:用于在应用程序部署开始之前运行初始化资源的步骤。

deploy:用于运行部署应用程序的步骤。 下载项目任务仅在部署作业的 deploy 挂钩中自动插入。 若要停止下载项目,请使用 - download: none 或选择要通过指定 下载管道项目任务下载的特定项目。

routeTraffic:用于运行为更新版本提供流量的步骤。

postRouteTraffic:用于在路由流量后运行步骤。 通常,这些任务监视已定义间隔的更新版本的运行状况。

on: failureon: success :用于运行回滚操作或清理的步骤。

RunOnce 部署策略

runOnce是最简单的部署策略,其中所有生命周期挂钩(即 preDeploydeployrouteTrafficpostRouteTraffic )都执行一次。 然后,执行 on:successon:failure

strategy: 
    runOnce:
      preDeploy:        
        pool: [ server | pool ] # See pool schema.        
        steps:
        - script: [ script | bash | pwsh | powershell | checkout | task | templateReference ]
      deploy:          
        pool: [ server | pool ] # See pool schema.        
        steps:
        ...
      routeTraffic:         
        pool: [ server | pool ]         
        steps:
        ...        
      postRouteTraffic:          
        pool: [ server | pool ]        
        steps:
        ...
      on:
        failure:         
          pool: [ server | pool ]           
          steps:
          ...
        success:          
          pool: [ server | pool ]           
          steps:
          ...

如果你使用的是自承载代理,则可以使用工作区清理选项来清理你的部署工作区。

  jobs:
  - deployment: MyDeploy
    pool:
      vmImage: 'ubuntu-latest'
    workspace:
      clean: all
    environment: staging

滚动部署策略

滚动部署将以前版本的应用程序的实例替换为一组固定的虚拟机的实例, (每次迭代中的滚动集) 。

目前仅支持将滚动策略提供给 VM 资源。

例如,滚动部署通常会等待每组虚拟机上的部署完成,然后再继续执行下一组部署。 你可以在每次迭代后执行运行状况检查,如果出现重大问题,则可以停止滚动部署。

可以通过在节点下 strategy: 指定关键字 rolling: 来配置滚动部署。 strategy.name此策略块中提供了该变量,它采用策略的名称。 在本例中,滚动。

strategy:
  rolling:
    maxParallel: [ number or percentage as x% ]
    preDeploy:        
      steps:
      - script: [ script | bash | pwsh | powershell | checkout | task | templateReference ]
    deploy:          
      steps:
      ...
    routeTraffic:         
      steps:
      ...        
    postRouteTraffic:          
      steps:
      ...
    on:
      failure:         
        steps:
        ...
      success:          
        steps:
        ...

支持所有生命周期挂钩,并创建生命周期挂接作业以在每个 VM 上运行。

preDeployrouteTraffic按定义的 maxParallel 每个批大小执行、 deploy 、和 postRouteTraffic 。 然后,执行 on: successon: failure

利用 maxParallel: <# or % of VMs> ,你可以控制要并行部署到的虚拟机目标的数量/百分比。 这可确保应用在这些计算机上运行,并且在部署发生在计算机的其余部分时,可以处理请求,从而减少总体停机时间。

注意

此功能有几个已知的空白部分。 例如,当你重试阶段时,它将在不只是失败目标的所有 Vm 上重新运行部署。

金丝雀部署策略

"无排放部署策略" 是一种高级的部署策略,有助于减轻推出新版本的应用程序所涉及的风险。 通过使用此策略,你可以先将更改集中到一小部分服务器。 随着新版本的更有把握,你可以将其发布到基础结构中的更多服务器,并将更多的流量路由到其中。

strategy: 
    canary:
      increments: [ number ]
      preDeploy:        
        pool: [ server | pool ] # See pool schema.        
        steps:
        - script: [ script | bash | pwsh | powershell | checkout | task | templateReference ]
      deploy:          
        pool: [ server | pool ] # See pool schema.        
        steps:
        ...
      routeTraffic:         
        pool: [ server | pool ]         
        steps:
        ...        
      postRouteTraffic:          
        pool: [ server | pool ]        
        steps:
        ...
      on:
        failure:         
          pool: [ server | pool ]           
          steps:
          ...
        success:          
          pool: [ server | pool ]           
          steps:
          ...

未完成的 preDeploy 部署策略支持 (一次执行生命周期挂钩) 并通过、 routeTrafficpostRouteTraffic 生命周期挂钩进行 deploy 循环访问。 然后,它会退出 successfailure 挂钩。

此策略中提供了以下变量:

strategy.name:策略的名称。 例如,"未的"。
strategy.action:要在 Kubernetes 群集上执行的操作。 例如,部署、升级或拒绝。
strategy.increment:当前交互中使用的递增值。 此变量仅在、 routeTrafficpostRouteTraffic 生命周期挂钩中 deploy 可用。

示例

RunOnce 部署策略

下面的示例 YAML 代码片段通过使用 runOnce 部署策略展示了部署作业的简单用法。 该示例包括一个结帐步骤。


jobs:
  # Track deployments on the environment.
- deployment: DeployWeb
  displayName: deploy Web App
  pool:
    vmImage: 'ubuntu-latest'
  # Creates an environment if it doesn't exist.
  environment: 'smarthotel-dev'
  strategy:
    # Default deployment strategy, more coming...
    runOnce:
      deploy:
        steps:
        - checkout: self 
        - script: echo my first deployment

每次运行此作业时,都会针对 smarthotel-dev 环境记录部署历史记录。

注意

  • 还可以创建具有空资源的环境,并将其用作抽象 shell 来记录部署历史记录,如前面的示例中所示。

下一个示例演示管道如何同时引用要用作部署作业目标的环境和资源。

jobs:
- deployment: DeployWeb
  displayName: deploy Web App
  pool:
    vmImage: 'ubuntu-latest'
  # Records deployment against bookings resource - Kubernetes namespace.
  environment: 'smarthotel-dev.bookings'
  strategy: 
    runOnce:
      deploy:
        steps:
          # No need to explicitly pass the connection details.
        - task: KubernetesManifest@0
          displayName: Deploy to Kubernetes cluster
          inputs:
            action: deploy
            namespace: $(k8sNamespace)
            manifests: |
              $(System.ArtifactsDirectory)/manifests/*
            imagePullSecrets: |
              $(imagePullSecret)
            containers: |
              $(containerRegistry)/$(imageRepository):$(tag)

此方法具有以下优点:

  • 记录环境中特定资源的部署历史记录,而不是记录环境中所有资源的历史记录。
  • 部署作业中的步骤 会自动继承 资源 (的连接详细信息,在本例中为 Kubernetes 命名空间 smarthotel-dev.bookings) ,因为部署作业已链接到环境。 在为作业的多个步骤设置相同的连接详细信息时,这很有用。

滚动部署策略

Vm 的滚动策略最多可在每个迭代中更新五个目标。 maxParallel 将确定可以并行部署的目标数。 选择包括在任何时候必须保持可用的目标的绝对数量或百分比,不包括正在部署的目标。 它还用于确定部署过程中的成功和失败条件。

jobs: 
- deployment: VMDeploy
  displayName: web
  environment:
    name: smarthotel-dev
    resourceType: VirtualMachine
  strategy:
    rolling:
      maxParallel: 5  #for percentages, mention as x%
      preDeploy:
        steps:
        - download: current
          artifact: drop
        - script: echo initialize, cleanup, backup, install certs
      deploy:
        steps:
        - task: IISWebAppDeploymentOnMachineGroup@0
          displayName: 'Deploy application to Website'
          inputs:
            WebSiteName: 'Default Web Site'
            Package: '$(Pipeline.Workspace)/drop/**/*.zip'
      routeTraffic:
        steps:
        - script: echo routing traffic
      postRouteTraffic:
        steps:
        - script: echo health check post-route traffic
      on:
        failure:
          steps:
          - script: echo Restore from backup! This is on failure
        success:
          steps:
          - script: echo Notify! This is on success

金丝雀部署策略

在下一个示例中,AKS 的 "未对的策略" 将首先部署包含10% 箱的更改,后跟20%,同时在中 postRouteTraffic 监视运行状况。 如果一切顺利,都将提升到100%。

jobs: 
- deployment: 
  environment: smarthotel-dev.bookings
  pool: 
    name: smarthotel-devPool
  strategy:                  
    canary:      
      increments: [10,20]  
      preDeploy:                                     
        steps:           
        - script: initialize, cleanup....   
      deploy:             
        steps: 
        - script: echo deploy updates... 
        - task: KubernetesManifest@0 
          inputs: 
            action: $(strategy.action)       
            namespace: 'default' 
            strategy: $(strategy.name) 
            percentage: $(strategy.increment) 
            manifests: 'manifest.yml' 
      postRouteTraffic: 
        pool: server 
        steps:           
        - script: echo monitor application health...   
      on: 
        failure: 
          steps: 
          - script: echo clean-up, rollback...   
        success: 
          steps: 
          - script: echo checks passed, notify... 

使用管道修饰器自动注入步骤

可以在部署作业中使用管道修饰器自动注入任何自定义步骤 (例如,漏洞扫描器) 每个部署作业的每个生命周期挂接。 由于管道修饰器可以应用于组织中的所有管道,因此可将其作为强制执行安全部署的一部分。

此外,如果定义了服务端,则可以将部署作业作为 容器作业 运行,以及 服务端汽车

支持输出变量

在部署作业的 生命周期挂钩 中定义输出变量,并在同一阶段内的其他下游步骤和作业中使用它们。

若要在两个阶段之间共享变量,请在一个阶段中输出一个项目,然后在后续阶段中使用它,或使用变量中描述的 stageDependencies 语法。

执行部署策略时,可以使用以下语法跨作业访问输出变量。

  • 对于 runOnce 策略: $[dependencies.<job-name>.outputs['<lifecycle-hookname>.<step-name>.<variable-name>']] (例如, $[dependencies.JobA.outputs['Deploy.StepA.VariableA']])
  • 对于 runOnce 策略加一个 resourceType: $[dependencies.<job-name>.outputs['<lifecycle-hookname>_<resource-name>.<step-name>.<variable-name>']] 。 (例如:$[dependencies.JobA.outputs['Deploy_VM1.StepA.VariableA']]
  • 对于未用策略:$[dependencies.<job-name>.outputs['<lifecycle-hookname>_<increment-value>.<step-name>.<variable-name>']]
  • 对于 滚动 策略: $[dependencies.<job-name>.outputs['<lifecycle-hookname>_<resource-name>.<step-name>.<variable-name>']]
# Set an output variable in a lifecycle hook of a deployment job executing canary strategy.
- deployment: A
  pool:
    vmImage: 'ubuntu-latest'
  environment: staging
  strategy:                  
    canary:      
      increments: [10,20]  # Creates multiple jobs, one for each increment. Output variable can be referenced with this.
      deploy:
        steps:
        - bash: echo "##vso[task.setvariable variable=myOutputVar;isOutput=true]this is the deployment variable value"
          name: setvarStep
        - bash: echo $(setvarStep.myOutputVar)
          name: echovar

# Map the variable from the job.
- job: B
  dependsOn: A
  pool:
    vmImage: 'ubuntu-latest'
  variables:
    myVarFromDeploymentJob: $[ dependencies.A.outputs['deploy_10.setvarStep.myOutputVar'] ]
  steps:
  - script: "echo $(myVarFromDeploymentJob)"
    name: echovar

runOnce对于作业,指定作业的名称,而不是生命周期挂钩:

# Set an output variable in a lifecycle hook of a deployment job executing runOnce strategy.
- deployment: A
  pool:
    vmImage: 'ubuntu-latest'
  environment: staging
  strategy:                  
    runOnce:
      deploy:
        steps:
        - bash: echo "##vso[task.setvariable variable=myOutputVar;isOutput=true]this is the deployment variable value"
          name: setvarStep
        - bash: echo $(setvarStep.myOutputVar)
          name: echovar

# Map the variable from the job.
- job: B
  dependsOn: A
  pool:
    vmImage: 'ubuntu-latest'
  variables:
    myVarFromDeploymentJob: $[ dependencies.A.outputs['A.setvarStep.myOutputVar'] ]
  steps:
  - script: "echo $(myVarFromDeploymentJob)"
    name: echovar

在部署作业中定义环境时,输出变量的语法会因定义环境的方式而有所不同。 在此示例中, env1 使用简写表示法,并 env2 包括具有定义的资源类型的完整语法。

stages:
- stage: StageA
  jobs:
  - deployment: A1
    pool:
      vmImage: 'ubuntu-latest'
    environment: env1
    strategy:                  
      runOnce:
        deploy:
          steps:
          - bash: echo "##vso[task.setvariable variable=myOutputVar;isOutput=true]this is the deployment variable value"
            name: setvarStep
          - bash: echo $(System.JobName)
  - deployment: A2
    pool:
      vmImage: 'ubuntu-latest'
    environment: 
      name: env2
      resourceType: virtualmachine
    strategy:                  
      runOnce:
        deploy:
          steps:
          - script: echo "##vso[task.setvariable variable=myOutputVarTwo;isOutput=true]this is the second deployment variable value"
            name: setvarStepTwo
  
  - job: B1
    dependsOn: A1
    pool:
      vmImage: 'ubuntu-latest'
    variables:
      myVarFromDeploymentJob: $[ dependencies.A1.outputs['A1.setvarStep.myOutputVar'] ]
      
    steps:
    - script: "echo $(myVarFromDeploymentJob)"
      name: echovar
 
  - job: B2
    dependsOn: A2
    pool:
      vmImage: 'ubuntu-latest'
    variables:
      myVarFromDeploymentJob: $[ dependencies.A2.outputs['A2.setvarStepTwo.myOutputVar'] ]
      myOutputVarTwo: $[ dependencies.A2.outputs['Deploy_vmsfortesting.setvarStepTwo.myOutputVarTwo'] ]
    
    steps:
    - script: "echo $(myOutputVarTwo)"
      name: echovartwo

从部署作业输出变量时,从下一个作业引用它将使用不同的语法,具体取决于是否要设置变量或将其用作阶段的条件。

stages:
- stage: StageA
  jobs:
  - job: A1
    steps:
      - pwsh: echo "##vso[task.setvariable variable=RunStageB;isOutput=true]true"
        name: setvarStep
      - bash: echo $(System.JobName)

- stage: StageB
  dependsOn: 
    - StageA
 
  # when referring to another stage, stage name is included in variable path
  condition: eq(dependencies.StageA.outputs['A1.setvarStep.RunStageB'], 'true')
  
  # Variables reference syntax differs slightly from inter-stage condition syntax
  variables:
    myOutputVar: $[stageDependencies.StageA.A1.outputs['setvarStep.RunStageB']]
  jobs:
  - deployment: B1
    pool:
      vmImage: 'ubuntu-latest'
    environment: envB
    strategy:                  
      runOnce:
        deploy:
          steps:
          - bash: echo $(myOutputVar)

详细了解如何 设置多作业输出变量

常见问题解答

管道停滞在消息 "作业正在挂起 ..."。 如何解决此问题?

如果两个作业之间存在名称冲突,则会发生这种情况。 验证同一阶段中的任何部署作业是否具有唯一名称,以及该作业和阶段名称是否不包含关键字。 如果重命名不能解决问题,请查看 管道运行疑难解答

部署组是否支持修饰器?

否。 不能在部署组中使用修饰器。