تمرين - توزيع تطبيق ويب
في شركة اللُعب الخاصة بك، التزم فريق تطوير موقع الويب الخاص بك بأحدث إصدار من موقع الويب في مستودع Git الخاص بك. أنت الآن جاهز لتحديث سير العمل الخاص بك لإنشاء موقع الويب ونشره في Azure App Service.
في أثناء العملية، ستقوم بما يلي:
- أضف سير عمل يسمى جديد لوظيفة البناء.
- حدّث سير العمل ليشمل وظيفة البناء.
- أضف اختبار BVT جديداً.
- حدّث وظيفة التوزيع لتوزيع التطبيق.
- تشغيل سير العمل.
أضف سير عمل يمكن إعادة استخدامه لوظيفة البناء
هنا، تقوم بإضافة تعريف وظيفة جديد يحتوي على الخطوات المطلوبة لإنشاء تطبيق الموقع.
فتح Visual Studio Code.
في مجلد .github/workflows، أنشئ ملفًا جديدًا باسم build.yml.
أضف المحتوى التالي إلى ملف مسار العمل 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. تقوم الوظيفة بعد ذلك بضغط الأداة المترجمة وتحميلها كأداة لسير العمل.
حفظ التغييرات الخاصة بك على الملف.
أضف وظيفة البناء إلى سير العمل
افتح ملف workflow.yml.
ضمن سطر الوظائف: قبل وظيفة 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
قم بتحديث وظيفة اختبار التوزيع للاعتماد على وظيفة الإنشاء الجديدة:
# 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 }}
قم بتحديث وظيفة توزيع الإنتاج لتعتمد أيضا على وظائف الإنشاء والوبر.
# 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
بطريقتين مختلفتين- تبعيات توزيع بيئة الاختبار الخاصة بك مدرجة في سطر واحد، وبيئة التشغيل الخاصة بك باستخدام قائمة متعددة الأسطر. والنهجان متكافئان.حفظ التغييرات الخاصة بك على الملف.
تحديث ملف اختبار BVT
أضاف مطورو موقع الويب نقطة نهاية صحية إلى موقع الويب. تتحقق نقطة النهاية هذه من أن موقع الويب متصل بالإنترنت وأنه يمكنه الوصول إلى قاعدة البيانات. هنا، تقوم بإضافة اختبار دخان جديد لاستدعاء الفحص الصحي من سير عمل التوزيع الخاص بك.
افتح ملف Website.Tests.ps1 في المجلد publish.
أضف حالة اختبار جديدة تستدعي فحص السلامة. تفشل حالة الاختبار إذا لم يكن رمز الاستجابة 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" } }
حفظ التغييرات الخاصة بك على الملف.
إضافة الإخراج إلى ملف Bicep
ستضيف قريباً خطوة توزيع لتقوم بنشر موقع الويب الخاص بك إلى Azure App Service. تتطلب خطوة النشر اسم تطبيق App Service. هنا، تقوم بفضح اسم التطبيق كمخرج من ملف Bicep الخاص بك.
افتح الملف main.bicep في المجلد publish.
في نهاية محتويات الملف، أضف اسم تطبيق App Service كمخرج:
output appServiceAppName string = appServiceApp.name output appServiceAppHostName string = appServiceApp.properties.defaultHostName
حفظ التغييرات الخاصة بك على الملف.
حدّث مهمة التوزيع لتوزيع الإخراج
الآن، تحتاج إلى تحديث مهمة التوزيع الخاصة بك لأخذ قيمة الإخراج من توزيع Bicep وإتاحته لبقية سير العمل.
افتح ملف deploy.yml في مجلد .github/workflows.
في تعريف وظيفة التوزيع، أضف مخرجات جديدة إلى
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
أضف وظيفة لتوزيع الموقع
ضمن تعريف وظيفة التوزيع، وفوق تعريف وظيفة اختبار الدخان، حدد وظيفة جديدة لتوزيع موقع الويب على خدمة التطبيقات:
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. تعمل كل وظيفة على مشغّل خاص بها، لذا يجب أن تكون قائمة بذاتها.
حفظ التغييرات الخاصة بك على الملف.
تحقق من محتويات ملف publish.yml، وتنفيذ التغييرات الخاصة بك
تحقق من أن ملف 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
حفظ التغييرات الخاصة بك على الملف.
في الوحدة الطرفية لـ Visual Studio Code، قم بتنفيذ التغييرات ودفعها إلى مستودع Git الخاص بك عن طريق تشغيل الأوامر التالية:
git add . git commit -m "Build and deploy website application" git push
هذه هي المرة الأولى التي تدفع فيها إلى هذا المستودع، لذلك قد يُطلب منك تسجيل الدخول.
في Windows، اكتب 1 للمصادقة باستخدام متصفح ويب، وحدد إدخال.
في «macOS»، حدد Authorize.
تظهر نافذة متصفح. قد تحتاج إلى تسجيل الدخول إلى «GitHub» مرة أخرى. قم بتحديد تخويل.
تشغيل سير العمل
في متصفحك، انتقل إلى Actions.
يظهر أول تشغيل لسير العمل الخاص بك، المسمى Initial commitكفشل. تشغل GitHub سير العمل تلقائيا عند إنشاء المستودع. لقد فشلت لأن الأسرار لم تكن جاهزة في ذلك الوقت. يمكنك تجاهل هذا الفشل.
حدد سير العمل deploy-toy-website-end-to-end.
حدد أحدث تشغيل لسير العمل الخاص بك.
انتظر حتى تنتهي مهمة البناء بنجاح.
انتظر حتى تنتهي وظيفة توزيع الاختبار/التوزيع بنجاح.
يتم سرد بعض التحذيرات في لوحة Annotations. كافة هذه التحذيرات بسبب طريقة Bicep يكتب رسائل إعلامية إلى سجل سير العمل. يمكنك تجاهل هذه التحذيرات.
يشغِّل سير العمل بعد ذلك وظيفة اختبار التوزيع/اختبار الدخان، ولكن يفشل اختبار الدخان:
حدد وظيفة اختبار التوزيع/اختبار الدخان لفتح سجل سير العمل.
حدد الخطوة تشغيل اختبارات الدخان لعرض المقطع المقترن من سجل سير العمل:
لاحظ أن سجل سير العمل يشير إلى أن موقع الويب والتكوين غير سليم. هناك مشكلة في اتصال التطبيق بقاعدة بيانات Azure SQL. لم تقم بعد بتوزيع قاعدة بيانات أو تكوينها، وهذا سبب عدم تمكن موقع الويب من الوصول إليها. ستصلح هذه المشكلة قريبا.