演習: ストレージ アカウントとデータベースをシード処理する
Web サイトのアプリケーションをビルドして Bicep ファイルで定義されている Azure App Service アプリにデプロイするようにワークフローを更新しました。ただし、データベースがまだ動作していないため、スモーク テスト ジョブが失敗しています。 このユニットでは、Azure SQL の新しい論理サーバーとデータベースをデプロイし、データベースのスキーマをビルドしてデプロイするようにワークフローを構成します。 また、チームが Web サイトを試すことができるように、ワークフローを更新してテスト環境用のサンプル製品データをいくつか追加します。
このプロセスでは、次のことを行います。
- BLOB コンテナーを Azure ストレージ アカウントに追加します。
- Azure SQL の論理サーバーとデータベースを追加します。
- データベース プロジェクトを DACPAC ファイルにビルドするようにビルド ジョブを更新する。
- Azure SQL の論理サーバーとデータベースに新しい変数とシークレットを追加する。
- 新しい変数とシークレットを使用するようにワークフローを更新する。
- DACPAC ファイルをデプロイするための新しいワークフロー ステップを追加する。
- ワークフローを実行して Web サイトを表示する。
ストレージ コンテナーを追加する
Bicep ファイルには既にストレージ アカウントが定義されていますが、BLOB コンテナーは定義されていません。 ここで、BLOB コンテナーを Bicep ファイルに追加します。 また、アプリケーションの構成設定を使用して、アプリケーションに対してストレージ アカウントと BLOB コンテナーの名前を指定します。 そうすることで、アプリはどのストレージ アカウントにアクセスするかを把握できます。
Visual Studio Code で、deploy フォルダーの main.bicep ファイルを開きます。
リソース名を定義する変数の下 (27 行目の近く) に、BLOB ストレージ コンテナーの名前の新しい変数定義を追加します。
var storageAccountImagesBlobContainerName = 'toyimages'
storageAccount
リソースを更新して BLOB コンテナーを定義します。resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = { name: storageAccountName location: location kind: 'StorageV2' sku: environmentConfigurationMap[environmentType].storageAccount.sku resource blobService 'blobServices' = { name: 'default' resource storageAccountImagesBlobContainer 'containers' = { name: storageAccountImagesBlobContainerName properties: { publicAccess: 'Blob' } } } }
アプリの
appSettings
プロパティを更新して 2 つの新しいアプリケーション設定を追加します。1 つはストレージ アカウント名用、もう 1 つは BLOB コンテナー名用です。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 } { name: 'ReviewApiUrl' value: reviewApiUrl } { name: 'ReviewApiKey' value: reviewApiKey } { name: 'StorageAccountName' value: storageAccount.name } { name: 'StorageAccountBlobEndpoint' value: storageAccount.properties.primaryEndpoints.blob } { name: 'StorageAccountImagesContainerName' value: storageAccount::blobService::storageAccountImagesBlobContainer.name } ] } } }
ファイルの内容の最後に、ストレージ アカウントと BLOB コンテナーの名前を公開するための新しい出力を追加します。
output storageAccountName string = storageAccount.name output storageAccountImagesBlobContainerName string = storageAccount::blobService::storageAccountImagesBlobContainer.name
ファイルに加えた変更を保存します。
変更を Git リポジトリにコミットしますが、まだプッシュしないでください。 Visual Studio Code ターミナルで、次のコマンドを実行します。
git add . git commit -m "Add storage container"
Azure SQL の論理サーバーとデータベースを追加します。
現時点では、Bicep ファイルは Azure SQL の論理サーバーもデータベースもデプロイしません。 このセクションでは、これらのリソースを Bicep ファイルに追加します。
main.bicep ファイルの先頭の近くの
reviewApiKey
パラメーターの下に、2 つの新しいパラメーターを追加します。@description('The administrator login username for the SQL server.') param sqlServerAdministratorLogin string @secure() @description('The administrator login password for the SQL server.') param sqlServerAdministratorLoginPassword string
リソース名を定義する変数の下に、Azure SQL の論理サーバーとデータベースの名前を定義するための新しい変数を追加します。
var sqlServerName = 'toy-website-${resourceNameSuffix}' var sqlDatabaseName = 'Toys'
今追加した変数の下に、アプリケーションがデータベースにアクセスするための接続文字列を作成する新しい変数を定義します。
// Define the connection string to access Azure SQL. var sqlDatabaseConnectionString = 'Server=tcp:${sqlServer.properties.fullyQualifiedDomainName},1433;Initial Catalog=${sqlDatabase.name};Persist Security Info=False;User ID=${sqlServerAdministratorLogin};Password=${sqlServerAdministratorLoginPassword};MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;'
注意
わかりやすくするために、アプリケーションでは管理者のログインとパスワードを使用してデータベースにアクセスします。 ただし、これは運用ソリューションには適していません。 App Service マネージド ID を使用してデータベースにアクセスし、アプリケーションが必要とする最小限のアクセス許可をマネージ ID に付与することをお勧めします。 このモジュールの [概要] ページの詳細情報へリンクします。
ファイルの内容の最後の近くの出力の上に、Azure SQL の論理サーバーとデータベースのリソースを追加します。
resource sqlServer 'Microsoft.Sql/servers@2022-05-01-preview' = { name: sqlServerName location: location properties: { administratorLogin: sqlServerAdministratorLogin administratorLoginPassword: sqlServerAdministratorLoginPassword } } resource sqlServerFirewallRule 'Microsoft.Sql/servers/firewallRules@2022-05-01-preview' = { parent: sqlServer name: 'AllowAllWindowsAzureIps' properties: { endIpAddress: '0.0.0.0' startIpAddress: '0.0.0.0' } } resource sqlDatabase 'Microsoft.Sql/servers/databases@2022-05-01-preview' = { parent: sqlServer name: sqlDatabaseName location: location sku: environmentConfigurationMap[environmentType].sqlDatabase.sku }
environmentConfigurationMap
変数を更新することで、データベースに使用する SKU を環境ごとに定義します。var environmentConfigurationMap = { Production: { appServicePlan: { sku: { name: 'S1' capacity: 1 } } storageAccount: { sku: { name: 'Standard_LRS' } } sqlDatabase: { sku: { name: 'Standard' tier: 'Standard' } } } Test: { appServicePlan: { sku: { name: 'F1' } } storageAccount: { sku: { name: 'Standard_GRS' } } sqlDatabase: { sku: { name: 'Standard' tier: 'Standard' } } } }
データベース接続文字列用の別のアプリ設定を App Service アプリに追加します。
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 } { name: 'ReviewApiUrl' value: reviewApiUrl } { name: 'ReviewApiKey' value: reviewApiKey } { name: 'StorageAccountName' value: storageAccount.name } { name: 'StorageAccountBlobEndpoint' value: storageAccount.properties.primaryEndpoints.blob } { name: 'StorageAccountImagesContainerName' value: storageAccount::blobService::storageAccountImagesBlobContainer.name } { name: 'SqlDatabaseConnectionString' value: sqlDatabaseConnectionString } ] } } }
ファイルの末尾に、Azure SQL 論理サーバーのホスト名とデータベースの名前を公開するための出力を追加します。
output appServiceAppName string = appServiceApp.name output appServiceAppHostName string = appServiceApp.properties.defaultHostName output storageAccountName string = storageAccount.name output storageAccountImagesBlobContainerName string = storageAccount::blobService::storageAccountImagesBlobContainer.name output sqlServerFullyQualifiedDomainName string = sqlServer.properties.fullyQualifiedDomainName output sqlDatabaseName string = sqlDatabase.name
ファイルに加えた変更を保存します。
データベース プロジェクトの新しいビルド ステップを追加する
Web サイト開発者は、Web サイト データベース テーブルをデプロイおよび構成するための Visual Studio データベース プロジェクトを準備済みです。 ここでは、データベース プロジェクトをビルドして DACPAC ファイルを作成し、それをワークフロー成果物としてアップロードするように、ワークフローの build 呼び出し先ワークフローを更新します。
.github/workflows フォルダーにある build.yml ファイルを開きます。
Visual Studio データベース プロジェクトをビルドし、生成された DACPAC ファイルをワークフロー成果物としてアップロードするために、build-database ジョブを追加します。
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 build-database: name: Build database runs-on: windows-latest steps: - uses: actions/checkout@v3 - name: Prepare MSBuild uses: microsoft/setup-msbuild@v1.1 - name: Build database project working-directory: ./src/ToyCompany/ToyCompany.Database run: MSBuild.exe ToyCompany.Database.sqlproj -property:Configuration=Release - name: Upload website as workflow artifact uses: actions/upload-artifact@v3 with: name: database path: ./src/ToyCompany/ToyCompany.Database/bin/Release/ToyCompany.Database.dacpac
build-database ジョブには Windows ランナーが使用されます。 現時点では、Visual Studio データベース プロジェクトが Windows オペレーティング システム上に作成されている必要があります。
ファイルに加えた変更を保存します。
シークレットを定義する
それぞれの環境に使用する Azure SQL 論理サーバーの管理者パスワードは安全に保存する必要があります。 ここでは、GitHub のシークレットを使用して情報を保護することにします。
ブラウザーで、[Settings] (設定)>[Secrets and variables] (シークレットと変数)>[Actions] (アクション) の順に移動します。
[New repository secret](新しいリポジトリのシークレット) ボタンを選択します。
シークレット名として「SQL_SERVER_ADMINISTRATOR_LOGIN_PASSWORD_TEST」を、その値として「SecurePassword!111」を入力します。
[Add secret](シークレットの追加) を選択します。
この手順を繰り返し、シークレット名に「SQL_SERVER_ADMINISTRATOR_LOGIN_PASSWORD_PRODUCTION」を、その値に「SecurePassword!999」を使用して、もう 1 つのシークレットを追加します。 [Add secret](シークレットの追加) を選択します。
シークレットと入力をワークフローに追加する
Visual Studio Code で、.github/workflows フォルダーにある deploy.yml ファイルを開きます。
ファイルの先頭に、
sqlServerAdministratorLogin
という名前の新しい入力と、sqlServerAdministratorLoginPassword
という名前の新しいシークレットを定義します。name: deploy on: workflow_call: inputs: environmentType: required: true type: string resourceGroupName: required: true type: string reviewApiUrl: required: true type: string sqlServerAdministratorLogin: required: true type: string secrets: AZURE_CLIENT_ID: required: true AZURE_TENANT_ID: required: true AZURE_SUBSCRIPTION_ID: required: true reviewApiKey: required: true sqlServerAdministratorLoginPassword: required: true
ファイルに加えた変更を保存します。
workflow.yml ファイルを開きます。
deploy-test の定義に
sqlServerAdministratorLogin
入力の値を定義し、sqlServerAdministratorLoginPassword
シークレットの値を伝達します。# 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 sqlServerAdministratorLogin: TestToyCompanyAdmin 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 }} sqlServerAdministratorLoginPassword: ${{ secrets.SQL_SERVER_ADMINISTRATOR_LOGIN_PASSWORD_TEST }}
運用環境の値を使用して、このプロセスを deploy-production の定義で繰り返します。
# 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 sqlServerAdministratorLogin: ToyCompanyAdmin 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 }} sqlServerAdministratorLoginPassword: ${{ secrets.SQL_SERVER_ADMINISTRATOR_LOGIN_PASSWORD_PRODUCTION }}
ファイルに加えた変更を保存します。
パラメーターの値と出力を追加する
sqlServerAdministratorLogin
と sqlServerAdministratorLoginPassword
の 2 つの新しい必須パラメーターが Bicep ファイルに追加されました。 ここでは、それらのパラメーターの値を、ワークフローの inputs と secrets から validate ジョブと deploy ジョブに伝達します。 さらに、Bicep デプロイの出力をジョブの出力に伝達します。
deploy.yml ファイルを開きます。
validate ジョブの Run preflight validation (プレフライト検証の実行) ステップを更新して、新しいパラメーターを追加します。
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 }} sqlServerAdministratorLogin=${{ inputs.sqlServerAdministratorLogin }} sqlServerAdministratorLoginPassword=${{ secrets.sqlServerAdministratorLoginPassword }} deploymentMode: Validate
"Run what-if (what-if の実行)" ステップを更新して、新しいパラメーターを追加します。
- 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 }} sqlServerAdministratorLogin=${{ inputs.sqlServerAdministratorLogin }} sqlServerAdministratorLoginPassword=${{ secrets.sqlServerAdministratorLoginPassword }} additionalArguments: --what-if
deploy ジョブの "Deploy Bicep file (Bicep ファイルのデプロイ)" ステップを更新して新しいパラメーターを追加します。
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 }} sqlServerAdministratorLogin=${{ inputs.sqlServerAdministratorLogin }} sqlServerAdministratorLoginPassword=${{ secrets.sqlServerAdministratorLoginPassword }}
deploy ジョブの定義に、Bicep ファイルの出力用の新しい出力を追加します。
deploy: needs: validate environment: ${{ inputs.environmentType }} runs-on: ubuntu-latest outputs: appServiceAppName: ${{ steps.deploy.outputs.appServiceAppName }} appServiceAppHostName: ${{ steps.deploy.outputs.appServiceAppHostName }} storageAccountName: ${{ steps.deploy.outputs.storageAccountName }} storageAccountImagesBlobContainerName: ${{ steps.deploy.outputs.storageAccountImagesBlobContainerName }} sqlServerFullyQualifiedDomainName: ${{ steps.deploy.outputs.sqlServerFullyQualifiedDomainName }} sqlDatabaseName: ${{ steps.deploy.outputs.sqlDatabaseName }}
データベース ジョブとデータ シード ジョブを追加する
このセクションでは、Web サイトのデータベース コンポーネントをデプロイするために必要なステップを定義します。 まず、ワークフローによって既にビルドされている DACPAC ファイルをデプロイするためのステップを追加します。 次に、データベースとストレージ アカウントにサンプル データを追加します。ただし、非運用環境でのみ使用されます。
deploy-website ジョブの下に、DACPAC ファイルをデプロイするための新しいジョブを追加します。
deploy-database: 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/sql-action@v1.2 name: Deploy DACPAC to database with: server-name: ${{ needs.deploy.outputs.sqlServerFullyQualifiedDomainName }} connection-string: ${{ format('Server={0};Initial Catalog={1};User Id={2};Password={3};', needs.deploy.outputs.sqlServerFullyQualifiedDomainName, needs.deploy.outputs.sqlDatabaseName, inputs.sqlServerAdministratorLogin, secrets.sqlServerAdministratorLoginPassword) }} dacpac-package: database/ToyCompany.Database.dacpac
追加したジョブと smoke-test ジョブの間に、データベースにサンプル データをシード処理するための新しいジョブを定義します。
seed-database: needs: - deploy - deploy-database environment: ${{ inputs.environmentType }} 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/sql-action@v1.2 name: Add test data to database with: server-name: ${{ needs.deploy.outputs.sqlServerFullyQualifiedDomainName }} connection-string: ${{ format('Server={0};Initial Catalog={1};User Id={2};Password={3};', needs.deploy.outputs.sqlServerFullyQualifiedDomainName, needs.deploy.outputs.sqlDatabaseName, inputs.sqlServerAdministratorLogin, secrets.sqlServerAdministratorLoginPassword) }} sql-file: 'deploy/sample-data/Toys.sql'
"Add test data to database (データベースへのテスト データの追加)" ステップには条件が適用されていることに注意してください。 つまり、非運用環境の場合にのみ実行されます。 この条件はジョブ全体にではなく、ステップに適用されるので、後続のジョブは環境の種類に関係なく、このジョブに依存することができます。
先ほど追加したジョブと smoke-test ジョブの間にもう 1 つジョブを定義します。Azure CLI を使用して、サンプル玩具の画像を BLOB コンテナーにアップロードするものです。
seed-storage-account: needs: deploy environment: ${{ inputs.environmentType }} 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/CLI@v1 name: Upload sample images with: inlineScript: | az storage blob upload-batch \ --account-name ${{ needs.deploy.outputs.storageAccountName }} \ --destination ${{ needs.deploy.outputs.storageAccountImagesBlobContainerName }} \ --source 'deploy/sample-data/toyimages'
azure/cli
アクションでは Linux を実行する必要があるため、このジョブでは Ubuntu ランナーが使用されていますが、前に定義したbuild-database
ジョブでは、Windows ランナーを使用してデータベース プロジェクトをビルドすることに注意してください。 このワークフローは、さまざまなオペレーティング システムを組み合わせて要件を実現する好例です。
スモーク テスト ジョブの依存関係を更新する
デプロイ ステップがすべて完了した後で実行されるように smoke-test ジョブの依存関係を更新します。
smoke-test: runs-on: ubuntu-latest needs: - deploy - deploy-website - deploy-database - seed-database - seed-storage-account 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
ファイルに加えた変更を保存します。
ファイルを確認して変更をコミットする
main.bicep ファイルが次のようになっていることを確認します。
@description('The location into which your Azure resources should be deployed.') param location string = resourceGroup().location @description('Select the type of environment you want to provision. Allowed values are Production and Test.') @allowed([ 'Production' 'Test' ]) param environmentType string @description('A unique suffix to add to resource names that need to be globally unique.') @maxLength(13) param resourceNameSuffix string = uniqueString(resourceGroup().id) @description('The URL to the product review API.') param reviewApiUrl string @secure() @description('The API key to use when accessing the product review API.') param reviewApiKey string @description('The administrator login username for the SQL server.') param sqlServerAdministratorLogin string @secure() @description('The administrator login password for the SQL server.') param sqlServerAdministratorLoginPassword string // Define the names for resources. var appServiceAppName = 'toy-website-${resourceNameSuffix}' var appServicePlanName = 'toy-website' var logAnalyticsWorkspaceName = 'workspace-${resourceNameSuffix}' var applicationInsightsName = 'toywebsite' var storageAccountName = 'mystorage${resourceNameSuffix}' var storageAccountImagesBlobContainerName = 'toyimages' var sqlServerName = 'toy-website-${resourceNameSuffix}' var sqlDatabaseName = 'Toys' // Define the connection string to access Azure SQL. var sqlDatabaseConnectionString = 'Server=tcp:${sqlServer.properties.fullyQualifiedDomainName},1433;Initial Catalog=${sqlDatabase.name};Persist Security Info=False;User ID=${sqlServerAdministratorLogin};Password=${sqlServerAdministratorLoginPassword};MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;' // Define the SKUs for each component based on the environment type. var environmentConfigurationMap = { Production: { appServicePlan: { sku: { name: 'S1' capacity: 1 } } storageAccount: { sku: { name: 'Standard_LRS' } } sqlDatabase: { sku: { name: 'Standard' tier: 'Standard' } } } Test: { appServicePlan: { sku: { name: 'F1' } } storageAccount: { sku: { name: 'Standard_GRS' } } sqlDatabase: { sku: { name: 'Standard' tier: 'Standard' } } } } resource appServicePlan 'Microsoft.Web/serverfarms@2022-03-01' = { name: appServicePlanName location: location sku: environmentConfigurationMap[environmentType].appServicePlan.sku } 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 } { name: 'ReviewApiUrl' value: reviewApiUrl } { name: 'ReviewApiKey' value: reviewApiKey } { name: 'StorageAccountName' value: storageAccount.name } { name: 'StorageAccountBlobEndpoint' value: storageAccount.properties.primaryEndpoints.blob } { name: 'StorageAccountImagesContainerName' value: storageAccount::blobService::storageAccountImagesBlobContainer.name } { name: 'SqlDatabaseConnectionString' value: sqlDatabaseConnectionString } ] } } } resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2022-10-01' = { name: logAnalyticsWorkspaceName location: location } resource applicationInsights 'Microsoft.Insights/components@2020-02-02' = { name: applicationInsightsName location: location kind: 'web' properties: { Application_Type: 'web' Request_Source: 'rest' Flow_Type: 'Bluefield' WorkspaceResourceId: logAnalyticsWorkspace.id } } resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = { name: storageAccountName location: location kind: 'StorageV2' sku: environmentConfigurationMap[environmentType].storageAccount.sku resource blobService 'blobServices' = { name: 'default' resource storageAccountImagesBlobContainer 'containers' = { name: storageAccountImagesBlobContainerName properties: { publicAccess: 'Blob' } } } } resource sqlServer 'Microsoft.Sql/servers@2022-05-01-preview' = { name: sqlServerName location: location properties: { administratorLogin: sqlServerAdministratorLogin administratorLoginPassword: sqlServerAdministratorLoginPassword } } resource sqlServerFirewallRule 'Microsoft.Sql/servers/firewallRules@2022-05-01-preview' = { parent: sqlServer name: 'AllowAllWindowsAzureIps' properties: { endIpAddress: '0.0.0.0' startIpAddress: '0.0.0.0' } } resource sqlDatabase 'Microsoft.Sql/servers/databases@2022-05-01-preview' = { parent: sqlServer name: sqlDatabaseName location: location sku: environmentConfigurationMap[environmentType].sqlDatabase.sku } output appServiceAppName string = appServiceApp.name output appServiceAppHostName string = appServiceApp.properties.defaultHostName output storageAccountName string = storageAccount.name output storageAccountImagesBlobContainerName string = storageAccount::blobService::storageAccountImagesBlobContainer.name output sqlServerFullyQualifiedDomainName string = sqlServer.properties.fullyQualifiedDomainName output sqlDatabaseName string = sqlDatabase.name
このようになっていない場合は、ファイルの内容と合うように更新してください。
deploy.yml ファイルが次のようになっていることを確認します。
name: deploy on: workflow_call: inputs: environmentType: required: true type: string resourceGroupName: required: true type: string reviewApiUrl: required: true type: string sqlServerAdministratorLogin: required: true type: string secrets: AZURE_CLIENT_ID: required: true AZURE_TENANT_ID: required: true AZURE_SUBSCRIPTION_ID: required: true reviewApiKey: required: true sqlServerAdministratorLoginPassword: 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 }} sqlServerAdministratorLogin=${{ inputs.sqlServerAdministratorLogin }} sqlServerAdministratorLoginPassword=${{ secrets.sqlServerAdministratorLoginPassword }} 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 }} sqlServerAdministratorLogin=${{ inputs.sqlServerAdministratorLogin }} sqlServerAdministratorLoginPassword=${{ secrets.sqlServerAdministratorLoginPassword }} additionalArguments: --what-if deploy: needs: validate environment: ${{ inputs.environmentType }} runs-on: ubuntu-latest outputs: appServiceAppName: ${{ steps.deploy.outputs.appServiceAppName }} appServiceAppHostName: ${{ steps.deploy.outputs.appServiceAppHostName }} storageAccountName: ${{ steps.deploy.outputs.storageAccountName }} storageAccountImagesBlobContainerName: ${{ steps.deploy.outputs.storageAccountImagesBlobContainerName }} sqlServerFullyQualifiedDomainName: ${{ steps.deploy.outputs.sqlServerFullyQualifiedDomainName }} sqlDatabaseName: ${{ steps.deploy.outputs.sqlDatabaseName }} 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 }} sqlServerAdministratorLogin=${{ inputs.sqlServerAdministratorLogin }} sqlServerAdministratorLoginPassword=${{ secrets.sqlServerAdministratorLoginPassword }} 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 deploy-database: 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/sql-action@v1.2 name: Deploy DACPAC to database with: server-name: ${{ needs.deploy.outputs.sqlServerFullyQualifiedDomainName }} connection-string: ${{ format('Server={0};Initial Catalog={1};User Id={2};Password={3};', needs.deploy.outputs.sqlServerFullyQualifiedDomainName, needs.deploy.outputs.sqlDatabaseName, inputs.sqlServerAdministratorLogin, secrets.sqlServerAdministratorLoginPassword) }} dacpac-package: database/ToyCompany.Database.dacpac seed-database: needs: - deploy - deploy-database environment: ${{ inputs.environmentType }} 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/sql-action@v1.2 name: Add test data to database with: server-name: ${{ needs.deploy.outputs.sqlServerFullyQualifiedDomainName }} connection-string: ${{ format('Server={0};Initial Catalog={1};User Id={2};Password={3};', needs.deploy.outputs.sqlServerFullyQualifiedDomainName, needs.deploy.outputs.sqlDatabaseName, inputs.sqlServerAdministratorLogin, secrets.sqlServerAdministratorLoginPassword) }} sql-file: 'deploy/sample-data/Toys.sql' seed-storage-account: needs: deploy environment: ${{ inputs.environmentType }} 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/CLI@v1 name: Upload sample images with: inlineScript: | az storage blob upload-batch \ --account-name ${{ needs.deploy.outputs.storageAccountName }} \ --destination ${{ needs.deploy.outputs.storageAccountImagesBlobContainerName }} \ --source 'deploy/sample-data/toyimages' smoke-test: runs-on: ubuntu-latest needs: - deploy - deploy-website - deploy-database - seed-database - seed-storage-account 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
このようになっていない場合は、ファイルの内容と合うように更新してください。
ファイルに加えた変更を保存します。
変更を Git リポジトリにコミットしてプッシュします。 Visual Studio Code ターミナルで、次のコマンドを実行します。
git add . git commit -m "Add SQL database" git push
ワークフローを実行する
ブラウザーでワークフロー実行に移動します。
最新の実行を選択します。
テスト環境のすべてのジョブが正常に完了するまで待ちます。 スモーク テストも成功するようになったことに注意してください。
運用環境のデプロイを含め、ワークフローが正常に完了するまで待ちます。
Web サイトを表示する
[deploy-test / deploy-website] ジョブを選択してワークフロー ログを開きます。
[Web サイトのデプロイ] ステップを選択します。
Ctrl キー (macOS の場合は⌘) を押したまま App Service アプリの URL を選択して新しいブラウザー タブで開きます。
[Toys] を選択します。
テスト環境ではサンプル データが表示されることに注意してください。
deploy-production / deploy-website ジョブのアプリについても上記の手順を繰り返します。
運用環境ではサンプル データが表示されないことに注意してください。
リソースをクリーンアップする
これで演習を完了したので、課金されないように Azure リソースを削除しましょう。
Visual Studio Code ターミナルで、次のコマンドを実行します。
az group delete --resource-group ToyWebsiteTest --yes --no-wait
az group delete --resource-group ToyWebsiteProduction --yes --no-wait
バックグラウンドでリソース グループが削除されます。
Remove-AzResourceGroup -Name ToyWebsiteTest -Force
Remove-AzResourceGroup -Name ToyWebsiteProduction -Force