تمرين - توزيع تطبيق ويب

مكتمل

في شركة اللُعب الخاصة بك، التزم فريق تطوير موقع الويب الخاص بك بأحدث إصدار من موقع الويب في مستودع Git الخاص بك. أنت الآن جاهز لتحديث سير العمل الخاص بك لإنشاء موقع الويب ونشره في Azure App Service.

في أثناء العملية، ستقوم بما يلي:

  • أضف سير عمل يسمى جديد لوظيفة البناء.
  • حدّث سير العمل ليشمل وظيفة البناء.
  • أضف اختبار BVT جديداً.
  • حدّث وظيفة التوزيع لتوزيع التطبيق.
  • تشغيل سير العمل.

أضف سير عمل يمكن إعادة استخدامه لوظيفة البناء

هنا، تقوم بإضافة تعريف وظيفة جديد يحتوي على الخطوات المطلوبة لإنشاء تطبيق الموقع.

  1. فتح Visual Studio Code.

  2. في مجلد .github/workflows، أنشئ ملفًا جديدًا باسم build.yml.

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

  3. أضف المحتوى التالي إلى ملف مسار العمل 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
    

    تقوم المهمة بتثبيت .NET SDK لبناء الحل. بعد ذلك، يتم تشغيل خطوة إنشاء لتحويل التعليمات البرمجية المصدر لتطبيق موقع الويب إلى ملف مترجم جاهز للتشغيل في Azure. تقوم الوظيفة بعد ذلك بضغط الأداة المترجمة وتحميلها كأداة لسير العمل.

  4. حفظ التغييرات الخاصة بك على الملف.

أضف وظيفة البناء إلى سير العمل

  1. افتح ملف workflow.yml.

  2. ضمن سطر الوظائف: قبل وظيفة lint، أضف وظيفة جديدة باسم build تستخدم سير العمل القابل لإعادة الاستخدام الذي حددته للتو:

    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. قم بتحديث وظيفة اختبار التوزيع للاعتماد على وظيفة الإنشاء الجديدة:

    # 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. قم بتحديث وظيفة توزيع الإنتاج لتعتمد أيضا على وظائف الإنشاء والوبر.

    # 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 }}
    

    نظرا لأن توزيع الإنتاج يعتمد على توزيع الاختبار، فلن تحتاج بدقة إلى تحديد التبعيات. ولكن من الجيد أن تكون صريحًا لتجنب تشغيل سير العمل بشكل غير صحيح إذا أعدت ترتيب أو إزالة وظائفك أو بيئاتك.

    لاحظ أنك تحدد القائمة needsبطريقتين مختلفتين- تبعيات توزيع بيئة الاختبار الخاصة بك مدرجة في سطر واحد، وبيئة التشغيل الخاصة بك باستخدام قائمة متعددة الأسطر. والنهجان متكافئان.

  5. حفظ التغييرات الخاصة بك على الملف.

تحديث ملف اختبار BVT

أضاف مطورو موقع الويب نقطة نهاية صحية إلى موقع الويب. تتحقق نقطة النهاية هذه من أن موقع الويب متصل بالإنترنت وأنه يمكنه الوصول إلى قاعدة البيانات. هنا، تقوم بإضافة اختبار دخان جديد لاستدعاء الفحص الصحي من سير عمل التوزيع الخاص بك.

  1. افتح ملف Website.Tests.ps1 في المجلد publish.

  2. أضف حالة اختبار جديدة تستدعي فحص السلامة. تفشل حالة الاختبار إذا لم يكن رمز الاستجابة 200، ما يشير إلى النجاح:

    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. حفظ التغييرات الخاصة بك على الملف.

إضافة الإخراج إلى ملف Bicep

ستضيف قريباً خطوة توزيع لتقوم بنشر موقع الويب الخاص بك إلى Azure App Service. تتطلب خطوة النشر اسم تطبيق App Service. هنا، تقوم بفضح اسم التطبيق كمخرج من ملف Bicep الخاص بك.

  1. افتح الملف main.bicep في المجلد publish.

  2. في نهاية محتويات الملف، أضف اسم تطبيق App Service كمخرج:

    output appServiceAppName string = appServiceApp.name
    output appServiceAppHostName string = appServiceApp.properties.defaultHostName
    
  3. حفظ التغييرات الخاصة بك على الملف.

حدّث مهمة التوزيع لتوزيع الإخراج

