Övning – Omstrukturera Bicep-filen
När du har granskat mallen med dina kollegor bestämmer du dig för att omstrukturera filen så att den blir enklare för dem att arbeta med. I den här övningen använder du de metodtips som du har lärt dig i föregående enheter.
Din uppgift
Granska Bicep-mallen som du sparade tidigare. Tänk på de råd du har läst om hur du strukturerar dina mallar. Försök att uppdatera mallen för att göra det enklare för dina kollegor att förstå.
I nästa avsnitt finns det några pekare på specifika delar av mallen och några tips om saker som du kanske vill ändra. Vi tillhandahåller en föreslagen lösning, men mallen kan se annorlunda ut, vilket är helt OK!
Dricks
När du går igenom refaktoriseringsprocessen är det bra att se till att Bicep-filen är giltig och att du inte oavsiktligt har introducerat några fel. Bicep-tillägget för Visual Studio Code hjälper till med detta. Se upp för eventuella röda eller gula vågiga rader under koden, eftersom de indikerar ett fel eller en varning. Du kan också visa en lista över problemen i filen genom att välja Visa>problem.
Uppdatera parametrarna
Vissa parametrar i mallen är inte tydliga. Tänk till exempel på följande parametrar:
@allowed([ 'F1' 'D1' 'B1' 'B2' 'B3' 'S1' 'S2' 'S3' 'P1' 'P2' 'P3' 'P4' ]) param skuName string = 'F1' @minValue(1) param skuCapacity int = 1
Vad används de till?
Dricks
Om du har en parameter som du försöker förstå kan Visual Studio Code hjälpa dig. Välj och håll (eller högerklicka) ett parameternamn var som helst i filen och välj Sök efter alla referenser.
Behöver mallen ange listan över tillåtna värden för parametern
skuName
? Vilka resurser påverkas av att välja olika värden för dessa parametrar? Finns det bättre namn som du kan ge parametrarna?Dricks
När du byter namn på identifierare måste du byta namn på dem konsekvent i alla delar av mallen. Detta är särskilt viktigt för parametrar, variabler och resurser som du refererar till i hela mallen.
Visual Studio Code är ett praktiskt sätt att byta namn på symboler: välj den identifierare som du vill byta namn på, välj F2, ange ett nytt namn och välj sedan Retur:
De här stegen byter namn på identifieraren och uppdaterar automatiskt alla referenser till den.
Parametern
managedIdentityName
har inget standardvärde. Kan du åtgärda det eller, ännu bättre, skapa namnet automatiskt i mallen?Titta på parameterdefinitionen
roleDefinitionId
:param roleDefinitionId string = 'b24988ac-6180-42a0-ab88-20f7382dd24c'
Varför finns det ett standardvärde på
b24988ac-6180-42a0-ab88-20f7382dd24c
? Vad betyder den långa identifieraren? Hur skulle någon annan veta om man ska använda standardvärdet eller åsidosätta det? Vad kan du göra för att förbättra identifieraren? Är det ens meningsfullt att ha detta som en parameter?Dricks
Den identifieraren är rolldefinitions-ID för deltagare för Azure. Hur kan du använda den informationen för att förbättra mallen?
Hur vet någon vad varje parameter är till för när någon distribuerar mallen? Kan du lägga till några beskrivningar som hjälper mallens användare?
Lägga till en konfigurationsuppsättning
Du pratar med dina kollegor och bestämmer dig för att använda specifika SKU:er för varje resurs, beroende på vilken miljö som distribueras. Du bestämmer dig för dessa SKU:er för var och en av dina resurser:
Resurs SKU för produktion SKU för icke-produktion App Service-plan S1, två instanser F1, en instans Lagringskonto GRS LRS SQL-databas S1 Grundläggande Kan du använda en konfigurationsuppsättning för att förenkla parameterdefinitionerna?
Uppdatera de symboliska namnen
Ta en titt på de symboliska namnen för resurserna i mallen. Vad kan du göra för att förbättra dem?
Din Bicep-mall innehåller resurser med en mängd olika versaler för deras symboliska namn, till exempel:
storageAccount
ochwebSite
, som använder camelCase-versaler.roleassignment
ochsqlserver
, som använder flat versaler.sqlserverName_databaseName
ochAppInsights_webSiteName
, som använder versaler för ormfall.
Kan du åtgärda dessa för att använda ett format konsekvent?
Titta på den här rolltilldelningsresursen:
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 } }
Är det symboliska namnet tillräckligt beskrivande för att hjälpa någon annan att arbeta med den här mallen?
Dricks
Anledningen till att identiteten behöver en rolltilldelning är att webbappen använder sin hanterade identitet för att ansluta till databasservern. Hjälper det dig att klargöra detta i mallen?
Några resurser har symboliska namn som inte återspeglar de aktuella namnen på Azure-resurser:
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' = { // ... }
Hanterade identiteter brukade kallas MSI: er, App Service-planer brukade kallas värdplaner och App Service-appar brukade kallas webbplatser.
Kan du uppdatera dessa till de senaste namnen för att undvika förvirring i framtiden?
Förenkla blobcontainerns definitioner
Titta på hur blobcontainrarna definieras:
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}' }
En av dem använder egenskapen
parent
och den andra inte. Kan du åtgärda dessa så att de är konsekventa?Blobcontainerns namn ändras inte mellan miljöer. Tror du att namnen måste anges med hjälp av parametrar?
Det finns två blobcontainrar. Kan de distribueras med hjälp av en loop?
Uppdatera resursnamnen
Det finns några parametrar som uttryckligen anger resursnamn:
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'
Finns det något annat sätt att göra det här?
Varning
Kom ihåg att resurser inte kan byta namn när de har distribuerats. När du ändrar mallar som redan används bör du vara försiktig när du ändrar hur mallen skapar resursnamn. Om mallen distribueras om och resursen har ett nytt namn skapar Azure en annan resurs. Den kan till och med ta bort den gamla resursen om du distribuerar den i fullständigt läge.
Du behöver inte oroa dig för detta här, eftersom det bara är ett exempel.
Den logiska SQL-serverns resursnamn anges med hjälp av en variabel, även om den behöver ett globalt unikt namn:
var sqlserverName = 'toywebsite${uniqueString(resourceGroup().id)}'
Hur kan du förbättra detta?
Uppdatera beroenden och underordnade resurser
Här är en av dina resurser, som innehåller en
dependsOn
egenskap. Behöver den verkligen det?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 ] }
Observera hur dessa underordnade resurser deklareras i mallen:
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 ] }
Hur kan du ändra hur dessa resurser deklareras? Finns det några andra resurser i mallen som också ska uppdateras?
Uppdatera egenskapsvärden
Ta en titt på resursegenskaperna för SQL-databasen:
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 } }
Är det vettigt att hårdkoda SKU:ns egenskapsvärde
name
? Och vilka är dessa konstiga värden förcollation
egenskaperna ochmaxSizeBytes
?Dricks
Egenskaperna
collation
ochmaxSizeBytes
är inställda på standardvärdena. Om du inte anger värdena själv används standardvärdena. Hjälper det dig att bestämma vad du ska göra med dem?Kan du ändra hur lagringen anslutningssträng anges så att det komplexa uttrycket inte definieras i förhållande till resursen?
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}': {} } } }
Ordning på element
Är du nöjd med ordningen på elementen i filen? Hur kan du förbättra filens läsbarhet genom att flytta runt elementen?
Ta en titt på variabeln
databaseName
. Hör den hemma där den är nu?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 } }
Har du lagt märke till den utkommenterade resursen
webSiteConnectionStrings
? Tror du att det måste finnas i filen?
Lägga till kommentarer, taggar och andra metadata
Tänk på något i mallen som kanske inte är uppenbart eller som behöver ytterligare förklaring. Kan du lägga till kommentarer för att göra det tydligare för andra som kan öppna filen i framtiden?
Ta en titt på resursens
webSite
identity
egenskap: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}': {} } } }
Den syntaxen är konstig, eller hur? Tror du att detta behöver en kommentar för att förklara det?
Titta på rolltilldelningsresursen:
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 } }
Resursnamnet använder
guid()
funktionen. Skulle det hjälpa att förklara varför?Kan du lägga till en beskrivning i rolltilldelningen?
Kan du lägga till en uppsättning taggar till varje resurs?
Föreslagen lösning
Här är ett exempel på hur du kan omstrukturera mallen. Mallen kanske inte ser exakt ut så här, eftersom formatmallen kan vara annorlunda.
@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'
}
}
Dricks
Om du arbetar med dina kollegor med GitHub eller Azure Repos är det här ett bra tillfälle att skicka en pull-begäran för att integrera dina ändringar i huvudgrenen. Det är en bra idé att skicka pull-begäranden när du har gjort en del refaktoriseringsarbete.