Übung: Umgestalten der Bicep-Datei

Abgeschlossen

Nachdem Sie die Vorlage mit Ihren Kollegen überprüft haben, beschließen Sie, die Datei umzugestalten, um ihre Verwendung für die Kollegen zu vereinfachen. In dieser Übung wenden Sie die bewährten Methoden an, die Sie in den vorherigen Lerneinheiten kennengelernt haben.

Ihre Aufgabe

Überprüfen Sie die Bicep-Vorlage, die Sie zuvor gespeichert haben. Rufen Sie sich die Ratschläge aus der Lerneinheit zum Strukturieren Ihrer Vorlagen in Erinnerung. Versuchen Sie, Ihre Vorlage zu aktualisieren, damit sie für Ihre Kollegen leichter verständlich ist.

Die nächsten Abschnitte enthalten Verweise auf bestimmte Teile der Vorlage und Hinweise zu Dingen, die Sie ändern sollten. Wir stellen eine empfohlene Lösung bereit, jedoch muss Ihre Vorlage nicht damit übereinstimmen.

Tipp

Während der Umgestaltung sollten Sie sicherstellen, dass Ihre Bicep-Datei gültig ist und Sie nicht versehentlich Fehler eingeführt haben. Hierfür ist die Bicep-Erweiterung für Visual Studio Code hilfreich. Achten Sie auf rote oder gelbe Wellenlinien unter Ihrem Code, da sie auf einen Fehler oder eine Warnung hinweisen. Sie können auch eine Liste der Probleme in Ihrer Datei anzeigen, indem Sie Ansicht>Probleme auswählen.

Aktualisieren der Parameter

  1. Die Bedeutung einiger Parameter in Ihrer Vorlage ist nicht ersichtlich. Betrachten Sie beispielsweise die folgenden Parameter:

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

    Zu welchem Zweck werden sie verwendet?

    Tipp

    Wenn Sie die Bedeutung eines Parameters ermitteln möchten, kann Visual Studio Code hilfreich sein. Klicken Sie an einer beliebigen Stelle in der Datei auf den Namen eines Parameters und halten Sie die Maustaste gedrückt (oder klicken Sie mit der rechten Maustaste auf den Parameter), und wählen Sie Alle Verweise suchen aus.

    Muss in der Vorlage die Liste der zulässigen Werte für den skuName-Parameter angegeben werden? Welche Ressourcen sind betroffen, wenn unterschiedliche Werte für diese Parameter ausgewählt werden? Gibt es bessere Namen, die Sie den Parametern geben können?

    Tipp

    Wenn Sie Bezeichner umbenennen, müssen Sie sie in allen Teilen der Vorlage konsistent umbenennen. Dies gilt insbesondere für Parameter, Variablen und Ressourcen, auf die Sie in der gesamten Vorlage verweisen.

    Visual Studio Code bietet eine bequeme Möglichkeit zum Umbenennen von Symbolen: Wählen Sie den Bezeichner aus, den Sie umbenennen möchten, drücken Sie F2, geben Sie einen neuen Namen ein, und drücken Sie dann die EINGABETASTE:

    Screenshot from Visual Studio Code that shows how to rename a symbol.

    Mit diesen Schritten wird der Bezeichner umbenannt und alle Verweise darauf werden automatisch aktualisiert.

  2. Der Parameter managedIdentityName hat keinen Standardwert. Können Sie dies korrigieren oder den Namen automatisch in der Vorlage erstellen lassen (dies wäre die bessere Möglichkeit)?

  3. Sehen Sie sich die Definition des roleDefinitionId-Parameters an:

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

    Warum lautet der Standardwert b24988ac-6180-42a0-ab88-20f7382dd24c? Was bedeutet dieser lange Bezeichner? Wie kann eine andere Person erkennen, ob der Standardwert verwendet oder überschrieben werden soll? Was können Sie tun, um den Bezeichner zu verbessern? Ist die Verwendung dieses Parameters überhaupt sinnvoll?

    Tipp

    Dieser Bezeichner ist die Rollendefinitions-ID der Rolle Mitwirkender für Azure. Wie können Sie diese Information verwenden, um die Vorlage zu verbessern?

  4. Wie kann eine Person, die die Vorlage bereitstellt, den Zweck der einzelnen Parameter erkennen? Können Sie Beschreibungen hinzufügen, um die Benutzer Ihrer Vorlage zu unterstützen?

