Esercizio - Distribuire un'applicazione Web

Completato

Nell'azienda di giocattoli, il team di sviluppo di siti Web ha eseguito il commit della versione più recente del sito Web nel repository Git. È ora possibile aggiornare il flusso di lavoro per compilare il sito Web e distribuirlo nel Servizio app di Azure.

Operazioni che verranno eseguite durante il processo:

  • Aggiungere un nuovo flusso di lavoro denominato per il processo di compilazione.
  • Aggiornare il flusso di lavoro per includere il processo di compilazione.
  • Aggiungere un nuovo smoke test.
  • Aggiornare il processo di distribuzione per distribuire l'applicazione.
  • Eseguire il flusso di lavoro.

Aggiungere un flusso di lavoro riutilizzabile per il processo di compilazione

In questo caso si aggiunge una nuova definizione del processo che contiene i passaggi necessari per compilare l'applicazione del sito Web.

  1. Aprire Visual Studio Code.

  2. Creare un nuovo file denominato build.yml nella cartella .github/workflows.

    Screenshot di Esplora risorse di Visual Studio Code con le cartelle .github e workflows e il file build.yml visualizzati.

  3. Aggiungere il contenuto seguente al file del flusso di lavoro 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
    

    Il processo installa .NET SDK per compilare la soluzione. Esegue quindi un passaggio di compilazione per trasformare il codice sorgente dell'applicazione del sito Web in un file compilato pronto per l'esecuzione in Azure. Il processo comprime poi l'artefatto compilato e lo carica come artefatto del flusso di lavoro.

  4. Salvare le modifiche apportate al file .

Aggiungere il processo di compilazione al flusso di lavoro

  1. Aprire il file workflow.yml.

  2. Sotto la riga processi: e prima del processo linting aggiungere un nuovo processo denominato compilazione che usa il flusso di lavoro riutilizzabile appena definito:

    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. Aggiornare il processo deploy-test in modo che dipenda dal nuovo processo di compilazione:

    # 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. Aggiornare il processo di distribuzione e produzione in modo da dipendere anche dai processi di compilazione 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 }}
    

    Poiché la distribuzione di produzione dipende dalla distribuzione di test, non è strettamente necessario specificare le dipendenze. È tuttavia consigliabile essere espliciti, per evitare che il flusso di lavoro venga eseguito in modo errato se si riordinano o rimuovono i processi o gli ambienti.

    Si noti che si specifica l'elenco needs in due modi diversi: le dipendenze della distribuzione dell'ambiente di test sono elencate in una sola riga e quelle dell'ambiente di produzione tramite un elenco su più righe. I due approcci sono equivalenti.

  5. Salvare le modifiche apportate al file.

Aggiornare il file di smoke test

Gli sviluppatori del sito Web hanno aggiunto un endpoint di integrità al sito Web. Questo endpoint verifica che il sito Web sia online e che possa raggiungere il database. In questo caso si aggiunge un nuovo smoke test per richiamare il controllo di integrità dal flusso di lavoro di distribuzione.

  1. Aprire il file Website.Tests.ps1 nella cartella deploy.

  2. Aggiungere un nuovo test case che richiama il controllo di integrità. Il test case ha esito negativo se il codice di risposta è diverso da 200, che indica l'esito positivo:

    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. Salvare le modifiche apportate al file.

Aggiungere l'output al file Bicep

Si aggiungerà presto un passaggio di distribuzione che pubblica il sito Web nel Servizio app di Azure. Il passaggio di pubblicazione richiede il nome dell'app del Servizio app. Si espone quindi il nome dell'app come output del file Bicep.

  1. Aprire il file main.bicep nella cartella deploy.

  2. Alla fine del contenuto del file aggiungere il nome dell'app del Servizio app come output:

    output appServiceAppName string = appServiceApp.name
    output appServiceAppHostName string = appServiceApp.properties.defaultHostName
    
  3. Salvare le modifiche apportate al file .

Aggiornare il processo di distribuzione per propagare l'output

