Übung: Hinzufügen mehrerer Umgebungen zu Ihrer Pipeline

Abgeschlossen

Nun können Sie Ihre Pipeline für die Bereitstellung in Ihrer Test- und Produktionsumgebung aktualisieren. In dieser Lerneinheit aktualisieren Sie Ihre Pipeline so, dass Vorlagen verwendet werden, damit Sie die Phasen in allen Umgebungen wiederverwenden können.

In dem Prozess gehen Sie wie folgt vor:

  • Fügen Sie eine Pipelinevorlage für die Lint-Phase hinzu.
  • Fügen Sie eine Pipelinevorlage hinzu, die die erforderlichen Phasen für die Bereitstellung in einer beliebigen Umgebung definiert.
  • Aktualisieren Sie Ihre Pipeline, um die Vorlagen zu verwenden.
  • Führen Sie Ihre Pipeline aus, und zeigen Sie die Ergebnisse an.

Hinzufügen einer Pipelinevorlage für die Lint-Phase

Die Lint-Phase erfolgt nur einmal während der Ausführung der Pipeline, unabhängig davon, in wie vielen Umgebungen die Pipeline bereitgestellt wird. Daher müssen Sie keine Vorlagen für die Lint-Phase verwenden. Damit die Definitionsdatei der Hauptpipeline aber einfach und leicht lesbar bleibt, entscheiden Sie sich dafür, die Lint-Phase in einer Vorlage zu definieren.

  1. Erstellen Sie in Visual Studio Code im Ordner deploy einen neuen Ordner mit dem Namen pipeline-templates.

  2. Erstellen Sie im Ordner pipeline-templates eine neue Datei mit dem Namen lint.yml.

    Screenshot: Visual Studio Code Explorer mit dem Ordner pipeline-templates und der Datei lint.yml

  3. Fügen Sie die folgende Pipelinevorlagendefinition in die Datei ein:

    jobs:
    - job: LintCode
      displayName: Lint code
      steps:
        - script: |
            az bicep build --file deploy/main.bicep
          name: LintBicepCode
          displayName: Run Bicep linter
    

    Die Lint-Phase ist identisch mit der Lint-Phase, die bereits in der Pipeline enthalten ist, aber jetzt befindet sie sich in einer separaten Pipelinevorlagendatei.

  4. Speichern Sie Ihre Änderungen, und schließen Sie die Datei.

Hinzufügen einer Pipelinevorlage für die Bereitstellung

