12. Dez 2022
Lesedauer 11 Min.
az plus d ist gleich Azure Developer CLI
Entwicklung und Deployment von Azure-Architekturen
CLIs sind das Taschenmesser der Entwickler. Das Azure Developer CLI soll Entwicklern helfen, Softwarelösungen für die Azure Cloud zu entwickeln und zu deployen.

Wer als Entwickler schon einmal mit Azure zu tun hatte, für den wird das Azure CLI ein Begriff sein. Das CLI wird mit dem Befehl az aufgerufen und bietet die Möglichkeit, nahezu jede Azure-Ressource zu erstellen, zu verändern oder abzufragen. Im Juli hat Microsoft das Azure Developer CLI vorgestellt [1], das seine Dienste unter dem Kürzel azd anbietet. Im Gegensatz zum Azure CLI, das sich konkret auf das Management von Azure-Ressourcen konzentriert, nimmt das Azure Developer CLI den kompletten Entwicklungszyklus von Cloud-Applikationen ins Visier. Microsoft selbst beschreibt azd als ein „entwicklerzentriertes Befehlszeilentool zum Erstellen von Cloud-Apps“, das „eine Reihe von Befehlen bereitstellt, die es dem Entwickler erlauben, über Projektvorlagen an DevOps-Workflows aus einer IDE heraus zu arbeiten“ [2].Die Schritte im Entwicklungs-Workflow, die von azd unterstützt werden, umfassen das Aufsetzen des Git-Repositorys (init), das Erstellen der Infrastruktur in Azure (provision), manuelles Deployment der Anwendung (deploy) und Aufsetzen einer CI/CD-Pipeline in GitHub (pipeline), die Überwachung der Anwendung (monitor) sowie zu guter Letzt die Zerstörung der Anwendung (vergleiche Bild 1).

Die Provider-Architekturvon Terraform(Bild 1)
Autor
Jeder Schritt ist im CLI über ein entsprechendes Verb abgebildet, wobei sich einige Befehle für die erstmalige Verwendung unter einem Synonym bündeln lassen, zum Beispiel erledigt das Wort up die Schritte init, provision und deploy in einem Rutsch. Unter der Haube verwendet das Azure Developer CLI Templates, die in einem Git-Repository untergebracht sind und die ein bestimmtes Format aufweisen müssen, das auch festgelegte Konfigurationsdateien umfasst. Für die Erstellung der Infrastruktur wird Bicep verwendet, über das in [3] berichtet wurde.
Will ich haben
Wer das Ganze auf seinem eigenen „Bare Metal“ testen möchte, benötigt zuerst einmal ein paar Voraussetzungen, über die die meisten Entwicklerrechner aber ohnehin verfügen sollten [4]. Man braucht einen Git-Client, das GitHub CLI und das Azure CLI. Danach kann man das Azure Developer CLI installieren:powershell -ex AllSigned -<span class="hljs-keyword">c</span> <span class="hljs-string">"Invoke-RestMethod </span>
<span class="hljs-string"> 'https://aka.ms/install-azd.ps1' | Invoke-Expression"</span>
Wem das mit den Vorbedingungen zu mühselig ist, der kann sich eine fertige Entwicklungsumgebung auch in einem Dev-Container [5] erstellen lassen. Wenn alles geklappt hat, kann man an der Kommandozeile azd eingeben und sollte mit einem kleinen Hilfetext belohnt werden.Um mit dem CLI arbeiten zu können, braucht man natürlich noch einen Azure-Account. Jeder Inhaber einer Visual Studio Subscription kann das CLI über seine Benefits mit einem vordefinierten Betrag nutzen. Wer keinen Zugriff auf eine Subscription hat, kann sich auch ein kostenloses Konto erstellen und im ersten Monat 200 US-Dollar verbrauchen sowie viele weitere Dienste die ersten zwölf Monate kostenlos nutzen [6].
Einmal Anwendung hin und wieder zurück
Um einen schnellen Eindruck vom CLI zu gewinnen, erzeugen wir eine Anwendung, testen sie und zerstören sie wieder. Das geht mit wenigen Zeilen auf der Kommandozeile. Zuerst muss man sich mit dem Azure CLI einloggen:<span class="hljs-attribute">az login</span>
Wenn man nicht von Grund auf neu starten möchte, kann man sich eine Vorlage aussuchen [7]. Da die To-do-Liste das neue „Hello World“ ist, wählen wir ebendiese auf Basis von C# mit einer CosmosDb für die Datenhaltung. Dann erzeugt man sich ein Verzeichnis für das Repository und befiehlt anschließend Folgendes:
azd up <span class="hljs-comment">--template todo-csharp-cosmos-sql </span>
Das CLI stellt dann ein paar Fragen (siehe Bild 2). Zuerst wird der Name für die zu erstellende Umgebung abgefragt. Dieser Name dient als Suffix für die Ressourcengruppe, die in Azure erstellt wird. Dann definiert man die Azure-Region, in der die Ressourcen erstellt werden sollen, und als Letztes muss man noch die Azure-Subscription auswählen.

