Oefening: Uw Bicep-bestand herstructureren

Voltooid

Nadat u uw sjabloon met uw collega's hebt gecontroleerd, besluit u het bestand te herstructureren om het voor hen gemakkelijker te maken om mee te werken. In deze oefening past u de aanbevolen procedures toe die u in de voorgaande lessen hebt geleerd.

Uw taak

Bekijk de Bicep-sjabloon die u eerder hebt opgeslagen. Denk na over het advies dat u hebt gelezen over het structuren van uw sjablonen. Werk uw sjabloon bij zodat uw collega's het gemakkelijker kunnen begrijpen.

In de volgende secties verwijzen we naar specifieke onderdelen van de sjabloon en enkele hints over dingen die u mogelijk wilt wijzigen. We bieden een voorgestelde oplossing, maar uw sjabloon kan er anders uitzien, wat perfect in orde is.

Tip

Wanneer u het herstructureringsproces doorloopt, is het goed om ervoor te zorgen dat uw Bicep-bestand geldig is en dat u niet per ongeluk fouten hebt geïntroduceerd. De Bicep-extensie voor Visual Studio Code helpt hierbij. Let op rode of gele golvende lijnen onder uw code, omdat deze duiden op een fout of waarschuwing. U kunt ook een lijst met de problemen in uw bestand bekijken door Problemen weergeven>te selecteren.

De parameters bijwerken

  1. Sommige parameters in uw sjabloon zijn niet duidelijk. Denk bijvoorbeeld aan deze parameters:

    @allowed([
      'F1'
      'D1'
      'B1'
      'B2'
      'B3'
      'S1'
      'S2'
      'S3'
      'P1'
      'P2'
      'P3'
      'P4'
    ])
    param skuName string = 'F1'
    
    @minValue(1)
    param skuCapacity int = 1
    

    Waar worden ze voor gebruikt?

    Tip

    Als u een parameter hebt die u wilt begrijpen, kan Visual Studio Code u hierbij helpen. Selecteer en houd een parameternaam ingedrukt (of klik er met de rechtermuisknop op) en selecteer Alle verwijzingen zoeken.

    Moet de sjabloon de lijst met toegestane waarden voor de skuName parameter opgeven? Welke resources worden beïnvloed door verschillende waarden voor deze parameters te kiezen? Zijn er betere namen die u de parameters kunt geven?

    Tip

    Wanneer u de naam van id's wijzigt, moet u de naam consistent wijzigen in alle onderdelen van uw sjabloon. Dit is met name belangrijk voor parameters, variabelen en resources waarnaar u in uw sjabloon verwijst.

    Visual Studio Code biedt een handige manier om de naam van symbolen te wijzigen: selecteer de id die u wilt wijzigen, selecteer F2, voer een nieuwe naam in en selecteer vervolgens Enter:

    Schermopname van Visual Studio Code waarin wordt getoond hoe u de naam van een symbool wijzigt.

    Met deze stappen wijzigt u de naam van de id en werkt u automatisch alle verwijzingen ernaar bij.

  2. De managedIdentityName parameter heeft geen standaardwaarde. Kunt u dat oplossen of, nog beter, de naam automatisch maken in de sjabloon?

  3. Bekijk de roleDefinitionId parameterdefinitie:

    param roleDefinitionId string = 'b24988ac-6180-42a0-ab88-20f7382dd24c'
    

    Waarom is er een standaardwaarde van b24988ac-6180-42a0-ab88-20f7382dd24c? Wat betekent die lange id? Hoe weet iemand anders of deze standaardwaarde moet gebruiken of overschrijven? Wat kunt u doen om de id te verbeteren? Is het zelfs zinvol om dit als parameter te hebben?

    Tip

    Deze id is de definitie-id van de rol inzender voor Azure. Hoe kunt u die informatie gebruiken om de sjabloon te verbeteren?

  4. Wanneer iemand de sjabloon implementeert, hoe weet hij of zij waar elke parameter voor is? Kunt u enkele beschrijvingen toevoegen om de gebruikers van uw sjabloon te helpen?

