練習 - 將多個環境新增至您的管線

已完成

現在您已準備好更新管線,以同時部署至測試環境和生產環境。 在本單元中,您會更新管線以使用範本,以便在不同環境間重複使用階段。

在此過程中,您將會:

  • 為 lint 階段新增管線範本。
  • 新增管線範本,以定義要部署至任何環境所需要的階段。
  • 更新管線以使用範本。
  • 執行管線並檢視結果。

為 lint 階段新增管線範本

不論管線部署到多少環境,系統都只會在管線執行期間執行一次 lint 階段。 因此,您不必真的使用 lint 階段的範本。 但為了讓主要管線的定義檔保持簡單且容易閱讀的狀態,您決定在範本中定義 lint 階段。

  1. 在 Visual Studio Code中,於 deploy 資料夾內建立名為 pipeline-templates 的新資料夾。

  2. 在名為 lint.ymlpipeline-templates 資料夾中建立新檔案。

    Visual Studio Code [總管] 的螢幕擷取畫面,其中顯示 [pipeline-templates] 資料夾和 lint 點 YML 檔案。

  3. 將下列管線範本定義貼到該檔案中:

    jobs:
    - job: LintCode
      displayName: Lint code
      steps:
        - script: |
            az bicep build --file deploy/main.bicep
          name: LintBicepCode
          displayName: Run Bicep linter
    

    此 lint 階段與管線中既存的 lint 階段相同,但現在位於不同的管線範本檔案中。

  4. 儲存變更並關閉該檔案。

新增用於部署的管線範本

