Exercício – implantar um aplicativo Web

Concluído

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

Durante o processo, você vai:

  • Adicione um novo fluxo de trabalho chamado para a tarefa de compilação.
  • Atualize o fluxo de trabalho para incluir o trabalho de compilação.
  • Adicione um smoke test.
  • Atualize o trabalho de implantação para implantar o aplicativo.
  • Execute o fluxo de trabalho.

Adicionar um fluxo de trabalho reutilizável para a tarefa de compilação

Aqui, você adiciona uma definição de trabalho que contém as etapas necessárias para criar o aplicativo de site.

  1. Abra o Visual Studio Code.

  2. Na pasta .github/workflows, crie um novo arquivo chamado build.yml.

    Captura de tela do Visual Studio Code Explorer, com as pastas .github e .workflows e o arquivo .YML de compilação mostrado.

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

    name: build-website
    
    on:
      workflow_call:
    
    jobs:
      build-application:
        name: Build application
        runs-on: ubuntu-latest
        steps:
        - uses: actions/checkout@v3
    
        - name: Install .NET Core
          uses: actions/setup-dotnet@v3
          with:
            dotnet-version: 3.1
    
        - name: Build publishable website
          run: |
            dotnet publish --configuration Release
          working-directory: ./src/ToyCompany/ToyCompany.Website
    
        - name: Zip publishable website
          run: |
            zip -r publish.zip .
          working-directory: ./src/ToyCompany/ToyCompany.Website/bin/Release/netcoreapp3.1/publish
    
        - name: Upload website as workflow artifact
          uses: actions/upload-artifact@v3
          with:
            name: website
            path: ./src/ToyCompany/ToyCompany.Website/bin/Release/netcoreapp3.1/publish/publish.zip
    

    O trabalho instala o SDK do .NET para criar a solução. Ele 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. O trabalho compacta o artefato compilado e o carrega como um artefato de fluxo de trabalho.

  4. Salve as alterações no arquivo.

Adicionar o trabalho de compilação ao fluxo de trabalho

  1. Abra o arquivo workflow.yml.

  2. Abaixo da linha trabalhos:, antes do trabalho lint, adicione um novo trabalho chamado build que usa o fluxo de trabalho reutilizável que você acabou de definir:

    name: deploy-toy-website-end-to-end
    concurrency: toy-company
    
    on:
      push:
        branches:
          - main
      workflow_dispatch:
    
    permissions:
      id-token: write
      contents: read
    
    jobs:
    
      # Build the application and database.
      build:
        uses: ./.github/workflows/build.yml
    
      # Lint the Bicep file.
      lint:
        uses: ./.github/workflows/lint.yml
    
  3. Atualize o trabalho deploy-test para depender do novo trabalho de build:

    # Deploy to the test environment.
    deploy-test:
      uses: ./.github/workflows/deploy.yml
      needs: [build, lint]
      with:
        environmentType: Test
        resourceGroupName: ToyWebsiteTest
        reviewApiUrl: https://sandbox.contoso.com/reviews
      secrets:
        AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID_TEST }}
        AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
        AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
        reviewApiKey: ${{ secrets.REVIEW_API_KEY_TEST }}
    
  4. Atualize o trabalho deploy-production para também depender dos trabalhos built e lint.

    # Deploy to the production environment.
    deploy-production:
      uses: ./.github/workflows/deploy.yml
      needs:
      - lint
      - build
      - deploy-test
      with:
        environmentType: Production
        resourceGroupName: ToyWebsiteProduction
        reviewApiUrl: https://api.contoso.com/reviews
      secrets:
        AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID_PRODUCTION }}
        AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
        AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
        reviewApiKey: ${{ secrets.REVIEW_API_KEY_PRODUCTION }}
    

    Como a implantação de produção depende da implantação de teste, você não precisa especificar as dependências. Mas, é uma boa prática ser explícito, para evitar que o fluxo de trabalho seja executado incorretamente se você reordenar ou remover trabalhos ou ambientes.

    Observe que você está especificando a lista needs de duas maneiras diferentes: as dependências da implantação do ambiente de teste são listadas em uma única linha e seu ambiente de produção usando uma lista de várias linhas. As duas abordagens são equivalentes.

  5. Salve as alterações no arquivo.

Atualizar o arquivo de smoke test

Os desenvolvedores de site adicionaram um ponto de extremidade de integridade ao site. Esse ponto de extremidade verifica se o site está online e se ele pode acessar o banco de dados. Aqui, você adiciona um smoke test para invocar a verificação de integridade do seu fluxo de trabalho de implantação.

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

  2. Adicione um caso de teste que invoca a verificação de integridade. O caso de teste falhará se o código de resposta não for 200, o que indica êxito:

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

