Partilhar via


Trabalhos de implementação

Serviços de DevOps do Azure | Azure DevOps Server 2022 | Azure DevOps Server 2020

Importante

  • Os nomes de cargos e estágios não podem conter palavras-chave (exemplo: deployment).
  • Cada trabalho em um estágio deve ter um nome exclusivo.

Nos pipelines do YAML, recomendamos que coloque os passos de implementação num tipo especial de trabalho chamado trabalho de implementação. Um trabalho de implementação é uma coleção de passos executados sequencialmente no ambiente. Um trabalho de implantação e um trabalho tradicional podem existir no mesmo estágio. O Azure DevOps dá suporte às estratégias runOnce, rolling e canary.

Os trabalhos de implementação apresentam os seguintes benefícios:

  • Histórico de implementações: obtém o histórico de implementações através dos pipelines, até um recurso específico e o estado das implementações para auditoria.
  • Aplicar estratégia de implementação: define como a aplicação é desenvolvida.

Um trabalho de implementação não clona automaticamente o repositório de origem. Você pode fazer checkout do repositório de origem em seu trabalho com checkout: selfo .

Nota

Este artigo se concentra na implantação com trabalhos de implantação. Para saber como implantar no Azure com pipelines, consulte Visão geral de Implantar no Azure.

Esquema

Aqui está a sintaxe completa para especificar um trabalho de implantação:

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 ]

Há uma sintaxe alternativa mais detalhada que você também pode usar para a environment propriedade.

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.

Para máquinas virtuais, não é necessário definir um pool. Todas as etapas definidas em um trabalho de implantação com um recurso de máquina virtual serão executadas nessa máquina virtual e não no agente no pool. Para outros tipos de recursos, como o Kubernetes, você precisa definir um pool para que as tarefas possam ser executadas nessa máquina.

Estratégias de implementação

Ao implantar atualizações de aplicativos, é importante que a técnica usada para entregar a atualização seja:

  • Habilite a inicialização.
  • Implante a atualização.
  • Encaminhe o tráfego para a versão atualizada.
  • Teste a versão atualizada após rotear o tráfego.
  • Em caso de falha, execute as etapas para restaurar para a última versão válida.

Conseguimos isso usando ganchos de ciclo de vida que podem executar etapas durante a implantação. Cada um dos ganchos do ciclo de vida é resolvido em um trabalho de agente ou um trabalho de servidor (ou um contêiner ou trabalho de validação no futuro), dependendo do pool atributo. Por padrão, os ganchos de ciclo de vida herdarão o pool deployment especificado pelo trabalho.

Os trabalhos de implantação usam a $(Pipeline.Workspace) variável de sistema.

Descrições de ganchos de ciclo de vida

preDeploy: Usado para executar etapas que inicializam recursos antes do início da implantação do aplicativo.

deploy: Usado para executar etapas que implantam seu aplicativo. A tarefa de download do artefato será injetada automaticamente somente no gancho para trabalhos de deploy implantação. Para interromper o download de artefatos, use - download: none ou escolha artefatos específicos para download especificando a tarefa Baixar Artefato de Pipeline.

routeTraffic: Usado para executar etapas que servem o tráfego para a versão atualizada.

postRouteTraffic: Usado para executar as etapas depois que o tráfego é roteado. Normalmente, essas tarefas monitoram a integridade da versão atualizada para um intervalo definido.

on: failure ou on: success: Usado para executar etapas para ações de reversão ou limpeza.

Estratégia de implantação do RunOnce

runOnce é a estratégia de implantação mais simples em que todos os ganchos do ciclo de vida, ou seja preDeploy deploy, , routeTraffice postRouteTraffic, são executados uma vez. Em seguida, ou on: success on: failure é executado.

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

Se você estiver usando agentes auto-hospedados, poderá usar as opções de limpeza do espaço de trabalho para limpar o espaço de trabalho de implantação.

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

Estratégia de implementação contínua

Uma implantação sem interrupção substitui instâncias da versão anterior de um aplicativo por instâncias da nova versão do aplicativo em um conjunto fixo de máquinas virtuais (conjunto contínuo) em cada iteração.