الآن، تحتاج إلى تحديث مهمة التوزيع الخاصة بك لأخذ قيمة الإخراج من توزيع Bicep وإتاحته لبقية سير العمل.

  1. افتح ملف deploy.yml في مجلد .github/workflows.

  2. في تعريف وظيفة التوزيع، أضف مخرجات جديدة إلى appServiceAppName:

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

    إشعار

    عند بدء العمل مع ملف YAML الخاص بك في Visual Studio Code، قد ترى بعض خطوط متعرج أحمر يخبرك أن هناك مشكلة. ويرجع ذلك إلى أن ملحق رمز Visual Studio لملفات YAML أحيانا تخمين غير صحيح لمخطط الملف.

    يمكنك تجاهل المشاكل التي تقارير الملحق. أو إذا كنت تفضل ذلك، يمكنك إضافة التعليمات البرمجية التالية إلى أعلى الملف لمنع تخمين الملحق:

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

أضف وظيفة لتوزيع الموقع

  1. ضمن تعريف وظيفة التوزيع، وفوق تعريف وظيفة اختبار الدخان، حدد وظيفة جديدة لتوزيع موقع الويب على خدمة التطبيقات:

    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
    

    إشعار

    كن حذرًا مع المسافة البادئة لملف YAML، مع التأكد من وضع مسافة بادئة للوظيفة الجديدة على مستوى الوظيفة deploy نفسه. إذا لم تكن متأكداً، فقم بنسخ محتويات ملف publish.yml بالكامل من المثال الموجود في الخطوة التالية.

    لاحظ أن الوظيفة تعتمد على مهمة التوزيع باستخدام الكلمة الأساسية needs. تضمن هذه التبعية عدم نشر موقع الويب حتى تصبح البنية الأساسية جاهزة. كما أنه يمكّن المهمة من الوصول إلى الإخراج appServiceAppName من مهمة التوزيع.

    لاحظ أيضًا أن هذه المهمة تتضمن خطوات لتنزيل عناصر سير العمل وتسجيل الدخول إلى Azure. تعمل كل وظيفة على مشغّل خاص بها، لذا يجب أن تكون قائمة بذاتها.

  2. حفظ التغييرات الخاصة بك على الملف.

تحقق من محتويات ملف publish.yml، وتنفيذ التغييرات الخاصة بك

  1. تحقق من أن ملف deploy.yml يبدو مثل المثال التالي:

    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. حفظ التغييرات الخاصة بك على الملف.

  3. في الوحدة الطرفية لـ Visual Studio Code، قم بتنفيذ التغييرات ودفعها إلى مستودع Git الخاص بك عن طريق تشغيل الأوامر التالية:

    git add .
    git commit -m "Build and deploy website application"
    git push
    
  4. هذه هي المرة الأولى التي تدفع فيها إلى هذا المستودع، لذلك قد يُطلب منك تسجيل الدخول.

    في Windows، اكتب 1 للمصادقة باستخدام متصفح ويب، وحدد إدخال.

    في «macOS»، حدد Authorize.

  5. تظهر نافذة متصفح. قد تحتاج إلى تسجيل الدخول إلى «GitHub» مرة أخرى. قم بتحديد تخويل.

تشغيل سير العمل

  1. في متصفحك، انتقل إلى Actions.

    يظهر أول تشغيل لسير العمل الخاص بك، المسمى Initial commitكفشل. تشغل GitHub سير العمل تلقائيا عند إنشاء المستودع. لقد فشلت لأن الأسرار لم تكن جاهزة في ذلك الوقت. يمكنك تجاهل هذا الفشل.

  2. حدد سير العمل deploy-toy-website-end-to-end.

  3. حدد أحدث تشغيل لسير العمل الخاص بك.

  4. انتظر حتى تنتهي مهمة البناء بنجاح.

    Screenshot of GitHub that shows the workflow run jobs.

  5. انتظر حتى تنتهي وظيفة توزيع الاختبار/التوزيع بنجاح.

    يتم سرد بعض التحذيرات في لوحة Annotations. كافة هذه التحذيرات بسبب طريقة Bicep يكتب رسائل إعلامية إلى سجل سير العمل. يمكنك تجاهل هذه التحذيرات.

  6. يشغِّل سير العمل بعد ذلك وظيفة اختبار التوزيع/اختبار الدخان، ولكن يفشل اختبار الدخان:

    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. حدد وظيفة اختبار التوزيع/اختبار الدخان لفتح سجل سير العمل.

  8. حدد الخطوة تشغيل اختبارات الدخان لعرض المقطع المقترن من سجل سير العمل:

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

    لاحظ أن سجل سير العمل يشير إلى أن موقع الويب والتكوين غير سليم. هناك مشكلة في اتصال التطبيق بقاعدة بيانات Azure SQL. لم تقم بعد بتوزيع قاعدة بيانات أو تكوينها، وهذا سبب عدم تمكن موقع الويب من الوصول إليها. ستصلح هذه المشكلة قريبا.