Trabajos de implementación

Azure Pipelines | Azure DevOps Server 2020

Importante

  • Los nombres de trabajos y fases no pueden contener palabras clave (ejemplo: deployment ).
  • Cada trabajo de una fase debe tener un nombre único.

En las canalizaciones de YAML, se recomienda colocar los pasos de implementación en un tipo especial de trabajo denominado trabajo de implementación. Un trabajo de implementación es una colección de pasos que se ejecutan secuencialmente en el entorno. Un trabajo de implementación y un trabajo tradicional pueden existir en la misma fase.

Los trabajos de implementación proporcionan las siguientes ventajas:

  • Historial deimplementación: obtiene el historial de implementación entre canalizaciones, hasta un recurso específico y el estado de las implementaciones para la auditoría.

  • Aplicar estrategia de implementación:defina cómo se va a implementar la aplicación.

    Nota

    Actualmente solo se admiten las estrategias runOnce,rollingy canary.

Un trabajo de implementación no clona automáticamente el repositorio de origen. Puede extraer el repositorio de origen dentro de su trabajo con checkout: self . Los trabajos de implementación solo admiten un paso de desprotección.

Schema

Esta es la sintaxis completa para especificar un trabajo de implementación:

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 ]

Hay una sintaxis alternativa más detallada que también puede usar para la environment propiedad .

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.

En el caso de las máquinas virtuales, no es necesario definir un grupo. Los pasos que defina en un trabajo de implementación con un recurso de máquina virtual se ejecutarán en esa máquina virtual y no en el agente del grupo. Para otros tipos de recursos, como Kubernetes, es necesario definir un grupo para que las tareas se puedan ejecutar en esa máquina.

Estrategias de implementación

Al implementar actualizaciones de aplicaciones, es importante que la técnica que use para entregar la actualización:

  • Habilite la inicialización.
  • Implemente la actualización.
  • Enruta el tráfico a la versión actualizada.
  • Pruebe la versión actualizada después de enrutar el tráfico.
  • En caso de error, ejecute los pasos para restaurar a la última versión correcta conocida.

Esto se consigue mediante el uso de enlaces de ciclo de vida que pueden ejecutar pasos durante la implementación. Cada uno de los enlaces de ciclo de vida se resuelve en un trabajo de agente o un trabajo de servidor (o un contenedor o trabajo de validación en el futuro), dependiendo del atributo. De forma predeterminada, los enlaces de ciclo de vida heredarán pool el especificado por el deployment trabajo.

Los trabajos de implementación usan la $(Pipeline.Workspace) variable del sistema.

Descripciones de enlaces de ciclo de vida

preDeploy: se usa para ejecutar pasos que inicializan recursos antes de que se inicie la implementación de la aplicación.

deploy: se usa para ejecutar los pasos que implementan la aplicación. La tarea Descargar artefacto solo se insertará automáticamente en el deploy enlace para los trabajos de implementación. Para detener la descarga de artefactos, use o elija artefactos específicos para descargar mediante la tarea Descargar artefacto - download: none- download: none.

routeTraffic: se usa para ejecutar pasos que atienden el tráfico a la versión actualizada.

postRouteTraffic: se usa para ejecutar los pasos después de enrutar el tráfico. Normalmente, estas tareas supervisan el estado de la versión actualizada para el intervalo definido.

on: failure o on: success : se usa para ejecutar pasos para acciones de reversión o limpieza.

Estrategia de implementación de RunOnce

runOncees la estrategia de implementación más sencilla en la que todos los enlaces de ciclo de vida, es preDeploydeployrouteTraffic decir, , y postRouteTraffic , se ejecutan una vez. A continuación, on:success se ejecuta o 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:
          ...

Si usa agentes auto hospedados, puede usar las opciones de limpieza del área de trabajo para limpiar el área de trabajo de implementación.

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

Estrategia de implementación gradual

Una implementación gradual reemplaza las instancias de la versión anterior de una aplicación por instancias de la nueva versión de la aplicación en un conjunto fijo de máquinas virtuales (conjunto gradual) en cada iteración.

Actualmente solo se admite la estrategia gradual en los recursos de máquina virtual.

Por ejemplo, una implementación gradual suele esperar a que se completen las implementaciones en cada conjunto de máquinas virtuales antes de continuar con el siguiente conjunto de implementaciones. Puede realizar una comprobación de estado después de cada iteración y, si se produce un problema significativo, se puede detener la implementación gradual.

Las implementaciones graduales se pueden configurar especificando la palabra clave rolling: en el strategy: nodo . La strategy.name variable está disponible en este bloque de estrategia, que toma el nombre de la estrategia. En este caso, gradual.

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

Se admiten todos los enlaces de ciclo de vida y se crean trabajos de enlace de ciclo de vida para ejecutarse en cada máquina virtual.

preDeploy, deploy , y se ejecutan una vez por tamaño de lote definido por routeTrafficpostRouteTrafficmaxParallel . A continuación, on: success se on: failure ejecuta o .

Con , puede controlar el número o porcentaje de destinos de máquina virtual en los maxParallel: <# or % of VMs> que se va a implementar en paralelo. Esto garantiza que la aplicación se ejecuta en estas máquinas y es capaz de controlar las solicitudes mientras se realiza la implementación en el resto de las máquinas, lo que reduce el tiempo de inactividad general.

Nota

Hay algunas lagunas conocidas en esta característica. Por ejemplo, cuando vuelva a intentar una fase, volverá a ejecutar la implementación en todas las máquinas virtuales, no solo en destinos con errores.

Estrategia de implementación de valores controlados

