Exercício – Adicionar vários ambientes ao seu pipeline

Concluído

Agora você está pronto para atualizar seu pipeline para implantar em seus ambientes de teste e produção. Nesta unidade, você atualizará seu pipeline para usar modelos para que você possa reutilizar as fases entre os ambientes.

Durante o processo, você vai:

  • Adicione um modelo de pipeline para a fase de lint.
  • Adicione um modelo de pipeline que define as fases necessárias para implantar em qualquer ambiente.
  • Atualize seu pipeline para usar os modelos.
  • Execute o pipeline e veja os resultados.

Adicionar um modelo de pipeline para a fase de lint

A fase de ling ocorre apenas uma vez durante a execução de pipeline, independentemente de quantos ambientes o pipeline implanta. Portanto, você não precisa realmente usar modelos para a fase de lint. Porém, para manter o arquivo de definição de pipeline principal simples e fácil de ler, você opta por definir a fase de lint em um modelo.

  1. No Visual Studio Code, crie uma pasta chamada pipeline-templates dentro da pasta deploy.

  2. Crie um arquivo na pasta pipeline-templates chamado lint.yml.

    Screenshot of Visual Studio Code Explorer, with the pipeline-templates folder and the lint dot Y M L file.

  3. Cole a seguinte definição de modelo de pipeline no arquivo:

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

    A fase de lint é igual à fase de lint que já está no pipeline, mas agora ela está em um arquivo de modelo de pipeline separado.

  4. Salve suas alterações e feche o arquivo.

Adicionar um modelo de pipeline para implantação

Crie um modelo de pipeline que defina todas as fases necessárias para implantar cada um dos ambientes. Você usa parâmetros de modelo para especificar as configurações que podem ser diferentes entre ambientes.

  1. Crie um arquivo na pasta pipeline-templates chamado deploy.yml.

    Screenshot of Visual Studio Code Explorer, with the pipeline-templates folder and the deploy dot YML file.

    Esse arquivo representa todas as atividades de implantação executadas para cada um dos ambientes.

  2. Cole os seguintes parâmetros de modelo de pipeline no arquivo:

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

    Observação

    Quando você começar a trabalhar com o arquivo YAML no Visual Studio Code, poderá ver algumas linhas onduladas vermelhas informando que há um problema. Isso ocorre porque a extensão do Visual Studio Code para arquivos YAML às vezes supõe incorretamente o esquema do arquivo.

    Você pode ignorar os problemas que a extensão relata. Ou, se preferir, você pode adicionar o seguinte código à parte superior do arquivo para suprimir a suposição da extensão:

    # yaml-language-server: $schema=./deploy.yml
    
  3. Abaixo dos parâmetros, cole a definição da fase de validação:

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

    Observe que uma condição é aplicada a essa fase. Ela é executada somente para ambientes que não são de produção.

    Observe também que o identificador de fase inclui o valor do parâmetro environmentType. Esse parâmetro garante que cada fase em seu pipeline tenha um identificador exclusivo. A fase também tem uma propriedade displayName para criar um nome bem formatado para leitura.

  4. Abaixo da fase de validação, cole a definição da fase de versão prévia:

    - ${{ 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}}
    

    Observe que essa fase também tem uma condição aplicada, mas é o oposto da condição da fase de validação. A fase de versão prévia é executada somente para o ambiente de produção.

  5. Abaixo da fase de versão prévia, cole a definição da fase de implantação:

    - 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. Abaixo da fase de implantação, cole a definição da fase de smoke test:

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

    Observe que a definição da variável appServiceAppHostName incorpora o parâmetro environmentType no se refere à fase que publicou o nome do host. Esse parâmetro garante que cada fase de smoke test seja executada no ambiente correto.

  7. Verifique se o arquivo deploy.yml agora se parece com o seguinte exemplo:

    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. Salve as alterações no arquivo.

Atualizar a definição de pipeline para usar os modelos

  1. Abra o arquivo azure-pipelines.yml.

  2. Atualize o arquivo para usar os novos modelos, substituindo o conteúdo pelo seguinte código:

    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
    

    Esse pipeline executa a fase lint uma vez. Ele então usa o arquivo de modelo deploy.yml duas vezes: uma vez por ambiente. Isso mantém a definição de pipeline clara e fácil de entender. Além disso, os comentários ajudam a explicar o que está acontecendo.

  3. Salve suas alterações.

  4. Faça commit e efetue push das alterações no repositório Git executando os seguintes comandos no terminal do Visual Studio Code:

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

Exibir a execução de pipeline

  1. No navegador, acesse Pipelines.

  2. Selecione a execução mais recente do pipeline.

    Observe que a execução de pipeline agora mostra todas as fases que você definiu no arquivo YAML. Talvez seja necessário rolar horizontalmente para ver todos eles.

    Screenshot of Azure Pipelines that shows the pipeline run stages.

  3. Aguarde até que o pipeline pause antes da fase Implantar (Ambiente de Produção). Pode levar alguns minutos para o pipeline chegar a esse ponto.

    Screenshot of Azure Pipelines that shows the pipeline run paused for approval.

  4. Aprove a implantação para o ambiente de produção selecionando o botão Examinar.

  5. Selecione o botão Aprovar.

    Screenshot of the Azure DevOps interface that shows the pipeline approval page and the Approve button.

    Aguarde até que o pipeline termine a execução.

  6. Selecione a guia Testes para mostrar os resultados de teste desta execução de pipeline.

    Observe que agora há quatro resultados de teste. O smoke test é executado nos ambientes de teste e de produção, para que você veja os resultados de ambos os conjuntos de testes.

    Screenshot of Azure Pipelines that shows the page for pipeline run tests, with four test results.

  7. Selecione Pipelines>Ambientes.

  8. Selecione o ambiente de Produção.

  9. Observe que, na tela de detalhes do ambiente, haverá uma visão geral do histórico de implantação do ambiente de produção.

    Screenshot of Azure Pipelines that shows the production environment, with the deployment history showing a single deployment.

  10. Selecione a implantação e selecione a guia Alterações.

    Observe que a guia Alterações mostra a lista de confirmações incluídas na implantação. Essa informação ajuda você a ver exatamente o que mudou em seu ambiente ao longo do tempo.

    Screenshot of Azure Pipelines that shows the production environment's deployment details, with a list of commits.

  11. No navegador, acesse o portal do Azure.

  12. Vá para o grupo de recursos ToyWebsiteProduction.

  13. Na lista de recursos, abra o aplicativo Serviço de Aplicativo do Azure.

    Screenshot of the Azure portal that shows the production App Service app and the App Service plan SKU details.

    Observe que o tipo de plano do serviço de aplicativo é S1.

  14. Vá para o aplicativo Serviço de Aplicativo no grupo de recursos ToyWebsiteTest.

    Observe que o tipo de plano do serviço de aplicativo é F1. Os dois ambientes usam configurações diferentes, como você definiu em seu arquivo Bicep.