Atualmente, oferecemos suporte apenas à estratégia contínua para recursos de VM.

Por exemplo, uma implantação sem interrupção normalmente aguarda a conclusão das implantações em cada conjunto de máquinas virtuais antes de prosseguir para o próximo conjunto de implantações. Você pode fazer uma verificação de integridade após cada iteração e, se ocorrer um problema significativo, a implantação contínua pode ser interrompida.

As implantações contínuas podem ser configuradas especificando a palavra-chave rolling: sob o strategy: nó. A strategy.name variável está disponível neste bloco de estratégia, que leva o nome da estratégia. Neste caso, rolando.

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

Todos os ganchos de ciclo de vida são suportados e os trabalhos de gancho de ciclo de vida são criados para serem executados em cada VM.

preDeploy, deploy, routeTraffic, e são executados uma vez por tamanho de lote postRouteTraffic definido por maxParallel. Em seguida, ou on: success on: failure é executado.

Com maxParallel: <# or % of VMs>o , você pode controlar o número/porcentagem de destinos de máquina virtual para implantar em paralelo. Isso garante que o aplicativo esteja sendo executado nessas máquinas e seja capaz de lidar com solicitações enquanto a implantação está ocorrendo no restante das máquinas, o que reduz o tempo de inatividade geral.

Nota

Existem algumas lacunas conhecidas neste recurso. Por exemplo, quando você tenta novamente um estágio, ele executa novamente a implantação em todas as VMs, não apenas em destinos com falha.

Estratégia de implementação canário

A estratégia de implantação Canary é uma estratégia de implantação avançada que ajuda a reduzir o risco envolvido na implantação de novas versões de aplicativos. Usando essa estratégia, você pode distribuir as alterações para um pequeno subconjunto de servidores primeiro. À medida que você ganha mais confiança na nova versão, pode liberá-la para mais servidores em sua infraestrutura e rotear mais tráfego para ela.

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

A estratégia de implantação Canary suporta o gancho de preDeploy ciclo de vida (executado uma vez) e itera com os ganchos , deployrouteTraffice postRouteTraffic ciclo de vida. Em seguida, ele sai com o success gancho ou failure gancho.

As seguintes variáveis estão disponíveis nesta estratégia:

strategy.name: Nome da estratégia. Por exemplo, canário.
strategy.action: A ação a ser executada no cluster Kubernetes. Por exemplo, implantar, promover ou rejeitar.
strategy.increment: O valor de incremento usado na interação atual. Esta variável está disponível apenas em deploy, routeTraffice postRouteTraffic ganchos de ciclo de vida.

Exemplos

Estratégia de implantação do RunOnce

O trecho YAML de exemplo a seguir mostra um uso simples de um trabalho de implantação usando a runOnce estratégia de implantação. O exemplo inclui uma etapa de checkout.


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

Com cada execução desse trabalho, o smarthotel-dev histórico de implantação é registrado no ambiente.

Nota

  • Também é possível criar um ambiente com recursos vazios e usá-lo como um shell abstrato para registrar o histórico de implantação, como mostrado no exemplo anterior.

O próximo exemplo demonstra como um pipeline pode referir um ambiente e um recurso a serem usados como destino para um trabalho de implantação.

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)

Esta abordagem tem os seguintes benefícios:

  • Registra o histórico de implantação em um recurso específico dentro do ambiente, em vez de registrar o histórico em todos os recursos dentro do ambiente.
  • As etapas no trabalho de implantação herdam automaticamente os detalhes de conexão do recurso (neste caso, um namespace Kubernetes, smarthotel-dev.bookings), porque o trabalho de implantação está vinculado ao ambiente. Isso é útil nos casos em que o mesmo detalhe de conexão é definido para várias etapas do trabalho.

Nota

Se estiver a utilizar um cluster AKS privado, certifique-se de que está ligado à rede virtual do cluster, uma vez que o ponto de extremidade do servidor API não está exposto através de um endereço IP público.