Erstellen Sie eine Pipelinevorlage, die alle Phasen definiert, die zum Bereitstellen der einzelnen Umgebungen erforderlich sind. Sie verwenden Vorlagenparameter, um die Einstellungen anzugeben, die sich in den verschiedenen Umgebungen unterscheiden können.

  1. Erstellen Sie im Ordner pipeline-templates eine neue Datei mit dem Namen deploy.yml.

    Screenshot: Visual Studio Code Explorer mit dem Ordner „pipeline-templates“ und der Datei „deploy.yml“

    Diese Datei stellt alle Bereitstellungsaktivitäten dar, die jeweils für eine Umgebung ausgeführt werden.

  2. Fügen Sie die folgenden Pipelinevorlagenparameter in die Datei ein:

    parameters:
    - name: environmentType
      type: string
    - name: resourceGroupName
      type: string
    - name: serviceConnectionName
      type: string
    - name: deploymentDefaultLocation
      type: string
      default: westus3
    

    Hinweis

    Wenn Sie beginnen, mit Ihrer YAML-Datei in Visual Studio Code zu arbeiten, werden möglicherweise einige rote Wellenlinien angezeigt, die darauf hindeuten, dass ein Problem vorliegt. Dies liegt daran, dass die Visual Studio Code-Erweiterung für YAML-Dateien manchmal fälschlicherweise das Schema der Datei errät.

    Sie können die Probleme ignorieren, die die Erweiterung meldet. Wenn Sie möchten, können Sie den folgenden Code am Anfang der Datei hinzufügen, um das Raten durch die Erweiterung zu unterdrücken:

    # yaml-language-server: $schema=./deploy.yml
    
  3. Fügen Sie unterhalb der Parameter die Definition der Überprüfungsphase ein:

    stages:
    
    - ${{ if ne(parameters.environmentType, 'Production') }}:
      - stage: Validate_${{parameters.environmentType}}
        displayName: Validate (${{parameters.environmentType}} Environment)
        jobs:
        - job: ValidateBicepCode
          displayName: Validate Bicep code
          steps:
            - task: AzureResourceManagerTemplateDeployment@3
              name: RunPreflightValidation
              displayName: Run preflight validation
              inputs:
                connectedServiceName: ${{parameters.serviceConnectionName}}
                location: ${{parameters.deploymentDefaultLocation}}
                deploymentMode: Validation
                resourceGroupName: ${{parameters.resourceGroupName}}
                csmFile: deploy/main.bicep
                overrideParameters: >
                  -environmentType ${{parameters.environmentType}}
    

    Beachten Sie, dass eine Bedingung auf diese Phase angewendet wird. Sie wird nur für Nicht-Produktionsumgebungen ausgeführt.

    Beachten Sie auch, dass der Phasenbezeichner den Wert des Parameters environmentType enthält. Dieser Parameter stellt sicher, dass jede Phase in Ihrer Pipeline über einen eindeutigen Bezeichner verfügt. Die Phase verfügt auch über eine displayName-Eigenschaft, um einen gut formatierten Namen zu erstellen, den Sie lesen können.

  4. Fügen Sie unterhalb der Überprüfungsphase die Definition der Vorschauphase ein:

    - ${{ if eq(parameters.environmentType, 'Production') }}:
      - stage: Preview_${{parameters.environmentType}}
        displayName: Preview (${{parameters.environmentType}} Environment)
        jobs:
        - job: PreviewAzureChanges
          displayName: Preview Azure changes
          steps:
            - task: AzureCLI@2
              name: RunWhatIf
              displayName: Run what-if
              inputs:
                azureSubscription: ${{parameters.serviceConnectionName}}
                scriptType: 'bash'
                scriptLocation: 'inlineScript'
                inlineScript: |
                  az deployment group what-if \
                    --resource-group ${{parameters.resourceGroupName}} \
                    --template-file deploy/main.bicep \
                    --parameters environmentType=${{parameters.environmentType}}
    

    Beachten Sie, dass für diese Phase auch eine Bedingung angewendet wird, aber sie ist das Gegenteil der Bedingung der Überprüfungsphase. Die Vorschauphase wird nur für die Produktionsumgebung ausgeführt.

  5. Fügen Sie unterhalb der Vorschauphase die Definition der Bereitstellungsphase ein:

    - stage: Deploy_${{parameters.environmentType}}
      displayName: Deploy (${{parameters.environmentType}} Environment)
      jobs:
      - deployment: DeployWebsite
        displayName: Deploy website
        environment: ${{parameters.environmentType}}
        strategy:
          runOnce:
            deploy:
              steps:
                - checkout: self
    
                - task: AzureResourceManagerTemplateDeployment@3
                  name: DeployBicepFile
                  displayName: Deploy Bicep file
                  inputs:
                    connectedServiceName: ${{parameters.serviceConnectionName}}
                    deploymentName: $(Build.BuildNumber)
                    location: ${{parameters.deploymentDefaultLocation}}
                    resourceGroupName: ${{parameters.resourceGroupName}}
                    csmFile: deploy/main.bicep
                    overrideParameters: >
                      -environmentType ${{parameters.environmentType}}
                    deploymentOutputs: deploymentOutputs
    
                - bash: |
                    echo "##vso[task.setvariable variable=appServiceAppHostName;isOutput=true]$(echo $DEPLOYMENT_OUTPUTS | jq -r '.appServiceAppHostName.value')"
                  name: SaveDeploymentOutputs
                  displayName: Save deployment outputs into variables
                  env:
                    DEPLOYMENT_OUTPUTS: $(deploymentOutputs)
    
  6. Fügen Sie unterhalb der Bereitstellungsphase die Definition der Stufe für die Feuerprobe ein:

    - stage: SmokeTest_${{parameters.environmentType}}
      displayName: Smoke Test (${{parameters.environmentType}} Environment)
      jobs:
      - job: SmokeTest
        displayName: Smoke test
        variables:
          appServiceAppHostName: $[ stageDependencies.Deploy_${{parameters.environmentType}}.DeployWebsite.outputs['DeployWebsite.SaveDeploymentOutputs.appServiceAppHostName'] ]
        steps:
          - task: PowerShell@2
            name: RunSmokeTests
            displayName: Run smoke tests
            inputs:
              targetType: inline
              script: |
                $container = New-PesterContainer `
                  -Path 'deploy/Website.Tests.ps1' `
                  -Data @{ HostName = '$(appServiceAppHostName)' }
                Invoke-Pester `
                  -Container $container `
                  -CI
    
          - task: PublishTestResults@2
            name: PublishTestResults
            displayName: Publish test results
            condition: always()
            inputs:
              testResultsFormat: NUnit
              testResultsFiles: 'testResults.xml'
    

    Beachten Sie, dass die Variablendefinition appServiceAppHostName den environmentType-Parameter enthält, wenn sie auf die Phase verweist, in der der Hostname veröffentlicht wurde. Dieser Parameter stellt sicher, dass jede Feuerprobephase für die richtige Umgebung ausgeführt wird.

  7. Vergewissern Sie sich, dass die Datei deploy.yml jetzt wie im folgenden Beispiel aussieht:

    parameters:
    - name: environmentType
      type: string
    - name: resourceGroupName
      type: string
    - name: serviceConnectionName
      type: string
    - name: deploymentDefaultLocation
      type: string
      default: westus3
    
    stages:
    
    - ${{ if ne(parameters.environmentType, 'Production') }}:
      - stage: Validate_${{parameters.environmentType}}
        displayName: Validate (${{parameters.environmentType}} Environment)
        jobs:
        - job: ValidateBicepCode
          displayName: Validate Bicep code
          steps:
            - task: AzureResourceManagerTemplateDeployment@3
              name: RunPreflightValidation
              displayName: Run preflight validation
              inputs:
                connectedServiceName: ${{parameters.serviceConnectionName}}
                location: ${{parameters.deploymentDefaultLocation}}
                deploymentMode: Validation
                resourceGroupName: ${{parameters.resourceGroupName}}
                csmFile: deploy/main.bicep
                overrideParameters: >
                  -environmentType ${{parameters.environmentType}}
    
    - ${{ if eq(parameters.environmentType, 'Production') }}:
      - stage: Preview_${{parameters.environmentType}}
        displayName: Preview (${{parameters.environmentType}} Environment)
        jobs:
        - job: PreviewAzureChanges
          displayName: Preview Azure changes
          steps:
            - task: AzureCLI@2
              name: RunWhatIf
              displayName: Run what-if
              inputs:
                azureSubscription: ${{parameters.serviceConnectionName}}
                scriptType: 'bash'
                scriptLocation: 'inlineScript'
                inlineScript: |
                  az deployment group what-if \
                    --resource-group ${{parameters.resourceGroupName}} \
                    --template-file deploy/main.bicep \
                    --parameters environmentType=${{parameters.environmentType}}
    
    - stage: Deploy_${{parameters.environmentType}}
      displayName: Deploy (${{parameters.environmentType}} Environment)
      jobs:
      - deployment: DeployWebsite
        displayName: Deploy website
        environment: ${{parameters.environmentType}}
        strategy:
          runOnce:
            deploy:
              steps:
                - checkout: self
    
                - task: AzureResourceManagerTemplateDeployment@3
                  name: DeployBicepFile
                  displayName: Deploy Bicep file
                  inputs:
                    connectedServiceName: ${{parameters.serviceConnectionName}}
                    deploymentName: $(Build.BuildNumber)
                    location: ${{parameters.deploymentDefaultLocation}}
                    resourceGroupName: ${{parameters.resourceGroupName}}
                    csmFile: deploy/main.bicep
                    overrideParameters: >
                      -environmentType ${{parameters.environmentType}}
                    deploymentOutputs: deploymentOutputs
    
                - bash: |
                    echo "##vso[task.setvariable variable=appServiceAppHostName;isOutput=true]$(echo $DEPLOYMENT_OUTPUTS | jq -r '.appServiceAppHostName.value')"
                  name: SaveDeploymentOutputs
                  displayName: Save deployment outputs into variables
                  env:
                    DEPLOYMENT_OUTPUTS: $(deploymentOutputs)
    
    - stage: SmokeTest_${{parameters.environmentType}}
      displayName: Smoke Test (${{parameters.environmentType}} Environment)
      jobs:
      - job: SmokeTest
        displayName: Smoke test
        variables:
          appServiceAppHostName: $[ stageDependencies.Deploy_${{parameters.environmentType}}.DeployWebsite.outputs['DeployWebsite.SaveDeploymentOutputs.appServiceAppHostName'] ]
        steps:
          - task: PowerShell@2
            name: RunSmokeTests
            displayName: Run smoke tests
            inputs:
              targetType: inline
              script: |
                $container = New-PesterContainer `
                  -Path 'deploy/Website.Tests.ps1' `
                  -Data @{ HostName = '$(appServiceAppHostName)' }
                Invoke-Pester `
                  -Container $container `
                  -CI
    
          - task: PublishTestResults@2
            name: PublishTestResults
            displayName: Publish test results
            condition: always()
            inputs:
              testResultsFormat: NUnit
              testResultsFiles: 'testResults.xml'
    
  8. Speichern Sie die geänderte Datei.

Aktualisieren der Pipelinedefinition zur Verwendung der Vorlagen

  1. Öffnen Sie die Datei azure-pipelines.yml.

  2. Aktualisieren Sie die Datei für die Verwendung der neuen Vorlagen, und ersetzen Sie dazu den Inhalt durch den folgenden Code:

    trigger:
      batch: true
      branches:
        include:
        - main
    
    pool:
      vmImage: ubuntu-latest
    
    stages:
    
    # Lint the Bicep file.
    - stage: Lint
      jobs: 
      - template: pipeline-templates/lint.yml
    
    # Deploy to the test environment.
    - template: pipeline-templates/deploy.yml
      parameters:
        environmentType: Test
        resourceGroupName: ToyWebsiteTest
        serviceConnectionName: ToyWebsiteTest
    
    # Deploy to the production environment.
    - template: pipeline-templates/deploy.yml
      parameters:
        environmentType: Production
        resourceGroupName: ToyWebsiteProduction
        serviceConnectionName: ToyWebsiteProduction
    

    Diese Pipeline führt die Lint-Phase einmal aus. Anschließend wird die Vorlagendatei deploy.yml zweimal verwendet: einmal pro Umgebung. Dadurch bleibt die Pipelinedefinition klar und leicht verständlich. Außerdem helfen die Kommentare dabei, zu erklären, was passiert.

  3. Speichern Sie die Änderungen.

  4. Committen und pushen Sie Ihre Änderungen in Ihr Git-Repository, indem Sie die folgenden Befehle im Visual Studio Code-Terminal ausführen:

    git add .
    git commit -m "Add pipeline templates"
    git push
    