建立管線範本,以定義要部署每個環境所需的所有階段。 您使用範本參數來指定在不同環境之間可能不同的設定。

  1. 在名為 deploy.ymlpipeline-templates 資料夾中建立新檔案。

    Visual Studio Code [總管] 的螢幕擷取畫面,其中顯示 [pipeline-templates] 資料夾和部署點 YML 檔案。

    此檔案會呈現針對您每個環境執行的所有部署活動。

  2. 將下列管線範本參數貼到該檔案中:

    parameters:
    - name: environmentType
      type: string
    - name: resourceGroupName
      type: string
    - name: serviceConnectionName
      type: string
    - name: deploymentDefaultLocation
      type: string
      default: westus3
    

    注意

    當您開始在 Visual Studio Code 中使用 YAML 檔案時,您可能會看到一些紅色波浪線來指出有問題存在。 這是因為 YAML 檔案的 Visual Studio Code 延伸模組有時會猜錯檔案的結構描述。

    您可以忽略延伸模組所報告的問題。 或者,如果您想要的話,也可以在檔案頂端新增下列程式碼,以隱藏擴充功能的猜測:

    # yaml-language-server: $schema=./deploy.yml
    
  3. 在參數下方,貼上驗證階段的定義:

    stages:
    
    - ${{ if ne(parameters.environmentType, 'Production') }}:
      - stage: Validate_${{parameters.environmentType}}
        displayName: Validate (${{parameters.environmentType}} Environment)
        jobs:
        - job: ValidateBicepCode
          displayName: Validate Bicep code
          steps:
            - task: AzureResourceManagerTemplateDeployment@3
              name: RunPreflightValidation
              displayName: Run preflight validation
              inputs:
                connectedServiceName: ${{parameters.serviceConnectionName}}
                location: ${{parameters.deploymentDefaultLocation}}
                deploymentMode: Validation
                resourceGroupName: ${{parameters.resourceGroupName}}
                csmFile: deploy/main.bicep
                overrideParameters: >
                  -environmentType ${{parameters.environmentType}}
    

    請注意,這個階段有適用的條件。 其只會針對非生產環境來執行。

    另請注意,階段識別碼包含 environmentType 參數的值。 此參數可確保管線中的每個階段都有唯一識別碼。 此階段也有 displayName 屬性,可建立易讀格式的名稱。

  4. 在驗證階段下方,貼上預覽階段的定義:

    - ${{ if eq(parameters.environmentType, 'Production') }}:
      - stage: Preview_${{parameters.environmentType}}
        displayName: Preview (${{parameters.environmentType}} Environment)
        jobs:
        - job: PreviewAzureChanges
          displayName: Preview Azure changes
          steps:
            - task: AzureCLI@2
              name: RunWhatIf
              displayName: Run what-if
              inputs:
                azureSubscription: ${{parameters.serviceConnectionName}}
                scriptType: 'bash'
                scriptLocation: 'inlineScript'
                inlineScript: |
                  az deployment group what-if \
                    --resource-group ${{parameters.resourceGroupName}} \
                    --template-file deploy/main.bicep \
                    --parameters environmentType=${{parameters.environmentType}}
    

    請注意,此階段也有適用的條件,但與驗證階段的條件相反。 預覽階段只會針對生產環境來執行。

  5. 在預覽階段下方,貼上部署階段的定義:

    - stage: Deploy_${{parameters.environmentType}}
      displayName: Deploy (${{parameters.environmentType}} Environment)
      jobs:
      - deployment: DeployWebsite
        displayName: Deploy website
        environment: ${{parameters.environmentType}}
        strategy:
          runOnce:
            deploy:
              steps:
                - checkout: self
    
                - task: AzureResourceManagerTemplateDeployment@3
                  name: DeployBicepFile
                  displayName: Deploy Bicep file
                  inputs:
                    connectedServiceName: ${{parameters.serviceConnectionName}}
                    deploymentName: $(Build.BuildNumber)
                    location: ${{parameters.deploymentDefaultLocation}}
                    resourceGroupName: ${{parameters.resourceGroupName}}
                    csmFile: deploy/main.bicep
                    overrideParameters: >
                      -environmentType ${{parameters.environmentType}}
                    deploymentOutputs: deploymentOutputs
    
                - bash: |
                    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)
    
  6. 在部署階段下方,貼上煙霧測試階段的定義:

    - 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'
    

    請注意,當 appServiceAppHostName 變數定義所指的是發佈了主機名稱的階段時,其中便會納入 environmentType 參數。 此參數可確保每個煙霧測試階段都會針對正確的環境來執行。

  7. 確認 deploy.yml 檔案現在看起來像下列範例:

    parameters:
    - name: environmentType
      type: string
    - name: resourceGroupName
      type: string
    - name: serviceConnectionName
      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
          steps:
            - task: AzureResourceManagerTemplateDeployment@3
              name: RunPreflightValidation
              displayName: Run preflight validation
              inputs:
                connectedServiceName: ${{parameters.serviceConnectionName}}
                location: ${{parameters.deploymentDefaultLocation}}
                deploymentMode: Validation
                resourceGroupName: ${{parameters.resourceGroupName}}
                csmFile: deploy/main.bicep
                overrideParameters: >
                  -environmentType ${{parameters.environmentType}}
    
    - ${{ if eq(parameters.environmentType, 'Production') }}:
      - stage: Preview_${{parameters.environmentType}}
        displayName: Preview (${{parameters.environmentType}} Environment)
        jobs:
        - job: PreviewAzureChanges
          displayName: Preview Azure changes
          steps:
            - task: AzureCLI@2
              name: RunWhatIf
              displayName: Run what-if
              inputs:
                azureSubscription: ${{parameters.serviceConnectionName}}
                scriptType: 'bash'
                scriptLocation: 'inlineScript'
                inlineScript: |
                  az deployment group what-if \
                    --resource-group ${{parameters.resourceGroupName}} \
                    --template-file deploy/main.bicep \
                    --parameters environmentType=${{parameters.environmentType}}
    
    - stage: Deploy_${{parameters.environmentType}}
      displayName: Deploy (${{parameters.environmentType}} Environment)
      jobs:
      - deployment: DeployWebsite
        displayName: Deploy website
        environment: ${{parameters.environmentType}}
        strategy:
          runOnce:
            deploy:
              steps:
                - checkout: self
    
                - task: AzureResourceManagerTemplateDeployment@3
                  name: DeployBicepFile
                  displayName: Deploy Bicep file
                  inputs:
                    connectedServiceName: ${{parameters.serviceConnectionName}}
                    deploymentName: $(Build.BuildNumber)
                    location: ${{parameters.deploymentDefaultLocation}}
                    resourceGroupName: ${{parameters.resourceGroupName}}
                    csmFile: deploy/main.bicep
                    overrideParameters: >
                      -environmentType ${{parameters.environmentType}}
                    deploymentOutputs: deploymentOutputs
    
                - bash: |
                    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)
    
    - 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'
    
  8. 儲存對檔案所做的變更。

