演習 - パイプラインに複数の環境を追加する

完了

テスト環境と運用環境の両方にパイプラインをデプロイするために、パイプラインを更新する準備ができました。 このユニットでは、環境をまたいでステージを再利用できるようにするために、テンプレートを使用するようにパイプラインを更新します。

このプロセスでは、次のことを行います。

  • リント ステージのパイプライン テンプレートを追加します。
  • 任意の環境にデプロイするために必要なステージを定義するパイプライン テンプレートを追加します。
  • テンプレートを使用するようにパイプラインを更新します。
  • パイプラインを実行して結果を確認します。

リント ステージのパイプライン テンプレートを追加する

パイプラインがいくつの環境に対してデプロイされるかに関わりなく、リント ステージはパイプラインの実行中に一度だけ行われます。 そのため、リント ステージのテンプレートを使用することは必須ではありません。 ただし、主要なパイプライン定義ファイルをシンプルかつ読みやすいものにするため、リント ステージをテンプレートで定義することにします。

  1. Visual Studio Code で、deploy フォルダー内に pipeline-templates という名前の新しいフォルダーを作成します。

  2. pipeline-templates フォルダーで lint.yml という名前の新しいファイルを作成します。

    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
    

    このリント ステージはすでにパイプラインにあるリント ステージと同じですが、現在は別のパイプライン テンプレート ファイルに含まれます。

  4. 変更を保存し、ファイルを閉じます。

デプロイ用のパイプライン テンプレートを追加する

各環境をデプロイするのに必要なすべてのステージを定義するパイプライン テンプレートを作成します。 テンプレート パラメーターを使って、環境ごとに違う可能性のある設定を指定します。

  1. pipeline-templates フォルダーで、deploy.yml という名前の新しいファイルを作成します。

    Visual Studio Code エクスプローラーのスクリーンショット。pipeline-templates フォルダーと deploy.yml ファイルが表示されています。

    このファイルは、それぞれの環境に対して実行されたすべてのデプロイ アクティビティを示します。

  2. 次のパイプライン テンプレート パラメーターをファイルに貼り付けます。

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

    Note

    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
    

    このパイプラインは、リント ステージを一度実行します。 その後、deploy.yml テンプレート ファイルを 2 回使用します。環境ごとに 1 回です。 これにより、パイプラインの定義が明確で理解しやすいものになります。 また、コメントは状況を説明するのに役立ちます。

  3. 変更を保存します。

  4. Visual Studio Code ターミナルで次のコマンドを実行し、変更をコミットして Git リポジトリにプッシュします。

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

パイプライン実行を表示する

  1. ブラウザーで、[Pipelines] に移動します。

  2. パイプラインの最新の実行を選択します。

    パイプライン実行には、YAML ファイルで定義したすべてのステージが示されています。 すべてを確認するには水平方向にスクロールする必要があるかもしれません。

    パイプライン実行のステージを示す Azure Pipelines のスクリーンショット。

  3. デプロイ (運用環境) ステージの前に、パイプラインが一時停止するのを待ちます。 パイプラインがここに達するまでに数分かかることがあります。

    承認のためにパイプライン実行が一時停止されたことを示す Azure Pipelines のスクリーンショット。

  4. [Review](レビュー) ボタンを選択して、運用環境へのデプロイを承認します。

  5. [承認] ボタンを選択します。

    パイプライン承認ページと [承認] ボタンを示す Azure DevOps インターフェイスのスクリーンショット。

    パイプラインの実行が完了するまで待機します。

  6. [テスト] タブを選んで、パイプライン実行からのテスト結果を表示します。

    4 つのテスト結果が表示されます。 スモーク テストはテスト環境と運用環境の両方に対して実行されるため、両方のテストの結果が表示されます。

    4 つのテスト結果が表示されているパイプライン実行テストのページを示す Azure Pipelines のスクリーンショット。

  7. [Pipelines]>[環境] を選択します。

  8. [運用] 環境を選択します。

  9. 環境の詳細画面に、運用環境のデプロイ履歴の概要が表示されます。

    運用環境を示す Azure Pipelines のスクリーンショット。一度のデプロイを示すデプロイ履歴が表示されています。

  10. デプロイを選択して、[Changes](変更) タブを選択します。

    [Changes](変更) タブに、デプロイに含まれるコミットの一覧が表示されます。 この情報から、時間の経過とともに環境内で何が変更されたのかを正確に把握できます。

    コミットの一覧を含む、運用環境のデプロイの詳細を示す Azure Pipelines のスクリーンショット。

  11. ブラウザーで、Azure portal に移動します。

  12. ToyWebsiteProduction リソース グループに移動します。

  13. リソースの一覧で、Azure App Service アプリを開きます。

    運用環境の App Service アプリと App Service プランの SKU 詳細を示す Azure portal のスクリーンショット。

    App Service プランの種類は S1 です。

  14. ToyWebsiteTest リソース グループの App Service アプリに移動します。

    App Service プランの種類は F1 です。 Bicep ファイルで定義した通り、2 つの環境は異なる設定を使用します。