演習 - パイプラインにテスト ステージを追加する
あなたは、勤務先の玩具会社のセキュリティ チームから、あなたの Web サイトが HTTPS を使用した場合にのみアクセスできることを確認するように依頼されました。 この演習では、セキュリティ チームの要件が満たされているかどうかを確認するスモーク テストを実行するようにパイプラインを構成します。
このプロセスでは、次のことを行います。
- テスト スクリプトをリポジトリに追加します。
- パイプラインの定義を更新して、テスト ステージを追加します。
- パイプラインを実行して、テストが失敗することを確認します。
- Bicep ファイルを修正し、パイプラインが正常に実行されることを確認します。
テスト スクリプトを追加する
まず、テスト スクリプトを追加して、HTTPS が使用されているときに Web サイトにアクセス可能であり、セキュリティで保護されていない HTTP プロトコルが使用されている場合はアクセスできないかどうかを確認します。
Visual Studio Code で、 配置 フォルダーに新しいファイルを作成します。 ファイル名をWebsite.Tests.ps1にします。
次のテスト コードをファイルに貼り付けます。
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" } }このコードは Pester のテスト ファイルです。 これには、
$HostNameというパラメーターが必要です。 ホスト名に対して 2 つのテストを実行します。- HTTPS 経由で Web サイトへの接続を試します。 サーバーが HTTP 応答状態コード (接続成功を示す 200 ~ 299) で応答した場合、テストは成功します。
- HTTP 経由で Web サイトへの接続を試します。 サーバーから 300 以上の HTTP 応答状態コードが返される場合、テストは合格です。
この演習では、テスト ファイルの詳細とそのしくみを理解する必要はありません。 関心がある場合は、モジュールの概要に一覧表示されているリソースを確認して詳細を確認できます。
Bicep ファイルの出力をステージの出力変数として発行する
前のステップで作成したテスト スクリプトには、テストするホスト名が必要です。 Bicep ファイルには既に出力が含まれていますが、スモーク テストで使用する前に、ステージ出力変数として発行する必要があります。
Visual Studio Code で、配置フォルダー内のazure-pipelines.yml ファイルを開きます。
デプロイ ステージで、デプロイ 手順を更新して出力を変数に発行します。
name: DeployBicepFile displayName: Deploy Bicep file inputs: connectedServiceName: $(ServiceConnectionName) deploymentName: $(Build.BuildNumber) location: $(deploymentDefaultLocation) resourceGroupName: $(ResourceGroupName) csmFile: deploy/main.bicep overrideParameters: > -environmentType $(EnvironmentType) deploymentOutputs: deploymentOutputsデプロイ プロセスでは、以前と同じタスクが引き続き使用されますが、デプロイからの出力は、
deploymentOutputsという名前のパイプライン変数に格納されるようになりました。 出力変数は JSON として書式設定されます。JSON 形式の出力をパイプライン変数に変換するには、デプロイ手順の下の次のスクリプト ステップを追加します。
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)デプロイが正常に完了すると、スクリプトは Bicep デプロイから各出力値にアクセスします。 このスクリプトでは、
jqツールを使用し、JSON 出力の関連部分にアクセスします。 その後、Bicep デプロイ出力と同じ名前のステージ出力変数に値が発行されます。注意
Microsoft がホストする Azure Pipelines のエージェントにプレインストールされています。 スクリプト ステップでそれらを使用するために特別な操作を行う必要はありません。
ファイルを保存します。
パイプラインにスモーク テスト ステージを追加する
テストを実行するスモーク テスト ステージを追加できるようになりました。
ファイルの下部に、 SmokeTest ステージの次の定義を追加します。
jobs: - job: SmokeTest displayName: Smoke test variables: appServiceAppHostName: $[ stageDependencies.Deploy.DeployWebsite.outputs['DeployWebsite.SaveDeploymentOutputs.appServiceAppHostName'] ] steps:このコードではステージとジョブが定義されます。 また、
appServiceAppHostNameという名前のジョブに変数が作成されます。 この変数は、前のセクションで作成した出力変数から値を取得します。ファイルの下部で、次のステップ定義を SmokeTest ステージに追加します。
- 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このステップでは PowerShell スクリプトを実行し、Pester テスト ツールを使用して先ほど記述したテスト スクリプトを実行します。
ファイルの下部で、次のステップ定義を SmokeTest ステージに追加します。
name: PublishTestResults displayName: Publish test results condition: always() inputs: testResultsFormat: NUnit testResultsFiles: 'testResults.xml'このステップでは、Pester によって作成されるテスト結果ファイルを取得し、それをパイプライン テストの結果として発行します。 すぐに結果がどのように表示されるかが表示されます。
ステップ定義に
condition: always()が含まれていることに注目してください。 この状況では、前のステップが失敗した場合でも、常にテスト結果を発行する必要があることが Azure Pipelines に示されます。 テストが失敗するとテスト ステップが失敗し、通常は失敗したステップの後にパイプラインの実行が停止するため、この条件は重要です。ファイルを保存します。
パイプライン定義を確認してコミットする
azure-pipelines.yml ファイルが次のコードであることを確認します。
trigger: batch: true branches: include: - main pool: Dafault variables: - name: deploymentDefaultLocation value: westus3 stages: - stage: Lint jobs: - job: LintCode displayName: Lint code steps: - script: | az bicep build --file deploy/main.bicep name: LintBicepCode displayName: Run Bicep linter - stage: Validate jobs: - job: ValidateBicepCode displayName: Validate Bicep code steps: - task: AzureResourceManagerTemplateDeployment@3 name: RunPreflightValidation displayName: Run preflight validation inputs: connectedServiceName: $(ServiceConnectionName) location: $(deploymentDefaultLocation) deploymentMode: Validation resourceGroupName: $(ResourceGroupName) csmFile: deploy/main.bicep overrideParameters: > -environmentType $(EnvironmentType) - stage: Preview jobs: - job: PreviewAzureChanges displayName: Preview Azure changes steps: - task: AzureCLI@2 name: RunWhatIf displayName: Run what-if inputs: azureSubscription: $(ServiceConnectionName) scriptType: 'bash' scriptLocation: 'inlineScript' inlineScript: | az deployment group what-if \ --resource-group $(ResourceGroupName) \ --template-file deploy/main.bicep \ --parameters environmentType=$(EnvironmentType) - stage: Deploy jobs: - deployment: DeployWebsite displayName: Deploy website environment: Website strategy: runOnce: deploy: steps: - checkout: self - task: AzureResourceManagerTemplateDeployment@3 name: DeployBicepFile displayName: Deploy Bicep file inputs: connectedServiceName: $(ServiceConnectionName) deploymentName: $(Build.BuildNumber) location: $(deploymentDefaultLocation) resourceGroupName: $(ResourceGroupName) csmFile: deploy/main.bicep overrideParameters: > -environmentType $(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 jobs: - job: SmokeTest displayName: Smoke test variables: appServiceAppHostName: $[ stageDependencies.Deploy.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 "Add test stage" git push
パイプラインを実行してテスト結果を確認する
Azure DevOps で、パイプラインに移動します。
パイプラインの最新の実行を選択します。
パイプラインが Lint、 Validate、 Preview の各ステージを完了するまで待ちます。 Azure Pipelines は最新の状態でページを自動的に更新しますが、ページを時々更新することをお勧めします。
[ 確認 ] ボタンを選択し、[承認] を選択 します。
パイプラインの実行が終了するまで待ちます。
デプロイ ステージが正常に完了したことを確認します。 SmokeTest ステージはエラーで終了します。
[ テスト ] タブを選択します。
テストの概要に、2 つのテストが実行されたことが示されている点に注目してください。 1 つは成功し、もう 1 つは失敗しています。 失敗したテストは、 Toy Web サイトとして表示されます。HTTP 経由でページを提供しません。
このテキストは、Web サイトがセキュリティ チームの要件を満たすように正しく構成されていないことを示します。
Bicep ファイルを更新する
Bicep 定義がセキュリティ チームの要件を満たしていないことを確認したら、修正します。
Visual Studio Code で、配置フォルダー内の main.bicep ファイルを開きます。
Azure App Service アプリの定義を見つけて、
httpsOnlyセクションにpropertiesプロパティを含むように更新します。resource appServiceApp 'Microsoft.Web/sites@2022-03-01' = { name: appServiceAppName location: location properties: { serverFarmId: appServicePlan.id httpsOnly: true siteConfig: { appSettings: [ { name: 'APPINSIGHTS_INSTRUMENTATIONKEY' value: applicationInsights.properties.InstrumentationKey } { name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' value: applicationInsights.properties.ConnectionString } ] } } }ファイルを保存します。
Visual Studio Code ターミナルで次のコマンドを実行し、変更をコミットして Git リポジトリにプッシュします。
git add . git commit -m "Configure HTTPS on website" git push
もう一度パイプラインを実行する
ブラウザーでパイプラインに移動します。
最新の実行を選択します。
パイプラインが Lint、 Validate、 Preview の各ステージを完了するまで待ちます。 Azure Pipelines は最新の状態でページを自動的に更新しますが、ページを時々更新することをお勧めします。
プレビュー ステージを選択し、What-If の結果をもう一度確認します。
what-if コマンドによって、
httpsOnlyプロパティの値の変更が検出されていることに注目してください。Resource and property changes are indicated with these symbols: + Create ~ Modify = Nochange The deployment will update the following scope: Scope: /subscriptions/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e/resourceGroups/ToyWebsiteTest ~ Microsoft.Web/sites/toy-website-nbfnedv766snk [2021-01-15] + properties.siteConfig.localMySqlEnabled: false + properties.siteConfig.netFrameworkVersion: "v4.6" ~ properties.httpsOnly: false => true = Microsoft.Insights/components/toywebsite [2020-02-02] = Microsoft.Storage/storageAccounts/mystoragenbfnedv766snk [2021-04-01] = Microsoft.Web/serverfarms/toy-website [2021-01-15] Resource changes: 1 to modify, 3 no change.パイプラインの実行に戻ります。
[ 確認 ] ボタンを選択し、[ 承認] を選択します。
パイプラインの実行が終了するまで待ちます。
SmokeTest ステージを含め、パイプライン全体が正常に完了していることに注意してください。 この結果は、両方のテストが成功したことを示します。
リソースのクリーンアップ
これで演習が完了したので、課金されないようにリソースを削除しましょう。
Visual Studio Code ターミナルで、次のコマンドを実行します。
az group delete --resource-group ToyWebsiteTest --yes --no-wait
バックグラウンドでリソース グループが削除されます。
Remove-AzResourceGroup -Name ToyWebsiteTest -Force