A questo punto, è necessario aggiornare il processo di distribuzione per accettare il valore dell'output dalla distribuzione Bicep e renderlo disponibile per il resto del flusso di lavoro.

  1. Aprire il file deploy.yml nella cartella .github/workflows.

  2. Nella definizione del processo di distribuzione aggiungere un nuovo output per appServiceAppName:

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

    Nota

    Quando si inizia a usare il file YAML in Visual Studio Code, è possibile che vengano visualizzate alcune righe ondulate rosse che segnalano un problema. Ciò è dovuto al fatto che l'estensione Visual Studio Code per i file YAML talvolta ipotizza in modo errato lo schema del file.

    È possibile ignorare i problemi segnalati dall'estensione. In alternativa, se lo si desidera è possibile aggiungere il codice seguente all'inizio del file per evitare che l'estensione venga ipotizzata:

    # yaml-language-server: $schema=./deploy.yml
    

Aggiungere un processo per distribuire il sito Web

  1. Sotto la definizione del processo di distribuzione e sopra la definizione del processo smoke test definire un nuovo processo per distribuire il sito Web in Servizio app:

    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
    

    Nota

    Prestare attenzione ai rientri del file YAML, assicurandosi che il rientro del nuovo processo sia allo stesso livello del processo deploy. Se non si è sicuri, copiare l'intero contenuto del file deploy.yml dall'esempio nel passaggio successivo.

    Si noti che il processo dipende dal processo di distribuzione usando la parola chiave needs. Questa dipendenza garantisce che il sito Web non venga distribuito finché l'infrastruttura non è pronta. Ciò consente inoltre al processo di accedere all'output appServiceAppName del processo di distribuzione.

    Si noti anche che questo processo include passaggi per scaricare gli artefatti del flusso di lavoro e accedere ad Azure. Ogni processo viene eseguito nel proprio strumento di esecuzione, quindi deve essere autonomo.

  2. Salvare le modifiche apportate al file .

Verificare il contenuto del file deploy.yml ed eseguire il commit delle modifiche

  1. Verificare che il file deploy.yml sia simile all'esempio seguente:

    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. Salvare le modifiche apportate al file.

  3. Nel terminale di Visual Studio Code eseguire il commit e il push delle modifiche nel repository Git usando i comandi seguenti:

    git add .
    git commit -m "Build and deploy website application"
    git push
    
  4. Questa è la prima volta che si esegue il push in questo repository, quindi è possibile che venga richiesto di accedere.

    In Windows digitare 1 per eseguire l'autenticazione usando un Web browser e premere INVIO.

    In macOS selezionare Autorizza.

  5. Verrà visualizzata una finestra del browser. Potrebbe essere necessario accedere di nuovo a GitHub. Seleziona Autorizza.

Eseguire il flusso di lavoro

  1. Nel browser passare ad Azioni.

    La prima esecuzione del flusso di lavoro, denominata Initial commit, viene visualizzata come errore. GitHub ha eseguito automaticamente il flusso di lavoro al momento della creazione del repository. L'operazione non è riuscita perché i segreti non erano pronti in quel momento. È possibile ignorare questo errore.

  2. Selezionare il flusso di lavoro deploy-toy-website-end-to-end.

  3. Selezionare l'esecuzione più recente del flusso di lavoro.

  4. Attendere il completamento del processo di compilazione.

    Screenshot di GitHub che mostra i processi di esecuzione del flusso di lavoro.

  5. Attendere il corretto completamento del processo deploy-test / deploy.

    Alcuni avvisi sono elencati nel pannello Annotazioni. Tutti questi avvisi sono dovuti al modo in cui Bicep scrive i messaggi informativi nel log del flusso di lavoro. È possibile ignorare questi avvisi.

  6. Il flusso di lavoro esegue quindi il processo deploy-test / smoke-test ma lo smoke test ha esito negativo:

    Screenshot di GitHub che mostra il processo smoke test dell'esecuzione del flusso di lavoro per l'ambiente di test. Lo stato mostra che il processo ha avuto esito negativo.

  7. Selezionare il processo deploy-test / smoke-test per aprire il log del flusso di lavoro.

  8. Selezionare il passaggio Run smoke tests per visualizzare la sezione associata del log del flusso di lavoro:

    Screenshot di GitHub che mostra il log dell'esecuzione del flusso di lavoro, con l'output dello smoke test visualizzato. Il risultato del test di integrità JSON è evidenziato.

    Si noti che il log del flusso di lavoro indica che il sito Web e la configurazione non sono integri. Si è verificato un problema di comunicazione dell'applicazione con il database SQL di Azure. Non è stato ancora distribuito o configurato un database, motivo per cui il sito Web non può accedervi. Questo problema verrà risolto a breve.