O Azure Pipelines recomenda configurar um agente auto-hospedado em uma VNET que tenha acesso à rede virtual do cluster. Consulte Opções para conexão com o cluster privado para obter detalhes.

Estratégia de implementação contínua

A estratégia contínua para VMs atualiza até cinco destinos em cada iteração. maxParallel determinará o número de alvos que podem ser implantados em paralelo. A seleção leva em conta o número absoluto ou a porcentagem de metas que devem permanecer disponíveis a qualquer momento, excluindo as metas para as quais estão sendo implantadas. Ele também é usado para determinar as condições de sucesso e falha durante a implantação.

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

Estratégia de implementação canário

No próximo exemplo, a estratégia canária para AKS implantará primeiro as mudanças com 10% de pods, seguido por 20%, enquanto monitora a saúde durante postRouteTraffico . Se tudo correr bem, vai subir a 100 por cento.

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

Use decoradores de tubulação para injetar etapas automaticamente

Os decoradores de pipeline podem ser usados em trabalhos de implantação para injetar automaticamente qualquer etapa personalizada (por exemplo, scanner de vulnerabilidade) em cada execução de gancho de ciclo de vida de cada trabalho de implantação. Como os decoradores de pipeline podem ser aplicados a todos os pipelines em uma organização, isso pode ser aplicado como parte da aplicação de práticas de implantação seguras.

Além disso, os trabalhos de implantação podem ser executados como um trabalho de contêiner junto com o side-car de serviços, se definido.

Suporte para variáveis de saída

Defina variáveis de saída nos ganchos de ciclo de vida de um trabalho de implantação e consuma-as em outras etapas e trabalhos downstream dentro do mesmo estágio.

Para compartilhar variáveis entre estágios, produza um artefato em um estágio e consuma-o em um estágio subsequente ou use a stageDependencies sintaxe descrita em variáveis.

Ao executar estratégias de implantação, você pode acessar variáveis de saída entre trabalhos usando a sintaxe a seguir.

  • Para a estratégia runOnce : $[dependencies.<job-name>.outputs['<job-name>.<step-name>.<variable-name>']] (por exemplo, $[dependencies.JobA.outputs['JobA.StepA.VariableA']])
  • Para a estratégia runOnce mais um resourceType: $[dependencies.<job-name>.outputs['Deploy_<resource-name>.<step-name>.<variable-name>']]. (por exemplo, $[dependencies.JobA.outputs['Deploy_VM1.StepA.VariableA']])
  • Para a estratégia canária : $[dependencies.<job-name>.outputs['<lifecycle-hookname>_<increment-value>.<step-name>.<variable-name>']]
  • Para a estratégia evolutiva : $[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

Para um runOnce trabalho, especifique o nome do trabalho em vez do gancho do ciclo de vida:

# 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

Quando você define um ambiente em um trabalho de implantação, a sintaxe da variável de saída varia dependendo de como o ambiente é definido. Neste exemplo, env1 usa notação abreviada e env2 inclui a sintaxe completa com um tipo de recurso definido.

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

Quando você produz uma variável de um trabalho no estágio um, fazer referência a ela a partir de um trabalho de implantação no próximo estágio usa sintaxe diferente, dependendo se você deseja definir uma variável ou usá-la como condição para o estágio.

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)

Quando você produz uma variável de um trabalho de implantação, use a sintaxe stageDependencies para fazer referência a ela a partir do próximo estágio (por exemplo, $[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)

Saiba mais sobre como definir uma variável de saída multitarefa

FAQ

Meu pipeline está preso com a mensagem "Job is pending...". Como posso corrigir isso?

Isso pode acontecer quando há um conflito de nome entre dois trabalhos. Verifique se todos os trabalhos de implantação no mesmo estágio têm um nome exclusivo e se os nomes de trabalho e estágio não contêm palavras-chave. Se a renomeação não corrigir o problema, revise as execuções de pipeline de solução de problemas.

Os decoradores são apoiados em grupos de implantação?

N.º Não é possível usar decoradores em grupos de implantação.