Übung: Seeding eines Speicherkontos und einer Datenbank
Sie haben Ihre Pipeline aktualisiert, um die Anwendung Ihrer Website zu erstellen und für die Azure App Service-App bereitzustellen, die in Ihrer Bicep-Datei definiert ist. Die Feuerprobephase ist jedoch fehlgeschlagen, da die Datenbank noch nicht funktioniert. In dieser Lerneinheit stellen Sie einen neuen logischen Azure SQL-Server und eine Datenbank zur Verfügung und konfigurieren Ihre Pipeline für das Erstellen und Bereitstellen des Datenbankschemas. Außerdem aktualisieren Sie Ihre Pipeline, um einige Beispielproduktdaten für Ihre Testumgebung hinzuzufügen, damit Ihr Team die Website ausprobieren kann.
Im Rahmen des Vorgangs führen Sie die folgenden Aufgaben aus:
- Fügen Sie dem Azure-Speicherkonto einen Blobcontainer hinzu.
- Fügen Sie einen logischen Azure SQL-Server und eine Datenbank hinzu.
- Aktualisieren Sie die Buildphase, um das Datenbankprojekt in einer DACPAC-Datei zu erstellen.
- Fügen Sie Ihrer Variablengruppe neue Variablen für den logischen Azure SQL-Server und die Datenbank hinzu.
- Aktualisieren Sie Ihre Bereitstellungsphasen, um die neuen Variablen als Parameterwerte zu verwenden.
- Fügen Sie neue Pipelineschritte hinzu, um Ihre DACPAC-Datei bereitzustellen.
- Führen Sie die Pipeline aus, und zeigen Sie die Website an.
Erstellen eines Speichercontainers
Ihre Bicep-Datei definiert bereits ein Speicherkonto, aber keinen Blobcontainer. Hier fügen Sie Ihrer Bicep-Datei einen Blobcontainer hinzu. Sie geben auch den Namen des Speicherkontos und Blobcontainers mithilfe der Konfigurationseinstellungen für die Anwendung an. Auf diese Weise weiß die App, auf welches Speicherkonto sie zugreifen soll.
Öffnen Sie in Visual Studio Code die Datei main.bicep im Ordner Bereitstellen.
Fügen Sie unter den Variablen, die Ressourcennamen definieren (in der Nähe von Zeile 27), eine neue Variablendefinition für den Namen des Blobspeichercontainers hinzu:
var storageAccountImagesBlobContainerName = 'toyimages'
Aktualisieren Sie die
storageAccount
-Ressource, um den Blobcontainer zu definieren: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' } } } }
Aktualisieren Sie die
appSettings
-Eigenschaft der App, um drei neue Anwendungseinstellungen für den Speicherkontonamen, den Blobendpunkt und den Blobcontainernamen hinzuzufügen: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 } ] } } }
Fügen Sie am Ende der Datei neue Ausgaben hinzu, um die Namen des Speicherkontos und des Blobcontainers verfügbar zu machen:
output storageAccountName string = storageAccount.name output storageAccountImagesBlobContainerName string = storageAccount::blobService::storageAccountImagesBlobContainer.name
Speichern Sie die geänderte Datei.
Committen Sie Ihre Änderungen in Ihr Git-Repository, aber pushen Sie sie noch nicht. Führen Sie im Visual Studio Code-Terminal die folgenden Befehle aus:
git add . git commit -m "Add storage container"
Hinzufügen eines logischen Azure SQL-Servers und einer Datenbank
Ihre Bicep-Datei stellt derzeit keinen logischen Azure SQL-Server oder eine Datenbank bereit. In diesem Abschnitt fügen Sie diese Ressourcen Ihrer Bicep-Datei hinzu.
Fügen Sie in der Datei main.bicep unter dem Parameter
reviewApiKey
zwei neue Parameter hinzu:@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
Fügen Sie unterhalb der Variablen, die Ressourcennamen definieren, neue Variablen hinzu, um die Namen Ihres logischen Azure SQL-Servers und der Datenbank zu definieren:
var sqlServerName = 'toy-website-${resourceNameSuffix}' var sqlDatabaseName = 'Toys'
Definieren Sie unter den soeben hinzugefügten Variablen eine neue Variable, die eine Verbindungszeichenfolge für die Anwendung für den Zugriff auf die Datenbank erstellt:
// 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;'
Hinweis
Der Einfachheit halber verwendet die Anwendung die Administratoranmeldung und das Kennwort für den Zugriff auf die Datenbank. Dies ist jedoch keine bewährte Methode für eine Produktionslösung. Es ist besser, eine von App Service verwaltete Identität für den Zugriff auf die Datenbank zu verwenden und der verwalteten Identität die für die Anwendung erforderlichen Mindestberechtigungen zu gewähren. Links zu weiteren Informationen finden Sie in der Zusammenfassung.
Fügen Sie am Ende der Datei oberhalb der Ausgaben den logischen Azure SQL-Server und die Datenbank als Ressourcen hinzu:
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 }
Aktualisieren Sie die Variable
environmentConfigurationMap
, um die Wertesku
zu definieren, die für Ihre Datenbank für jede Umgebung verwendet werden: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' } } } }
Fügen Sie Ihrer App Service-App eine weitere App-Einstellung für die Datenbankverbindungszeichenfolge hinzu:
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 } ] } } }
Fügen Sie am Ende der Datei Ausgaben hinzu, um den Hostnamen des logischen Azure SQL-Servers und den Namen der Datenbank verfügbar zu machen:
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
Speichern Sie die geänderte Datei.
Hinzufügen neuer Buildschritte für das Datenbankprojekt
Ihre Websiteentwickler haben ein Visual Studio-Datenbankprojekt vorbereitet, das Ihre Websitedatenbanktabelle bereitstellt und konfiguriert. Hier aktualisieren Sie die Buildphase Ihrer Pipeline, um das Datenbankprojekt in einer DACPAC-Datei zu erstellen und als Pipelineartefakt zu veröffentlichen.
Öffnen Sie im Ordner deploy/pipeline-templates die Datei build.yml.
Zum Erstellen des Visual Studio-Datenbankprojekts kopieren Sie die generierte DACPAC-Datei in einen Stagingordner und veröffentlichen sie als Pipelineartefakt; fügen Sie die folgenden Schritte hinzu:
jobs: - job: Build displayName: Build application and database pool: vmImage: windows-latest steps: # Build, copy, and publish the website. - task: DotNetCoreCLI@2 displayName: Build publishable website inputs: command: 'publish' publishWebProjects: true - task: CopyFiles@2 displayName: Copy publishable website inputs: sourceFolder: '$(Build.SourcesDirectory)/src/ToyCompany/ToyCompany.Website/bin' contents: '**/publish.zip' targetFolder: '$(Build.ArtifactStagingDirectory)/website' flattenFolders: true - task: PublishBuildArtifacts@1 displayName: Publish website as pipeline artifact inputs: pathToPublish: '$(Build.ArtifactStagingDirectory)/website' artifactName: 'website' # Build, copy, and publish the DACPAC file. - task: VSBuild@1 displayName: Build Visual Studio solution inputs: solution: '$(Build.SourcesDirectory)/src/ToyCompany/ToyCompany.Database/ToyCompany.Database.sqlproj' - task: CopyFiles@2 displayName: Copy DACPAC inputs: sourceFolder: '$(Build.SourcesDirectory)/src/ToyCompany/ToyCompany.Database/bin' contents: '**/*.dacpac' targetFolder: '$(Build.ArtifactStagingDirectory)/database' flattenFolders: true - task: PublishBuildArtifacts@1 displayName: Publish DACPAC as pipeline artifact inputs: pathToPublish: '$(Build.ArtifactStagingDirectory)/database' artifactName: 'database'
Speichern Sie die geänderte Datei.
Hinzufügen von Werten zu den Variablengruppen
Wechseln Sie in Ihrem Browser zu Pipelines>Bibliothek.
Wählen Sie die Variablengruppe ToyWebsiteProduction aus.
Fügen Sie die folgenden Variablen zur Variablengruppe hinzu:
Name Wert SqlServerAdministratorLogin ToyCompanyAdmin SqlServerAdministratorLoginPassword SecurePassword!111 Wählen Sie das Vorhängeschlosssymbol neben der Variablen SqlServerAdministratorLoginPassword aus. Dieses Feature weist Azure Pipelines an, den Wert der Variablen sicher zu behandeln.
Speichern Sie die Variablengruppe.
Wiederholen Sie den Vorgang, um der Variablengruppe ToyWebsiteTest die folgenden Variablen hinzuzufügen:
Name Wert SqlServerAdministratorLogin TestToyCompanyAdmin SqlServerAdministratorLoginPassword SecurePassword!999 Denken Sie daran, das Vorhängeschlosssymbol neben der Variablen SqlServerAdministratorLoginPassword auszuwählen und die Variablengruppe zu speichern.
Hinzufügen von Parameterwerten zu den Phasen „Überprüfen“ und „Vorschau“
Die Bicep-Datei verfügt jetzt über zwei neue obligatorische Parameter: sqlServerAdministratorLogin
und sqlServerAdministratorLoginPassword
. Hier geben Sie diese Parameterwerte sowohl für die Überprüfungs- als auch für die Vorschauphase von Ihrer Variablengruppe weiter.
Öffnen Sie in Visual Studio Code im Ordner deploy/pipeline-templates die Datei deploy.yml.
Aktualisieren Sie den Schritt RunPreflightValidation der Überprüfungsphase, um die neuen Parameter hinzuzufügen.
- task: AzureResourceManagerTemplateDeployment@3 name: RunPreflightValidation displayName: Run preflight validation inputs: connectedServiceName: ToyWebsite${{parameters.environmentType}} location: ${{parameters.deploymentDefaultLocation}} deploymentMode: Validation resourceGroupName: $(ResourceGroupName) csmFile: deploy/main.bicep overrideParameters: > -environmentType $(EnvironmentType) -reviewApiUrl $(ReviewApiUrl) -reviewApiKey $(ReviewApiKey) -sqlServerAdministratorLogin $(SqlServerAdministratorLogin) -sqlServerAdministratorLoginPassword $(SqlServerAdministratorLoginPassword)
Aktualisieren Sie den Schritt RunWhatIf der Vorschauphase, indem Sie die neuen Parameter hinzufügen.
inlineScript: | az deployment group what-if \ --resource-group $(ResourceGroupName) \ --template-file deploy/main.bicep \ --parameters environmentType=$(EnvironmentType) \ reviewApiUrl=$(ReviewApiUrl) \ reviewApiKey=$(ReviewApiKey) \ sqlServerAdministratorLogin=$(SqlServerAdministratorLogin) \ sqlServerAdministratorLoginPassword=$(SqlServerAdministratorLoginPassword)
Wichtig
Achten Sie darauf, den umgekehrten Schrägstrich (
\
) am Ende der Zeile, die denreviewApiKey
-Parameterwert festlegt, und in der nachfolgenden Zeile hinzuzufügen. Das Zeichen\
gibt an, dass es weitere Zeilen gibt, die Teil desselben Azure CLI-Befehls sind.
Hinzufügen von Parameterwerten zur Bereitstellungsphase
Aktualisieren Sie den Schritt DeployBicepFile der Bereitstellungsphase, indem Sie die neuen Parameter hinzufügen:
- task: AzureResourceManagerTemplateDeployment@3 name: DeployBicepFile displayName: Deploy Bicep file inputs: connectedServiceName: ToyWebsite${{parameters.environmentType}} deploymentName: $(Build.BuildNumber) location: ${{parameters.deploymentDefaultLocation}} resourceGroupName: $(ResourceGroupName) csmFile: deploy/main.bicep overrideParameters: > -environmentType $(EnvironmentType) -reviewApiUrl $(ReviewApiUrl) -reviewApiKey $(ReviewApiKey) -sqlServerAdministratorLogin $(SqlServerAdministratorLogin) -sqlServerAdministratorLoginPassword $(SqlServerAdministratorLoginPassword) deploymentOutputs: deploymentOutputs
Erstellen Sie Pipelinevariablen, die die Werte der Bicep-Ausgaben enthalten, die Sie kürzlich für das Speicherkonto und die Azure SQL-Ressourcen hinzugefügt haben:
- bash: | echo "##vso[task.setvariable variable=appServiceAppName]$(echo $DEPLOYMENT_OUTPUTS | jq -r '.appServiceAppName.value')" echo "##vso[task.setvariable variable=appServiceAppHostName;isOutput=true]$(echo $DEPLOYMENT_OUTPUTS | jq -r '.appServiceAppHostName.value')" echo "##vso[task.setvariable variable=storageAccountName]$(echo $DEPLOYMENT_OUTPUTS | jq -r '.storageAccountName.value')" echo "##vso[task.setvariable variable=storageAccountImagesBlobContainerName]$(echo $DEPLOYMENT_OUTPUTS | jq -r '.storageAccountImagesBlobContainerName.value')" echo "##vso[task.setvariable variable=sqlServerFullyQualifiedDomainName]$(echo $DEPLOYMENT_OUTPUTS | jq -r '.sqlServerFullyQualifiedDomainName.value')" echo "##vso[task.setvariable variable=sqlDatabaseName]$(echo $DEPLOYMENT_OUTPUTS | jq -r '.sqlDatabaseName.value')" name: SaveDeploymentOutputs displayName: Save deployment outputs into variables env: DEPLOYMENT_OUTPUTS: $(deploymentOutputs)
Hinzufügen von Schritten für die Datenbankbereitstellung
In diesem Abschnitt definieren Sie die Schritte, die zum Bereitstellen der Datenbankkomponenten Ihrer Website erforderlich sind. Zunächst fügen Sie einen Schritt zum Bereitstellen der DACPAC-Datei hinzu, die die Pipeline zuvor erstellt hat. Anschließend fügen Sie der Datenbank und dem Speicherkonto Beispieldaten hinzu, jedoch nur für Nicht-Produktionsumgebungen.
Fügen Sie unterhalb des Schritts DeployWebsiteApp in der Bereitstellungsphase einen neuen Schritt zum Bereitstellen der DACPAC-Datei hinzu:
- task: SqlAzureDacpacDeployment@1 name: DeploySqlDatabaseDacpac displayName: Deploy DACPAC to database inputs: ConnectedServiceNameARM: ToyWebsite${{parameters.environmentType}} authenticationType: 'server' serverName: $(sqlServerFullyQualifiedDomainName) databaseName: $(sqlDatabaseName) sqlUsername: $(SqlServerAdministratorLogin) sqlPassword: $(SqlServerAdministratorLoginPassword) deployType: 'DacpacTask' deploymentAction: 'Publish' dacpacFile: '$(Pipeline.Workspace)/database/ToyCompany.Database.dacpac'
Definieren Sie unterhalb des gerade hinzugefügten Schritts einen Schritt zum Seeding der Datenbank mit Beispieldaten.
- ${{ if ne(parameters.environmentType, 'Production') }}: - task: SqlAzureDacpacDeployment@1 name: AddTestDataToDatabase displayName: Add test data to database inputs: ConnectedServiceNameARM: ToyWebsite${{parameters.environmentType}} authenticationType: 'server' serverName: $(sqlServerFullyQualifiedDomainName) databaseName: $(sqlDatabaseName) sqlUsername: $(SqlServerAdministratorLogin) sqlPassword: $(SqlServerAdministratorLoginPassword) deployType: 'sqlTask' sqlFile: 'deploy/sample-data/Toys.sql'
Beachten Sie, dass für diesen Schritt eine Bedingung angewendet wird, sodass er nur für Nicht-Produktionsumgebungen ausgeführt wird.
Fügen Sie unterhalb des gerade hinzugefügten Schritts und im Bereich der Bedingung einen Schritt zum Hochladen einiger Spielzeug-Beispielbilder in den Blobcontainer mithilfe der Azure CLI hinzu:
- task: AzureCLI@2 name: UploadSampleImages displayName: Upload sample images inputs: azureSubscription: ToyWebsite${{parameters.environmentType}} scriptType: 'bash' scriptLocation: 'inlineScript' inlineScript: | az storage blob upload-batch \ --account-name $(storageAccountName) \ --destination $(storageAccountImagesBlobContainerName) \ --source 'deploy/sample-data/toyimages'
Überprüfen von Dateien und Commit ihrer Änderungen
Überprüfen Sie, ob die Datei main.bicep wie folgt aussieht:
@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
Falls nicht, aktualisieren Sie sie so, dass sie mit dem Dateiinhalt übereinstimmt.
Überprüfen Sie, ob die Datei deploy.yml wie folgt aussieht:
parameters: - name: environmentType 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 variables: - group: ToyWebsite${{parameters.environmentType}} steps: - task: AzureResourceManagerTemplateDeployment@3 name: RunPreflightValidation displayName: Run preflight validation inputs: connectedServiceName: ToyWebsite${{parameters.environmentType}} location: ${{parameters.deploymentDefaultLocation}} deploymentMode: Validation resourceGroupName: $(ResourceGroupName) csmFile: deploy/main.bicep overrideParameters: > -environmentType $(EnvironmentType) -reviewApiUrl $(ReviewApiUrl) -reviewApiKey $(ReviewApiKey) -sqlServerAdministratorLogin $(SqlServerAdministratorLogin) -sqlServerAdministratorLoginPassword $(SqlServerAdministratorLoginPassword) - ${{ if eq(parameters.environmentType, 'Production') }}: - stage: Preview_${{parameters.environmentType}} displayName: Preview (${{parameters.environmentType}} Environment) jobs: - job: PreviewAzureChanges displayName: Preview Azure changes variables: - group: ToyWebsite${{parameters.environmentType}} steps: - task: AzureCLI@2 name: RunWhatIf displayName: Run what-if inputs: azureSubscription: ToyWebsite${{parameters.environmentType}} scriptType: 'bash' scriptLocation: 'inlineScript' inlineScript: | az deployment group what-if \ --resource-group $(ResourceGroupName) \ --template-file deploy/main.bicep \ --parameters environmentType=$(EnvironmentType) \ reviewApiUrl=$(ReviewApiUrl) \ reviewApiKey=$(ReviewApiKey) \ sqlServerAdministratorLogin=$(SqlServerAdministratorLogin) \ sqlServerAdministratorLoginPassword=$(SqlServerAdministratorLoginPassword) - stage: Deploy_${{parameters.environmentType}} displayName: Deploy (${{parameters.environmentType}} Environment) jobs: - deployment: DeployWebsite displayName: Deploy website pool: vmImage: windows-latest variables: - group: ToyWebsite${{parameters.environmentType}} environment: ${{parameters.environmentType}} strategy: runOnce: deploy: steps: - checkout: self - task: AzureResourceManagerTemplateDeployment@3 name: DeployBicepFile displayName: Deploy Bicep file inputs: connectedServiceName: ToyWebsite${{parameters.environmentType}} deploymentName: $(Build.BuildNumber) location: ${{parameters.deploymentDefaultLocation}} resourceGroupName: $(ResourceGroupName) csmFile: deploy/main.bicep overrideParameters: > -environmentType $(EnvironmentType) -reviewApiUrl $(ReviewApiUrl) -reviewApiKey $(ReviewApiKey) -sqlServerAdministratorLogin $(SqlServerAdministratorLogin) -sqlServerAdministratorLoginPassword $(SqlServerAdministratorLoginPassword) deploymentOutputs: deploymentOutputs - bash: | echo "##vso[task.setvariable variable=appServiceAppName]$(echo $DEPLOYMENT_OUTPUTS | jq -r '.appServiceAppName.value')" echo "##vso[task.setvariable variable=appServiceAppHostName;isOutput=true]$(echo $DEPLOYMENT_OUTPUTS | jq -r '.appServiceAppHostName.value')" echo "##vso[task.setvariable variable=storageAccountName]$(echo $DEPLOYMENT_OUTPUTS | jq -r '.storageAccountName.value')" echo "##vso[task.setvariable variable=storageAccountImagesBlobContainerName]$(echo $DEPLOYMENT_OUTPUTS | jq -r '.storageAccountImagesBlobContainerName.value')" echo "##vso[task.setvariable variable=sqlServerFullyQualifiedDomainName]$(echo $DEPLOYMENT_OUTPUTS | jq -r '.sqlServerFullyQualifiedDomainName.value')" echo "##vso[task.setvariable variable=sqlDatabaseName]$(echo $DEPLOYMENT_OUTPUTS | jq -r '.sqlDatabaseName.value')" name: SaveDeploymentOutputs displayName: Save deployment outputs into variables env: DEPLOYMENT_OUTPUTS: $(deploymentOutputs) - task: AzureRmWebAppDeployment@4 name: DeployWebsiteApp displayName: Deploy website inputs: appType: webApp ConnectionType: AzureRM azureSubscription: ToyWebsite${{parameters.environmentType}} ResourceGroupName: $(ResourceGroupName) WebAppName: $(appServiceAppName) Package: '$(Pipeline.Workspace)/website/publish.zip' - task: SqlAzureDacpacDeployment@1 name: DeploySqlDatabaseDacpac displayName: Deploy DACPAC to database inputs: ConnectedServiceNameARM: ToyWebsite${{parameters.environmentType}} authenticationType: 'server' serverName: $(sqlServerFullyQualifiedDomainName) databaseName: $(sqlDatabaseName) sqlUsername: $(SqlServerAdministratorLogin) sqlPassword: $(SqlServerAdministratorLoginPassword) deployType: 'DacpacTask' deploymentAction: 'Publish' dacpacFile: '$(Pipeline.Workspace)/database/ToyCompany.Database.dacpac' - ${{ if ne(parameters.environmentType, 'Production') }}: - task: SqlAzureDacpacDeployment@1 name: AddTestDataToDatabase displayName: Add test data to database inputs: ConnectedServiceNameARM: ToyWebsite${{parameters.environmentType}} authenticationType: 'server' serverName: $(sqlServerFullyQualifiedDomainName) databaseName: $(sqlDatabaseName) sqlUsername: $(SqlServerAdministratorLogin) sqlPassword: $(SqlServerAdministratorLoginPassword) deployType: 'sqlTask' sqlFile: 'deploy/sample-data/Toys.sql' - task: AzureCLI@2 name: UploadSampleImages displayName: Upload sample images inputs: azureSubscription: ToyWebsite${{parameters.environmentType}} scriptType: 'bash' scriptLocation: 'inlineScript' inlineScript: | az storage blob upload-batch \ --account-name $(storageAccountName) \ --destination $(storageAccountImagesBlobContainerName) \ --source 'deploy/sample-data/toyimages' - 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'
Falls nicht, aktualisieren Sie sie so, dass sie mit dem Dateiinhalt übereinstimmt.
Speichern Sie die geänderte Datei.
Committen und pushen Sie Ihre Änderungen in Ihr Git-Repository. Führen Sie im Visual Studio Code-Terminal die folgenden Befehle aus:
git add . git commit -m "Add SQL database" git push
Führen Sie die Pipeline aus.
Wechseln Sie in Ihrem Browser zu Pipelines.
Wählen Sie die letzte Ausführung Ihrer Pipeline aus.
Warten Sie, bis alle Phasen für die Testumgebung erfolgreich abgeschlossen wurden. Beachten Sie, dass die Feuerprobe jetzt auch erfolgreich ist.
Warten Sie, bis die Pipeline vor der Phase Vorschau (Produktionsumgebung) noch mal angehalten wird, da sie dieses Mal die Berechtigung für eine andere Variablengruppe benötigt.
Wählen Sie Anzeigen und dann Zulassen>Zulassen aus.
Die Phase Vorschau (Produktionsumgebung) wurde erfolgreich abgeschlossen.
Überwachen Sie die Pipeline beim Abschließen der letzten Phasen.
Die Phase Bereitstellen (Produktionsumgebung) wird erfolgreich abgeschlossen, und die Phase Feuerprobe (Produktionsumgebung) wird ebenfalls erfolgreich abgeschlossen.
Anzeigen der Website
Wählen Sie die Phase Bereitstellen (Testumgebung) aus, um das Pipelineprotokoll zu öffnen.
Wählen Sie den Schritt Website bereitstellen aus.
Halten Sie die STRG-TASTE gedrückt (⌘ unter macOS), und wählen Sie die URL der App Service-App aus, um sie auf einer neuen Browserregisterkarte zu öffnen.
Wählen Sie Toys aus.
Beachten Sie, dass Beispieldaten in der Testumgebung angezeigt werden.
Wiederholen Sie den vorherigen Prozess für die App der Phase Bereitstellen (Produktionsumgebung).
Beachten Sie, dass in der Produktionsumgebung keine Beispieldaten angezeigt werden.
Bereinigen von Ressourcen
Nachdem die Übung abgeschlossen ist, müssen Sie die Ressourcen entfernen, damit Ihnen dafür keine Gebühren berechnet werden.
Führen Sie im Visual Studio Code-Terminal die folgenden Befehle aus:
az group delete --resource-group ToyWebsiteTest --yes --no-wait
az group delete --resource-group ToyWebsiteProduction --yes --no-wait
Die Ressourcengruppe wird im Hintergrund gelöscht.
Remove-AzResourceGroup -Name ToyWebsiteTest -Force
Remove-AzResourceGroup -Name ToyWebsiteProduction -Force