練習 - 部署 Web 應用程式
在您的玩具公司,您的網站開發小組已向您的 Git 存放庫認可最新版的網站。 現在,您已準備好更新管線來建置網站,並將其部署至 Azure App Service。
在此程序中,您將執行下列工作:
- 新增建置作業的新管線範本。
- 更新管線以包括建置作業。
- 新增煙霧測試。
- 更新部署階段以部署應用程式。
- 執行管線。
新增建置作業的管線範本
新增包含建立網站應用程式所需步驟的新工作定義。
打開 Visual Studio Code。
在 deploy/pipeline-templates 資料夾中,建立名為 build.yml 的新檔案。
將下列內容新增至 build.yml 管線範本檔案:
jobs: - job: Build displayName: Build application and database pool: vmImage: windows-latest steps: # Build, copy, and publish the website. - task: DotNetCoreCLI@2 displayName: Build publishable website inputs: command: 'publish' publishWebProjects: true - task: CopyFiles@2 displayName: Copy publishable website inputs: sourceFolder: '$(Build.SourcesDirectory)/src/ToyCompany/ToyCompany.Website/bin' contents: '**/publish.zip' targetFolder: '$(Build.ArtifactStagingDirectory)/website' flattenFolders: true - task: PublishBuildArtifacts@1 displayName: Publish website as pipeline artifact inputs: pathToPublish: '$(Build.ArtifactStagingDirectory)/website' artifactName: 'website'
作業會執行建置步驟,將網站應用程式的原始程式碼轉換成準備好在 Azure 中執行的已編譯檔案。 作業接著會將編譯的成品複製到暫存資料夾,並將其發佈為管線成品。
儲存對檔案所做的變更。
重新命名第一個管線階段,並新增建置作業
開啟 [deploy] 資料夾中的 azure-pipelines.yml 檔案。
修改 Lint 階段。 將之重新命名為 Build,然後新增使用您所建立的 build.yml 管線範本的建置作業。
trigger: batch: true branches: include: - main pool: vmImage: ubuntu-latest stages: - stage: Build jobs: # Build the Visual Studio solution. - template: pipeline-templates/build.yml # Lint the Bicep file. - template: pipeline-templates/lint.yml # Deploy to the test environment. - template: pipeline-templates/deploy.yml parameters: environmentType: Test # Deploy to the production environment. - template: pipeline-templates/deploy.yml parameters: environmentType: Production
儲存對檔案所做的變更。
更新煙霧測試檔案
網站開發人員已將健康情況端點新增至網站。 此端點會檢查網站是否在線上,以及是否可以連線到資料庫。 在這裡,您會新增一個新的煙霧測試,以從您的部署管線叫用健康情況檢查。
開啟 [deploy] 資料夾中的 Website.Tests.ps1 檔案。
新增測試案例來叫用健康情況檢查。 如果回應碼不是 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 服務的部署步驟,但發佈步驟需要 App Service 應用程式的名稱。 在這裡,您會公開應用程式名稱作為 Bicep 檔案的輸出。
在 deploy 資料夾中開啟 main.bicep 檔案。
在檔案內容的結尾,新增 App Service 應用程式的名稱作為輸出。
output appServiceAppName string = appServiceApp.name output appServiceAppHostName string = appServiceApp.properties.defaultHostName
儲存對檔案所做的變更。
更新部署階段
開啟 deploy/pipeline-templates 資料夾中的 deploy.yml 檔案。
在 [Deploy] \(部署\) 階段部署作業的定義中 (接近第 59 行),將作業設定為使用 Windows 裝載的代理程式集區:
- stage: Deploy_${{parameters.environmentType}} displayName: Deploy (${{parameters.environmentType}} Environment) jobs: - deployment: DeployWebsite displayName: Deploy website pool: vmImage: windows-latest variables: - group: ToyWebsite${{parameters.environmentType}} environment: ${{parameters.environmentType}} strategy:
您稍後將新增以搭配資料庫使用的一些管線步驟,需要 Windows 作業系統才能執行。 您可以將不同的代理程式集區用於管線中的不同作業,因此其他作業會繼續使用 Ubuntu Linux 管線代理程式集區。
在 Deploy 作業的 SaveDeploymentOutputs 步驟中,新增具有 Bicep 部署輸出中應用程式名稱值的新管線變數:
- bash: | echo "##vso[task.setvariable variable=appServiceAppName]$(echo $DEPLOYMENT_OUTPUTS | jq -r '.appServiceAppName.value')" echo "##vso[task.setvariable variable=appServiceAppHostName;isOutput=true]$(echo $DEPLOYMENT_OUTPUTS | jq -r '.appServiceAppHostName.value')" name: SaveDeploymentOutputs displayName: Save deployment outputs into variables env: DEPLOYMENT_OUTPUTS: $(deploymentOutputs)
請注意,
appServiceAppHostName
變數已套用isOutput=true
屬性,因為該變數會用於煙霧測試階段。 變數appServiceAppName
會在相同的管線階段和作業中設定及使用。 因此,它不需要isOutput=true
設定。在部署作業內容結束時,新增將應用程式部署至 Azure App Service 的新步驟:
steps: - checkout: self - task: AzureResourceManagerTemplateDeployment@3 name: DeployBicepFile displayName: Deploy Bicep file inputs: connectedServiceName: ToyWebsite${{parameters.environmentType}} deploymentName: $(Build.BuildNumber) location: ${{parameters.deploymentDefaultLocation}} resourceGroupName: $(ResourceGroupName) csmFile: deploy/main.bicep overrideParameters: > -environmentType $(EnvironmentType) -reviewApiUrl $(ReviewApiUrl) -reviewApiKey $(ReviewApiKey) deploymentOutputs: deploymentOutputs - bash: | echo "##vso[task.setvariable variable=appServiceAppName]$(echo $DEPLOYMENT_OUTPUTS | jq -r '.appServiceAppName.value')" echo "##vso[task.setvariable variable=appServiceAppHostName;isOutput=true]$(echo $DEPLOYMENT_OUTPUTS | jq -r '.appServiceAppHostName.value')" name: SaveDeploymentOutputs displayName: Save deployment outputs into variables env: DEPLOYMENT_OUTPUTS: $(deploymentOutputs) - task: AzureRmWebAppDeployment@4 name: DeployWebsiteApp displayName: Deploy website inputs: appType: webApp ConnectionType: AzureRM azureSubscription: ToyWebsite${{parameters.environmentType}} ResourceGroupName: $(ResourceGroupName) WebAppName: $(appServiceAppName) Package: '$(Pipeline.Workspace)/website/publish.zip'
注意
請小心使用 YAML 檔案的縮排,確保新部署步驟在與
DeployBicepFile
步驟相同的層級縮排。 如果您不確定,請從下一個步驟中的範例複製整個 deploy.yml 檔案內容。請注意,您並未在管線定義中明確下載成品。 因為您使用部署作業,所以 Azure Pipelines 會自動為您下載成品。
確認 deploy.yml 檔案內容,並認可您的變更
確認 deploy.yml 檔案看起來像下列範例:
parameters: - name: environmentType type: string - name: deploymentDefaultLocation type: string default: westus3 stages: - ${{ if ne(parameters.environmentType, 'Production') }}: - stage: Validate_${{parameters.environmentType}} displayName: Validate (${{parameters.environmentType}} Environment) jobs: - job: ValidateBicepCode displayName: Validate Bicep code variables: - group: ToyWebsite${{parameters.environmentType}} steps: - task: AzureResourceManagerTemplateDeployment@3 name: RunPreflightValidation displayName: Run preflight validation inputs: connectedServiceName: ToyWebsite${{parameters.environmentType}} location: ${{parameters.deploymentDefaultLocation}} deploymentMode: Validation resourceGroupName: $(ResourceGroupName) csmFile: deploy/main.bicep overrideParameters: > -environmentType $(EnvironmentType) -reviewApiUrl $(ReviewApiUrl) -reviewApiKey $(ReviewApiKey) - ${{ if eq(parameters.environmentType, 'Production') }}: - stage: Preview_${{parameters.environmentType}} displayName: Preview (${{parameters.environmentType}} Environment) jobs: - job: PreviewAzureChanges displayName: Preview Azure changes variables: - group: ToyWebsite${{parameters.environmentType}} steps: - task: AzureCLI@2 name: RunWhatIf displayName: Run what-if inputs: azureSubscription: ToyWebsite${{parameters.environmentType}} scriptType: 'bash' scriptLocation: 'inlineScript' inlineScript: | az deployment group what-if \ --resource-group $(ResourceGroupName) \ --template-file deploy/main.bicep \ --parameters environmentType=$(EnvironmentType) \ reviewApiUrl=$(ReviewApiUrl) \ reviewApiKey=$(ReviewApiKey) - stage: Deploy_${{parameters.environmentType}} displayName: Deploy (${{parameters.environmentType}} Environment) jobs: - deployment: DeployWebsite displayName: Deploy website pool: vmImage: windows-latest variables: - group: ToyWebsite${{parameters.environmentType}} environment: ${{parameters.environmentType}} strategy: runOnce: deploy: steps: - checkout: self - task: AzureResourceManagerTemplateDeployment@3 name: DeployBicepFile displayName: Deploy Bicep file inputs: connectedServiceName: ToyWebsite${{parameters.environmentType}} deploymentName: $(Build.BuildNumber) location: ${{parameters.deploymentDefaultLocation}} resourceGroupName: $(ResourceGroupName) csmFile: deploy/main.bicep overrideParameters: > -environmentType $(EnvironmentType) -reviewApiUrl $(ReviewApiUrl) -reviewApiKey $(ReviewApiKey) deploymentOutputs: deploymentOutputs - bash: | echo "##vso[task.setvariable variable=appServiceAppName]$(echo $DEPLOYMENT_OUTPUTS | jq -r '.appServiceAppName.value')" echo "##vso[task.setvariable variable=appServiceAppHostName;isOutput=true]$(echo $DEPLOYMENT_OUTPUTS | jq -r '.appServiceAppHostName.value')" name: SaveDeploymentOutputs displayName: Save deployment outputs into variables env: DEPLOYMENT_OUTPUTS: $(deploymentOutputs) - task: AzureRmWebAppDeployment@4 name: DeployWebsiteApp displayName: Deploy website inputs: appType: webApp ConnectionType: AzureRM azureSubscription: ToyWebsite${{parameters.environmentType}} ResourceGroupName: $(ResourceGroupName) WebAppName: $(appServiceAppName) Package: '$(Pipeline.Workspace)/website/publish.zip' - stage: SmokeTest_${{parameters.environmentType}} displayName: Smoke Test (${{parameters.environmentType}} Environment) jobs: - job: SmokeTest displayName: Smoke test variables: appServiceAppHostName: $[ stageDependencies.Deploy_${{parameters.environmentType}}.DeployWebsite.outputs['DeployWebsite.SaveDeploymentOutputs.appServiceAppHostName'] ] steps: - task: PowerShell@2 name: RunSmokeTests displayName: Run smoke tests inputs: targetType: inline script: | $container = New-PesterContainer ` -Path 'deploy/Website.Tests.ps1' ` -Data @{ HostName = '$(appServiceAppHostName)' } Invoke-Pester ` -Container $container ` -CI - task: PublishTestResults@2 name: PublishTestResults displayName: Publish test results condition: always() inputs: testResultsFormat: NUnit testResultsFiles: 'testResults.xml'
儲存對檔案所做的變更。
在 Visual Studio Code 終端機中執行下列命令,以認可您所做的變更,並將其推送至您的 Git 存放庫:
git add . git commit -m "Build and deploy website application" git push
執行管線
在您的瀏覽器中,移至 [管線]。
選取管線的最近一次執行。
等候 [Build] \(建置\) 階段順利完成。
管線在執行驗證 (測試環境)階段之前暫停,因為管線需要權限才能使用階段所參考的變數群組。 您必須核准管線對變數群組的存取權,因為這是您第一次在此專案中執行管線。 當您再次執行管線時,您便不需要核准相同變數群組的存取權。
選取 [檢視]。
選取 [允許]。
選取 [允許]。
[Validate (Test Environment)] \(驗證 (測試環境)\) 階段已順利完成。
管線會繼續,且部署 (測試環境) 階段順利完成。 管線接著會執行 [Smoke Test (Test Environment)] \(煙霧測試 (測試環境)\) 階段,但是煙霧測試階段會失敗。
選取 [煙霧測試 (測試環境)] 階段來開啟管線記錄。
選取 [Run smoke tests] \(執行煙霧測試\) 步驟,以檢視管線記錄的相關聯區段。
請注意,管線記錄包括健康情況檢查回應。 回應表示應用程式與 Azure SQL Database 的通訊發生問題。 資料庫尚未部署或設定,因此無法供網站存取。 在下一個練習中,您會修正此設定問題。