Adicionar saída ao arquivo Bicep

Em breve, você adicionará uma etapa de implantação que publica seu site no Serviço de Aplicativo do Azure. 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 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. Salve as alterações no arquivo.

Atualizar o trabalho de implantação para propagar a saída

Agora, você precisa atualizar seu trabalho de implantação para obter o valor da saída da implantação do Bicep e disponibilizá-lo para o restante do fluxo de trabalho.

  1. Abra o arquivo deploy.yml na pasta .github/workflows.

  2. Na definição do trabalho deploy, adicione uma nova saída para o appServiceAppName:

    deploy:
      needs: validate
      environment: ${{ inputs.environmentType }}
      runs-on: ubuntu-latest
      outputs:
        appServiceAppName: ${{ steps.deploy.outputs.appServiceAppName }}
        appServiceAppHostName: ${{ steps.deploy.outputs.appServiceAppHostName }}
      steps:
    

    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
    

Adicionar um trabalho para implantar o site

  1. Abaixo da definição de trabalho deploy e acima da definição de trabalho de smoke-test, defina um novo trabalho para implantar o site no Serviço de Aplicativo:

    deploy-website:
      needs: deploy
      environment: ${{ inputs.environmentType }}
      runs-on: ubuntu-latest
      steps:
      - uses: actions/download-artifact@v3
      - uses: azure/login@v1
        name: Sign in to Azure
        with:
          client-id: ${{ secrets.AZURE_CLIENT_ID }}
          tenant-id: ${{ secrets.AZURE_TENANT_ID }}
          subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
      - uses: azure/webapps-deploy@v2
        name: Deploy website
        with:
          app-name: ${{ needs.deploy.outputs.appServiceAppName }}
          package: website/publish.zip
    

    Observação

    Tenha cuidado com o recuo do arquivo YAML, garantindo que o novo trabalho seja recuado no mesmo nível que o trabalho deploy. Se você não tiver certeza, copie todo o conteúdo do arquivo deploy.yml do exemplo na próxima etapa.

    Observe que o trabalho depende do trabalho de deploy usando a palavra-chave needs. Essa dependência garante que o site não seja implantado até que a infraestrutura esteja pronta. Ele também permite que o trabalho acesse a saída appServiceAppName do trabalho deploy.

    Além disso, observe que esse trabalho inclui etapas para baixar os artefatos do fluxo de trabalho e para entrar no Azure. Cada trabalho é executado em seu próprio executor. Portanto, ele precisa ser independente.

  2. Salve as alterações no arquivo.

