Microsoft Azure Container Instances: erste Eindrücke

Nachdem ich im letzten Artikel einen Blick auf den Azure App Service geworfen habe, der auch letztlich auf Docker-Containern basiert, stand als nächstes der Test des von Microsoft Azure Container Instances getauften Services auf dem Plan.  Dabei wird eine Docker-Umgebung bereit gestellt, innerhalb der die jeweiligen Container lauffähig sind. Das Ganze funktioniert, ohne dass vorab virtuelle Maschinen eingerichtet werden müssen. Als Ressourcen lassen sich Anzahl CPU-Cores und RAM wählen. 

Dennoch erscheint mir die Unterscheidung zwischen App Service, der wiederum auch einen Web-App für Container beinhaltet, und Container Instances nicht allzu trennscharf. Zum Service namens Web-App für Container innerhalb des Azure App Service komme ich in einem späteren Artikel, aber da beide Services auch auf Docker-Containern basieren, könnte Microsoft hier ein wenig konkreter werden und die Unterschiede deutlicher herausstellen. 

Container-Instanz Quickstart

Zunächst habe ich mich wieder an das einfache Beispiel im Quickstart-Artikel gehalten. Das Erstellen der Ressourcengruppe hatte ich im letzten Artikel ausführlich beschrieben. Für den Test der Container-Instances habe ich daher zunächst eine neue Ressourcengruppe namens geschkenetrgcnt1 erstellt.

Microsoft stellt eine kleine Beispiel-Anwendung bereit, die im Docker-Hub öffentlich verfügbar ist. Ebenfalls können eigene und private Docker-Images verwendet werden, dazu bietet Azure wiederum eine Image Registry an. Doch zunächst zum einfachsten Beispiel, ein Container wird allgemein erstellt mit:

Bezogen auf die vormals erstellte Ressourcengruppe und mit einem eindeutigen Container- sowie DNS-Namen gibt das az-Kommando folgendes zurück:

Zumindest ist darin keine Fehlermeldung zu lesen, auch wenn der Status zunächst “pending” lautet. Es dauert einen Moment, denn das Image muss auch zunächst herunter geladen werden, bevor es gestartet werden kann. Mit dem Parameter --dns-name-label wird der Hostname gewählt, unter dem der Container auf Port 80 (--ports) später erreichbar sein soll. Die restlichen Parameter sind ebenso selbsterklärend. 

Nun kann geprüft werden, ob der neu erstellte Container wirklich läuft.

Einerseits wie immer per Azure-Web-UI, andererseits auch via az-Kommando. Dabei kann auch die Ausgabe eingeschränkt werden, denn ansonsten würde Azure immer sämtliche Container-Daten übermitteln. Zur Einschränkung dient der Parameter “--query“, beispielsweise ‘--query "{FQDN:ipAddress.fqdn,ProvisioningState:provisioningState}"‘. Wenn zusätzlich noch das Ausgabeformat von JSON auf eine Tabellendarstellung geändert wird, erhält man z.B. folgendes:

Hier werden insofern nur der vollständige Hostname (FQDN) und der Bereitstellungsstatus angezeigt. Aufgrund des erfolgreichen Starts konnte daraufhin auch die entsprechende Website angezeigt werden. 

Analog zu den App Services lassen sich auch die Log-Ausgaben des Containers betrachten. Allgemein:

Und in diesem Beispiel:

Dabei wurden die Logs des Containers auf die Standardausgabe geleitet, so dass sie außerhalb des Containers erreichbar sind. Darüber hinaus lässt sich auch der Ausgabestream anzeigen, was wiederum analog zum Docker-Befehl “docker logs -f <containername>” ist. 

Zuletzt wurde der Container noch gelöscht, allgemein lautet das Kommando wie folgt:

Konkret wiederum:

Zwar wird hier bei der Ausgabe noch der Status “running” angezeigt, jedoch wurde kurz darauf der Container entfernt. Dies lässt sich wiederum mit dem Kommando “az container show...” überprüfen. 

In der Web-UI waren die Ergebnisse weniger eindeutig. Denn im Dashboard wurde die soeben gelöschte Container-Instanz noch angezeigt.

Demgegenüber zeigt sich folgendes Bild, wenn man die Container-Instanz unter “Alle Ressourcen” im Dashboard angeklickt hat:

Dies erscheint mir ein wenig inkonsistent zu sein, evtl. ist die Cache-Zeit im Dashboard zu hoch eingestellt oder ähnliches, denn nach einer gewissen Wartezeit war auch die Container-Instanz in der Übersicht nicht mehr zu sehen. 