Das CLIin Aktion(Bild 2)
Autor
Danach beginnt das CLI mit der Arbeit, deren Fortschritt sich mit dem zuerst angegebenen URL verfolgen lässt. In einem ersten Schritt wird das zur Vorlage gehörende Repository geklont. Dann werden in Azure alle Ressourcen angelegt. Wenn alles fertig ist, kann man im Dateisystem das geklonte Repository, in Azure jede Menge Ressourcen und im Browser das fertige Produkt bewundern (vergleiche Bild 3).

Das Ergebnisvon azd up(Bild 3)
Autor
Wenn man dann nach ein paar Runden spielen mit der To-do-Liste keine Lust mehr hat, kann man das Ganze mit dem Befehl azd down wieder löschen. Dieser Befehl löscht alle in Azure angelegten Ressourcen unwiederbringlich. Im Produktivbetrieb sollte man damit also vorsichtig sein, weshalb das CLI um eine extra Bestätigung des Befehls bittet. Ein paar Minuten später ist der ganze Spuk dann auch schon wieder vorüber, und weg ist die To-do-Liste.
Und noch mal von vorn: init, provision, deploy
Wem der Schnelldurchlauf zu rasant war, für den kommen nun noch einmal alle Schritte schön der Reihe nach.Der Befehl azd up erledigt gleich drei Dinge auf einmal: Der erste Schritt ist init, mit dem eine neue Applikation initialisiert wird. Wenn man kein Template angibt, ist diese Applikation leer, aber mit dem Developer CLI kompatibel. Das bedeutet, es werden einige Dateien und Ordner mit grundlegenden Konfigurationen angelegt. Für den Anfang ist es einfacher, mit einem Template zu starten. Dafür kann man den Parameter --template mitgeben und auf ein kompatibles Git-Repository verweisen.azd init <span class="hljs-comment">--template todo-csharp-cosmos-sql </span>
Wer die VS-Code-Extension verwendet, bekommt die Microsoft-Beispiel-Repos bereits angeboten, kann aber auch ein eigenes Respository benennen – ein init für eine leere Applikation erlaubt die Extension nicht. Der init-Befehl klont das Repository und fragt die Informationen zu Environment, Azure Region und Subscription ab, wie oben beschrieben. Damit ist die Initialisierung abgeschlossen und der Befehl ist beendet.Der nächste Schritt ist die Bereitstellung von Ressourcen in Azure. Dies geschieht über das Verb provision, was uns den bereits aus Bild 2 bekannten Link für den Fortschritt der Bereitstellung beschert. Nun dauert es wieder eine Weile, bis alle Ressourcen erstellt sind.
<span class="hljs-attribute">azd provision</span>
Anders als bei der Verwendung von azd up erhält man nach Abschluss des Befehls aber noch keinen URL zu der Anwendung, da diese noch nicht deployt wurde. Dies muss in diesem Fall in einem separaten Deployment-Schritt erfolgen, der sich über das Verb deploy starten lässt:
<span class="hljs-attribute">azd deploy</span>
Nach Abschluss des Befehls erhält man die URLs zum Aufrufen des Frontends und des Backends. Damit ist man nun am gleichen Punkt angelangt, den man auch mittels azd up erreicht hat.
Wie geht es jetzt weiter? Mit mehr Umgebungen!
Wenn man nicht direkt mittels azd down die gesamte Arbeit wieder zunichtemachen möchte, kann man einfach noch mehr Umgebungen erzeugen. Je nach Entwicklungsmodell möchte man eine Entwicklungsumgebung für alle oder eine pro Entwickler, eventuell eine Staging- und auf jeden Fall eine Produktivumgebung verwenden.Die erste Umgebung wird bereits beim Initialisieren des Projekts angelegt. Welche Umgebungen es gibt, lässt sich jederzeit mit folgendem Befehl in Erfahrung bringen:azd env <span class="hljs-built_in">list</span>
Das Unterkommando env ist auch für alle weiteren Vorgänge im Zusammenhang mit den Umgebungen zuständig. Um eine neue Umgebung anzulegen, verwendet man den Befehl
azd env <span class="hljs-keyword">new</span>
und wird dann nach der Azure Location und der Subscription für die neue Umgebung gefragt. So kann man zum Beispiel die Produktionsumgebung in einer anderen Subscription unterbringen als die Testumgebung. Innerhalb einer Umgebung lassen sich Umgebungsvariablen anlegen:
azd env <span class="hljs-keyword">set</span> API_BASE_URL
<span class="hljs-comment"> https:</span>//<span class="hljs-comment">localhost:5000</span>
<span class="hljs-comment"> -e dev</span>
Der Parameter -e wählt dabei die zu verwendende Umgebung aus. Man kann sich die gesetzten Variablen auch über das CLI anzeigen lassen:
<span class="hljs-string">azd </span><span class="hljs-string">env </span><span class="hljs-built_in">get-values</span> -e <span class="hljs-string">dev </span>
Lässt man den Parameter -e weg, wirken alle env-Befehle auf die Standardumgebung. Welche das ist, kann man mittels des list-Befehls herausfinden und über
azd <span class="hljs-keyword">env</span> <span class="hljs-keyword">select</span> dev
ändern. Alle Umgebungen werden in einem Unterverzeichnis .azure im Code abgelegt. Das Azure CLI liest diese Dateien und gibt die Werte der Variablen zum Beispiel an die Bicep-Skripte weiter, die zur Erstellung der Infrastruktur verwendet werden.Um das Projekt in einer neuen Umgebung zu deployen, durchläuft man den provision/deploy-Zyklus unter Angabe der Zielumgebung im Parameter -e oder durch vorheriges Setzen der Standardumgebung. Innerhalb der gleichen Subscription werden unterschiedliche Umgebungen über Ressourcengruppen getrennt. Gleichsam kann man eine Umgebung mittels des down-Befehls wieder abreißen.
Etwas mehr Automatisierung und Überwachung, bitte!
Wenn man den grundlegenden Aufbau eines Projekts fertiggestellt hat, geht es daran, die Entwicklung und das Deployment durch Automatisierung in geregelte Bahnen zu lenken. Je nach verwendetem Stack kann dies zum Beispiel durch Azure DevOps Pipelines oder GitHub Actions realisiert werden. Das Azure Developer CLI unterstützt out of the box erst mal nur GitHub Actions. Die Nutzung von Azure DevOps ist möglich, dazu muss man allerdings den Anweisungen in der README.md unter .azdo\pipelines folgen. Diese führt durch den Prozess der Konfiguration innerhalb von Azure DevOps sowie die Authentifizierung mit Azure. Die Readme stellt in Aussicht, dass dieser Prozess vielleicht irgendwann im Azure Developer CLI integriert wird.Wer GitHub verwendet, hat es einfacher. Ausgehend davon, dass wir bereits ein Repository angelegt und unseren Code dorhin gesynct haben – sollte dies nicht der Fall sein, leitet das CLI auch durch diesen Prozess –, reicht der folgende Befehl, um loszulegen:azd pipeline <span class="hljs-built_in">config</span>
Zunächst muss man sich mit dem GitHub CLI bei GitHub anmelden. Das geht zum Beispiel über einen Webbrowser, das CLI präsentiert dann einen Einmal-Code, den man im Browser eingeben muss (vergleiche Bild 4):

