Exercice – Déployer une application web

Effectué

Dans votre entreprise de jouets, votre équipe de développement de site web a validé la dernière version du site web dans votre référentiel Git. Vous êtes maintenant prêt à mettre à jour votre workflow pour générer le site web et le déployer sur Azure App Service.

Pendant ce processus, vous allez :

  • Ajoutez un nouveau workflow appelé pour la tâche de génération.
  • Mettre à jour le workflow pour inclure le travail de génération.
  • Ajouter un nouveau test de détection de fumée.
  • Mettre à jour le travail de déploiement pour déployer l’application.
  • Exécutez le workflow.

Ajouter un workflow réutilisable pour le travail de génération

Ici, vous ajoutez une nouvelle définition de travail qui contient les étapes nécessaires à la génération de l’application de site web.

  1. Ouvrez Visual Studio Code.

  2. Créez un fichier dans le dossier .github/workflows nommé build.yml.

    Capture d’écran de l’Explorer Visual Studio Code, avec les dossiers github et de workflows, ainsi que le fichier build.yml.

  3. Ajoutez le contenu suivant au fichier de workflow 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
    

    Le travail installe le SDK .NET pour générer la solution. Il exécute ensuite une étape de génération pour transformer le code source de l’application de site web en un fichier compilé prêt à être exécuté dans Azure. Le travail compresse ensuite l’artefact compilé et le charge en tant qu’artefact de workflow.

  4. Enregistrez les modifications apportées au fichier.

Ajouter la tâche de génération au workflow

  1. Ouvrez le fichier workflow.yml.

  2. Sous la ligne jobs:, avant le travail lint, ajoutez un nouveau travail nommé build qui utilise le workflow réutilisable que vous venez de définir :

    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. Mettez à jour le travail deploy-test pour dépendre du nouveau travail 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. Mettez à jour le travail deploy-production pour qu’il dépende également des travaux build et 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 }}
    

    Étant donné que le déploiement de production dépend du déploiement de test, vous n’avez pas vraiment besoin de spécifier les dépendances. Toutefois, il est conseillé d’être explicite, afin d’éviter que votre workflow s’exécute de manière incorrecte si vous réorganisez ou supprimez vos travaux ou environnements.

    Notez que vous spécifiez la liste needs de deux manières différentes : les dépendances du déploiement de votre environnement de test sont répertoriées sur une seule ligne et votre environnement de production utilise une liste multiligne. Les deux approches sont équivalentes.

  5. Enregistrez les modifications apportées au fichier.

Mettre à jour le fichier de test de détection de fumée

Les développeurs du site web ont ajouté un point de terminaison d’intégrité au site web. Ce point de terminaison vérifie que le site web est en ligne et qu’il peut accéder à la base de données. Ici, vous ajoutez un nouveau test de détection de fumée pour appeler le contrôle d’intégrité à partir de votre workflow de déploiement.

  1. Ouvrez le fichier Website.Tests.ps1 dans le dossier deploy.

  2. Ajoutez un nouveau cas de test qui appelle le contrôle d’intégrité. Le cas de test échoue si le code de réponse n’est pas 200, valeur qui indique une réussite :

    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. Enregistrez les modifications apportées au fichier.

Ajouter la sortie au fichier Bicep

Vous allez bientôt ajouter une étape de déploiement qui publie votre site web sur Azure App Service. L’étape de publication requiert le nom de l’application App Service. Ici, vous exposez le nom de l’application en tant que sortie de votre fichier Bicep.

  1. Ouvrez le fichier main.bicep dans le dossier deploy.

  2. À la fin du contenu du fichier, ajoutez le nom de l’application App Service comme sortie :

    output appServiceAppName string = appServiceApp.name
    output appServiceAppHostName string = appServiceApp.properties.defaultHostName
    
  3. Enregistrez les modifications apportées au fichier.

Mettre à jour le travail de déploiement pour propager la sortie