Een configuratieset toevoegen

  1. U spreekt uw collega's aan en besluit specifieke SKU's te gebruiken voor elke resource, afhankelijk van de omgeving die wordt geïmplementeerd. U besluit over deze SKU's voor elk van uw resources:

    Bron SKU voor productie SKU voor niet-productie
    App Service-plan S1, twee exemplaren F1, één exemplaar
    Opslagaccount GRS LRS
    SQL-database S1 Basis
  2. Kunt u een configuratieset gebruiken om de parameterdefinities te vereenvoudigen?

De symbolische namen bijwerken

Bekijk de symbolische namen voor de resources in de sjabloon. Wat kunt u doen om ze te verbeteren?

  1. Uw Bicep-sjabloon bevat resources met een verscheidenheid aan hoofdlettergebruiksstijlen voor hun symbolische namen, zoals:

    • storageAccount en webSite, die camelCase-hoofdlettergebruik gebruiken.
    • roleassignment en sqlserver, die gebruikmaken van platte hoofdlettergebruik.
    • sqlserverName_databaseName en AppInsights_webSiteName, die slang hoofdlettergebruik gebruiken.

    Kunt u deze herstellen om één stijl consistent te gebruiken?

  2. Bekijk deze resource voor roltoewijzing:

    resource roleassignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
      name: guid(roleDefinitionId, resourceGroup().id)
    
      properties: {
        principalType: 'ServicePrincipal'
        roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitionId)
        principalId: msi.properties.principalId
      }
    }
    

    Is de symbolische naam beschrijvend genoeg om iemand anders te helpen met deze sjabloon te werken?

    Tip

    De reden waarom de identiteit een roltoewijzing nodig heeft, is dat de web-app de beheerde identiteit gebruikt om verbinding te maken met de databaseserver. Helpt dat u om dit in de sjabloon te verduidelijken?

  3. Een paar resources hebben symbolische namen die niet overeenkomen met de huidige namen van Azure-resources:

    resource hostingPlan 'Microsoft.Web/serverfarms@2023-12-01' = {
      // ...
    }
    resource webSite 'Microsoft.Web/sites@2023-12-01' = {
      // ...
    }
    resource msi 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-07-31-preview' = {
      // ...
    }
    

    Beheerde identiteiten worden msis genoemd, App Service-abonnementen worden hostingplannen genoemd en App Service-apps worden websites genoemd.

    Kunt u deze bijwerken naar de nieuwste namen om verwarring in de toekomst te voorkomen?

De blobcontainerdefinities vereenvoudigen

  1. Bekijk hoe de blobcontainers worden gedefinieerd:

    resource container1 'Microsoft.Storage/storageAccounts/blobServices/containers@2023-05-01' = {
      parent: storageAccount::blobServices
      name: container1Name
    }
    
    resource productmanuals 'Microsoft.Storage/storageAccounts/blobServices/containers@2023-05-01' = {
      name: '${storageAccount.name}/default/${productmanualsName}'
    }
    

    Een van hen gebruikt de parent eigenschap en de andere niet. Kunt u deze oplossen om consistent te zijn?

  2. De namen van de blobcontainers veranderen niet tussen omgevingen. Denkt u dat de namen moeten worden opgegeven met behulp van parameters?

  3. Er zijn twee blobcontainers. Kunnen ze worden geïmplementeerd met behulp van een lus?

De resourcenamen bijwerken

  1. Er zijn enkele parameters waarmee resourcenamen expliciet worden ingesteld:

    param managedIdentityName string
    param roleDefinitionId string = 'b24988ac-6180-42a0-ab88-20f7382dd24c'
    param webSiteName string = 'webSite${uniqueString(resourceGroup().id)}'
    param container1Name string = 'productspecs'
    param productmanualsName string = 'productmanuals'
    

    Is er een andere manier om dit te doen?

    Let op

    Houd er rekening mee dat de naam van resources niet kan worden gewijzigd zodra ze zijn geïmplementeerd. Wanneer u sjablonen wijzigt die al in gebruik zijn, moet u voorzichtig zijn wanneer u de manier wijzigt waarop de sjabloon resourcenamen maakt. Als de sjabloon opnieuw wordt geïmplementeerd en de resource een nieuwe naam heeft, maakt Azure een andere resource. De oude resource kan zelfs worden verwijderd als u deze in de modus Volledig implementeert.

    U hoeft zich hier geen zorgen te maken, omdat dit slechts een voorbeeld is.

  2. De resourcenaam van de logische SQL-server wordt ingesteld met behulp van een variabele, ook al heeft deze een wereldwijd unieke naam nodig:

    var sqlserverName = 'toywebsite${uniqueString(resourceGroup().id)}'
    

    Hoe kun je dit verbeteren?

