Exercice – Alimenter un compte de stockage et une base de données
Vous avez mis à jour votre flux de travail pour générer et déployer l’application de votre site web sur l’application Azure App Service définie dans votre fichier Bicep, mais le travail de test de fumée échoue, car la base de données ne fonctionne pas encore. Dans cette unité, vous allez déployer une nouvelle base de données et un nouveau serveur logique Azure SQL, et vous allez configurer votre workflow pour générer et déployer le schéma de la base de données. Vous allez également mettre à jour votre workflow pour ajouter des exemples de données de produits pour votre environnement de test, afin que votre équipe puisse essayer le site web.
Pendant ce processus, vous allez :
- Ajouter un conteneur d’objets blob dans le compte de stockage Azure.
- Ajouter une base de données et un serveur logique Azure SQL.
- Mettre à jour le travail de génération pour générer le projet de base de données dans un fichier DACPAC.
- Ajoutez de nouvelles variables et de nouveaux secrets pour la base de données et le serveur logique Azure SQL.
- Mettez à jour votre workflow pour utiliser les nouvelles variables et les nouveaux secrets.
- Ajouter de nouvelles étapes de workflow pour déployer votre fichier DACPAC.
- Exécutez le workflow et affichez le site web.
Ajouter un conteneur de stockage
Votre fichier Bicep définit déjà un compte de stockage, mais il ne définit pas de conteneur d’objets blob. Ici, vous ajoutez un conteneur d’objets blob à votre fichier Bicep. Vous fournissez également le nom du compte de stockage et du conteneur d’objets blob à l’application à l’aide de ses paramètres de configuration. De cette façon, l’application sait à quel compte de stockage accéder.
Dans Visual Studio Code, ouvrez le fichier main.bicep dans le dossier deploy.
Sous les variables qui définissent les noms des ressources (près de la ligne 27), ajoutez une nouvelle définition de variable pour le nom du conteneur de stockage d’objets blob :
var storageAccountImagesBlobContainerName = 'toyimages'
Mettez à jour la ressource
storageAccount
pour définir le conteneur d’objets 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' } } } }
Mettez à jour la propriété
appSettings
de l’application pour ajouter deux nouveaux paramètres d’application, un pour le nom du compte de stockage et l’autre pour le nom du conteneur d’objets 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 } ] } } }
À la fin du contenu du fichier, ajoutez de nouvelles sorties pour exposer les noms du compte de stockage et du conteneur d’objets blob :
output storageAccountName string = storageAccount.name output storageAccountImagesBlobContainerName string = storageAccount::blobService::storageAccountImagesBlobContainer.name
Enregistrez les modifications apportées au fichier.
Validez vos modifications dans votre dépôt Git, mais ne les envoyez (push) pas encore. Dans le terminal Visual Studio Code, exécutez les commandes suivantes :
git add . git commit -m "Add storage container"
Ajouter une base de données et un serveur logique Azure SQL
Votre fichier Bicep ne déploie pas actuellement une base de données ou un serveur logique Azure SQL. Dans cette section, vous allez ajouter ces ressources à votre fichier Bicep.
Vers le haut du fichier main.bicep, sous le paramètre
reviewApiKey
, ajoutez les deux paramètres suivants :@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
Sous les variables qui définissent les noms des ressources, ajoutez de nouvelles variables pour définir les noms de votre base de données et de votre serveur logique Azure SQL :
var sqlServerName = 'toy-website-${resourceNameSuffix}' var sqlDatabaseName = 'Toys'
Sous les variables que vous venez d’ajouter, définissez une nouvelle variable qui crée une chaîne de connexion pour que l’application accède à la base de données :
// 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;'
Notes
Par souci de simplicité, l’application utilise la connexion et le mot de passe de l’administrateur pour accéder à la base de données. Toutefois, il ne s’agit pas là d’une bonne pratique pour une solution de production. Il est préférable d’utiliser une identité managée par App Service pour accéder à la base de données et d’accorder à cette identité managée les autorisations minimales requises par l’application. Nous allons créer un lien vers plus d’informations dans la page Résumé de ce module.
Près de la fin du contenu du fichier, au-dessus des sorties, ajoutez les ressources de base de données et de serveur logique 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 }
Mettez à jour la variable
environmentConfigurationMap
pour définir les références SKU à utiliser pour votre base de données pour chaque environnement :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' } } } }
Ajoutez un autre paramètre d’application à votre application App Service pour la chaîne de connexion à la base de données :
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 } ] } } }
En bas du fichier, ajoutez des sorties pour exposer le nom d’hôte du serveur logique Azure SQL et le nom de la base de données :
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
Enregistrez les modifications apportées au fichier.
Ajouter de nouvelles étapes de génération pour le projet de base de données
Les développeurs de votre site web ont préparé un projet de base de données Visual Studio qui déploie et configure la table de base de données de votre site web. Ici, vous mettez à jour le workflow de génération pour générer le projet de base de données dans un fichier DACPAC et le charger en tant qu’artefact de workflow.
Ouvrez le fichier build.yml dans le dossier .github/workflows.
Pour générer le projet de base de données Visual Studio et télécharger le fichier DACPAC généré en tant qu’artefact de workflow, ajoutez le travail 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
Le travail build-database utilise un exécuteur Windows. Actuellement, les projets de base de données Visual Studio doivent être générés sur le système d’exploitation Windows.
Enregistrez les modifications apportées au fichier.
Définir les secrets
Vous devez stocker de façon sécurisée le mot de passe administrateur de votre serveur logique Azure SQL pour chaque environnement. Vous décidez d’utiliser des secrets GitHub pour protéger les informations.
Dans votre navigateur, accédez à Paramètres>Secrets et variables>Actions.
Sélectionnez le bouton New repository secret.
Entrez SQL_SERVER_ADMINISTRATOR_LOGIN_PASSWORD_TEST comme nom de secret, et SecurePassword!111 comme valeur.
Sélectionnez Ajouter un secret.
Répétez le processus pour ajouter une autre clé secrète nommée SQL_SERVER_ADMINISTRATOR_LOGIN_PASSWORD_PRODUCTION comme nom de secret, et SecurePassword!999 comme valeur. Sélectionnez Ajouter un secret.
Ajouter les secrets et les entrées à votre workflow
Dans Visual Studio Code, ouvrez le fichier deploy.yml situé dans le dossier .github/workflows.
En haut du fichier, définissez une nouvelle entrée nommée
sqlServerAdministratorLogin
et une nouvelle clé secrète nomméesqlServerAdministratorLoginPassword
: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
Enregistrez les modifications apportées au fichier.
Ouvrez le fichier workflow.yml.
Dans la définition deploy-test, définissez une valeur pour l’entrée
sqlServerAdministratorLogin
, puis propagez la valeur de la clé secrètesqlServerAdministratorLoginPassword
:# 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 }}
Répétez le processus dans la définition deploy-production, avec les valeurs de l’environnement de 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 }}
Enregistrez les modifications apportées au fichier.
Ajouter des valeurs de paramètre et des sorties
Le fichier Bicep comporte désormais deux nouveaux paramètres obligatoires : sqlServerAdministratorLogin
et sqlServerAdministratorLoginPassword
. Ici, vous propagez ces valeurs de paramètre à partir de vos entrées et secrets de workflow pour les travaux validate et deploy. Vous propagez également les sorties des déploiements Bicep vers les sorties du travail.
Ouvrez le fichier deploy.yml.
Mettez à jour l’étape RunPreflightValidation du travail Valider pour ajouter ces nouveaux paramètres :
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
Mettez à jour l’étape Exécuter une simulation pour ajouter les nouveaux paramètres :
- 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
Mettez à jour l’étape DeployBicepFile du travail deploy pour ajouter ces nouveaux paramètres :
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 }}
Dans la définition du travail deploy, ajoutez de nouvelles sorties pour les sorties du fichier 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 }}
Ajouter des travaux de base de données et d’ajout de données
Dans cette section, vous allez définir les étapes nécessaires au déploiement des composants de base de données de votre site web. Tout d’abord, vous allez ajouter une étape pour déployer le fichier DACPAC précédemment généré par le workflow. Ensuite, vous ajoutez des exemples de données dans la base de données et le compte de stockage, mais seulement pour les environnements hors production.
Sous le travail de deploy-website, ajoutez un nouveau travail pour déployer le fichier 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
Sous le travail que vous venez d’ajouter, et au-dessus du travail smoke-test, définissez un nouveau travail pour initialiser la base de données avec des exemples de données.
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'
Notez que l’étape Ajouter des données de test à la base de données est sujette à une condition. Autrement dit, elle ne s’exécute que pour les environnements hors production. La condition est appliquée à l’étape et non à l’ensemble du travail, de sorte que les travaux ultérieurs peuvent dépendre de ce travail, quel que soit le type d’environnement.
Sous le travail que vous venez d’ajouter, et au-dessus du travail smoke-test, définissez un autre travail pour charger des exemples d’images de jouet dans le conteneur d’objets blob à l’aide d’Azure CLI :
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'
Notez que ce travail utilise un exécuteur Ubuntu, car l’action
azure/cli
nécessite l’exécution de Linux, mais le travailbuild-database
que vous avez défini précédemment utilise un exécuteur Windows pour générer le projet de base de données. Ce workflow est un bon exemple d’utilisation de divers systèmes d’exploitation pour répondre à vos besoins.
Mettre à jour les dépendances pour le travail smoke-test
Mettez à jour les dépendances du travail smoke-test pour vous assurer qu’uk s’exécute une fois toutes les étapes de déploiement terminées :
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
Enregistrez les modifications apportées au fichier.
Vérifier les fichiers et valider vos modifications
Vérifiez que votre fichier main.bicep ressemble à ceci :
@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
Si ce n’est pas le cas, mettez-le à jour pour qu’il corresponde au contenu du fichier.
Vérifiez que votre fichier deploy.yml ressemble à ceci :
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
Si ce n’est pas le cas, mettez-le à jour pour qu’il corresponde au contenu du fichier.
Enregistrez les modifications apportées au fichier.
Validez et envoyez (push) vos modifications vers votre dépôt Git. Dans le terminal Visual Studio Code, exécutez les commandes suivantes :
git add . git commit -m "Add SQL database" git push
Exécuter le workflow
Dans votre navigateur, accédez aux exécutions de votre workflow.
Sélectionnez la dernière exécution.
Attendez que tous les travaux de l’environnement de test se terminent correctement. Notez que le test de détection de fumée réussit également désormais.
Attendez que le workflow se termine correctement, y compris le déploiement de production.
Voir le site web
Sélectionnez le travail deploy-test/deploy-website pour ouvrir le journal du workflow.
Sélectionnez l’étape Déployer le site web.
Maintenez la touche Ctrl enfoncée (⌘ sur macOS) et sélectionnez l’URL de l’application App Service pour l’ouvrir dans un nouvel onglet de navigateur.
Sélectionnez Jouets.
Notez que les exemples de données s’affichent dans l’environnement de test.
Répétez le processus précédent pour l’application de la tâche deploy-production/deploy-website.
Notez qu’aucun exemple de données ne s’affiche dans l’environnement de production.
Nettoyer les ressources
Maintenant que vous avez terminé cet exercice, vous pouvez supprimer les ressources Azure afin qu’elles ne vous soient pas facturées.
Dans le terminal Visual Studio Code, exécutez les commandes suivantes :
az group delete --resource-group ToyWebsiteTest --yes --no-wait
az group delete --resource-group ToyWebsiteProduction --yes --no-wait
Le groupe de ressources est supprimé en arrière-plan.
Remove-AzResourceGroup -Name ToyWebsiteTest -Force
Remove-AzResourceGroup -Name ToyWebsiteProduction -Force