Ćwiczenie — wdrażanie aplikacji internetowej

Ukończone

W twojej firmie zajmującej się tworzeniem witryn internetowych zaangażował najnowszą wersję witryny internetowej do repozytorium Git. Teraz możesz zaktualizować przepływ pracy, aby skompilować witrynę internetową i wdrożyć go w usłudze aplikacja systemu Azure Service.

W tym procesie wykonasz następujące czynności:

  • Dodaj nowy nazywany przepływ pracy dla zadania kompilacji.
  • Zaktualizuj przepływ pracy, aby uwzględnić zadanie kompilacji.
  • Dodaj nowy test weryfikacyjny kompilacji.
  • Zaktualizuj zadanie wdrożenia, aby wdrożyć aplikację.
  • Uruchom przepływ pracy.

Dodawanie przepływu pracy wielokrotnego użytku dla zadania kompilacji

W tym miejscu dodasz nową definicję zadania zawierającą kroki wymagane do utworzenia aplikacji witryny internetowej.

  1. Otwórz Visual Studio Code.

  2. W folderze .github/workflows utwórz nowy plik o nazwie build.yml.

    Screenshot of Visual Studio Code Explorer, with the dot github and workflows folders and the build dot YML file shown.

  3. Dodaj następującą zawartość do pliku przepływu pracy 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
    

    Zadanie instaluje zestaw SDK platformy .NET w celu skompilowania rozwiązania. Następnie uruchamia krok kompilacji, aby przekształcić kod źródłowy aplikacji witryny internetowej w skompilowany plik gotowy do uruchomienia na platformie Azure. Zadanie następnie kompresuje skompilowany artefakt i przekazuje go jako artefakt przepływu pracy.

  4. Zapisz zmiany w pliku.

Dodawanie zadania kompilacji do przepływu pracy

  1. Otwórz plik workflow.yml.

  2. Poniżej zadań: wiersz przed zadaniem lint dodaj nowe zadanie o nazwie build, które używa właśnie zdefiniowanego przepływu pracy wielokrotnego użytku:

    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. Zaktualizuj zadanie deploy-test, aby zależeć od nowego zadania kompilacji:

    # 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. Zaktualizuj zadanie wdrażania produkcyjnego, aby również zależeć od zadań kompilacji i 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 }}
    

    Ponieważ wdrożenie produkcyjne zależy od wdrożenia testowego, nie trzeba ściśle określać zależności. Dobrym rozwiązaniem jest jednak uniknięcie nieprawidłowego uruchamiania przepływu pracy w przypadku zmiany kolejności lub usunięcia zadań lub środowisk.

    Zwróć uwagę, że lista jest określana needs na dwa różne sposoby — zależności wdrożenia środowiska testowego są wyświetlane w jednym wierszu, a środowisko produkcyjne przy użyciu listy wielowierszowej. Te dwa podejścia są równoważne.

  5. Zapisz zmiany w pliku.

Aktualizowanie pliku testu weryfikacyjnego kompilacji

Deweloperzy witryny internetowej dodali do witryny internetowej punkt końcowy kondycji. Ten punkt końcowy sprawdza, czy witryna internetowa jest w trybie online i czy może dotrzeć do bazy danych. W tym miejscu dodasz nowy test weryfikacyjny kompilacji w celu wywołania kontroli kondycji z przepływu pracy wdrażania.

  1. Otwórz plik Website.Tests.ps1 w folderze deploy.

  2. Dodaj nowy przypadek testowy, który wywołuje kontrolę kondycji. Przypadek testowy kończy się niepowodzeniem, jeśli kod odpowiedzi nie ma wartości 200, co oznacza powodzenie:

    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. Zapisz zmiany w pliku.

Dodawanie danych wyjściowych do pliku Bicep

Wkrótce dodasz krok wdrożenia, który publikuje witrynę internetową w usłudze aplikacja systemu Azure Service. Krok publikowania wymaga nazwy aplikacji usługi App Service. W tym miejscu uwidaczniasz nazwę aplikacji jako dane wyjściowe z pliku Bicep.

  1. Otwórz plik main.bicep w folderze deploy.

  2. Na końcu zawartości pliku dodaj nazwę aplikacji usługi App Service jako dane wyjściowe:

    output appServiceAppName string = appServiceApp.name
    output appServiceAppHostName string = appServiceApp.properties.defaultHostName
    
  3. Zapisz zmiany w pliku.

Aktualizowanie zadania wdrożenia w celu propagowania danych wyjściowych