Verifique o conteúdo do arquivo deploy.yml e faça o commit de suas alterações

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

    name: deploy
    
    on:
      workflow_call:
        inputs:
          environmentType:
            required: true
            type: string
          resourceGroupName:
            required: true
            type: string
          reviewApiUrl:
            required: true
            type: string
        secrets:
          AZURE_CLIENT_ID:
            required: true
          AZURE_TENANT_ID:
            required: true
          AZURE_SUBSCRIPTION_ID:
            required: true
          reviewApiKey:
            required: true
    
    jobs:
      validate:
         runs-on: ubuntu-latest
         steps:
         - uses: actions/checkout@v3
         - uses: azure/login@v1
           name: Sign in to Azure
           with:
             client-id: ${{ secrets.AZURE_CLIENT_ID }}
             tenant-id: ${{ secrets.AZURE_TENANT_ID }}
             subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
         - if: inputs.environmentType != 'Production'
           uses: azure/arm-deploy@v1
           name: Run preflight validation
           with:
             deploymentName: ${{ github.run_number }}
             resourceGroupName: ${{ inputs.resourceGroupName }}
             template: ./deploy/main.bicep
             parameters: >
               environmentType=${{ inputs.environmentType }}
               reviewApiUrl=${{ inputs.reviewApiUrl }}
               reviewApiKey=${{ secrets.reviewApiKey }}
             deploymentMode: Validate
         - if: inputs.environmentType == 'Production'
           uses: azure/arm-deploy@v1
           name: Run what-if
           with:
             failOnStdErr: false
             resourceGroupName: ${{ inputs.resourceGroupName }}
             template: ./deploy/main.bicep
             parameters: >
               environmentType=${{ inputs.environmentType }}
               reviewApiUrl=${{ inputs.reviewApiUrl }}
               reviewApiKey=${{ secrets.reviewApiKey }}
             additionalArguments: --what-if
    
      deploy:
        needs: validate
        environment: ${{ inputs.environmentType }}
        runs-on: ubuntu-latest
        outputs:
          appServiceAppName: ${{ steps.deploy.outputs.appServiceAppName }}
          appServiceAppHostName: ${{ steps.deploy.outputs.appServiceAppHostName }}
        steps:
        - uses: actions/checkout@v3
        - uses: azure/login@v1
          name: Sign in to Azure
          with:
            client-id: ${{ secrets.AZURE_CLIENT_ID }}
            tenant-id: ${{ secrets.AZURE_TENANT_ID }}
            subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
        - uses: azure/arm-deploy@v1
          id: deploy
          name: Deploy Bicep file
          with:
            failOnStdErr: false
            deploymentName: ${{ github.run_number }}
            resourceGroupName: ${{ inputs.resourceGroupName }}
            template: ./deploy/main.bicep
            parameters: >
               environmentType=${{ inputs.environmentType }}
               reviewApiUrl=${{ inputs.reviewApiUrl }}
               reviewApiKey=${{ secrets.reviewApiKey }}
    
      deploy-website:
        needs: deploy
        environment: ${{ inputs.environmentType }}
        runs-on: ubuntu-latest
        steps:
        - uses: actions/download-artifact@v3
        - uses: azure/login@v1
          name: Sign in to Azure
          with:
            client-id: ${{ secrets.AZURE_CLIENT_ID }}
            tenant-id: ${{ secrets.AZURE_TENANT_ID }}
            subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
        - uses: azure/webapps-deploy@v2
          name: Deploy website
          with:
            app-name: ${{ needs.deploy.outputs.appServiceAppName }}
            package: website/publish.zip
    
      smoke-test:
        runs-on: ubuntu-latest
        needs: deploy
        steps:
        - uses: actions/checkout@v3
        - run: |
            $container = New-PesterContainer `
              -Path 'deploy/Website.Tests.ps1' `
              -Data @{ HostName = '${{needs.deploy.outputs.appServiceAppHostName}}' }
            Invoke-Pester `
              -Container $container `
              -CI
          name: Run smoke tests
          shell: pwsh
    
  2. Salve as alterações no arquivo.

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

    git add .
    git commit -m "Build and deploy website application"
    git push
    
  4. Essa é a primeira vez que você efetuou push desse repositório. Por isso, pode aparecer uma solicitação para entrar.

    No Windows, digite 1 para autenticar usando um navegador da Web e selecione Enter.

    No macOS, selecione Autorizar.

  5. Uma janela do navegador é exibida. Talvez seja necessário entrar no GitHub novamente. Selecione Autorizar.

Executar o fluxo de trabalho

  1. No navegador, acesse Ações.

    A primeira execução do fluxo de trabalho, Commit Inicial, é mostrada como uma falha. O GitHub executou automaticamente o fluxo de trabalho quando você criou o repositório. Ele falhou porque os segredos não estavam prontos naquele momento. Você pode ignorar essa falha.

  2. Selecione o fluxo de trabalho deploy-toy-website-end-to-end.

  3. Selecione a execução mais recente do fluxo de trabalho.

  4. Aguarde até que o trabalho build seja concluído com êxito.

    Captura de tela do GitHub que mostra os trabalhos de execução do fluxo de trabalho.

  5. Aguarde até que o trabalho deploy-test / deploy seja concluído com sucesso.

    Alguns avisos são listados no painel Anotações. Todos esses avisos são causados pela maneira como o Bicep grava mensagens informativas no log do fluxo de trabalho. Você pode ignorar esses avisos.

  6. O fluxo de trabalho executa o trabalho deploy-test / smoke-test, mas o smoke test falha:

    Captura de tela do GitHub que mostra o trabalho do smoke test da execução do fluxo de trabalho para o ambiente de teste. O status mostra que o trabalho falhou.

  7. Selecione o trabalho deploy-test / smoke-test para abrir o log do fluxo de trabalho.

  8. Selecione a etapa Executar smoke tests para exibir a seção associada do log do fluxo de trabalho:

    Captura de tela do GitHub mostrando o log de execução do fluxo de trabalho, com a saída do teste de aceitação do build exibida. O resultado do teste de integridade JSON está destacado.

    Observe que o log do fluxo de trabalho indica que o site e a configuração não estão íntegros. Ocorreu um problema com a comunicação do aplicativo com Banco de Dados SQL do Azure. Você ainda não implantou nem configurou um banco de dados, por isso, o site não pode acessá-lo. Esse problema será corrigido em breve.