Afhankelijkheden en onderliggende resources bijwerken

  1. Hier volgt een van uw resources, die een dependsOn eigenschap bevat. Heeft het echt nodig?

    resource sqlserverName_AllowAllAzureIPs 'Microsoft.Sql/servers/firewallRules@2023-08-01-preview' = {
      name: '${sqlserver.name}/AllowAllAzureIPs'
      properties: {
        endIpAddress: '0.0.0.0'
        startIpAddress: '0.0.0.0'
      }
      dependsOn: [
        sqlserver
      ]
    }
    
  2. U ziet hoe deze onderliggende resources worden gedeclareerd in uw sjabloon:

    resource sqlserverName_databaseName 'Microsoft.Sql/servers/databases@2023-08-01-preview' = {
      name: '${sqlserver.name}/${databaseName}'
      location: location
      sku: {
        name: 'Basic'
      }
      properties: {
        collation: 'SQL_Latin1_General_CP1_CI_AS'
        maxSizeBytes: 1073741824
      }
    }
    
    resource sqlserverName_AllowAllAzureIPs 'Microsoft.Sql/servers/firewallRules@2023-08-01-preview' = {
      name: '${sqlserver.name}/AllowAllAzureIPs'
      properties: {
        endIpAddress: '0.0.0.0'
        startIpAddress: '0.0.0.0'
      }
      dependsOn: [
        sqlserver
      ]
    }
    

    Hoe kunt u wijzigen hoe deze resources worden gedeclareerd? Zijn er andere resources in de sjabloon die ook moeten worden bijgewerkt?

Eigenschapswaarden bijwerken

  1. Bekijk de resource-eigenschappen van de SQL-database:

    resource sqlserverName_databaseName 'Microsoft.Sql/servers/databases@2023-08-01-preview' = {
      name: '${sqlserver.name}/${databaseName}'
      location: location
      sku: {
        name: 'Basic'
      }
      properties: {
        collation: 'SQL_Latin1_General_CP1_CI_AS'
        maxSizeBytes: 1073741824
      }
    }
    

    Is het zinvol om de eigenschapswaarde van name de SKU in code te codeeren? En wat zijn die rare waarden voor de collation en maxSizeBytes eigenschappen?

    Tip

    De collation en maxSizeBytes eigenschappen worden ingesteld op de standaardwaarden. Als u de waarden zelf niet opgeeft, worden de standaardwaarden gebruikt. Helpt dat u om te bepalen wat u met hen moet doen?

  2. Kunt u de manier wijzigen waarop de opslag verbindingsreeks is ingesteld, zodat de complexe expressie niet inline is gedefinieerd met de resource?

    resource webSite 'Microsoft.Web/sites@2023-12-01' = {
      name: webSiteName
      location: location
      properties: {
        serverFarmId: hostingPlan.id
        siteConfig: {
          appSettings: [
            {
              name: 'APPINSIGHTS_INSTRUMENTATIONKEY'
              value: AppInsights_webSiteName.properties.InstrumentationKey
            }
            {
              name: 'StorageAccountConnectionString'
              value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.name};EndpointSuffix=${environment().suffixes.storage};AccountKey=${listKeys(storageAccount.id, storageAccount.apiVersion).keys[0].value}'
            }
          ]
        }
      }
      identity: {
        type: 'UserAssigned'
        userAssignedIdentities: {
          '${msi.id}': {}
        }
      }
    }
    

Volgorde van elementen

  1. Bent u tevreden met de volgorde van de elementen in het bestand? Hoe kunt u de leesbaarheid van het bestand verbeteren door de elementen te verplaatsen?

  2. Bekijk de databaseName variabele. Behoort het tot waar het nu is?

    var databaseName = 'ToyCompanyWebsite'
    resource sqlserverName_databaseName 'Microsoft.Sql/servers/databases@2023-08-01-preview' = {
      name: '${sqlserver.name}/${databaseName}'
      location: location
      sku: {
        name: 'Basic'
      }
      properties: {
        collation: 'SQL_Latin1_General_CP1_CI_AS'
        maxSizeBytes: 1073741824
      }
    }
    
  3. Hebt u de uitgecommentareerde resource gezien? webSiteConnectionStrings Denk je dat dat in het bestand moet staan?

Opmerkingen, tags en andere metagegevens toevoegen

Denk na over iets in de sjabloon die misschien niet duidelijk is of die aanvullende uitleg nodig heeft. Kunt u opmerkingen toevoegen om het duidelijker te maken voor anderen die het bestand in de toekomst kunnen openen?

  1. Bekijk de eigenschap van webSite de identity resource:

    resource webSite 'Microsoft.Web/sites@2023-12-01' = {
      name: webSiteName
      location: location
      properties: {
        serverFarmId: hostingPlan.id
        siteConfig: {
          appSettings: [
            {
              name: 'APPINSIGHTS_INSTRUMENTATIONKEY'
              value: AppInsights_webSiteName.properties.InstrumentationKey
            }
            {
              name: 'StorageAccountConnectionString'
              value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.name};EndpointSuffix=${environment().suffixes.storage};AccountKey=${listKeys(storageAccount.id, storageAccount.apiVersion).keys[0].value}'
            }
          ]
        }
      }
      identity: {
        type: 'UserAssigned'
        userAssignedIdentities: {
          '${msi.id}': {}
        }
      }
    }
    

    Die syntaxis is vreemd, hè? Denkt u dat dit een opmerking nodig heeft om het uit te leggen?

  2. Bekijk de resource voor roltoewijzing:

    resource roleassignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
      name: guid(roleDefinitionId, resourceGroup().id)
    
      properties: {
        principalType: 'ServicePrincipal'
        roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitionId)
        principalId: msi.properties.principalId
      }
    }
    

    De resourcenaam maakt gebruik van de guid() functie. Zou het helpen om uit te leggen waarom?

  3. Kunt u een beschrijving toevoegen aan de roltoewijzing?

  4. Kunt u een set tags toevoegen aan elke resource?

Voorgestelde oplossing

Hier volgt een voorbeeld van hoe u de sjabloon kunt herstructureren. Uw sjabloon ziet er mogelijk niet precies zo uit, omdat uw stijl mogelijk anders is.

@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 administrator login username for the SQL server.')
param sqlServerAdministratorLogin string

@secure()
@description('The administrator login password for the SQL server.')
param sqlServerAdministratorLoginPassword string

@description('The tags to apply to each resource.')
param tags object = {
  CostCenter: 'Marketing'
  DataClassification: 'Public'
  Owner: 'WebsiteTeam'
  Environment: 'Production'
}

// Define the names for resources.
var appServiceAppName = 'webSite${resourceNameSuffix}'
var appServicePlanName = 'AppServicePLan'
var sqlServerName = 'sqlserver${resourceNameSuffix}'
var sqlDatabaseName = 'ToyCompanyWebsite'
var managedIdentityName = 'WebSite'
var applicationInsightsName = 'AppInsights'
var storageAccountName = 'toywebsite${resourceNameSuffix}'
var blobContainerNames = [
  'productspecs'
  'productmanuals'
]

@description('Define the SKUs for each component based on the environment type.')
var environmentConfigurationMap = {
  Production: {
    appServicePlan: {
      sku: {
        name: 'S1'
        capacity: 2
      }
    }
    storageAccount: {
      sku: {
        name: 'Standard_GRS'
      }
    }
    sqlDatabase: {
      sku: {
        name: 'S1'
        tier: 'Standard'
      }
    }
  }
  Test: {
    appServicePlan: {
      sku: {
        name: 'F1'
        capacity: 1
      }
    }
    storageAccount: {
      sku: {
        name: 'Standard_LRS'
      }
    }
    sqlDatabase: {
      sku: {
        name: 'Basic'
      }
    }
  }
}

@description('The role definition ID of the built-in Azure \'Contributor\' role.')
var contributorRoleDefinitionId = 'b24988ac-6180-42a0-ab88-20f7382dd24c'
var storageAccountConnectionString = 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.name};EndpointSuffix=${environment().suffixes.storage};AccountKey=${listKeys(storageAccount.id, storageAccount.apiVersion).keys[0].value}'

resource sqlServer 'Microsoft.Sql/servers@2023-08-01-preview' = {
  name: sqlServerName
  location: location
  tags: tags
  properties: {
    administratorLogin: sqlServerAdministratorLogin
    administratorLoginPassword: sqlServerAdministratorLoginPassword
    version: '12.0'
  }
}

resource sqlDatabase 'Microsoft.Sql/servers/databases@2023-08-01-preview' = {
  parent: sqlServer
  name: sqlDatabaseName
  location: location
  sku: environmentConfigurationMap[environmentType].sqlDatabase.sku
  tags: tags
}

resource sqlFirewallRuleAllowAllAzureIPs 'Microsoft.Sql/servers/firewallRules@2023-08-01-preview' = {
  parent: sqlServer
  name: 'AllowAllAzureIPs'
  properties: {
    endIpAddress: '0.0.0.0'
    startIpAddress: '0.0.0.0'
  }
}

resource appServicePlan 'Microsoft.Web/serverfarms@2023-12-01' = {
  name: appServicePlanName
  location: location
  sku: environmentConfigurationMap[environmentType].appServicePlan.sku
  tags: tags
}

resource appServiceApp 'Microsoft.Web/sites@2023-12-01' = {
  name: appServiceAppName
  location: location
  tags: tags
  properties: {
    serverFarmId: appServicePlan.id
    siteConfig: {
      appSettings: [
        {
          name: 'APPINSIGHTS_INSTRUMENTATIONKEY'
          value: applicationInsights.properties.InstrumentationKey
        }
        {
          name: 'StorageAccountConnectionString'
          value: storageAccountConnectionString
        }
      ]
    }
  }
  identity: {
    type: 'UserAssigned'
    userAssignedIdentities: {
      '${managedIdentity.id}': {} // This format is required when working with user-assigned managed identities.
    }
  }
}

resource storageAccount 'Microsoft.Storage/storageAccounts@2023-05-01' = {
  name: storageAccountName
  location: location
  sku: environmentConfigurationMap[environmentType].storageAccount.sku
  kind: 'StorageV2'
  properties: {
    accessTier: 'Hot'
  }

  resource blobServices 'blobServices' existing = {
    name: 'default'

    resource containers 'containers' = [for blobContainerName in blobContainerNames: {
      name: blobContainerName
    }]
  }
}

@description('A user-assigned managed identity that is used by the App Service app to communicate with a storage account.')
resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-07-31-preview'= {
  name: managedIdentityName
  location: location
  tags: tags
}

@description('Grant the \'Contributor\' role to the user-assigned managed identity, at the scope of the resource group.')
resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
  name: guid(contributorRoleDefinitionId, resourceGroup().id) // Create a GUID based on the role definition ID and scope (resource group ID). This will return the same GUID every time the template is deployed to the same resource group.
  properties: {
    principalType: 'ServicePrincipal'
    roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', contributorRoleDefinitionId)
    principalId: managedIdentity.properties.principalId
    description: 'Grant the "Contributor" role to the user-assigned managed identity so it can access the storage account.'
  }
}

resource applicationInsights 'Microsoft.Insights/components@2020-02-02' = {
  name: applicationInsightsName
  location: location
  kind: 'web'
  tags: tags
  properties: {
    Application_Type: 'web'
  }
}

Tip

Als u met uw collega's werkt met GitHub of Azure-opslagplaatsen, is dit een goed moment om een pull-aanvraag in te dienen om uw wijzigingen te integreren in de hoofdvertakking. Het is een goed idee om pull-aanvragen in te dienen nadat u een deel van het herstructureren van werk hebt uitgevoerd.