Authentifizierungdes GitHub CLI über den Browser(Bild 4)
Autor
? Authenticate Git <span class="hljs-keyword">with</span> your GitHub credentials? Yes
? How would you like <span class="hljs-built_in">to</span> authenticate GitHub CLI? Login
<span class="hljs-keyword">with</span> <span class="hljs-keyword">a</span> web browser
! First copy your <span class="hljs-literal">one</span>-<span class="hljs-built_in">time</span> code: A9E2<span class="hljs-number">-2</span>D63
Press Enter <span class="hljs-built_in">to</span> <span class="hljs-built_in">open</span> github.com <span class="hljs-keyword">in</span> your browser...
Nach der Anmeldung konfiguriert das Azure Developer CLI mithilfe des GitHub CLI alles Notwendige. Jede Änderung am Code, die zum Remote gepusht wird, löst nun einen Lauf der Pipeline aus, der den aktuellen Codestand kompiliert und deployt (vergleiche Bild 5). Betrachtet man die Schritte, die die Pipeline ausführt, erkennt man, dass diese sich genau an dem orientieren, was wir lokal von unserer Konsole aus getan haben, nämlich im Grunde azd provision und azd deploy. Dies lässt sich auch in der Definition der Pipeline nachschauen, die sich im Projektverzeichnis im Ordner .github\workflows befindet. Dort kann der Workflow noch an die eigenen Wünsche und Bedürfnisse angepasst werden.

