Wer Azure-Ressourcen nicht mehr per Hand im Portal zusammenklicken möchte, braucht eine reproduzierbare Beschreibung seiner Infrastruktur. Azure Bicep liefert dafür eine verständliche deklarative Sprache und verbindet Infrastructure as Code mit einem sauberen DevOps-Workflow. Ich zeige, wie das Werkzeug funktioniert, wann es sich für Hosting eignet, wie eine robuste Datei aufgebaut ist und welche Fehler in produktiven Umgebungen besonders häufig auftreten.
Die wichtigsten Punkte für Azure-Deployments auf einen Blick
- Deklarativ: Bicep beschreibt den gewünschten Zielzustand, statt jeden Einzelschritt vorzugeben.
- Weniger Aufwand: Die Syntax ist deutlich kompakter und lesbarer als klassische ARM-JSON-Templates.
- DevOps-tauglich: Dateien lassen sich versionieren, testen und über Azure DevOps oder GitHub Actions ausrollen.
- Wiederverwendbar: Module, Parameter und Umgebungsdateien helfen bei standardisierten Plattformen.
- Sicherer Betrieb: Mit What-if, Linting und kontrollierten Berechtigungen lassen sich viele Fehler vor dem Deployment erkennen.
Was Bicep in Azure tatsächlich leistet
Bicep ist eine domänenspezifische Sprache für Azure Resource Manager. In einer Datei beschreibe ich Ressourcen wie App Services, Storage Accounts, virtuelle Netzwerke oder Datenbanken und definiere deren Eigenschaften. Azure ermittelt anschließend, welche Änderungen nötig sind, um den gewünschten Zustand herzustellen.
Die Dateien werden vor der Bereitstellung in ARM-Templates übersetzt. Das bedeutet, dass Bicep keine eigene parallele Deployment-Plattform neben Azure bildet, sondern eine angenehmere Schreibweise für die vorhandene Azure-Infrastruktur verwendet. Laut Microsoft Learn bietet die Sprache unter anderem Typensicherheit, Module und Unterstützung für aktuelle Ressourcentypen.
Der Unterschied zu imperativen Skripten ist entscheidend. Ein PowerShell- oder CLI-Skript sagt beispielsweise, in welcher Reihenfolge Ressourcen angelegt werden sollen. Bicep beschreibt dagegen, welche Ressourcen am Ende existieren sollen. Abhängigkeiten erkennt Azure häufig aus den Referenzen zwischen den Ressourcen automatisch.
Ein kleines, aber realistisches Beispiel
param location string = resourceGroup().location
param storageName string
resource storage 'Microsoft.Storage/storageAccounts@2023-05-01' = {
name: storageName
location: location
sku: {
name: 'Standard_LRS'
}
kind: 'StorageV2'
properties: {
supportsHttpsTrafficOnly: true
minimumTlsVersion: 'TLS1_2'
}
}
output storageId string = storage.idSchon dieses kurze Beispiel legt einen Storage Account mit HTTPS-Pflicht und TLS 1.2 an. Der konkrete Name kommt als Parameter hinein, während der Standort standardmäßig aus der Ressourcengruppe übernommen wird. Genau solche Vorgaben machen Infrastruktur nachvollziehbar und verhindern, dass wichtige Sicherheitseinstellungen im Portal vergessen werden.
Warum sich die Sprache für Hosting und DevOps eignet
Beim Hosting entstehen selten nur einzelne Ressourcen. Eine Webanwendung benötigt oft ein Netzwerk, einen App Service oder Containerdienst, Monitoring, Identitäten, Secrets und eine Datenbank. Bicep macht diese Bausteine als einheitlichen, versionierten Code sichtbar. Für mich liegt darin der größte praktische Vorteil: Ein neues Teammitglied kann die Zielarchitektur im Repository nachvollziehen, ohne zuerst die gesamte Azure-Umgebung durchsuchen zu müssen.
Besonders hilfreich sind Parameter für unterschiedliche Umgebungen. Entwicklungs-, Staging- und Produktionssysteme können dieselbe Grundstruktur verwenden, aber jeweils andere SKU-Größen, Namen oder Netzwerkbereiche erhalten. So bleibt die Architektur konsistent, während die Kosten in der Entwicklung niedriger bleiben.
| Baustein | Nutzen im DevOps-Prozess |
|---|---|
| Parameter | Trennen Umgebungswerte von der eigentlichen Infrastrukturdefinition. |
| Module | Kapseln wiederkehrende Komponenten wie Netzwerk, Logging oder Datenbanken. |
| What-if | Zeigt geplante Änderungen vor dem tatsächlichen Rollout. |
| Linting | Findet Stilprobleme und typische Fehlkonfigurationen bereits im Quellcode. |
| Versionskontrolle | Macht Änderungen prüfbar und ermöglicht Reviews sowie Rollbacks der Codebasis. |
Die Sprache ersetzt allerdings nicht jede DevOps-Entscheidung. Sie kümmert sich vor allem um die Bereitstellung der Azure-Infrastruktur, nicht automatisch um Builds, Anwendungstests, Datenbankmigrationen oder das Management von Geheimnissen. Ein gutes System trennt diese Aufgaben, verbindet sie aber in einer gemeinsamen Pipeline.
Module statt riesiger Einzeldateien
Eine Bicep-Datei mit mehreren tausend Zeilen wird schnell unübersichtlich. Ich teile größere Plattformen deshalb in Module auf, zum Beispiel für Netzwerk, Identität, Monitoring und Anwendungshosting. Ein Modul ist eine wiederverwendbare Bicep-Datei mit klar definierten Eingaben und Ausgaben.
module appModule './modules/app-service.bicep' = {
name: 'webAppDeployment'
params: {
appName: appName
location: location
planId: appPlan.id
}
}Das lohnt sich vor allem dann, wenn mehrere Anwendungen nach demselben Muster betrieben werden. Für ein einmaliges kleines Testprojekt wäre eine zusätzliche Modulstruktur dagegen eher Ballast. Wiederverwendung sollte ein echtes Muster abbilden, nicht nur möglichst viele Dateien erzeugen.

