Exercício - Implantar um aplicativo Web

Concluído

Na sua empresa de brinquedos, sua equipe de desenvolvimento de sites comprometeu a versão mais recente do site com seu repositório Git. Agora, você está pronto para atualizar seu pipeline para criar o site e implantá-lo no Serviço de Aplicativo do Azure.

Nesse processo, você executa as seguintes tarefas:

  • Adicione um novo modelo de pipeline para o trabalho de compilação.
  • Atualize o pipeline para incluir o trabalho de compilação.
  • Adicione um novo teste de fumaça.
  • Atualize o estágio de implantação para implantar o aplicativo.
  • Executar o pipeline.

Adicionar um modelo de pipeline para o trabalho de compilação

Adicione uma nova definição de tarefa que contenha as etapas necessárias para criar o aplicativo de site.

  1. Abra o Visual Studio Code.

  2. Na pasta deploy/pipeline-templates, crie um novo arquivo chamado build.yml.

    Screenshot of Visual Studio Code Explorer, with the pipeline-templates folder and the 'build.yml' file shown.

  3. Adicione o seguinte conteúdo ao arquivo de modelo de pipeline build.yml :

    jobs:
    - job: Build
      displayName: Build application and database
      pool:
        vmImage: windows-latest
    
      steps:
    
      # Build, copy, and publish the website.
      - task: DotNetCoreCLI@2
        displayName: Build publishable website
        inputs:
          command: 'publish'
          publishWebProjects: true
    
      - task: CopyFiles@2
        displayName: Copy publishable website
        inputs:
          sourceFolder: '$(Build.SourcesDirectory)/src/ToyCompany/ToyCompany.Website/bin'
          contents: '**/publish.zip'
          targetFolder: '$(Build.ArtifactStagingDirectory)/website'
          flattenFolders: true
    
      - task: PublishBuildArtifacts@1
        displayName: Publish website as pipeline artifact
        inputs:
          pathToPublish: '$(Build.ArtifactStagingDirectory)/website'
          artifactName: 'website'
    

    O trabalho executa uma etapa de compilação para transformar o código-fonte do aplicativo de site em um arquivo compilado pronto para ser executado no Azure. Em seguida, o trabalho copia o artefato compilado para uma pasta de preparo temporária e o publica como um artefato de pipeline.

  4. Guarde as alterações ao ficheiro.

Renomeie o primeiro estágio de pipeline e adicione um trabalho de compilação

  1. Abra o arquivo azure-pipelines.yml na pasta deploy .

  2. Modifique o estágio Lint . Renomeie-o para Build e adicione um trabalho de compilação que use o modelo de pipeline build.yml que você criou.

    trigger:
      batch: true
      branches:
        include:
        - main
    
    pool:
      vmImage: ubuntu-latest
    
    stages:
    
    - stage: Build
      jobs:
      # Build the Visual Studio solution.
      - template: pipeline-templates/build.yml
    
      # Lint the Bicep file.
      - template: pipeline-templates/lint.yml
    
    # Deploy to the test environment.
    - template: pipeline-templates/deploy.yml
      parameters:
        environmentType: Test
    
    # Deploy to the production environment.
    - template: pipeline-templates/deploy.yml
      parameters:
        environmentType: Production
    
  3. Guarde as alterações ao ficheiro.

Atualizar o arquivo de teste de fumaça

Os desenvolvedores do site adicionaram um ponto de extremidade de integridade ao site. Este ponto de extremidade verifica se o site está online e se pode chegar ao banco de dados. Aqui, você adiciona um novo teste de fumaça para invocar a verificação de integridade do pipeline de implantação.

  1. Abra o arquivo Website.Tests.ps1 na pasta deploy .

  2. Adicione um novo caso de teste que invoque a verificação de integridade. O caso de teste falhará se o código de resposta não for 200, o que indica sucesso.

    param(
      [Parameter(Mandatory)]
      [ValidateNotNullOrEmpty()]
      [string] $HostName
    )
    
    Describe 'Toy Website' {
    
        It 'Serves pages over HTTPS' {
          $request = [System.Net.WebRequest]::Create("https://$HostName/")
          $request.AllowAutoRedirect = $false
          $request.GetResponse().StatusCode |
            Should -Be 200 -Because "the website requires HTTPS"
        }
    
        It 'Does not serves pages over HTTP' {
          $request = [System.Net.WebRequest]::Create("http://$HostName/")
          $request.AllowAutoRedirect = $false
          $request.GetResponse().StatusCode | 
            Should -BeGreaterOrEqual 300 -Because "HTTP is not secure"
        }
    
        It 'Returns a success code from the health check endpoint' {
          $response = Invoke-WebRequest -Uri "https://$HostName/health" -SkipHttpErrorCheck
          Write-Host $response.Content
          $response.StatusCode |
            Should -Be 200 -Because "the website and configuration should be healthy"
        }
    
    }
    
  3. Guarde as alterações ao ficheiro.

Adicionar saída ao arquivo Bicep