Ein eigenes Image als Container-Instanz

Der erste Test war somit erfolgreich abgeschlossen. Da jedoch der Test einer PHP-Anwendung mit dem Azure App Service so grandios gescheitert ist, wollte ich testen, ob diese Grav-Installation vielleicht im Rahmen der Container Instances, also innerhalb eines Containers funktionieren würde. Die nächsten Schritte im Azure Container Instances Tutorial versprachen dabei Unterstützung bei Azure-relevanten Teil. Konkret wird im ersten Teil auf die Vorbereitung eingegangen, d.h. Erstellen eines Beispiel-Images und ein lokaler Test. Da ich diesmal jedoch die Grav-Installation in einem Image verpacken wollte, war der Teil für mich erstmal weniger interessant. Auf dem Entwicklungsrechner, d.h. der Linux-Server, auf dem die Azure-CLI installiert ist, lief bereits Docker. Der nächste Schritt bestand daraus, ein Docker-Image zu erstellen und lokal zu testen. Darauf werde ich im Folgenden nicht weiter eingehen, nur soviel – für den Test habe ich sämtliche notwendigen Dateien und Dienste in ein Docker-Image gepackt. Dies war so ungefähr das genaue Gegenteil von dem, was an anderer Stelle beschrieben ist. Und für eine Produktionsumgebung würde ich ein derartiges Vorgehen auch nicht empfehlen. Letztlich umfasste das Docker-Image nicht nur Nginx, sondern auch PHP als php-fpm, beide wurden mittels Supervisord gestartet, dazu diente wiederum ein minimales Shellskript. Darüber hinaus wurden alle Dateien, die zu Grav gehörten, in das Image kopiert, was ebenfalls das Gegenteil aller Empfehlungen darstellt. Daher sei auch deutlich an dieser Stelle gesagt, dass es sich nur um ein Test-Image handelte, da ich wissen wollte, ob die Azure Container Instances mit der PHP-Anwendung zurecht kommen. Es sprach zwar nichts dagegen, aber beim App Service hatte das Deployment nicht funktioniert, insofern war der Test eher darauf ausgerichtet, die Verwendung eines eigenen Images zu testen, als dass eine Produktionsumgebung hergestellt werden sollte. Oberhalb von Container Instances lassen sich übrigens Containergruppen bilden, die wiederum aus mehreren Containern auf einem Host bestehen können. Wenn es hingegen darum geht, viele Container verwenden und diese orchestrieren zu wollen, so existiert dafür eine Lösung bei Azure, die auf Kubernetes basiert. 

Als Voraussetzung für die folgende Beschreibung gilt nun, dass Docker auf dem lokalen Rechner bzw. Entwicklungsserver läuft, dass das zu verwendende Docker-Image ebenso dort vorhanden ist, und im besten Fall ist es darauf bereits getestet und funktioniert ohne auffällige Fehler. 

Anlegen einer Docker Image Registry

Der erste Schritt besteht darin, eine private Image-Registry anzulegen. Azure bietet eine derartige Möglichkeit, so dass eigene Docker-Images in eine private Registry hochgeladen werden können. Die Registry ist jedoch nicht nur innerhalb von Azure verfügbar, sondern bietet letztlich eine gemanagte Version einer privaten Image-Registry, wie sie auch von Docker selbst angeboten wird. 

Die Ressourcengruppe war bereits angelegt, insofern konnte die Azure Container Registry direkt erstellt werden. Allgemein wie folgt:

Und konkret:

Zwar dauerte das Erstellen der Container Registry relativ lange, aber der Status versprach, dass es funktioniert hätte. 

Danach kann sich bei der Container Registry per Azure-CLI eingeloggt werden:

Insofern:

Zwar wird der Hostname des Registry-Servers bereits beim Erstellen ausgegeben, aber auch dieser Details lassen sich jederzeit nachträglich anzeigen.

Bereitstellen eines Docker-Images im Registry-Server

Das Vorgehen des Hochladens zum Registry-Server ist völlig analog zu Docker – oder vielmehr, es ist handelt sich um das Docker-Standard-Verfahren, wie auch im Artikel zum Aufbau einer privaten Registry beschrieben. Zunächst wird das lokale Image mit einem Tag versehen. Das von mir genutzt Test-Image ist unter dem Namen “phpapp” lokal auffindbar, insofern wird dieses Image mit dem entsprechend mit dem Hostname des Registry-Servers, dem Image-Namen und der Versionsnummer “getaggt”:

Die Auflistung zeigt den erfolgreichen Abschluss, der Tag ist verfügbar, beide Einträge in der Liste referenzieren dasselbe Image, die Image-ID ist identisch. 

Danach muss das Image noch mit “docker push” an den Registry-Server übertragen werden. Auch bei dieser Standard-Aktion von Docker kommt kein Azure-CLI-Kommando zum Einsatz.

Ob das Hochladen funktioniert hat, lässt sich wiederum mit einem Azure-Cli-Kommando überprüfen:

Dabei steht “acr” für Azure Container Registry, die Ausgabe sieht nach dem erfolgreichen Hochladen wie folgt aus:

Auch die Versionsbezeichnung, d.h. der Tag kann betrachtet werden:

Konkret somit:

Dieser Schritt hat insofern wie gewünscht funktioniert. Natürlich lassen sich die Images auch in der Azure-UI finden.

Azure Container Registry – Speicherbelegung

Üblicherweise muss man sich bei privaten Registries einloggen, bei Docker wäre dies per “docker login <Registry>” und anschließender Eingabe des Passworts möglich. Falls man sich beim Ausführen des docker-Kommandos gefragt haben sollte, wieso keine Authentifizierung notwendig war – diesen Schritt hat die Azure-CLI bereits erledigt. Docker speichert die Authenfizierungsdaten. d.h. den entsprechenden Key, also kein Passwort im Klartext, in der Datei “~/.docker/config.json”. Genau darin ist für die Azure Container Registry ein Eintrag zu finden, so dass Docker diese Daten nutzt, um sich bei der Registry zu identifizieren. 

Erstellen der Container-Instanz

Um nun einen Container aus dem frisch erstellten und in die Azure Registry hochgeladenen Image zu erstellen, fehlt noch ein Schritt. Dieser mutet vielleicht etwas seltsam an, denn bei der Erzeugung des Containers müssen neben dem Hostnamen des Registry-Servers auch der Username und das Passwort für die Azure Container Registry übergeben werden. Als Username fungiert der Name, unter dem die Registry erstellt wurde, im Beispiel weiter oben war dies “geschkenetphpapp“. Doch beim Erzeugen musste kein Passwort gewähnt werden. Azure hat jedoch ein Passwort generiert, die Credentials sogar im Docker-Config-File eingetragen. Insofern wäre es sicherlich auch möglich gewesen, dass Azure einfach auf die Credentials zurück greift, die im System ja bereits gespeichert sind, sobald ein Registry-Server von Azure selbst genutzt wird. Sich das Passwort tatsächlich mit einem Query-Kommando anzeigen lassen und dann wiederum beim Erzeugen des Containers übergeben zu müssen, erscheint mir recht hakelig. Natürlich besteht auch die Möglichkeit, andere private Docker-Image-Registries zu nutzen, aber das sollte Azure doch recht einfach herausfinden können. Und besonders sicher erscheint mir die explizite Query eines Passworts mit anschileßender Übergabe per Azure-CLI ebenfalls nicht. 

Um die Registry-Informationen anzusehen, wird das Kommando “az acr show…” verwendet. Beispielsweise kann der Name des Servers abgefragt werden:

Wie erwartet erscheint somit:

Um das Passwort zu erhalten, bedient man sich folgender Query:

Im Beispiel wäre das dann:

Mit all diesen Daten kann nun endlich der Container erzeugt werden. Das Kommando ist etwas länger geraten und lautet:

Wie man anhand der Parameter erkennt, lassen sich dabei auch Eigenschaften des Containers übermitteln, in dem Fall die Anzahl der CPU-Cores und die zu nutzende RAM-Kapazität. Darüber hinaus wird der Port 80 nach außen hin freigegeben. 

Im Beispiel:

Die Ausgabe ist sehr umfangreich, es finden sich so gut wie alle Daten zum neuen Container darin. Der Status wird noch als “pending” angezeigt, was daran liegt, dass das Docker-Image erst von der Azure Container Registry herunter geladen werden muss. Danach wird der Container erzeugt. Der Status kann auch wieder via az-Kommando überprüft werden:

Oder konkret:

Das war es auch schon! Der Container konnte erfolgreich gestartet werden, natürlich lassen sich noch Informationen herausfinden wie der Hostname, unter dem die Website erreicht werden konnte, aber dieselben Informationen sind auch bereits in der Rückgabe des Start-Kommandos enthalten:

Der Container läuft, das Login in die Admin-UI von Grav war problemlos möglich.