La estrategia de implementación de riesgo es una estrategia de implementación avanzada que ayuda a mitigar el riesgo que implica la implementación de nuevas versiones de aplicaciones. Con esta estrategia, puede realizar primero los cambios en un pequeño subconjunto de servidores. A medida que obtenga más confianza en la nueva versión, puede liberarla a más servidores de la infraestructura y enrutar más tráfico a ella.

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

La estrategia de implementación de valor canario admite el enlace de ciclo de vida (se ejecuta una vez) e itera con los enlaces de ciclo de vida preDeploydeploy , y routeTrafficpostRouteTraffic . A continuación, se cierra con el success enlace failure o .

Las siguientes variables están disponibles en esta estrategia:

strategy.name: nombre de la estrategia. Por ejemplo, canary.
strategy.action: acción que se va a realizar en el clúster de Kubernetes. Por ejemplo, implemente, promueva o rechace.
strategy.increment: valor de incremento utilizado en la interacción actual. Esta variable solo está disponible en los enlaces deploy de ciclo de vida , y routeTrafficpostRouteTraffic .

Ejemplos

Estrategia de implementación de RunOnce

En el siguiente fragmento de código YAML de ejemplo se muestra un uso sencillo de un trabajo de implementación mediante la estrategia runOnce de implementación. En el ejemplo se incluye un paso de desprotección.


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

Con cada ejecución de este trabajo, el historial de implementación se registra en el smarthotel-dev entorno.

Nota

  • También es posible crear un entorno con recursos vacíos y usarlo como un shell abstracto para registrar el historial de implementación, como se muestra en el ejemplo anterior.

En el ejemplo siguiente se muestra cómo una canalización puede hacer referencia tanto a un entorno como a un recurso que se usará como destino de un trabajo de implementación.

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)

Este enfoque tiene las siguientes ventajas:

  • Registra el historial de implementación en un recurso específico dentro del entorno, en lugar de registrar el historial en todos los recursos dentro del entorno.
  • Los pasos del trabajo de implementación heredan automáticamente los detalles de conexión del recurso (en este caso, un espacio de nombres de Kubernetes, ), porque el trabajo de implementación está vinculado al entorno. Esto resulta útil en los casos en los que se establece el mismo detalle de conexión para varios pasos del trabajo.

Estrategia de implementación gradual

La estrategia gradual para las máquinas virtuales actualiza hasta cinco destinos en cada iteración. maxParallel determinará el número de destinos que se pueden implementar en paralelo. La selección tiene en cuenta el número absoluto o el porcentaje de destinos que deben permanecer disponibles en cualquier momento excluyendo los destinos en los que se está realizando la implementación. También se usa para determinar las condiciones de acierto y error durante la implementación.

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

Estrategia de implementación de valores controlados

En el ejemplo siguiente, la estrategia de valores canarios para AKS implementará primero los cambios con pods del 10 por ciento, seguidos del 20 por ciento, mientras supervisa el estado durante postRouteTraffic . Si todo va bien, se promoverá al 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... 

Uso de decoradores de canalización para insertar pasos automáticamente

Los decoradores de canalización se pueden usar en los trabajos de implementación para insertar automáticamente cualquier paso personalizado (por ejemplo, el analizador de vulnerabilidades) en cada ejecución de enlace de ciclo de vida de cada trabajo de implementación. Dado que los decoradores de canalizaciones se pueden aplicar a todas las canalizaciones de una organización, esto se puede aprovechar como parte de la aplicación de prácticas de implementación seguras.

Además, los trabajos de implementación se pueden ejecutar como un trabajo de contenedor junto con el coche lateral de los servicios, si se definen.

Compatibilidad con variables de salida

Defina las variables de salida en los enlaces de ciclo de vida de un trabajo de implementación y conséctelas en otros pasos y trabajos de nivel inferior dentro de la misma fase.

Para compartir variables entre fases, genera un artefacto en una fase y, a continuación, lo consume en una fase posterior, o usa la sintaxis descrita en las variables.

Al ejecutar estrategias de implementación, puede acceder a variables de salida entre trabajos mediante la sintaxis siguiente.

  • Para la estrategia runOnce: (por ejemplo, $[dependencies.JobA.outputs['Deploy.StepA.VariableA']] )
  • Para la estrategia runOnce más un resourceType: . (por ejemplo, $[dependencies.JobA.outputs['Deploy_VM1.StepA.VariableA']])
  • Para la estrategia de los canarios:
  • Para la estrategia gradual:
# 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 un trabajo, especifique el nombre del trabajo en lugar del runOnce enlace de 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

Al definir un entorno en un trabajo de implementación, la sintaxis de la variable de salida varía en función de cómo se defina el entorno. En este ejemplo, env1 usa la notación abreviada e env2 incluye la sintaxis completa con un 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
      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

Cuando se genera una variable desde un trabajo de implementación, al hacer referencia a ella desde el siguiente trabajo se usa una sintaxis diferente en función de si desea establecer una variable o usarla como condición para la fase.

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)

Más información sobre cómo establecer una variable de salida de varios trabajos

Preguntas más frecuentes

Mi canalización está bloqueada con el mensaje "El trabajo está pendiente...". ¿Cómo lo puedo corregir?

Esto puede ocurrir cuando hay un conflicto de nombres entre dos trabajos. Compruebe que los trabajos de implementación de la misma fase tienen un nombre único y que los nombres de trabajo y fase no contienen palabras clave. Si el cambio de nombre no corrige el problema, revise la solución de problemas de ejecuciones de canalización.

¿Se admiten decoradores en grupos de implementación?

No. No se pueden usar elementos decorator en grupos de implementación.