Maintenant, vous devez mettre à jour votre travail deply pour prendre la valeur de la sortie du déploiement Bicep et la rendre disponible pour le reste du workflow.

  1. Ouvrez le fichier deploy.yml dans le dossier .github/workflows.

  2. Dans la définition du travail deploy, ajoutez une nouvelle sortie pour appServiceAppName :

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

    Notes

    Quand vous commencez à travailler avec votre fichier YAML dans Visual Studio Code, vous pouvez voir des lignes ondulées rouges indiquant un problème. Il arrive en effet que l’extension Visual Studio Code pour les fichiers YAML devine de façon incorrecte le schéma du fichier.

    Vous pouvez ignorer les problèmes signalés par l’extension. Sinon, si vous préférez, vous pouvez ajouter le code suivant en haut du fichier pour supprimer la recherche de l’extension :

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

Ajouter un travail pour déployer le site web

  1. Sous la définition du travail deploy, et au-dessus de la définition du travail smoke-test, définissez un nouveau travail pour déployer le site web sur App Service :

    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
    

    Notes

    Soyez vigilant avec la mise en retrait du fichier YAML et veillez à ce que le nouveau travail soit mis en retrait au même niveau que le travail deploy. Si vous n’êtes pas sûr, copiez l’intégralité du contenu du fichier deploy.yml à partir de l’exemple figurant à l’étape suivante.

    Notez que le travail dépend du travail deploy quand vous utilisez le mot clé needs. Cette dépendance garantit que le site web n’est pas déployé tant que l’infrastructure n’est pas prête. Il permet également au travail d’accéder à la sortie appServiceAppName du travail deploy.

    Notez également que ce travail comprend des étapes permettant de télécharger les artefacts de workflow et de se connecter à Azure. Chaque travail s’exécute sur son propre exécuteur et doit donc être autonome.

  2. Enregistrez les modifications apportées au fichier.

Vérifier le contenu du fichier deploy.yml et valider vos modifications

  1. Vérifiez que votre fichier deploy.yml ressemble à l’exemple suivant :

    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. Enregistrez les modifications apportées au fichier.

  3. Dans le terminal Visual Studio Code, validez et envoyez (push) vos modifications dans votre dépôt Git en exécutant les commandes suivantes :

    git add .
    git commit -m "Build and deploy website application"
    git push
    
  4. C’est votre premier envoi (push) vers ce dépôt et vous pouvez donc être invité à vous connecter.

    Sur Windows, tapez 1 pour vous authentifier à l’aide d’un navigateur web, puis sélectionnez Entrée.

    Sur macOS, sélectionnez Autoriser.

  5. Une fenêtre de navigateur s’affiche. Vous devrez peut-être vous reconnecter à GitHub. Sélectionnez Autoriser.

Exécuter le workflow

  1. Dans votre navigateur, accédez à Actions.

    La première exécution de votre workflow, appelée commit initial, est signalée comme ayant échoué. GitHub a automatiquement exécuté le workflow quand vous avez créé le dépôt. L’exécution a échoué en raison des secrets qui n’étaient pas prêts à ce moment-là. Vous pouvez ignorer cet échec.

  2. Sélectionnez le workflow deploy-toy-website-end-to-end.

  3. Sélectionnez l’exécution la plus récente de votre workflow.

  4. Attendez que le travail Générer se termine avec succès.

    Capture d’écran de GitHub montrant l’exécution des travaux du workflow.

  5. Attendez que le travail deploy-test/deploy se termine correctement.

    Certains avertissements sont listés dans le panneau Annotations. Tous ces avertissements sont dus à la façon dont Bicep écrit des messages d’information dans le journal du workflow. Vous pouvez ignorer ces avertissements.

  6. Le workflow exécute ensuite le travail deploy-test/smoke-test, mais le test de détection de fumée échoue :

    Capture d’écran de GitHub qui affiche le travail de test de détection de fumée de l’exécution de workflow pour l’environnement de test. L’état indique que le travail a échoué.

  7. Sélectionnez le travail de deploy-test/smoke-test pour ouvrir le journal du workflow.

  8. Sélectionnez l’étape Effectuer des tests de détection de fumée pour consulter la section associée du journal de workflow :

    Capture d’écran de GitHub montrant le journal d’exécution du workflow, avec la sortie du test de détection de fumée affichée. Le résultat du test d’intégrité JSON est mis en surbrillance.

    Notez que le journal de workflow indique que le site web et la configuration ne sont pas intègres. Il y a un problème avec la communication de l’application avec Azure SQL Database. Vous n’avez pas encore déployé ni configuré de base de données, ce qui explique pourquoi le site web ne peut pas y accéder. Vous allez résoudre ce problème bientôt.