Ćwiczenie — inicjowanie konta magazynu i bazy danych
Zaktualizowano przepływ pracy w celu skompilowania i wdrożenia aplikacji witryny internetowej w aplikacji usługi aplikacja systemu Azure Service zdefiniowanej w pliku Bicep, ale zadanie testu weryfikacyjnego kompilacji kończy się niepowodzeniem, ponieważ baza danych nie działa jeszcze. W tej lekcji wdrożysz nowy serwer logiczny i bazę danych usługi Azure SQL. Skonfigurujesz przepływ pracy w celu skompilowania i wdrożenia schematu bazy danych. Zaktualizujesz również przepływ pracy, aby dodać przykładowe dane produktów dla środowiska testowego, aby twój zespół mógł wypróbować witrynę internetową.
W tym procesie wykonasz następujące czynności:
- Dodaj kontener obiektów blob do konta usługi Azure Storage.
- Dodaj serwer logiczny i bazę danych usługi Azure SQL.
- Zaktualizuj zadanie kompilacji, aby skompilować projekt bazy danych w pliku DACPAC.
- Dodaj nowe zmienne i wpisy tajne dla serwera logicznego i bazy danych azure SQL.
- Zaktualizuj przepływ pracy, aby używał nowych zmiennych i wpisów tajnych.
- Dodaj nowe kroki przepływu pracy, aby wdrożyć plik DACPAC.
- Uruchom przepływ pracy i wyświetl witrynę internetową.
Dodawanie kontenera magazynu
Plik Bicep definiuje już konto magazynu, ale nie definiuje kontenera obiektów blob. W tym miejscu dodasz kontener obiektów blob do pliku Bicep. Należy również podać nazwę konta magazynu i kontenera obiektów blob do aplikacji przy użyciu jej ustawień konfiguracji. Dzięki temu aplikacja wie, do którego konta magazynu ma uzyskać dostęp.
W programie Visual Studio Code otwórz plik main.bicep w folderze deploy .
Poniżej zmiennych definiujących nazwy zasobów (w pobliżu wiersza 27) dodaj nową definicję zmiennej dla nazwy kontenera magazynu obiektów blob:
var storageAccountImagesBlobContainerName = 'toyimages'
Zaktualizuj zasób,
storageAccount
aby zdefiniować kontener obiektów 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' } } } }
Zaktualizuj właściwość aplikacji
appSettings
, aby dodać dwa nowe ustawienia aplikacji: jedną dla nazwy konta magazynu i jedną dla nazwy kontenera obiektów 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 } ] } } }
Na końcu zawartości pliku dodaj nowe dane wyjściowe, aby uwidocznić nazwy konta magazynu i kontenera obiektów blob:
output storageAccountName string = storageAccount.name output storageAccountImagesBlobContainerName string = storageAccount::blobService::storageAccountImagesBlobContainer.name
Zapisz zmiany w pliku.
Zatwierdź zmiany w repozytorium Git, ale nie wypchnij ich jeszcze. W terminalu programu Visual Studio Code uruchom następujące polecenia:
git add . git commit -m "Add storage container"
Dodawanie serwera logicznego i bazy danych azure SQL
Plik Bicep nie wdraża obecnie serwera logicznego ani bazy danych Azure SQL. W tej sekcji dodasz te zasoby do pliku Bicep.
W pliku main.bicep dodaj dwa nowe parametry poniżej
reviewApiKey
parametru w górnej części pliku:@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
Poniżej zmiennych definiujących nazwy zasobów dodaj nowe zmienne, aby zdefiniować nazwy serwera logicznego i bazy danych Azure SQL:
var sqlServerName = 'toy-website-${resourceNameSuffix}' var sqlDatabaseName = 'Toys'
Poniżej właśnie dodanych zmiennych zdefiniuj nową zmienną, która tworzy parametry połączenia dla aplikacji w celu uzyskania dostępu do bazy danych:
// 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;'
Uwaga
Dla uproszczenia aplikacja używa identyfikatora logowania administratora i hasła w celu uzyskania dostępu do bazy danych. Nie jest to jednak dobre rozwiązanie dla rozwiązania produkcyjnego. Lepiej użyć tożsamości zarządzanej usługi App Service w celu uzyskania dostępu do bazy danych i przyznać tożsamości zarządzanej minimalne uprawnienia wymagane przez aplikację. Link do dodatkowych informacji znajduje się na stronie Podsumowanie tego modułu.
Na końcu zawartości pliku powyżej danych wyjściowych dodaj zasoby serwera logicznego i bazy danych 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 }
Zaktualizuj zmienną
environmentConfigurationMap
, aby zdefiniować jednostki SKU do użycia dla bazy danych dla każdego środowiska: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' } } } }
Dodaj kolejne ustawienie aplikacji do aplikacji usługi App Service dla bazy danych parametry połączenia:
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 } ] } } }
W dolnej części pliku dodaj dane wyjściowe, aby uwidocznić nazwę hosta serwera logicznego Azure SQL i nazwę bazy danych:
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
Zapisz zmiany w pliku.
Dodawanie nowych kroków kompilacji dla projektu bazy danych
Deweloperzy witryny internetowej przygotowali projekt bazy danych programu Visual Studio, który wdraża i konfiguruje tabelę bazy danych witryny internetowej. W tym miejscu zaktualizujesz kompilację przepływu pracy o nazwie workflow, aby skompilować projekt bazy danych w pliku DACPAC i przekazać go jako artefakt przepływu pracy.
Otwórz plik build.yml w folderze .github/workflows.
Aby skompilować projekt bazy danych programu Visual Studio i przekazać wygenerowany plik DACPAC jako artefakt przepływu pracy, dodaj zadanie kompilacji bazy danych :
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
Zadanie kompilacji bazy danych używa modułu uruchamiającego system Windows. Obecnie projekty baz danych programu Visual Studio muszą być tworzone w systemie operacyjnym Windows.
Zapisz zmiany w pliku.
Definiowanie wpisów tajnych
Musisz bezpiecznie przechowywać hasło administratora serwera logicznego usługi Azure SQL dla każdego środowiska. Decydujesz się używać wpisów tajnych usługi GitHub do ochrony informacji.
W przeglądarce przejdź do pozycji Ustawienia>Wpisy tajne i zmienne>Akcje.
Wybierz przycisk Nowy wpis tajny repozytorium.
Wprowadź SQL_SERVER_ADMINISTRATOR_LOGIN_PASSWORD_TEST jako nazwę wpisu tajnego i wartość SecurePassword!111 .
Wybierz przycisk Add secret (Dodaj wpis tajny).
Powtórz ten proces, aby dodać inny wpis tajny o nazwie SQL_SERVER_ADMINISTRATOR_LOGIN_PASSWORD_PRODUCTION jako nazwę wpisu tajnego i wartość SecurePassword!999 . Wybierz przycisk Add secret (Dodaj wpis tajny).
Dodawanie wpisów tajnych i danych wejściowych do przepływu pracy
W programie Visual Studio Code otwórz plik deploy.yml w folderze .github/workflows .
W górnej części pliku zdefiniuj nowe dane wejściowe o nazwie i nowy wpis tajny o nazwie
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
Zapisz zmiany w pliku.
Otwórz plik workflow.yml.
W definicji deploy-test zdefiniuj wartość danych
sqlServerAdministratorLogin
wejściowych i propaguj wartość wpisu tajnegosqlServerAdministratorLoginPassword
:# 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 }}
Powtórz proces w definicji deploy-production z wartościami środowiska produkcyjnego:
# 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 }}
Zapisz zmiany w pliku.
Dodawanie wartości parametrów i danych wyjściowych
Plik Bicep ma teraz dwa nowe obowiązkowe parametry: sqlServerAdministratorLogin
i sqlServerAdministratorLoginPassword
. W tym miejscu propagujesz te wartości parametrów z danych wejściowych i wpisów tajnych przepływu pracy dla zadań sprawdzania poprawności i wdrażania . Propagujesz również dane wyjściowe wdrożeń Bicep do danych wyjściowych zadania.
Otwórz plik deploy.yml.
Zaktualizuj krok weryfikacji uruchom wstępne zadanie, aby dodać nowe parametry:
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
Zaktualizuj krok Uruchom co-jeżeli, aby dodać nowe parametry:
- 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
Zaktualizuj krok Wdrażanie pliku Bicep zadania wdrażania, aby dodać nowe parametry:
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 }}
W definicji zadania wdrażania dodaj nowe dane wyjściowe dla danych wyjściowych pliku 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 }}
Dodawanie zadań inicjuj bazy danych i danych
W tej sekcji zdefiniujesz kroki wymagane do wdrożenia składników bazy danych witryny internetowej. Najpierw należy dodać krok wdrażania pliku DACPAC utworzonego wcześniej przez przepływ pracy. Następnie dodasz przykładowe dane do bazy danych i konta magazynu, ale tylko dla środowisk nieprodukcyjnych.
Poniżej zadania deploy-website dodaj nowe zadanie w celu wdrożenia pliku 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
Poniżej właśnie dodanego zadania i powyżej zadania testu weryfikacyjnego kompilacji zdefiniuj nowe zadanie rozmieszczania bazy danych z przykładowymi danymi.
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'
Zwróć uwagę, że krok Dodawanie danych testowych do bazy danych ma zastosowany warunek. Oznacza to, że działa tylko dla środowisk nieprodukcyjnych. Warunek jest stosowany do kroku, a nie do całego zadania, aby późniejsze zadania mogły zależeć od tego zadania niezależnie od typu środowiska.
Poniżej właśnie dodanego zadania i powyżej zadania testu weryfikacyjnego kompilacji zdefiniuj inne zadanie przekazywania przykładowych obrazów do kontenera obiektów blob przy użyciu interfejsu wiersza polecenia platformy Azure:
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'
Zwróć uwagę, że to zadanie używa modułu uruchamiającego system Ubuntu, ponieważ
azure/cli
akcja wymaga uruchomienia systemu Linux, alebuild-database
zdefiniowane wcześniej zadanie używa modułu uruchamiającego system Windows do kompilowania projektu bazy danych. Ten przepływ pracy jest dobrym przykładem użycia różnych systemów operacyjnych w celu osiągnięcia wymagań.
Aktualizowanie zależności zadania testu kompilacji
Zaktualizuj zależności zadania testu weryfikacyjnego kompilacji, aby upewnić się, że działa po zakończeniu wszystkich kroków wdrażania:
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
Zapisz zmiany w pliku.
Weryfikowanie plików i zatwierdzanie zmian
Sprawdź, czy plik main.bicep wygląda następująco:
@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
Jeśli tak nie jest, zaktualizuj ją tak, aby była zgodna z zawartością pliku.
Sprawdź, czy plik deploy.yml wygląda następująco:
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
Jeśli tak nie jest, zaktualizuj ją tak, aby była zgodna z zawartością pliku.
Zapisz zmiany w pliku.
Zatwierdź i wypchnij zmiany do repozytorium Git. W terminalu programu Visual Studio Code uruchom następujące polecenia:
git add . git commit -m "Add SQL database" git push
Uruchom przepływ pracy
W przeglądarce przejdź do przebiegów przepływu pracy.
Wybierz najnowszy przebieg.
Poczekaj, aż wszystkie zadania środowiska testowego zakończą się pomyślnie. Zwróć uwagę, że test weryfikacyjny kompilacji również zakończy się pomyślnie.
Poczekaj na pomyślne zakończenie przepływu pracy, w tym wdrożenie produkcyjne.
Wyświetlanie witryny internetowej
Wybierz zadanie deploy-test/deploy-website, aby otworzyć dziennik przepływu pracy.
Wybierz krok Wdróż witrynę internetową .
Przytrzymaj wciśnięty Ctrl (} w systemie macOS) i wybierz adres URL aplikacji usługi App Service, aby otworzyć go na nowej karcie przeglądarki.
Wybierz pozycję Zabawki.
Zwróć uwagę, że przykładowe dane są wyświetlane w środowisku testowym.
Powtórz poprzedni proces dla aplikacji zadania deploy-production/deploy-website .
Zwróć uwagę, że w środowisku produkcyjnym nie są wyświetlane żadne przykładowe dane.
Czyszczenie zasobów
Po ukończeniu ćwiczenia należy usunąć zasoby platformy Azure, aby nie były naliczane opłaty.
W terminalu programu Visual Studio Code uruchom następujące polecenia:
az group delete --resource-group ToyWebsiteTest --yes --no-wait
az group delete --resource-group ToyWebsiteProduction --yes --no-wait
Grupa zasobów jest usuwana w tle.
Remove-AzResourceGroup -Name ToyWebsiteTest -Force
Remove-AzResourceGroup -Name ToyWebsiteProduction -Force