So wird aus einer Bicep-Datei ein kontrolliertes Deployment
Der Einstieg ist unkompliziert. Benötigt werden typischerweise die Azure CLI, die Bicep-Erweiterung für Visual Studio Code und ein Azure-Konto mit passenden Berechtigungen. Die Azure CLI bringt die Bicep CLI bei benötigten Befehlen in der Regel automatisch mit, kann aber auch separat verwaltet werden.
- Ein Repository für die Infrastruktur anlegen und die Bicep-Dateien versionieren.
- Parameter für Standort, Namen, Größen und Umgebungswerte definieren.
- Die Datei lokal prüfen und mit dem Bicep-Linter auf mögliche Probleme untersuchen.
- Mit
what-ifkontrollieren, welche Änderungen Azure vornehmen würde. - Das Deployment zunächst in einer Entwicklungsressourcengruppe ausführen.
- Nach Review und Tests über eine Pipeline nach Staging und Produktion ausrollen.
Ein typischer CLI-Aufruf für eine Ressourcengruppe sieht so aus:
az deployment group what-if \
--resource-group rg-web-dev \
--template-file main.bicep \
--parameters storageName=stwebdev001
az deployment group create \
--resource-group rg-web-dev \
--template-file main.bicep \
--parameters storageName=stwebdev001Der erste Befehl verändert noch nichts. Er zeigt geplante Neuerstellungen, Änderungen und Löschungen. Ich würde diese Prüfung für produktive Deployments zur Pflicht machen, weil ein falsch gesetzter Parameter sonst schnell eine unerwartete SKU-Änderung oder das Entfernen einer Ressource auslösen kann.
Eine Pipeline mit klaren Sicherheitsstufen
In Azure DevOps oder GitHub Actions sollte ein Pull Request zunächst nur validieren und prüfen. Erst nach der Freigabe folgt das Deployment in eine nichtproduktive Umgebung. Produktion erhält idealerweise eine zusätzliche manuelle Genehmigung oder eine vergleichbare Schutzregel.
- Pull Request: Syntaxprüfung, Linting und What-if ausführen.
- Build: Module und Artefakte reproduzierbar zusammenstellen.
- Staging: Infrastruktur ausrollen und Anwendungstests starten.
- Produktion: Deployment mit geschützter Identität und Genehmigung durchführen.
Für die Pipeline sollte keine persönliche Entwickleridentität verwendet werden. Besser ist eine verwaltete Identität oder ein Workload-Identitätsverbund mit möglichst begrenzten Rechten. Secrets gehören in einen Secret Store wie Azure Key Vault und nicht in Parameterdateien oder das Git-Repository.
Welche Struktur in der Praxis gut funktioniert
Für kleinere Projekte reicht oft eine überschaubare Struktur. Bei mehreren Umgebungen und Teams zahlt sich eine klare Trennung schnell aus.
infra/
main.bicep
modules/
network.bicep
monitoring.bicep
app-service.bicep
parameters/
dev.bicepparam
staging.bicepparam
prod.bicepparamIn main.bicep liegt die Orchestrierung. Die Module beschreiben einzelne Plattformbausteine, während die Parameterdateien umgebungsspezifische Werte enthalten. Produktionswerte sollten dabei nicht automatisch als frei lesbare Geheimnisse im Repository liegen.
Benennung und Abhängigkeiten
Ressourcennamen müssen global oder innerhalb eines Dienstes eindeutig sein. Zufällige Namen wirken zunächst bequem, erschweren aber Betrieb, Support und Kostenkontrolle. Ich bevorzuge ein konsistentes Schema mit Anwendung, Umgebung und Region, beispielsweise stshopprodweu01.
Abhängigkeiten sollten möglichst durch echte Referenzen entstehen. Wenn ein App Service die ID eines App Service Plans verwendet, erkennt Bicep die Reihenfolge automatisch. Manuelle dependsOn-Einträge sind nur nötig, wenn keine direkte Referenz existiert. Zu viele davon machen Deployments langsamer und verschleiern die tatsächliche Architektur.
Parameter mit sinnvollen Grenzen
Parameter erhöhen die Flexibilität, können aber auch schlechte Konfigurationen ermöglichen. Für Regionen, SKUs und Netzwerkbereiche nutze ich deshalb erlaubte Werte oder klare Validierungen. Ein Produktionsdeployment sollte nicht versehentlich mit einer Entwickler-SKU oder einem ungeprüften Standort starten.
@allowed([
'westeurope'
'germanywestcentral'
])
param location string = 'westeurope'
@allowed([
'B1'
'P1v3'
])
param appServiceSku string = 'B1'Solche Einschränkungen sind keine vollständige Governance, aber sie fangen viele alltägliche Fehler früh ab. Für größere Organisationen kommen zusätzlich Azure Policy, getrennte Abonnements und zentrale Landing Zones hinzu.
Typische Fehler und die Grenzen von Bicep
Der häufigste Fehler ist die Annahme, Infrastructure as Code mache jede Änderung automatisch sicher. Bicep sorgt für Wiederholbarkeit, aber eine falsche Definition bleibt falsch und wird sehr zuverlässig erneut ausgerollt. Deshalb gehören Code-Review, What-if und Tests zum Prozess.
- Geheimnisse im Code: Passwörter, Schlüssel und Tokens niemals direkt in Bicep-Dateien speichern.
- Ungeprüfte API-Versionen: Ressourcentypen und Eigenschaften vor dem Einsatz anhand der aktuellen Azure-Referenz prüfen.
- Portaländerungen: Manuelle Änderungen können vom deklarativen Zielzustand abweichen und später überschrieben werden.
- Zu breite Berechtigungen: Pipeline-Identitäten nur mit den für das Deployment nötigen Rollen ausstatten.
- Unkontrollierte Löschungen: Änderungen an produktiven Ressourcen immer mit What-if und Schutzmechanismen prüfen.
- Monolithische Dateien: Große Templates ohne Module erschweren Tests, Reviews und Wiederverwendung.
Auch beim State-Modell gibt es einen wichtigen Unterschied zu Terraform. Bicep benötigt keinen eigenen zentralen State, weil Azure Resource Manager den Zielzustand der Ressourcen verwaltet. Das vereinfacht den Einstieg, bedeutet aber nicht, dass Drift ignoriert werden sollte. Abweichungen zwischen Code und Portalzustand müssen weiterhin erkannt und bereinigt werden.
Lesen Sie auch: Docker oder VM? Die passende Basis für Hosting und DevOps
Bicep oder Terraform?
Für eine fast ausschließlich auf Azure ausgerichtete Plattform ist Bicep oft der direkteste Weg. Es folgt den Azure-Ressourcenmodellen sehr eng und erhält neue Azure-Funktionen in der Regel ohne zusätzliche Provider-Abstraktion. Terraform ist besonders interessant, wenn mehrere Cloud-Anbieter oder viele externe Dienste mit einer gemeinsamen Sprache verwaltet werden sollen.
| Kriterium | Bicep | Terraform |
|---|---|---|
| Azure-Fokus | Sehr eng an Azure Resource Manager angebunden | Über Provider abstrahiert |
| Multi-Cloud | Nur eingeschränkt geeignet | Stärker auf mehrere Plattformen ausgelegt |
| State-Verwaltung | Kein separater Terraform-State nötig | State-Datei muss sicher verwaltet werden |
| Einstieg in Azure | Direkt und meist unkompliziert | Zusätzliche Provider- und State-Konzepte |
Ich würde die Entscheidung nicht nach Marketingbegriffen treffen. Ausschlaggebend sind Cloud-Strategie, vorhandenes Know-how und Governance. Ein Team mit reinem Azure-Fokus gewinnt häufig durch die Nähe von Bicep zu den nativen Ressourcen. Bei einer heterogenen Plattform kann Terraform den geringeren Gesamtaufwand verursachen.
Was ein belastbarer Start in 30 Tagen braucht
Ein realistischer Einstieg muss nicht mit der gesamten Cloud-Plattform beginnen. Ich würde zunächst eine kleine, aber echte Anwendung auswählen und ihre Entwicklungsumgebung vollständig als Code beschreiben. Dazu gehören der Hostingdienst, Monitoring, Identität und alle Abhängigkeiten, die für einen reproduzierbaren Betrieb nötig sind.
In der ersten Woche entsteht die Grundstruktur mit Repository, Namenskonventionen und Linting. Danach folgen Module und Parameter für Development und Staging. In der dritten Phase wird die Pipeline mit What-if und geschützter Identität ergänzt. Erst wenn dieser Ablauf zuverlässig funktioniert, sollte die Produktionsumgebung angeschlossen werden.
Am Ende sollte jedes Deployment dieselben Fragen beantworten können. Was wird erstellt, warum wird es geändert und wer hat die Änderung freigegeben? Wenn diese Informationen im Code, im Pull Request und im Pipeline-Lauf sichtbar sind, wird Azure-Betrieb deutlich planbarer.
Die richtige Rolle von Bicep in einer Azure-Plattform
Bicep ist besonders stark, wenn Azure-Infrastruktur verständlich, wiederholbar und eng mit dem Entwicklungsprozess verbunden werden soll. Es reduziert Template-Overhead, unterstützt modulare Architekturen und passt gut zu automatisierten Deployments über Azure DevOps oder GitHub Actions.
Der größte Nutzen entsteht aber nicht durch die Sprache allein. Entscheidend sind kleine Module, sichere Identitäten, überprüfte Änderungen und klare Verantwortlichkeiten. Wer diese Grundlagen schafft, erhält kein bloßes Skript für die Cloud, sondern eine wartbare Beschreibung der Plattform, auf der Anwendungen zuverlässig betrieben werden können.