Anzeigen der Pipelineausführung

  1. Wechseln Sie in Ihrem Browser zu Pipelines.

  2. Wählen Sie die letzte Ausführung Ihrer Pipeline aus.

    Beachten Sie, dass die Pipelineausführung nun alle Phasen zeigt, die Sie in der YAML-Datei definiert haben. Möglicherweise müssen Sie horizontal scrollen, um alle zu sehen.

    Screenshot: Azure Pipelines mit den Phasen der Pipelineausführung

  3. Warten Sie, bis die Pipeline vor der Phase Bereitstellen (Produktionsumgebung) angehalten wurde. Es kann einige Minuten dauern, bis die Pipeline diesen Punkt erreicht hat.

    Screenshot: Azure Pipelines, wobei die Pipelineausführung zur Genehmigung angehalten wurde

  4. Genehmigen Sie die Bereitstellung in der Produktionsumgebung, indem Sie auf die Schaltfläche Überprüfen klicken.

  5. Wählen Sie die Schaltfläche Genehmigen aus.

    Screenshot: Azure DevOps-Benutzeroberfläche mit der Pipelinegenehmigungsseite und der Schaltfläche „Genehmigen“

    Warten Sie, bis die Ausführung der Pipeline abgeschlossen ist.

  6. Wählen Sie die Registerkarte Test aus, um die Testergebnisse aus dieser Pipelineausführung anzuzeigen.

    Beachten Sie, dass jetzt vier Testergebnisse vorhanden sind. Die Feuerprobe wird sowohl in der Test- als auch in der Produktionsumgebung ausgeführt, sodass die Ergebnisse für beide Testsätze angezeigt werden.

    Screenshot: Azure Pipelines mit der Seite für Pipelineausführungstests mit vier Testergebnissen

  7. Wählen Sie Pipelines>Umgebungen aus.

  8. Wählen Sie die Umgebung Produktion aus.

  9. Beachten Sie, dass auf dem Bildschirm mit den Umgebungsdetails eine Übersicht über den Bereitstellungsverlauf der Produktionsumgebung angezeigt wird.

    Screenshot: Azure Pipelines mit der Produktionsumgebung und einer einzelnen Bereitstellung im Bereitstellungsverlauf

  10. Wählen Sie die Bereitstellung und dann die Registerkarte Änderungen aus.

    Beachten Sie, dass auf der Registerkarte Änderungen die Liste der in der Bereitstellung enthaltenen Commits angezeigt wird. Anhand dieser Informationen können Sie genau sehen, was sich im Lauf der Zeit in Ihrer Umgebung geändert hat.

    Screenshot: Azure Pipelines mit den Bereitstellungsdetails der Produktionsumgebung und einer Liste von Commits

  11. Navigieren Sie in Ihrem Browser zum Azure-Portal.

  12. Wechseln Sie zur Ressourcengruppe ToyWebsiteProduction.

  13. Öffnen Sie in der Liste der Ressourcen die Azure App Service-App.

    Screenshot: Azure-Portal mit der Produktions-App Service-App und den Details der SKU des App Service-Plans

    Beachten Sie, dass der Typ des App Service-Plans S1 ist.

  14. Wechseln Sie zur App Service-App in der Ressourcengruppe ToyWebsiteTest.

    Beachten Sie, dass der Typ des App Service-Plans F1 ist. Die beiden Umgebungen verwenden unterschiedliche Einstellungen, wie Sie es in Ihrer Bicep-Datei definiert haben.