分享方式:


部署工作

Azure DevOps Services |Azure DevOps Server 2022 |Azure DevOps Server 2020

重要

  • 作業和階段名稱不能包含關鍵詞(例如: deployment)。
  • 階段中的每個作業都必須有唯一的名稱。

在 YAML 管線中,我們建議您將部署步驟放在稱為部署作業的特殊作業類型中。 部署作業是對環境循序執行的一連串步驟。 部署作業和 傳統作業 可以存在於相同的階段。 Azure DevOps 支援 runOnce滾動Canary 策略。

部署作業提供下列優勢:

  • 部署歷程記錄:您可以跨管線取得部署歷程記錄,並深究至部署的特定資源和狀態,以進行稽核。
  • 套用部署策略:您可以定義應用程式的推出方式。

部署作業不會自動複製來源存放庫。 您可以使用 來簽出作業 checkout: self內的來源存放庫。

注意

本文著重於部署作業的部署。 若要瞭解如何使用管線部署至 Azure,請參閱 部署至 Azure 概觀

結構描述

以下是指定部署作業的完整語法:

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 容器或驗證作業)。 根據預設,生命週期攔截會繼承 pool 作業所 deployment 指定的 。

部署作業會 $(Pipeline.Workspace) 使用系統變數。

生命週期勾點的描述

preDeploy:用來執行在應用程式部署開始前初始化資源的步驟。

deploy:用來執行部署應用程式的步驟。 下載成品工作只會自動插入部署作業的 deploy 勾點中。 若要停止下載成品,請指定 [下載管線成品] 工作,使用- download: none或選擇要下載的特定成品。

routeTraffic:用來執行提供流量至更新版本的步驟。

postRouteTraffic:用來在路由傳送流量之後執行步驟。 一般而言,這些工作會監視已定義間隔更新版本的健康情況。

on: failureon: success:用來執行復原動作或清除的步驟。

RunOnce 部署策略

runOnce 是最簡單的部署策略,其中所有生命周期攔截,即 preDeploy deployrouteTrafficpostRouteTraffic,都會執行一次。 然後,on:success會執行或 on: 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 上執行。

preDeploydeployrouteTrafficpostRouteTraffic 會根據 所 maxParallel定義的批次大小執行一次。 然後會執行 on: successon: failure

透過 maxParallel: <# or % of VMs>,您可以控制要平行部署至的虛擬機目標數目/百分比。 這可確保應用程式正在這些計算機上執行,而且能夠在部署發生在機器的其餘部分時處理要求,進而降低整體停機時間。

注意

這項功能有一些已知的差距。 例如,當您重試階段時,它會在所有 VM 上重新執行部署,而不只是失敗的目標。

Canary 部署策略

Canary 部署策略是進階部署策略,可協助降低推出新版本應用程式所涉及的風險。 使用此策略,就可以先對一小部分的伺服器推出變更。 隨著您對新版本的信心增加,便能發行到基礎結構中的更多伺服器,然後將更多流量路由到該版本。

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:
          ...

Canary 部署策略支援preDeploy生命週期攔截(執行一次),並使用、 routeTrafficpostRouteTraffic 生命週期攔截進行反覆運算deploy。 然後,它會以 successfailure 勾點結束。

此策略提供下列變數:

strategy.name:策略的名稱。 例如,Canary。
strategy.action:要在 Kubernetes 叢集上執行的動作。 例如,部署、升級或拒絕。
strategy.increment:目前互動中使用的遞增值。 此變數僅適用於 deployrouteTrafficpostRouteTraffic 生命週期勾點。

範例

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 環境記錄部署歷程記錄。

注意

  • 您也可以建立具有空白資源的環境,並使用該環境做為抽象殼層來記錄部署歷程記錄,如上一個範例所示。

下一個範例示範管線如何同時參考環境和資源,做為部署作業的目標。

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因為部署作業已連結至環境。 在針對作業的多個步驟設定相同的連線詳細數據的情況下,這非常有用。

注意

如果您使用私人 AKS 叢集,請確定您已連線到叢集的虛擬網路,因為 API 伺服器端點不會透過公用 IP 位址公開。

Azure Pipelines 建議在可存取叢集虛擬網路的 VNET 內設定自我裝載代理程式。 如需詳細資訊,請參閱 連線到私人叢集 的選項。

輪流部署策略

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

Canary 部署策略

在下一個範例中,AKS 的 Canary 策略會先部署具有 10% Pod 的變更,後面接著 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['<job-name>.<step-name>.<variable-name>']] (例如, $[dependencies.JobA.outputs['JobA.StepA.VariableA']]
  • 針對 runOnce 策略加上 resourceType: $[dependencies.<job-name>.outputs['Deploy_<resource-name>.<step-name>.<variable-name>']]。 (例如,$[dependencies.JobA.outputs['Deploy_VM1.StepA.VariableA']])
  • 對於 Canary 策略: $[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
      resourceName: vmsfortesting
      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.myOutputVarTwo'] ]
      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)

當您從部署作業輸出變數時,請使用 stageDependencies 語法從下一個階段參考它(例如, $[stageDependencies.<stage-name>.<job-name>.outputs[Deploy_<resource-name>.<step-name>.<variable-name>]]

stages:
- stage: StageA
  jobs:
    - deployment: A1
      environment: 
        name:  env1
        resourceName: DevEnvironmentV
        resourceType: virtualMachine
      strategy:
        runOnce:
          deploy:
            steps:
              - script: echo "##vso[task.setvariable variable=myVar;isOutput=true]true"
                name: setvarStep
              - script: |
                  echo "Value of myVar in the same Job : $(setVarStep.myVar)"
                displayName: 'Verify variable in StageA'
- stage: StageB
  dependsOn: StageA

  # Full Variables syntax for inter-stage jobs
  variables:
    myOutputVar: $[stageDependencies.StageA.A1.outputs['Deploy_DevEnvironmentV.setvarStep.myVar']]
  jobs:
  - deployment: B1
    pool:
      vmImage: 'ubuntu-latest'
    environment: envB
    strategy:                  
      runOnce:
        deploy:
          steps:
          - bash: echo $(myOutputVar)

深入瞭解如何 設定多作業輸出變數

常見問題集

我的管線停滯在訊息「作業擱置中...」。 我該怎麼辦?

當兩個作業之間發生名稱衝突時,可能會發生這種情況。 確認相同階段中的任何部署作業都有唯一的名稱,且該作業和階段名稱不包含關鍵詞。 如果重新命名無法修正問題,請檢閱 管線執行的疑難解答。

部署群組是否支持裝飾專案?

否。 您無法在部署群組中使用裝飾專案。