Die Geschwindigkeit ist ebenfalls zufriedenstellend. Zumindest konnte ich keine größeren Verzögerungen bemerken. Jedoch darf nicht vergessen werden, dass es sich dabei auch nur um einen einzigen Container handelt. Darin verpackt sind alle notwendigen Server-Dienste, aber auch Dateien. Mehrere Container lassen sich in Container-Gruppen strukturieren, so ist es möglich, z.B. den Web-Server getrennt von der Datenbank zu betreiben. Wobei hier im Beispiel keine Datenbank genutzt wurde, eine Möglichkeit der Aufteilung wäre etwa die Trennung von Nginx (Web-Server bzw. Proxy) und php-fpm-Service. 

Darüber hinaus gehende Funktionen, etwa zur Orchestrierung mehrerer oder einer Vielzahl von Containern ist erst mit den Kubernetes-Diensten möglich. 

Fazit

Letztlich bieten die Azure Container-Instances somit eine Teilmenge dessen, was im einfachsten Fall mit einer Installation eines Docker-Daemons auf einem Host möglich ist. Denn wenn man sich die verfügbaren Kommandos für die Container-Gruppe ansieht, wird man feststellen, dass darin kein Kommando für das Stoppen eines Containers vorhanden ist:

Es ist also nicht möglich, einen laufenden Container zu stoppen und wieder fortzusetzen. Das ist aus Sicht des Cloud-Providers auch logisch, denn möglicherweise wird beim Erzeugen des Containers ein völlig anderer Host verwendet, der zufällig an der Reihe war. Infolge dessen sind auch die im Container während der Laufzeit geänderten Daten nicht mehr vorhanden. Das entspricht zwar einerseits dem Konzept der “ephemeral” (“flüchtig”) Container , die nach Belieben gestartet, gestoppt, verschoben usw. werden können, bedingt aber auch, dass sich der Nutzer von Azure eine Möglichkeit suchen muss, um Persistenz zu erhalten. Für eine Datenbank besitzt Azure dafür ebenso gemanagte Lösungen wie zur Speicherung von Dateien (z.B. Azure-Dateifreigabe). Somit gilt wie immer – es kommt auf die Anwendung an! Die Komplexität ist gegenüber eines einfachen Docker-Daemons, der auf einer fest definierten (virtuellen) Maschine genutzt wird, natürlich höher. Es können keine lokalen Verzeichnisse in die Container gemountet werden, die Container lassen sich nicht beenden und neu starten, ohne dass sie ihren Zustand verlieren. Das alles wäre bei Docker auf einer klassischen VM möglich. Andererseits sind dort die Möglichkeiten zur Skalierung beschränkt bzw. der Aufwand dafür, z.B. verteilen Speicher oder verteilte Datenbanken zu betreiben, ist wesentlich höher.

Nicht zuletzt ist auch der Preis zu berücksichtigen. Die einfachste Container Instanz mit einem CPU-Core und einem GB RAM würde pro Monat laut Prognose mehr als 40 EUR kosten. Darin inbegriffen sind die Container Registry, die momentan zwei Versionen eines Docker-Images beinhaltet. In Relation zu Angeboten von günstigen VMs der einschlägigen Provider wären die Kosten damit um ein Vielfaches höher. Für das Hosting einer kleinen Website im privaten Rahmen, oder auch für einen Freiberufler, der auch kein Problem damit hat, eine VM zu administrieren, lohnt sich die Nutzung von Azure somit kaum. In der Zielgruppe von Unternehmenskunden mag dies schon wieder ganz anders aussehen, wenn eine Stunde Personalaufwand mit einem höheren Aufwand zu beziffern ist als die Kosten für einen Monat Azure Container Instances. Davon abgesehen bietet Azure ebenfalls im einfachsten Fall virtuelle Maschinen an, auf denen dann beliebige Services installiert werden können. Der Preisunterschied zwischen der einfachsten Azure-Variante verglichen mit anderen VM-Anbietern ist hier nicht ganz zu hoch, wobei Azure wesentlich mehr Ausstattungsvarianten bietet als klassische Provider. 

Ich habe mir nach den Container Instances noch die Containergruppen angesehen und die “Web-App für Container” genannten Dienste getestet. Letzterer Dienst ist wiederum beim App Service angesiedelt. Die Ergebnisse werde ich noch kurz zusammenfassen, danach jedoch auch den Test von Azure voraussichtlich beenden, auch wenn ich damit insgesamt nur einen Bruchteil von Azure unter die Lupe genommen haben werde.  Immerhin stimmen die Ergebnisse des Tests der Container Instances positiv – sie haben letztlich wie erwartet funktioniert. 

 

 

Ähnliche Beiträge

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

Tags: