Udostępnij za pośrednictwem


Zadania wdrażania

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

Ważne

  • Nazwy zadań i etapów nie mogą zawierać słów kluczowych (na przykład: deployment).
  • Każde zadanie na etapie musi mieć unikatową nazwę.

W przypadku potoków YAML zaleca się umieszczenie kroków wdrożenia w specjalnym typie zadania o nazwie zadanie wdrażania. Zadanie wdrożenia to kolekcja kroków, które są uruchamiane sekwencyjnie względem środowiska. Zadanie wdrożenia i tradycyjne zadanie mogą istnieć na tym samym etapie. Usługa Azure DevOps obsługuje strategie runOnce, rolling i kanary .

Zadania wdrożenia zapewniają następujące korzyści:

  • Historia wdrożenia: uzyskujesz historię wdrożenia we wszystkich potokach, dla określonych zasobów i stanów wdrożeń na potrzeby inspekcji.
  • Stosowanie strategii wdrożenia: definiujesz sposób wdrażania aplikacji.

Zadanie wdrożenia nie klonuje automatycznie repozytorium źródłowego. Możesz wyewidencjonować repozytorium źródłowe w ramach zadania za pomocą polecenia checkout: self.

Uwaga

Ten artykuł koncentruje się na wdrażaniu z zadaniami wdrażania. Aby dowiedzieć się, jak wdrażać na platformie Azure za pomocą potoków, zobacz Wdrażanie na platformie Azure — omówienie.

Schemat

Oto pełna składnia określająca zadanie wdrożenia:

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 ]

Istnieje bardziej szczegółowa, alternatywna składnia, której można również użyć dla environment właściwości .

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.

W przypadku maszyn wirtualnych nie trzeba definiować puli. Wszystkie kroki zdefiniowane w zadaniu wdrożenia z zasobem maszyny wirtualnej będą uruchamiane względem tej maszyny wirtualnej, a nie względem agenta w puli. W przypadku innych typów zasobów, takich jak Kubernetes, należy zdefiniować pulę, aby zadania mogły być uruchamiane na tym komputerze.

Strategie wdrażania

Podczas wdrażania aktualizacji aplikacji ważne jest, aby technika używana do dostarczania aktualizacji:

  • Włącz inicjowanie.
  • Wdróż aktualizację.
  • Kierowanie ruchu do zaktualizowanej wersji.
  • Przetestuj zaktualizowaną wersję po routingu ruchu.
  • W przypadku awarii uruchom kroki przywracania do ostatniej znanej dobrej wersji.

Osiągamy to za pomocą punktów zaczepienia cyklu życia, które mogą uruchamiać kroki podczas wdrażania. Każdy z punktów zaczepienia cyklu życia jest rozpoznawany jako zadanie agenta lub zadanie serwera (albo kontener lub zadanie weryfikacji w przyszłości), w zależności od atrybutu pool . Domyślnie haki cyklu życia będą dziedziczyć pool określone przez deployment zadanie.

Zadania wdrażania używają zmiennej $(Pipeline.Workspace) systemowej.

Opisy punktów zaczepienia cyklu życia

preDeploy: służy do uruchamiania kroków inicjowania zasobów przed rozpoczęciem wdrażania aplikacji.

deploy: służy do uruchamiania kroków wdrażania aplikacji. Zadanie pobierania artefaktu zostanie automatycznie wprowadzone tylko w haczyku deploy dla zadań wdrażania. Aby zatrzymać pobieranie artefaktów, użyj - download: none lub wybierz określone artefakty do pobrania, określając zadanie Pobierz artefakt potoku.

routeTraffic: służy do uruchamiania kroków obsługujących ruch do zaktualizowanej wersji.

postRouteTraffic: służy do uruchamiania kroków po kierowaniu ruchu. Zazwyczaj te zadania monitorują kondycję zaktualizowanej wersji dla zdefiniowanego interwału.

on: failure lub on: success: służy do uruchamiania kroków dla akcji wycofywania lub czyszczenia.

Strategia wdrażania RunOnce

runOnce jest najprostszą strategią wdrażania, w której wszystkie elementy zaczepienia cyklu życia, czyli preDeploydeploy, routeTraffici postRouteTraffic, są wykonywane raz. Następnie wykonywana jest wartość on:success lub 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:
          ...

Jeśli używasz własnych agentów, możesz użyć opcji czyszczenia obszaru roboczego, aby wyczyścić obszar roboczy wdrożenia.

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

Strategia wdrażania stopniowego

Wdrożenie stopniowe zastępuje wystąpienia poprzedniej wersji aplikacji wystąpieniami nowej wersji aplikacji w stałym zestawie maszyn wirtualnych (zestaw kroczący) w każdej iteracji.

Obecnie obsługujemy tylko strategię stopniowej dla zasobów maszyny wirtualnej.

Na przykład wdrożenie stopniowe zwykle czeka na wdrożenia dla każdego zestawu maszyn wirtualnych do ukończenia przed przejściem do następnego zestawu wdrożeń. Możesz przeprowadzić kontrolę kondycji po każdej iteracji i jeśli wystąpi istotny problem, wdrożenie stopniowe można zatrzymać.

Wdrożenia stopniowe można skonfigurować, określając słowo kluczowe rolling: w węźle strategy: . Zmienna strategy.name jest dostępna w tym bloku strategii, który przyjmuje nazwę strategii. W tym przypadku stopniowe.

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

Wszystkie haki cyklu życia są obsługiwane, a zadania punktów zaczepienia cyklu życia są tworzone do uruchamiania na każdej maszynie wirtualnej.

preDeploy, , deployrouteTraffici postRouteTraffic są wykonywane raz na rozmiar partii zdefiniowany przez maxParallel. Następnie wykonywana jest wartość on: success lub on: failure .

Za pomocą programu maxParallel: <# or % of VMs>można kontrolować liczbę/procent miejsc docelowych maszyn wirtualnych, aby wdrożyć je równolegle. Dzięki temu aplikacja jest uruchomiona na tych maszynach i może obsługiwać żądania, gdy wdrożenie odbywa się na pozostałych maszynach, co zmniejsza całkowity przestój.

Uwaga

Istnieje kilka znanych luk w tej funkcji. Na przykład ponawianie próby etapu spowoduje ponowne uruchomienie wdrożenia na wszystkich maszynach wirtualnych, które nie tylko nie zakończyły się niepowodzeniem.

Strategia wdrażania kanarkowego

Strategia wdrażania kanarowego to zaawansowana strategia wdrażania, która pomaga ograniczyć ryzyko związane z wdrażaniem nowych wersji aplikacji. Korzystając z tej strategii, można najpierw wdrożyć zmiany w małym podzestawie serwerów. Gdy zyskujesz większą pewność co do nowej wersji, możesz zwolnić ją na więcej serwerów w infrastrukturze i kierować do niej większy ruch.

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

Strategia wdrażania kanarowego obsługuje preDeploy punkt zaczepienia cyklu życia (wykonywany raz) i iteruje przy deployużyciu punktów zaczepienia , routeTraffici postRouteTraffic cyklu życia. Następnie kończy się za pomocą haka success lub failure .

W tej strategii są dostępne następujące zmienne:

strategy.name: nazwa strategii. Na przykład kanary.
strategy.action: Akcja do wykonania w klastrze Kubernetes. Na przykład wdróż, podwyższ poziom lub odrzuć.
strategy.increment: wartość przyrostowa używana w bieżącej interakcji. Ta zmienna jest dostępna tylko w deploypunktach zaczepienia , routeTraffici postRouteTraffic cyklu życia.

Przykłady

Strategia wdrażania RunOnce

Poniższy przykładowy fragment kodu YAML przedstawia proste użycie zadania wdrażania przy użyciu runOnce strategii wdrażania. Przykład zawiera krok wyewidencjonowania.


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

W przypadku każdego uruchomienia tego zadania historia wdrożenia jest rejestrowana w smarthotel-dev środowisku.

Uwaga

  • Istnieje również możliwość utworzenia środowiska z pustymi zasobami i użycia go jako abstrakcyjnej powłoki do rejestrowania historii wdrożenia, jak pokazano w poprzednim przykładzie.

W następnym przykładzie pokazano, jak potok może odwoływać się zarówno do środowiska, jak i zasobu, który ma być używany jako element docelowy zadania wdrożenia.

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)

Ta metoda ma następujące zalety:

  • Rejestruje historię wdrażania dla określonego zasobu w środowisku, w przeciwieństwie do rejestrowania historii na wszystkich zasobach w środowisku.
  • Kroki w zadaniu wdrażania automatycznie dziedziczą szczegóły połączenia zasobu (w tym przypadku przestrzeń nazw Kubernetes), smarthotel-dev.bookingsponieważ zadanie wdrożenia jest połączone ze środowiskiem. Jest to przydatne w przypadkach, w których ten sam szczegół połączenia jest ustawiany dla wielu kroków zadania.

Strategia wdrażania stopniowego

Strategia stopniowej maszyn wirtualnych aktualizuje maksymalnie pięć elementów docelowych w każdej iteracji. maxParallel Określi liczbę obiektów docelowych, które można wdrożyć równolegle. Wybór odpowiada bezwzględnej liczbie lub procentowi miejsc docelowych, które muszą pozostać dostępne w dowolnym momencie z wyłączeniem miejsc docelowych, do których są wdrażane. Służy również do określania warunków powodzenia i niepowodzenia podczas wdrażania.

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

Strategia wdrażania kanarkowego

W następnym przykładzie strategia kanargu dla usługi AKS najpierw wdroży zmiany z 10-procentowymi zasobnikami, a następnie 20 procentami, monitorując kondycję podczas wykonywania postRouteTrafficoperacji . Jeśli wszystko pójdzie dobrze, będzie promować do 100 procent.

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

Automatyczne wstrzykiwanie kroków za pomocą dekoratorów potoków

Dekoratory potoków mogą być używane w zadaniach wdrażania w celu automatycznego wstrzykiwania dowolnego niestandardowego kroku (na przykład skanera luk w zabezpieczeniach) do każdego wykonania każdego zadania wdrażania w ramach cyklu życia. Ponieważ dekoratory potoków można stosować do wszystkich potoków w organizacji, można je stosować w ramach wymuszania bezpiecznych praktyk wdrażania.

Ponadto zadania wdrażania można uruchamiać jako zadanie kontenera wraz z samochodem bocznym usług, jeśli zostały zdefiniowane.

Obsługa zmiennych wyjściowych

Zdefiniuj zmienne wyjściowe w punktach zaczepienia cyklu życia zadania wdrożenia i używają ich w innych krokach podrzędnych i zadaniach w ramach tego samego etapu.

Aby udostępnić zmienne między etapami, wyprowadź artefakt w jednym etapie, a następnie użyj go w kolejnym etapie lub użyj składni opisanej stageDependencies w zmiennych.

Podczas wykonywania strategii wdrażania można uzyskać dostęp do zmiennych wyjściowych między zadaniami przy użyciu następującej składni.

  • W przypadku strategii runOnce : $[dependencies.<job-name>.outputs['<job-name>.<step-name>.<variable-name>']] (na przykład $[dependencies.JobA.outputs['JobA.StepA.VariableA']])
  • Dla strategii runOnce plus resourceType: $[dependencies.<job-name>.outputs['<job-name>_<resource-name>.<step-name>.<variable-name>']]. (na przykład $[dependencies.JobA.outputs['Deploy_VM1.StepA.VariableA']])
  • Strategia kanarowa : $[dependencies.<job-name>.outputs['<lifecycle-hookname>_<increment-value>.<step-name>.<variable-name>']]
  • W przypadku strategii stopniowej : $[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 W przypadku zadania określ nazwę zadania zamiast haka cyklu życia:

# 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

Podczas definiowania środowiska w zadaniu wdrażania składnia zmiennej wyjściowej różni się w zależności od sposobu definiowania środowiska. W tym przykładzie env1 użyto notacji skróconej i env2 zawiera pełną składnię ze zdefiniowanym typem zasobu.

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

Podczas wyprowadzania zmiennej z zadania wdrożenia, odwoływanie się do niego z następnego zadania używa innej składni w zależności od tego, czy chcesz ustawić zmienną lub użyć jej jako warunku dla etapu.

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)

Dowiedz się więcej na temat ustawiania zmiennej wyjściowej z wieloma zadaniami

Często zadawane pytania

Mój potok jest zablokowany z komunikatem "Zadanie jest oczekujące...". Jak rozwiązać ten problem?

Może się to zdarzyć, gdy występuje konflikt nazw między dwoma zadaniami. Sprawdź, czy wszystkie zadania wdrażania na tym samym etapie mają unikatową nazwę, a nazwy zadań i etapów nie zawierają słów kluczowych. Jeśli zmiana nazwy nie rozwiąże problemu, zapoznaj się z tematem Rozwiązywanie problemów z przebiegami potoku.

Czy dekoratory są obsługiwane w grupach wdrożeń?

L.p. Nie można używać dekoratorów w grupach wdrożeń.