Esercizio - Effettuare il refactoring del file Bicep
Dopo aver esaminato il modello con i colleghi, si decide di effettuare il refactoring del file in modo che possano usarlo più facilmente. In questo esercizio si applicano le procedure consigliate apprese nelle unità precedenti.
Attività dell'utente
Esaminare il modello Bicep salvato in precedenza. Tenere presenti le indicazioni lette su come strutturare i modelli. Provare ad aggiornare il modello in modo che risulti più comprensibile per i colleghi.
Nelle sezioni successive sono disponibili alcune linee guida per parti specifiche del modello e alcuni suggerimenti sugli elementi che potrebbe essere necessario modificare. La soluzione presentata è un suggerimento. Il modello in uso potrebbe essere diverso, il che è perfettamente accettabile.
Suggerimento
Durante il processo di refactoring, è opportuno assicurarsi che il file Bicep sia valido e che non siano stati introdotti accidentalmente errori. A questo scopo, è utile l'estensione Bicep per Visual Studio Code. Prestare attenzione a eventuali righe ondulate rosse o gialle sotto il codice, perché indicano un errore o un avviso. È anche possibile visualizzare un elenco dei problemi nel file selezionando Visualizza>Problemi.
Aggiornare i parametri
Alcuni parametri nel modello non sono chiari. Ad esempio, considerare questi parametri:
@allowed([ 'F1' 'D1' 'B1' 'B2' 'B3' 'S1' 'S2' 'S3' 'P1' 'P2' 'P3' 'P4' ]) param skuName string = 'F1' @minValue(1) param skuCapacity int = 1
Per che cosa vengono usati?
Suggerimento
Se non è chiara la natura di un parametro, Visual Studio Code può essere utile. Selezionare e tenere premuto (o fare clic con il pulsante destro del mouse) su un nome di parametro in un punto qualsiasi del file e selezionare Trova tutti i riferimenti.
Il modello deve specificare l'elenco di valori consentiti per il parametro
skuName
? Quali risorse sono interessate dalla scelta di valori diversi per questi parametri? Esistono nomi migliori che è possibile assegnare ai parametri?Suggerimento
Quando si rinominano gli identificatori, assicurarsi di farlo in modo coerente in tutte le parti del modello. È importante soprattutto per i parametri, le variabili e le risorse a cui si fa riferimento in tutto il modello.
Visual Studio Code offre un modo pratico per rinominare i simboli: selezionare l'identificatore che si vuole rinominare, premere F2, immettere un nuovo nome e quindi premere INVIO:
Questi passaggi consentono di rinominare l'identificatore e aggiornare automaticamente tutti i riferimenti.
Il parametro
managedIdentityName
non ha un valore predefinito. È possibile risolvere il problema o, meglio ancora, creare automaticamente il nome nel modello?Analizzare la definizione del parametro
roleDefinitionId
:param roleDefinitionId string = 'b24988ac-6180-42a0-ab88-20f7382dd24c'
Perché è presente un valore predefinito
b24988ac-6180-42a0-ab88-20f7382dd24c
? Cosa significa questo lungo identificatore? In che modo un altro utente può stabilire se usare il valore predefinito o eseguirne l'override? Cosa si può fare per migliorare l'identificatore? Ha senso usarlo come parametro?Suggerimento
Tale identificatore è l'ID definizione del ruolo Contributor per Azure. Come si possono usare queste informazioni per migliorare il modello?
Quando un utente distribuisce il modello, come può sapere a che cosa serve ogni parametro? È possibile aggiungere descrizioni utili agli utenti del modello?
Aggiungere un set di configurazione
Dopo aver parlato con i colleghi, si decide di usare SKU specifici per ogni risorsa, a seconda dell'ambiente da distribuire. Si scelgono questi SKU per ognuna delle risorse:
Conto risorse SKU per la produzione SKU per la non produzione Piano di servizio app S1, due istanze F1, una istanza Account di archiviazione GRS LRS Database SQL S1 Di base È possibile usare un set di configurazione per semplificare le definizioni dei parametri?
Aggiornare i nomi simbolici
Esaminare i nomi simbolici per le risorse nel modello. Cosa si può fare per migliorarli?
Il modello Bicep contiene risorse con svariati stili per l'uso di maiuscole e minuscole nei nomi simbolici, ad esempio:
storageAccount
ewebSite
, che usano lo stile camelCase.roleassignment
esqlserver
, che usano solo lettere minuscole.sqlserverName_databaseName
eAppInsights_webSiteName
, che usano lo stile snake_case.
È possibile sistemarle e usare un solo stile in modo coerente?
Esaminare questa risorsa assegnazione di ruolo:
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 } }
Il nome simbolico è sufficientemente descrittivo da consentire a qualcun altro di usare questo modello?
Suggerimento
Il motivo per cui è necessaria un'assegnazione di ruolo per l'identità è che l'app Web usa la propria identità gestita per connettersi al server di database. Si è in grado di chiarire questo concetto nel modello?
Alcune risorse hanno nomi simbolici che non corrispondono ai nomi correnti delle risorse di Azure:
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' = { // ... }
Le identità gestite venivano chiamate MSI, i piani di servizio app venivano chiamati piani di hosting e le app di Servizio app venivano chiamate siti Web.
È possibile aggiornarli con i nomi più recenti per evitare confusione in futuro?
Semplificare le definizioni dei contenitori BLOB
Osservare come vengono definiti i contenitori BLOB:
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}' }
Uno di essi usa la proprietà
parent
, l'altro no. È possibile correggerli in modo che siano coerenti?I nomi dei contenitori BLOB non cambieranno tra gli ambienti. Si ritiene che i nomi debbano essere specificati usando i parametri?
Sono presenti due contenitori BLOB. Si possono distribuire usando un ciclo?
Aggiornare i nomi delle risorse
Esistono alcuni parametri che impostano in modo esplicito i nomi delle risorse:
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'
Esiste un altro modo per farlo?
Attenzione
Tenere presente che le risorse non possono essere rinominate dopo la distribuzione. Se si modificano modelli già in uso, prestare attenzione quando si modifica il modo in cui il modello crea i nomi delle risorse. Se il modello viene distribuito nuovamente e la risorsa ha un nuovo nome, Azure creerà un'altra risorsa. Potrebbe persino eliminare la risorsa precedente se lo si distribuisce in modalità completa.
Non è necessario preoccuparsene, dal momento che è solo un esempio.
Il nome della risorsa del server logico SQL viene impostato usando una variabile, anche se è necessario un nome univoco globale:
var sqlserverName = 'toywebsite${uniqueString(resourceGroup().id)}'
Come è possibile risolvere il problema?
Aggiornare le dipendenze e le risorse figlio
Ecco una delle risorse, che include una proprietà
dependsOn
. È davvero necessaria?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 ] }
Si noti come queste risorse figlio vengono dichiarate nel modello:
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 ] }
Come è possibile modificare il modo in cui queste risorse vengono dichiarate? Nel modello sono presenti anche altre risorse che devono essere aggiornate?
Aggiornare i valori delle proprietà
Esaminare le proprietà della risorsa database SQL:
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 } }
Ha senso impostare come hardcoded il valore della proprietà
name
dello SKU? E che cosa sono quegli strani valori delle proprietàcollation
emaxSizeBytes
?Suggerimento
Le proprietà
collation
emaxSizeBytes
vengono impostate sui valori predefiniti. Se non si specificano i valori manualmente, verranno usati i valori predefiniti. Questo è utile per decidere come procedere in proposito?È possibile modificare la modalità di impostazione della stringa di connessione di archiviazione in modo che l'espressione complessa non sia definita inline con la risorsa?
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}': {} } } }
Ordine degli elementi
Si è soddisfatti dell'ordine degli elementi nel file? Come si può migliorare la leggibilità del file spostando gli elementi?
Esaminare la variabile
databaseName
. Va bene dove si trova ora?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 } }
Si è notato che la risorsa
webSiteConnectionStrings
è stata impostata come commento? Si ritiene che debba essere presente nel file?
Aggiungere commenti, tag e altri metadati
Si pensi a qualsiasi elemento del modello che potrebbe non risultare ovvio o richiedere una spiegazione aggiuntiva. È possibile aggiungere commenti per renderlo più chiaro per gli altri utenti che potrebbero aprire il file in futuro?
Esaminare la proprietà
identity
della risorsawebSite
: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}': {} } } }
Non è insolita questa sintassi? Si ritiene che sia necessario spiegarla con un commento?
Esaminare la risorsa assegnazione di ruolo:
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 } }
Il nome della risorsa usa la funzione
guid()
. Può essere utile spiegare perché?È possibile aggiungere una descrizione all'assegnazione di ruolo?
È possibile aggiungere un set di tag a ogni risorsa?
Soluzione suggerita
Ecco un esempio di come è possibile effettuare il refactoring del modello. Il modello potrebbe non essere esattamente come il seguente, perché lo stile potrebbe essere diverso.
@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'
}
}
Suggerimento
Se si lavora con i colleghi usando GitHub o Azure Repos, questo è il momento ideale per inviare una richiesta pull per integrare le modifiche nel ramo principale. È consigliabile inviare le richieste pull dopo un'operazione di refactoring.