Hinzufügen eines Konfigurationssatzes

  1. Sie sprechen mit Ihren Kollegen und entscheiden sich, für jede Ressource bestimmte SKUs abhängig von der bereitzustellenden Umgebung zu verwenden. Sie entscheiden sich für die folgenden SKUs für die einzelnen Ressourcen:

    Resource SKU für Produktion SKU für Nicht-Produktion
    App Service-Plan S1, zwei Instanzen F1, eine Instanz
    Speicherkonto GRS LRS
    SQL-Datenbank S1 Basic
  2. Können Sie mit einem Konfigurationssatz die Parameterdefinitionen vereinfachen?

Aktualisieren der symbolischen Namen

Sehen Sie sich die symbolischen Namen für die Ressourcen in der Vorlage an. Wie können Sie diese verbessern?

  1. Ihre Bicep-Vorlage enthält Ressourcen mit einer Vielzahl von Formaten der Groß-/Kleinschreibung für die symbolischen Namen, z. B.:

    • storageAccount und webSite (camelCase-Schreibweise)
    • roleassignment und sqlserver (Kleinschreibung)
    • sqlserverName_databaseName und AppInsights_webSiteName (snake_case-Schreibweise)

    Können Sie diese verschiedenen Schreibweisen vereinheitlichen?

  2. Sehen Sie sich diese Ressource für die Rollenzuweisung an:

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

    Ist der symbolische Name für andere Benutzer dieser Vorlage aussagekräftig genug?

    Tipp

    Die Identität erfordert eine Rollenzuweisung, da die Web-App die verwaltete Identität zum Herstellen einer Verbindung mit dem Datenbankserver verwendet. Können Sie den Namen in der Vorlage anhand dieser Information aussagekräftiger machen?

  3. Einige Ressourcen haben symbolische Namen, die nicht den aktuellen Namen der Azure-Ressourcen entsprechen:

    resource hostingPlan 'Microsoft.Web/serverfarms@2020-06-01' = {
      // ...
    }
    resource webSite 'Microsoft.Web/sites@2020-06-01' = {
      // ...
    }
    resource msi 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = {
      // ...
    }
    

    Verwaltete Identitäten wurden früher als MSIs bezeichnet, App Service-Pläne wurden als Hostingpläne bezeichnet, und App Service-Apps wurden als Websites bezeichnet.

    Können Sie diese Namen aktualisieren, um in Zukunft Verwirrung zu vermeiden?

Vereinfachen der Blobcontainerdefinitionen

  1. Sehen Sie sich an, wie die Blobcontainer definiert sind:

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

    Für einen von ihnen wird die parent-Eigenschaft verwendet, und für den anderen wird sie nicht verwendet. Können Sie dies vereinheitlichen?

  2. Die Namen der Blobcontainer bleiben zwischen Umgebungen unverändert. Glauben Sie, dass die Namen mithilfe von Parametern angegeben werden müssen?

  3. Es sind zwei Blobcontainer vorhanden. Können sie mithilfe einer Schleife bereitgestellt werden?

Aktualisieren der Ressourcennamen

  1. Es sind einige Parameter vorhanden, die Ressourcennamen explizit festlegen:

    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'
    

    Lässt sich dies auf andere Weise durchführen?

    Achtung

    Beachten Sie, dass Ressourcen nicht umbenannt werden können, sobald sie bereitgestellt wurden. Gehen Sie beim Ändern bereits verwendeter Vorlagen vorsichtig vor, wenn Sie die Art und Weise ändern, in der durch die Vorlage Ressourcennamen erstellt werden. Wenn die Vorlage erneut bereitgestellt wird und die Ressource einen neuen Namen hat, erstellt Azure eine weitere Ressource. Die alte Ressource wird möglicherweise sogar gelöscht, wenn Sie sie im Modus Vollständig bereitstellen.

    Sie brauchen sich hier keine Sorgen deswegen zu machen, da es sich nur um ein Beispiel handelt.

  2. Der Ressourcenname des logischen SQL-Servers wird mithilfe einer Variablen festgelegt, obwohl er einen global eindeutigen Namen erfordert:

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

    Wie können Sie dies verbessern?

Aktualisieren von Abhängigkeiten und untergeordneten Ressourcen

  1. Unten ist eine Ihrer Ressourcen dargestellt, die die dependsOn-Eigenschaft enthält. Wird sie wirklich benötigt?

    resource sqlserverName_AllowAllAzureIPs 'Microsoft.Sql/servers/firewallRules@2014-04-01' = {
      name: '${sqlserver.name}/AllowAllAzureIPs'
      properties: {
        endIpAddress: '0.0.0.0'
        startIpAddress: '0.0.0.0'
      }
      dependsOn: [
        sqlserver
      ]
    }
    
  2. Beachten Sie, wie diese untergeordneten Ressourcen in Ihrer Vorlage deklariert werden:

    resource sqlserverName_databaseName 'Microsoft.Sql/servers/databases@2020-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@2014-04-01' = {
      name: '${sqlserver.name}/AllowAllAzureIPs'
      properties: {
        endIpAddress: '0.0.0.0'
        startIpAddress: '0.0.0.0'
      }
      dependsOn: [
        sqlserver
      ]
    }
    

    Wie können Sie die Deklaration dieser Ressourcen ändern? Gibt es weitere Ressourcen in der Vorlage, die ebenfalls aktualisiert werden sollten?