Você deseja adicionar uma etapa de implantação que publique seu site no Serviço de Aplicativo do Azure, mas a etapa de publicação requer o nome do aplicativo do Serviço de Aplicativo. Aqui, você expõe o nome do aplicativo como uma saída do seu arquivo Bicep.

  1. Abra o arquivo main.bicep na pasta deploy .

  2. No final do conteúdo do arquivo, adicione o nome do aplicativo do Serviço de Aplicativo como uma saída.

    output appServiceAppName string = appServiceApp.name
    output appServiceAppHostName string = appServiceApp.properties.defaultHostName
    
  3. Guarde as alterações ao ficheiro.

Atualizar estágio de implantação

  1. Abra o arquivo deploy.yml na pasta deploy/pipeline-templates .

  2. Na definição do trabalho de implantação do estágio Implantar (próximo à Linha 59), configure o trabalho para usar o pool de agentes hospedados do Windows:

    - stage: Deploy_${{parameters.environmentType}}
      displayName: Deploy (${{parameters.environmentType}} Environment)
      jobs:
      - deployment: DeployWebsite
        displayName: Deploy website
        pool:
          vmImage: windows-latest
        variables:
        - group: ToyWebsite${{parameters.environmentType}}
        environment: ${{parameters.environmentType}}
        strategy:
    

    Algumas das etapas de pipeline adicionadas posteriormente para trabalhar com seu banco de dados exigem que o sistema operacional Windows seja executado. Você pode usar diferentes pools de agentes para diferentes trabalhos em seu pipeline, para que os outros trabalhos continuem a usar o pool de agentes de pipeline do Ubuntu Linux.

  3. Na etapa SaveDeploymentOutputs do trabalho Deploy, adicione uma nova variável de pipeline com o valor do nome do aplicativo da saída da implantação do Bicep:

    - bash: |
        echo "##vso[task.setvariable variable=appServiceAppName]$(echo $DEPLOYMENT_OUTPUTS | jq -r '.appServiceAppName.value')"
        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)
    

    Observe que a appServiceAppHostName variável tem a isOutput=true propriedade aplicada a ela, porque essa variável é usada na etapa de teste de fumaça. A appServiceAppName variável é definida e usada no mesmo estágio e trabalho de pipeline. Então, ele não precisa da isOutput=true configuração.

  4. No final do Implantar conteúdo do trabalho, adicione uma nova etapa para implantar o aplicativo no Serviço de Aplicativo do Azure:

    steps:
      - checkout: self
    
      - task: AzureResourceManagerTemplateDeployment@3
        name: DeployBicepFile
        displayName: Deploy Bicep file
        inputs:
          connectedServiceName: ToyWebsite${{parameters.environmentType}}
          deploymentName: $(Build.BuildNumber)
          location: ${{parameters.deploymentDefaultLocation}}
          resourceGroupName: $(ResourceGroupName)
          csmFile: deploy/main.bicep
          overrideParameters: >
            -environmentType $(EnvironmentType)
            -reviewApiUrl $(ReviewApiUrl)
            -reviewApiKey $(ReviewApiKey)
          deploymentOutputs: deploymentOutputs
    
      - bash: |
          echo "##vso[task.setvariable variable=appServiceAppName]$(echo $DEPLOYMENT_OUTPUTS | jq -r '.appServiceAppName.value')"
          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)
    
      - task: AzureRmWebAppDeployment@4
        name: DeployWebsiteApp
        displayName: Deploy website
        inputs:
          appType: webApp
          ConnectionType: AzureRM
          azureSubscription: ToyWebsite${{parameters.environmentType}}
          ResourceGroupName: $(ResourceGroupName)
          WebAppName: $(appServiceAppName)
          Package: '$(Pipeline.Workspace)/website/publish.zip'
    

    Nota

    Tenha cuidado com o recuo do arquivo YAML, garantindo que a nova etapa de implantação seja recuada no mesmo nível da DeployBicepFile etapa. Se não tiver certeza, copie todo o conteúdo do arquivo deploy.yml do exemplo na próxima etapa.

    Observe que você não baixou explicitamente o artefato na definição de pipeline. Como você usa um trabalho de implantação, o Azure Pipelines baixa automaticamente o artefato para você.