更新管線定義以使用範本

  1. 開啟 azure-pipelines.yml 檔案。

  2. 將檔案的內容取代為下列程式碼,以更新檔案來使用新的範本:

    trigger:
      batch: true
      branches:
        include:
        - main
    
    pool:
      vmImage: ubuntu-latest
    
    stages:
    
    # Lint the Bicep file.
    - stage: Lint
      jobs: 
      - template: pipeline-templates/lint.yml
    
    # Deploy to the test environment.
    - template: pipeline-templates/deploy.yml
      parameters:
        environmentType: Test
        resourceGroupName: ToyWebsiteTest
        serviceConnectionName: ToyWebsiteTest
    
    # Deploy to the production environment.
    - template: pipeline-templates/deploy.yml
      parameters:
        environmentType: Production
        resourceGroupName: ToyWebsiteProduction
        serviceConnectionName: ToyWebsiteProduction
    

    此管線會執行 lint 階段一次。 然後,會使用 deploy.yml 範本檔案兩次:每個環境使用一次。 這可讓管線定義變得清楚且容易理解。 此外,註解會有助於說明發生了什麼情況。

  3. 儲存您的變更。

  4. 在 Visual Studio Code 終端機中執行下列命令,以認可所做的變更,並將其推送至您的 Git 存放庫:

    git add .
    git commit -m "Add pipeline templates"
    git push
    

檢視管線執行

  1. 在您的瀏覽器中,移至 [管線]

  2. 選取管線的最近一次執行。

    請注意,管線執行現在會顯示您在 YAML 檔案中定義的所有階段。 您可能需要水平捲動才能看到完整內容。

    Azure Pipelines 的螢幕擷取畫面,其中顯示管線執行階段。

  3. 等候管線在部署 (實際執行環境) 階段之前暫停。 管線可能需要幾分鐘的時間才會進行到這邊。

    Azure Pipelines 的螢幕擷取畫面,其中顯示暫停以待核准的管線執行。

  4. 選取 [檢閱] 按鈕,以核准部署至生產環境。

  5. 選取 [核准] 按鈕。

    Azure DevOps 介面的螢幕擷取畫面,其中顯示管線核准頁面和 [核准] 按鈕。

    等候管線執行完成。

  6. 選取 [測試] 索引標籤,以顯示此管線執行的測試結果。

    請注意,現在有四個測試結果。 測試環境和生產環境都會執行煙霧測試,因此您會看到這兩組測試的結果。

    Azure Pipelines 的螢幕擷取畫面,其中顯示管線執行測試的頁面,並包含四個測試結果。

  7. 選取 [管線]>[環境]

  8. 選取 [生產] 環境。

  9. 請注意,在 [環境詳細資料] 畫面上,您會看到生產環境的部署歷程記錄概觀。

    Azure Pipelines 的螢幕擷取畫面,其中顯示實際執行環境,以及顯示單一部署的部署歷程記錄。

  10. 選取部署,然後選取 [變更] 索引標籤。

    請注意,[變更] 索引標籤會顯示部署中包含的認可清單。 此資訊可協助您確切地了解環境在各個時間的變化。

    Azure Pipelines 的螢幕擷取畫面,其中顯示實際執行環境的部署詳細資料,以及認可清單。

  11. 在瀏覽器中,移至 Azure 入口網站

  12. 移至 [ToyWebsiteProduction] 資源群組。

  13. 在資源清單中,開啟 Azure App Service 應用程式。

    Azure 入口網站的螢幕擷取畫面,其中顯示實際執行 App Service 應用程式與 App Service 方案 SKU 詳細資料。

    請注意,App Service 方案的類型為 S1

  14. 移至 [ToyWebsiteTest] 資源群組中的 App Service 應用程式。

    請注意,App Service 方案的類型為 [F1]。 這兩個環境會使用不同的設定 (如 Bicep 檔案中的定義)。