Teraz należy zaktualizować zadanie wdrażania , aby pobrać wartość danych wyjściowych z wdrożenia Bicep i udostępnić je pozostałej części przepływu pracy.

  1. Otwórz plik deploy.yml w folderze .github/workflows.

  2. W definicji zadania wdrażania dodaj nowe dane wyjściowe dla elementu appServiceAppName:

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

    Uwaga

    Gdy zaczniesz pracować z plikiem YAML w programie Visual Studio Code, mogą pojawić się czerwone ziewione wiersze informujące o problemie. Dzieje się tak, ponieważ rozszerzenie programu Visual Studio Code dla plików YAML czasami niepoprawnie odgaduje schemat pliku.

    Możesz zignorować problemy zgłaszane przez rozszerzenie. Jeśli wolisz, możesz dodać następujący kod na początku pliku, aby pominąć odgadywanie rozszerzenia:

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

Dodawanie zadania w celu wdrożenia witryny internetowej

  1. Poniżej definicji zadania wdrażania i powyżej definicji zadania testu weryfikacyjnego kompilacji zdefiniuj nowe zadanie, aby wdrożyć witrynę internetową w usłudze 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
    

    Uwaga

    Zachowaj ostrożność przy użyciu wcięcia pliku YAML, upewniając się, że nowe zadanie jest wcięcie na tym samym poziomie co deploy zadanie. Jeśli nie masz pewności, skopiuj całą zawartość pliku deploy.yml z przykładu w następnym kroku.

    Zwróć uwagę, że zadanie zależy od zadania wdrażania przy użyciu słowa kluczowego needs . Ta zależność gwarantuje, że witryna internetowa nie zostanie wdrożona, dopóki infrastruktura nie będzie gotowa. Umożliwia również zadanie uzyskiwania dostępu do appServiceAppName danych wyjściowych z zadania wdrażania .

    Zwróć również uwagę, że to zadanie obejmuje kroki pobierania artefaktów przepływu pracy i logowania się na platformę Azure. Każde zadanie jest uruchamiane na własnym module uruchamiającym, więc musi być samodzielne.

  2. Zapisz zmiany w pliku.

Sprawdź zawartość pliku deploy.yml i zatwierdź zmiany

  1. Sprawdź, czy plik deploy.yml wygląda następująco:

    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. Zapisz zmiany w pliku.

  3. W terminalu programu Visual Studio Code zatwierdź i wypchnij zmiany do repozytorium Git, uruchamiając następujące polecenia:

    git add .
    git commit -m "Build and deploy website application"
    git push
    
  4. Jest to pierwsze wypchnięcie do tego repozytorium, więc może zostać wyświetlony monit o zalogowanie się.

    W systemie Windows wpisz 1 , aby uwierzytelnić się przy użyciu przeglądarki internetowej, a następnie wybierz klawisz Enter.

    W systemie macOS wybierz pozycję Autoryzuj.

  5. Pojawi się okno przeglądarki. Może być konieczne ponowne zalogowanie się do usługi GitHub. Wybierz pozycję Autoryzuj.

Uruchom przepływ pracy

  1. W przeglądarce przejdź do pozycji Akcje.

    Pierwszy przebieg przepływu pracy z etykietą Zatwierdzenie początkowe jest wyświetlany jako błąd. Usługa GitHub automatycznie uruchamiała przepływ pracy podczas tworzenia repozytorium. Nie powiodło się, ponieważ wpisy tajne nie były w tym czasie gotowe. Możesz zignorować ten błąd.

  2. Wybierz przepływ pracy deploy-toy-website-end.

  3. Wybierz najnowszy przebieg przepływu pracy.

  4. Poczekaj na pomyślne zakończenie zadania kompilacji .

    Screenshot of GitHub that shows the workflow run jobs.

  5. Poczekaj na pomyślne zakończenie zadania deploy-test/deploy .

    Niektóre ostrzeżenia są wyświetlane w panelu Adnotacje . Wszystkie te ostrzeżenia są spowodowane tym, że Bicep zapisuje komunikaty informacyjne w dzienniku przepływu pracy. Możesz zignorować te ostrzeżenia.

  6. Następnie przepływ pracy uruchamia zadanie deploy-test/smoke-test , ale test weryfikacyjny kompilacji kończy się niepowodzeniem:

    Screenshot of GitHub that shows the workflow run's smoke test job for the test environment. The status shows that the job has failed.

  7. Wybierz zadanie deploy-test/smoke-test, aby otworzyć dziennik przepływu pracy.

  8. Wybierz krok Uruchom testy weryfikacyjne kompilacji, aby wyświetlić skojarzona sekcja dziennika przepływu pracy:

    Screenshot of GitHub showing the workflow run log, with the output of the smoke test displayed. The JSON health test result is highlighted.

    Zwróć uwagę, że dziennik przepływu pracy wskazuje witrynę internetową i konfiguracja nie jest w dobrej kondycji. Wystąpił problem z komunikacją aplikacji z usługą Azure SQL Database. Nie wdrożono jeszcze ani nie skonfigurowano bazy danych, dlatego witryna internetowa nie może uzyskać do niej dostępu. Wkrótce rozwiążesz ten problem.