Verifique o conteúdo do arquivo deploy.yml e confirme as alterações

  1. Verifique se o arquivo deploy.yml se parece com o exemplo a seguir:

    parameters:
    - name: environmentType
      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
          variables:
          - group: ToyWebsite${{parameters.environmentType}}
          steps:
            - task: AzureResourceManagerTemplateDeployment@3
              name: RunPreflightValidation
              displayName: Run preflight validation
              inputs:
                connectedServiceName: ToyWebsite${{parameters.environmentType}}
                location: ${{parameters.deploymentDefaultLocation}}
                deploymentMode: Validation
                resourceGroupName: $(ResourceGroupName)
                csmFile: deploy/main.bicep
                overrideParameters: >
                  -environmentType $(EnvironmentType)
                  -reviewApiUrl $(ReviewApiUrl)
                  -reviewApiKey $(ReviewApiKey)
    
    - ${{ if eq(parameters.environmentType, 'Production') }}:
      - stage: Preview_${{parameters.environmentType}}
        displayName: Preview (${{parameters.environmentType}} Environment)
        jobs:
        - job: PreviewAzureChanges
          displayName: Preview Azure changes
          variables:
          - group: ToyWebsite${{parameters.environmentType}}
          steps:
            - task: AzureCLI@2
              name: RunWhatIf
              displayName: Run what-if
              inputs:
                azureSubscription: ToyWebsite${{parameters.environmentType}}
                scriptType: 'bash'
                scriptLocation: 'inlineScript'
                inlineScript: |
                  az deployment group what-if \
                    --resource-group $(ResourceGroupName) \
                    --template-file deploy/main.bicep \
                    --parameters environmentType=$(EnvironmentType) \
                                 reviewApiUrl=$(ReviewApiUrl) \
                                 reviewApiKey=$(ReviewApiKey)
    
    - stage: Deploy_${{parameters.environmentType}}
      displayName: Deploy (${{parameters.environmentType}} Environment)
      jobs:
      - deployment: DeployWebsite
        displayName: Deploy website
        pool:
          vmImage: windows-latest
        variables:
        - group: ToyWebsite${{parameters.environmentType}}
        environment: ${{parameters.environmentType}}
        strategy:
          runOnce:
            deploy:
              steps:
                - checkout: self
    
                - task: AzureResourceManagerTemplateDeployment@3
                  name: DeployBicepFile
                  displayName: Deploy Bicep file
                  inputs:
                    connectedServiceName: ToyWebsite${{parameters.environmentType}}
                    deploymentName: $(Build.BuildNumber)
                    location: ${{parameters.deploymentDefaultLocation}}
                    resourceGroupName: $(ResourceGroupName)
                    csmFile: deploy/main.bicep
                    overrideParameters: >
                      -environmentType $(EnvironmentType)
                      -reviewApiUrl $(ReviewApiUrl)
                      -reviewApiKey $(ReviewApiKey)
                    deploymentOutputs: deploymentOutputs
    
                - bash: |
                    echo "##vso[task.setvariable variable=appServiceAppName]$(echo $DEPLOYMENT_OUTPUTS | jq -r '.appServiceAppName.value')"
                    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)
    
                - task: AzureRmWebAppDeployment@4
                  name: DeployWebsiteApp
                  displayName: Deploy website
                  inputs:
                    appType: webApp
                    ConnectionType: AzureRM
                    azureSubscription: ToyWebsite${{parameters.environmentType}}
                    ResourceGroupName: $(ResourceGroupName)
                    WebAppName: $(appServiceAppName)
                    Package: '$(Pipeline.Workspace)/website/publish.zip'
    
    - 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'
    
  2. Guarde as alterações ao ficheiro.

  3. No terminal do Visual Studio Code, confirme e envie suas alterações para o repositório Git executando os seguintes comandos:

    git add .
    git commit -m "Build and deploy website application"
    git push
    

Executar o pipeline

  1. No seu navegador, vá para Pipelines.

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

    Screenshot of Azure DevOps showing the pipeline run list. The latest pipeline run is highlighted.

    Aguarde até que o estágio Build termine com êxito.

    O pipeline pausa antes de executar o estágio Validar (Ambiente de Teste) porque o pipeline precisa de permissão para usar o grupo de variáveis ao qual o estágio se refere. Você precisa aprovar o acesso do pipeline ao grupo de variáveis, porque você está executando o pipeline neste projeto pela primeira vez. Ao executar o pipeline novamente, não é necessário aprovar o acesso ao mesmo grupo de variáveis.

  3. Selecione Exibir.

    Screenshot of Azure DevOps showing the pipeline run paused at the Validate stage. Permission is required to continue. The View button is highlighted.

  4. Selecione Permitir.

    Screenshot of Azure DevOps showing that the pipeline needs permission to use the ToyWebsiteTest variable group. The Permit button is highlighted.

  5. Selecione Permitir.

    Screenshot of Azure DevOps showing the permission confirmation interface. The Permit button is highlighted.

    O estágio Validar (Ambiente de Teste) é concluído com êxito.

    O pipeline continua e o estágio Implantar (Ambiente de Teste) é concluído com êxito. Em seguida, o pipeline executa o estágio de teste de fumaça (ambiente de teste), mas o estágio de teste de fumaça falha.

  6. Selecione o estágio Teste de fumaça (Ambiente de teste) para abrir o log do pipeline.

    Screenshot of Azure DevOps showing the pipeline run's Smoke Test stage for the test environment. The status shows that the stage failed.

  7. Selecione a etapa Executar testes de fumaça para exibir a seção associada do log de pipeline.

    Screenshot of Azure DevOps showing the pipeline run log, with the output of the smoke test displayed. The JSON health test result is highlighted.

    Observe que o log de pipeline inclui a resposta da verificação de integridade. A resposta indica que há um problema com a comunicação do aplicativo com o Banco de Dados SQL do Azure. O banco de dados ainda não está implantado ou configurado, e é por isso que o site não pode acessá-lo. No próximo exercício, corrija esse problema de configuração.