Einführung
Genau wie der Bizeps den Arm verschönert, ist Bicep auch eine Verschönerung von ARM-Templates.
Im Grunde bietet es die gleichen Funktionen wie ARM-Templates, soll aber dennoch leichter zu lesen sein, da es nicht auf JSON basiert.
Was ist Bicep?
Bicep ist eine ARM-Vorlagensprache für das deklarative Bereitstellen von Azure-Resourcen.
Bicep ist eine Domain Specific Language (DSL), was bedeutet, dass sie für eine bestimmte Domäne entworfen wurde.
Wie wird das Tool genutzt?
In diesem Beitrag benutze ich Visual Studio Code (VS Code) und die Azure CLI, um Bicep– Dateien zu erstellen und in Azure bereitzustellen. Dazu brauchen wir die Bicep-Extension um die Vorlagen zu erstellen.
Und wir benötigen die Azure CLI, um die Ressourcen in der Vorlage bereitzustellen.
Um eine Bicep-Vorlage zu erstellen, muss erstmal eine Bicep-Datei erstellt werden. Man kann ganz einfach in VS Code eine Datei mit der Dateiendung FileName.bicep erstellen.
Wenn man dann ein Bicep-Template erstellt hat und bereitstellen will, sollte man erst einmal überprüfen ob die Ressourcen erzeugt werden können. Dazu gibt man folgendes im Terminal ein:
az deployment group validate -g ResourceGroupName –template-file FileName.bicep
Wenn keine Fehlermeldung kommt und man die Ressourcen nun erzeugen will, gibt man folgendes ein:
az deployment group create -g ResourceGroupName –template-file FileName.bicep
Man kann eine Bicep-Vorlage auf verschiedenen Ebenen bereitstellen, innerhalb von Ressourcengruppen, Subscriptions, ManagementGroups und Tenants. Standardmäßig wird die Ressourcengruppe als Ebene benutzt.
Dateistruktur einer Bicep-Vorlage
Eine Bicep Datei besitzt keine spezifische Vorlage wie beim JSON ARM-Template, sie hat aber eine gewisse Dateistruktur. In Bicep-Vorlagen kann man folgende Datentypen verwenden: array, bool, int, Object, secureObject, secureString und string.
Näheres zu den Datentypen kann man HIER finden.
Parameter
Parameter sind Werte, die vom Entwickler vorgegeben werden können, um die Bereitstellung anzupassen. Es gibt auch die Möglichkeit eine Parameter Datei zu erstellen, um dort alle Parameter übersichtlich zu sammeln.
An jedem Parameter hängt optional ein sog. Decorator, dies sind Bedingungen zum Parameter. In unserem Beispiel weiter unten im Text stellen wir z.B. die Bedingung, dass der Parameter maximal 11 Zeichen lang sein darf. Die Basis-Syntax von Decorators ist wie folgt:
@()
param =
Variables
Variablen werden benutzt, um Ausdrücke in der Vorlagensprache zu vereinfachen. Der Datentyp bei Variablen wird von dem Wert abgeleitet. Man sollte Variablen nur bei Werten benutzen, die sich oft im Template wiederholen.
var =
Resources
Um Ressourcen zu erzeugen, braucht es einen logischen Namen(resource–symbolic-name) für die Ressource, sowie einen Ressourcentyp und eine API–Version. Diese werden aber für die meisten Ressourcen durch die IntelliSense Unterstützung von der Bicep-Extension für VS Code schon vorgegeben.
Der logische Name ist dafür da, um Ressourcen logisch im Template voneinander abgrenzen zu können. Dies ist z.B. notwendig, um Ressourcen gleichen Typs mit verschiedenen Konfigurationseinstellungen erstellen zu können.
resource '@' = {
}
Functions
Bicep bietet – anders als ARM-Templates – keinen Block zum Erstellen von benutzerdefinierten Funktionen an, man kann aber dennoch vordefinierte Funktionen benutzen. Mehr dazu unter dem Link.
Outputs
Outputs benutzt man, um Werte aus der Bereitstellung zurückzugeben.
output =
Anhand eines kleinen Beispiels, in dem ich einen Storage Account erzeuge und den Connection String ausgeben lasse, kann man besser verstehen, wie eine Bicep Datei aufgebaut ist / geschrieben wird.
@maxLength(11)
param storagePrefix string
param storageSKU string = 'Standard_LRS'
param location string = resourceGroup().location
var uniqueStorageName = '${storagePrefix}${uniqueString(resourceGroup().id)}'
resource storage 'Microsoft.Storage/storageAccounts@2021-04-01' = {
name: uniqueStorageName
location: location
sku: {
name: storageSKU
}
kind: 'StorageV2'
properties: {
supportsHttpsTrafficOnly: true
}
}
output storageName string = storage.name
// Determine our connection string
var StorageConnectionString = 'DefaultEndpointsProtocol=https;AccountName=${storage.name};EndpointSuffix=${environment().suffixes.storage};AccountKey=${listKeys(storage.id, storage.apiVersion).keys[0].value}'
// Output our variable
output StorageAccountConnectionString string = StorageConnectionString
Vergleicht man die ARM-Vorlage vom letzten Blog-Beitrag mit dieser Bicep-Vorlage, sieht man, dass die gleichen Funktionen ausgeführt werden, aber die Bicep-Datei um einiges kürzer und einfacher zu lesen ist.
Ein cooles Feature von Bicep ist, dass Bicep dazu fähig ist, auf Daten von Ressourcen zuzugreifen, die noch nicht existieren.
In unserem Beispiel greift Bicep direkt auf die Account Keys von unserem noch nicht existierenden Storage Account zu; so leicht ist das in anderen Infrastructure-As-Code-Tools nicht immer.
Beispiel: Erzeugen eines Modern Data Warehouse
Wie am Anfang erwähnt, erzeuge ich ein Modern Data Warehouse und ergänze unser Beispiel oben mit dem Storage Account um einen Container, eine Azure Data Factory, einen SQL–Server sowie eine SQL-Datenbank. Der Code für unser Beispiel sieht dann wie folgt aus:
@description('Specifies the name of the Azure Storage account.')
@maxLength(11)
param storagePrefix string
@description('Specifies the name of the blob container.')
param containerName string
@description('Specifies the name of the Azure Data Factory.')
param dataFactoryPrefix string
@description('Specifies the name of the Azure SQL-Server.')
param SQLserverPrefix string
@description('Specifies the Login to SQL-Server.')
param administratorLogin string
@description('Specifies the Login Password to SQL-Server.')
param administratorLoginPassword string
@description('Specifies the name of the Azure SQL-DB.')
param SQLDBPrefix string
var location = resourceGroup().location
var uniqueStorageName = '${storagePrefix}${uniqueString(resourceGroup().id)}'
var uniqueDataFactoryName = '${dataFactoryPrefix}${uniqueString(resourceGroup().id)}'
var uniqueSQLServerName = '${SQLserverPrefix}${uniqueString(resourceGroup().id)}'
var uniqueSQLDBName = '${SQLDBPrefix}${uniqueString(resourceGroup().id)}'
resource storage 'Microsoft.Storage/storageAccounts@2021-04-01' = {
name: uniqueStorageName
location: location
sku: {
name: 'Standard_LRS'
}
kind: 'StorageV2'
properties: {
}
}
resource container 'Microsoft.Storage/storageAccounts/blobServices/containers@2021-04-01'={
name : '${storage.name}/default/${containerName}'
dependsOn:[
storage
]
}
resource adf 'Microsoft.DataFactory/factories@2018-06-01' = {
properties: {}
name: uniqueDataFactoryName
location: location
identity: {
type: 'SystemAssigned'
}
}
resource SQLServer 'Microsoft.Sql/servers@2021-02-01-preview' = {
name: uniqueSQLServerName
location: location
properties: {
administratorLogin: administratorLogin
administratorLoginPassword: administratorLoginPassword
}
}
resource SQLDB 'Microsoft.Sql/servers/databases@2021-02-01-preview' = {
properties: {}
name: '${SQLServer.name}/${uniqueSQLDBName}'
location: location
sku: {
name: 'Standard'
tier: 'Standard'
}
dependsOn:[
SQLServer
]
}
// Determine our connection string
var StorageConnectionString = 'DefaultEndpointsProtocol=https;AccountName=${storage.name};EndpointSuffix=${environment().suffixes.storage};AccountKey=${listKeys(storage.id, storage.apiVersion).keys[0].value}'
// Output our variable
output StorageAccountConnectionString string = StorageConnectionString
output StorageName string = storage.name
Fazit
Zum Abschluss dieses Blogbeitrages erläutere ich die Vor- und Nachteile von Bicep-Templates.
Wie bei ARM-Templates eignet sich Visual Studio Code zur Entwicklung von Bicep-Vorlagen. Man hat einige grundsätzliche Vorteile dabei, wie unter anderem eine Quellcodeverwaltung.
Des weiteren bietet die Erweiterung, die man benötigt, viele weitere Vorteile, wie zum Beispiel IntelliSense zur Deklarierung von Ressourcen. Durch die Erweiterung kann man sich auch die Bereitstellung visualisieren lassen, als Beispiel für eine Visualisierung hier die Bereitstellung für unser MDWH.
Ebenso wie ARM-Templates unterstützen Bicep-Vorlagen den, “Day-Zero”-Support, was bedeutet, dass man neue Ressourcen oder Features, sobald diese im Azure Portal verfügbar sind, auch direkt über Bicep bereitstellen kann.
Bei Verwendung der Azure-CLI unterstützen Bicep-Bereitstellungen die validate-Funktion, mit der man vor der Bereitstellung in Sekundenschnelle herausfinden kann, ob Fehler entstehen, könnten.
Wenn man bereits ARM-Vorlagen hat und mit Bicep weiterarbeiten möchte, kann man durch die Azure CLI ARM-Vorlagen zu Bicep-Vorlagen automatisch transformieren:
az bicep decompile –file fileName.json
Man kann sagen, dass die Vorteile, die ARM-Vorlagen bereits haben, auch zu den Vorteilen von Bicep-Vorlagen gehören. Einige der Nachteile von ARM werden durch Bicep gelöst, wie zum Beispiel der Nachteil, dass ARM-Vorlagen so schwer zu lesen sind. Bicep-Vorlagen sind eindeutig einfacher zu lesen, und sind kürzer vom Umfang.
So schön die Vorteile sein mögen, haben auch Bicep-Vorlagen Nachteile.
Ein sehr großer Nachteil ist, dass man Bicep (wie auch ARM), nur in Azure benutzen kann. Dieses Tool ist daher ebenso, wie ARM also nur für solche Entwiclungs-Teams interessant, die sich fest auf diesen Cloud Provider eingeschossen haben.
Ebenso ein wichtiger Punkt, weshalb ich mich gegen Bicep entschieden habe, war der Fakt, dass man während der Bereitstellung keine lokalen Dateien in einen Storage Container hochladen kann; eine Beschränkung, die. auch bei ARM vorliegt.