Aktualisieren von Eigenschaftswerten

  1. Sehen Sie sich die Eigenschaften der SQL-Datenbankressource an:

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

    Ist es sinnvoll, den Wert der name-Eigenschaft der SKU hartzucodieren? Und was hat es mit den eigenartigen Werten für die Eigenschaften collation und maxSizeBytes auf sich?

    Tipp

    Die Eigenschaften collation und maxSizeBytes sind auf die Standardwerte festgelegt. Wenn Sie die Werte nicht selbst angeben, werden die Standardwerte verwendet. Hilft Ihnen dies zu entscheiden, wie Sie diese Werte behandeln sollten?

  2. Können Sie die Art und Weise ändern, wie die Speicherverbindungszeichenfolge festgelegt wird, sodass der komplexe Ausdruck nicht inline mit der Ressource definiert wird?

    resource webSite 'Microsoft.Web/sites@2020-06-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}': {}
        }
      }
    }
    

Reihenfolge der Elemente

  1. Sind Sie mit der Reihenfolge der Elemente in der Datei einverstanden? Wie können Sie die Lesbarkeit der Datei verbessern, indem Sie die Elemente verschieben?

  2. Werfen wir einen Blick auf die databaseName-Variable. Befindet sie sich an der richtigen Stelle?

    var databaseName = 'ToyCompanyWebsite'
    resource sqlserverName_databaseName 'Microsoft.Sql/servers/databases@2020-08-01-preview' = {
      name: '${sqlserver.name}/${databaseName}'
      location: location
      sku: {
        name: 'Basic'
      }
      properties: {
        collation: 'SQL_Latin1_General_CP1_CI_AS'
        maxSizeBytes: 1073741824
      }
    }
    
  3. Haben Sie die auskommentierte Ressource webSiteConnectionStrings bemerkt? Glauben Sie, dass dies in der Datei vorhanden sein muss?

Hinzufügen von Kommentaren, Tags und anderen Metadaten

Denken Sie an Inhalt der Vorlage, dessen Bedeutung nicht offensichtlich ist oder der eine zusätzliche Erläuterung erfordert. Können Sie Kommentare hinzufügen, um ihn für andere Benutzer, die die Datei in Zukunft möglicherweise öffnen, besser verständlich zu machen?

  1. Sehen Sie sich die identity-Eigenschaft der webSite-Ressource an:

    resource webSite 'Microsoft.Web/sites@2020-06-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}': {}
        }
      }
    }
    

    Finden Sie nicht auch, dass diese Syntax ungewöhnlich ist? Sind Sie der Meinung, dass ein erläuternder Kommentar erforderlich ist?

  2. Sehen Sie sich die Ressource für die Rollenzuweisung an:

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

    Der Name der Ressource verwendet die guid()-Funktion. Ist es sinnvoll, den Grund dafür zu erläutern?

  3. Können Sie der Rollenzuweisung eine Beschreibung hinzufügen?

  4. Können Sie jeder Ressource einen Satz von Tags hinzufügen?

Vorgeschlagene Lösung

Hier ist ein Beispiel dafür, wie Sie die Vorlage umgestalten können. Ihre Vorlage sieht möglicherweise nicht genau so aus, da Sie eventuell ein anderes Format verwenden.

@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@2019-06-01-preview' = {
  name: sqlServerName
  location: location
  tags: tags
  properties: {
    administratorLogin: sqlServerAdministratorLogin
    administratorLoginPassword: sqlServerAdministratorLoginPassword
    version: '12.0'
  }
}

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

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

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

resource appServiceApp 'Microsoft.Web/sites@2020-06-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@2019-06-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@2018-11-30' = {
  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@2020-04-01-preview' = {
  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@2018-05-01-preview' = {
  name: applicationInsightsName
  location: location
  kind: 'web'
  tags: tags
  properties: {
    Application_Type: 'web'
  }
}

Tipp

Wenn Sie bei der Zusammenarbeit mit Ihren Kollegen GitHub oder Azure Repos verwenden, ist dies eine gute Gelegenheit, einen Pull Request zu übermitteln, um Ihre Änderungen in den Mainbranch zu integrieren. Es empfiehlt sich, einen Pull Requests zu übermitteln, nachdem Sie eine Umgestaltung durchgeführt haben.