Ein GitHub-Workflowwird bei jedem Push ausgelöst(Bild 5)
Autor
Wenn der Workflow erfolgreich war, lassen sich die Ergebnisse der Änderungen dann in Azure bestaunen (vergleiche Bild 5, rechte Seite).Ist die Applikation also nun deployt, werden sicherlich bald die ersten interessierten Kunden vorbeischauen. Dann wird es unabdingbar, den Betrieb der Seite zu überwachen. Dazu erzeugen die Azure-Developer-CLI-Templates Application-Insights-Ressourcen für die Webseiten und APIs. Neben umfangreichen Möglichkeiten einer statischen Analyse der Daten liefert App Insights auch Livemetriken. Diese kann man über das Azure CLI mit dem Befehl
azd<span class="hljs-built_in"> monitor </span>
im Browser öffnen (vergleiche Bild 6). Der monitor-Befehl ist dabei tatsächlich nur ein Shortcut in das Azure-Portal, er trägt also selbst nicht zum Monitoring bei und das Monitoring läuft auch, wenn der Befehl nicht ausgeführt wurde.

Livemetrikender Applikation in App Insights(Bild 6)
Autor
Wie funktioniert das alles und kann ich das auch?
Ein solches Template zu nutzen ist ja schon mal eine feine Sache, um mit einer Technologie warm zu werden. Wer ernsthaftere Interessen hat, wird früher oder später dem Template-Stadium entwachsen.Dazu muss der Projektordner eine bestimmte, auf Konventionen basierte Struktur aufweisen. Die vollständige Projektstruktur ist in Listing 1 abgebildet [8]. Es muss nicht immer der gesamte Umfang enthalten sein. Der Quellcode des Projekts gehört in den Unterordner src, der direkt unterhalb des Projektordners liegt. Der azd init-Befehl erzeugt eine erste Umgebung in dem .azure-Ordner mit den Informationen, die vom CLI abgefragt werden. Damit die Infrastruktur in Azure angelegt werden kann, ist es nötig, diese mittels Bicep-Dateien zu beschreiben, die im Unterverzeichnis infra abgelegt werden müssen.Listing 1: Struktur eines Azure-Developer-CLI-Projekts (in Anlehnung an [8])
+-- <span class="hljs-selector-class">.azure</span> [ Contains environmental information ] <br/>¦ +-- dev [ Example name, contains information about the <span class="hljs-string">"dev"</span> environment] <br/>¦ ¦ +-- <span class="hljs-selector-class">.env</span> [ Environment variables <span class="hljs-keyword">for</span> this environment ] <br/>¦ ¦ +-- <span class="hljs-selector-class">.main</span><span class="hljs-selector-class">.parameter</span><span class="hljs-selector-class">.json</span> [ Bicep paramter values <span class="hljs-keyword">for</span> this environment ] <br/>¦ +-- config<span class="hljs-selector-class">.json</span> [ Contains the selected default environment ] <br/>+-- <span class="hljs-selector-class">.devcontainer</span> [ For DevContainer ] <br/>+-- <span class="hljs-selector-class">.github</span> [ Configure GitHub workflow ] <br/>¦ +-- workflows <br/>¦ ¦ +-- azure-dev<span class="hljs-selector-class">.yml</span> [ The workflow definition file ] <br/>+-- <span class="hljs-selector-class">.vscode</span> [ VS Code workspace ] <br/>+-- assets [ Assets used by README<span class="hljs-selector-class">.MD</span> ] <br/>+-- infra [ Creates and configures Azure resources ] <br/>¦ +-- main<span class="hljs-selector-class">.bicep</span> [ Main infrastructure file ] <br/>¦ +-- main<span class="hljs-selector-class">.parameters</span><span class="hljs-selector-class">.json</span> [ Parameters file ] <br/>¦ +-- resources<span class="hljs-selector-class">.bicep</span> [ Resources file ] <br/>+-- src [ Contains directories <span class="hljs-keyword">for</span> the app <span class="hljs-selector-tag">code</span> ] <br/>+-- azure<span class="hljs-selector-class">.yaml</span> [ Describes the app and type of Azure resources]
Damit das Deployment der Applikation gelingt, braucht das CLI mehr Informationen über deren Aufbau. Diese werden in Form der Datei azure.yaml im Projektverzeichnis geliefert. Diese ähnelt vom Aufbau her einer Docker-Compose-Datei, hat aber einen proprietären Aufbau, der unter [9] als JSON-Schema beschrieben ist.Für das To-do-Listen-Beispiel besitzt die Datei den Aufbau aus Listing 2. Es beginnt mit dem Namen der App, gefolgt von einer Auflistung der einzelnen Bestandteile. Jeder Service bekommt als oberste Ebene einen Namen, darunter folgt die Angabe, wo sich der Code zu diesem Service befindet (project) und in welcher Sprache der Service verfasst ist (language). Wird keine Sprache angegeben, gilt C# als Standard. Der Parameter dist besagt, wo die Artefakte zur Veröffentlichung zu finden sind. Über den Parameter host wird beschrieben, mit welcher Art von Azure-Dienst dieser Service bereitgestellt werden soll. Unterstützt werden App Services, Container Apps, Azure Functions und Static Web Apps. Für jeden Service muss es in der Bicep-Definition eine Ressource gleichen Namens geben, damit das CLI weiß, in welches Azure-Objekt deployt werden muss.
Listing 2: Aufbau der Datei azure.yaml
# yaml-<span class="hljs-keyword">language</span>-server: <br/> $schema=http<span class="hljs-variable">s:</span>//raw.githubusercontent.<span class="hljs-keyword">com</span>/Azure/<br/> azure-dev/main/schemas/v1.<span class="hljs-number">0</span>/azure.yaml.json <br/><br/>name: todo-csharp-mongo <br/><br/>metadat<span class="hljs-variable">a:</span> <br/> template: todo-csharp-mongo@<span class="hljs-number">0.0</span>.<span class="hljs-number">1</span>-beta <br/><br/>service<span class="hljs-variable">s:</span> <br/> we<span class="hljs-variable">b:</span> <br/> projec<span class="hljs-variable">t:</span> src/web <br/> dis<span class="hljs-variable">t:</span> build <br/> <span class="hljs-keyword">language</span>: js <br/> hos<span class="hljs-variable">t:</span> appservice <br/><br/> api: <br/> projec<span class="hljs-variable">t:</span> src/api <br/> <span class="hljs-keyword">language</span>: csharp <br/> hos<span class="hljs-variable">t:</span> appservice
Damit die automatische Konfiguration der CI/CD-Pipeline gelingt, muss eine GitHub-Workflow-Definition in den Ordner .github/workflows gelegt werden.
Fazit
Das Azure Developer CLI erleichtert die Durchführung von Standardaufgaben im Projektlebenszyklus. Wer mit einem neuen Projekt startet und sich an das verlangte Projektdesign hält, kann hier stark profitieren. Die per Konvention vorgegebene Ordnerstruktur ist vernünftig und gut organisiert – über Namen kann man immer vortrefflich streiten.Bei der Wahl der Entwicklungsplattform tendiert das CLI zur Nutzung von GitHub – wer Azure DevOps nutzt, hat im CI/CD-Teil mit größeren Hürden zu kämpfen. Für die Infrastrukturbeschreibung ist man auf Bicep festgelegt. Wer zum Beispiel Terraform verwendet, kann nicht vom Azure CLI profitieren. Dass der Befehl azd down zur Zerstörung der gesamten Infrastruktur so leicht von den Lippen geht, ist ein Risiko, das man auf jeden Fall im Auge haben sollte. Wenn man mit diesen Rahmenbedingungen leben kann, erleichtert das CLI die frühe Phase von Projekten deutlich. In gut etablierten Projekten, in denen sich die Entwicklungs- und Deployment-Abläufe bereits eingespielt haben, dürfte sich die Einführung der CLI dagegen kaum lohnen. Sobald ein Projekt etwas mehr Reife annimmt, wird es sich eventuell auch wieder vom CLI lösen können. Durch die offene Struktur des CLI ist dies aber auch ohne Weiteres möglich. Auf diese Weise bleibt man in jede Richtung beweglich, und das macht das Azure Developer CLI zu einem guten Tool, das den Entwickler unterstützen kann, wenn es sinnvoll und nötig ist, ohne dabei langfristig im Weg zu stehen.Fussnoten
- Savannah Ostrowski, Introducing the Azure Developer CLI (azd), http://www.dotnetpro.de/SL2301AZD1
- Microsoft Ignite, What is the Azure Developer CLI (preview)?, http://www.dotnetpro.de/SL2301AZD2
- Tobias Richling, Muskelpaket für Azure, dotnetpro 7/2022, Seite 62 ff., http://www.dotnetpro.de/A2207Bicep
- Microsoft Ignite, Erste Schritte mit Azure Developer CLI (Vorschau), http://www.dotnetpro.de/SL2301AZD3
- VS Code, Developing inside a Container, http://www.dotnetpro.de/SL2301AZD4
- Azure-Einstieg, https://azure.microsoft.com/de-de/free
- Azure-Samples auf GitHub, http://www.dotnetpro.de/SL2301AZD5
- Microsoft Ignite, Make your project compatible with Azure Developer CLI (preview), http://www.dotnetpro.de/SL2301AZD6
- azure.yaml.json auf GitHub, http://www.dotnetpro.de/SL2301AZD7