Für den Umgang mit Virtualisierungtechnik haben sich an vielen Stellen Container durchgesetzt. Docker ist eine Software, die zur Verwaltung, Erstellung und dem Betrieb von Containern verwendet werden kann. Docker ist nicht die einzige Software dieser Art, erfreut sich aber plattformübergreifend größter Beliebtheit. Das liegt hauptsächlich daran, wie einfach der Einsatz ist – sowohl im Alltag einzelner Entwickler als auch in komplexen Deployment-Szenarien.

In diesem Artikel werden Sie lernen, wie Sie Docker-Container auf dem eigenen Computer betreiben können. Der Einstieg ist einfach, aber es gibt viele Optionen und Möglichkeiten. Im alltäglichen Umgang müssen Sie auch wissen, wie Sie zur Laufzeit mit Containern interagieren, Daten daraus extrahieren bzw. sichern, Log-Ausgaben prüfen, und Ihr System nach einiger Zeit aufräumen und von Altlasten befreien.

Eine Anmerkung zwischendurch: Die Art von Virtualisierung, die mit Docker erreicht wird, ist deutlich anders als etwa die von virtuellen Maschinen. Dieser Artikel ist nicht der Rahmen, in dem im Detail auf Gemeinsamkeiten und Unterschiede eingegangen werden kann. Als kurze Zusammenfassung soll der folgende Satz dienen: Virtuelle Maschinen bieten vollständige virtuelle Systemumgebungen mit eigenem Betriebssystem auf Basis von speziell reservierten Ressourcen, während Container eine leichtgewichtige Kapselung von Prozessen bewirken und sich die Systemumgebung des Hosts teilen. Die genaue Implementation der Containertechnologie hängt letztlich unter anderem vom Hostsystem ab.

Bevor Sie mit Containern arbeiten können, müssen Sie Docker natürlich auf Ihrem System installieren. Auf diesen Schritt möchte ich nicht im Detail eingehen, da dies von der Systemumgebung abhängig und vom Anbieter gut dokumentiert ist. Auf Mac oder Windows brauchen Sie lediglich einen Installer laufenzulassen, während unter Linux gewöhnlich ein Paket für Ihre Distribution angeboten wird. Auf der offiziellen „Get Started“-Webseite finden Sie die Informationen, die für eine erfolgreiche Installation erforderlich sind. Wenn Sie Docker in einer Cloud-Umgebung einsetzen, bekommen Sie vom Betreiber Hilfestellung bei der Inbetriebnahme.

Wenn Docker fertig installiert ist, sollten Sie erfolgreich ein Kommando wie dieses ausführen können, um einen ersten Testlauf zu starten:

Bereits bei diesem Aufruf sind einige relevante Punkte zu erkennen. Zunächst wurde im Beispiel sudo verwendet, um den Aufruf mit root-Rechten auszuführen. Dies ist je nach Installation bei Linux oder Mac erforderlich, denn Docker benötigt gewisse Rechte im System, die ein „normaler“ Benutzer nicht hat. Es ist möglich, dem eigenen Benutzerkonto diese Rechte auf dem Weg über eine Gruppe zuzuweisen, aber das bringt gewisse potentielle Sicherheitsprobleme mit sich. Daher ist der Aufruf mit sudo eventuell der bessere Weg, wenn auch etwas weniger komfortabel im Umgang.

Der zweite interessante Punkt ist, dass Docker sich für ein bestimmtes Tag entscheidet, da der Name des Images „hello-world“ ohne Tag angegeben wurde. (Das Tag ist die Bezeichnung, die hinter dem Doppelpunkt angegeben ist, also „latest“ in diesem Beispiel.) Von manchen Images gibt es viele unterschiedliche Versionen, und so ist die explizite Angabe eines Tags oft notwendig. Speziell im Deployment sollte gewöhnlich auch deshalb ein Tag angegeben werden, damit die Kompatibilität mit anderen Komponenten eines Systems gewährleistet ist. Als Entwickler arbeiten wir mit bestimmten Versionen, während wir Anwendungscode schreiben – wenn später ganz andere Versionen im praktischen Einsatz verwendet werden, können sich diese natürlich auch anders verhalten.

Artefakte von Docker

Dieser erste Start eines Docker-Containers hat nun bereits Spuren im System hinterlassen. Wie Sie gesehen haben, hat Docker ein Image heruntergeladen. Das Image stellt den statischen Zustand dar, der von einem Entwickler erzeugt und in einem Repository (in diesem Fall dem Docker-Hub) verfügbar gemacht worden ist. Nachdem das Image einmal auf dem lokalen System vorliegt, bleibt es dort und wird nicht noch einmal heruntergeladen – es sei denn, Sie verwenden eine andere Version des Images, oder weisen Docker ausdrücklich an, das lokale Image zu aktualisieren. Mithilfe eines Unterkommandos können Sie das Image sehen:

Übrigens gibt es von diesem Unterkommando – wie manchem anderen – mehrere Varianten. Mit docker images erreichen Sie dieselbe Ausgabe wie mit docker image ls. Ich selbst bevorzuge der Konsistenz halber die klar strukturierten Subkommandos, aber Docker kennt oft verschiedene, eventuell kürzere Versionen.

Die Handhabung der Images erscheint logisch: Einmal heruntergeladen bleiben Sie auf dem System für spätere Verwendung. Allerdings gibt es ein weiteres Artefakt des kurzen Testlaufs, denn der Container ist ebenfalls noch vorhanden. Aber Sie sehen diesen nur, wenn Sie die Option -a übergeben, da der Container derzeit nicht in Verwendung ist.

Im folgenden Beispiel sehen Sie bereits zwei Container für das Image „hello-world“, denn ich hatte zu Testzwecken das Kommando docker run zweimal ausgeführt.

Tatsächlich ist es so, dass docker run eine Kombination von zwei Befehlen darstellt: docker create und docker start. Mit create wird ein Container erzeugt, aber zunächst nicht gestartet. Mit start geht dann die eigentliche Ausführung los. Das „hello-world“-Image enthält lediglich einen kurzlebigen Prozess, so dass die Ausführung schnell beendet ist. Der Container bleibt danach bestehen, was für diese Art von Container gewöhnlich nicht der Sinn ist. Es ist möglich, den Container später noch einmal zu starten (mit -a, damit die Ausgabe auch zu sehen ist – dies geschieht bei run automatisch), und Sie können bei run auch die Option --rm angeben, damit der Container nach der Ausführung automatisch entfernt wird.

Im Beispiel ist eine weitere Besonderheit zu sehen: Die verkürzte Referenz auf den Container. In der Ausgabe weiter vorn in diesem Artikel können Sie die längere ID des Containers sehen: c0ec918e1b5a (auch dies ist noch nicht die vollständige ID, sondern nur eine längere Form). Natürlich ist es möglich, Containern spezifische Namen zuzuweisen (mit --name <name>), aber im alltäglichen Umgang ist das leicht einmal vergessen. In diesem Fall ist es gut zu wissen, dass Docker jede verkürzte Form der ID akzeptiert, solange diese im System eindeutig ist.

Container im Vorder- und Hintergrund

Oben haben Sie gesehen, dass beim Start des Containers mit run die Ausgabe direkt auf der Konsole erschien. Dahingegen war bei der Verwendung von start die Option -a notwendig (sie steht für „attach“), um wiederum die Ausgabe zu sehen. Das Kommando run stellt gewissermassen eine Ausnahme dar, indem es automatisch die Ausgabe des Containerprozesses anzeigt. Sie können -d („detach“) verwenden, um den Container im Hintergrund laufen zu lassen. Dies ist nach einer Eingewöhnungszeit sehr angenehm, da die Ausgabe der meisten Container eher zu Debugzwecken nützlich ist und nicht dauernd benötigt wird. Mit -d können auf einer Konsole mehrere Container gestartet werden, die dann gemeinsam im Hintergrund laufen. Wenn einmal ein Blick auf die Konsolenausgabe notwendig ist, bietet sich das Kommando logs dazu an.

Das Kommando docker ps dient dazu, die gerade laufenden Container anzuzeigen. Da es analog zum Unix-Kommando ps ist, verwende ich es auch instinktiv, obwohl es dieselbe Ausgabe liefert wie das längere docker container ls (ohne die vorher gezeigte Option -a). Im Beispiel wird der Name „redis“ verwendet, um die Logs des laufenden Containers abzurufen.

Umgekehrt kann es manchmal helfen, kurzlebige Docker-Container direkt mit bestimmten Ein- und Ausgabekanälen zu verbinden. Hier einige Bespiele zum Aufruf der JavaScript-Laufzeitumgebung „Node“ als Docker-Container. Dieser Container verhält sich ähnlich dem Node, dass Sie eventuell von der Kommandozeile her kennen. Wenn Sie allerdings den Node-Container ohne weitere Optionen starten, tut er anscheinend nichts. Die Kombination der Parameter -i und -t ist erforderlich, damit der Container interaktiv mit der Kommandozeile verbunden ist, so dass Sie mit dem JavaScript-REPL arbeiten können.

Normalerweise kann das Kommando node den Namen einer ausführbaren JavaScript-Datei als Aufrufparameter entgegennehmen. Im Falle des Containers ist die Datei allerdings extern, so dass zur Ausführung der einfachere Weg darin besteht, den Inhalt durch eine Pipe zu schicken. Zu diesem Zweck ist noch immer der Parameter -i erforderlich, aber auf -t muss verzichtet werden, da keine Interaktion mit dem laufenden Container benötigt wird.

Netzwerkports und Umgebungsvariablen

In der Ausgabe von docker ps war oben bereits zu sehen, dass Container auch Netzwerkports zugeordnet haben können. Bei redis geschieht dies etwa für den TCP-Port 6379. Normalerweise, also ohne besondere Optionen, stellt Docker einem Container ein automatisch erzeugtes privates Netzwerk zur Verfügung. Dies bedeutet, dass der redis-Container bisher nicht ohne Umstände kontaktiert werden kann. Für den praktischen Einsatz, besonders im Deployment, kann es notwendig sein, Containern spezifische private Netze zuzuweisen, damit die richtigen Container in einem Gesamtsystem zusammenarbeiten können, während andere Gruppen explizit nicht in Kontakt stehen. In einfachen Fällen, sowie bei der Arbeit als Entwickler, kann es allerdings auch nützlich sein, den Port eines Containers auf dem Hostsystem abzubilden. Dies lässt sich mit der Option -p erreichen:

Mit dieser Option wird der Port 6379 vom Host auf denselben Port des Containers abgebildet. Wenn also auf dem Host nun eine Anwendung versucht, redis auf seinem Standard-Port 6379 zu kontaktieren, dann redet diese Anwendung tatsächlich mit dem Container – ohne es zu wissen.

Wie Sie angesichts der Syntax sicherlich bereits verstanden haben, ist es auch möglich, für den Host einen anderen Port zu verwenden. So können Sie etwa zwei Instanzen eines Servers gleichzeitig starten und über unterschiedliche Ports damit arbeiten – sehr praktisch für Migrationsarbeiten oder Tests. Dies ist eines der Merkmale, die Docker für die Arbeit als Entwickler sehr angenehm machen.

Für den Start von Containern gibt es außer der Netzwerkkonfiguration noch einen weiteren wichtigen Mechanismus: die Übergabe von Umgebungsvariablen (Environment-Variablen). Es ist üblich, dass Docker-Images auf solche Weise konfiguriert werden, entweder beim ersten Start, oder bei jedem Start. Wenn Sie etwa einen Datenbankserver als Docker-Container starten, nimmt dieser eventuell beim ersten Start über eine Umgebungsvariable ein Passwort für den Admin-Benutzer entgegen. Bei MySQL heißt diese Variable MYSQL_ROOT_PASSWORD, und sie muss übergeben werden, damit der Container korrekt starten kann. Der Dokumentation zum Image für MySQL können Sie entnehmen, dass derzeit 12 andere Umgebungsvariablen erkannt werden.

Um eine einzelne Variable an der Kommandozeile zu übergeben, verwenden Sie die Option -e. Hier ein Beispiel:

Sie können die Option -e mehrfach angeben, um mehrere verschiedene Variablen zu setzen. Oft ist es allerdings nicht klug, besonders Variablen mit Passwörtern an der Kommandozeile anzugeben, denn so werden die Werte auch in der Shell-Historie abgelegt, wo sie eventuell für andere Anwender (oder Eindringlinge!) sichtbar sein könnten. Es gibt daher auch die Möglichkeit, Umgebungsvariablen in einer separaten Datei abzulegen, die zumindest mit Datei-Systemberechtigungen geschützt sein kann.

Im Beispiel können Sie sehen, dass die Datei nur für einen einzelnen Benutzer lesbar ist, so dass das darin enthaltene Passwort relativ gut geschützt ist. Solch eine Datei kann auch mehrere Variablen gleichzeitig definieren. Mit der Option --env-file wird sie beim Start des Containers ausgewertet, und die Werte werden für den neuen Container gesetzt.

Einführung in den Betrieb von Docker-Containern – Fazit

Damit ist das Ende des ersten Teils erreicht. Der Überblick soll Ihnen ermöglichen, interaktiv mit Docker zu arbeiten, Container zu starten und zu beenden, sowie mit Parametern und Umgebungsvariablen die nötigsten Details für Start und Ablauf zu beeinflussen. Im zweiten Teil werden Sie sehen, wie die im Container entstehenden Daten abgelegt werden und wie Sie vom Host aus darauf zugreifen können. Bis dahin empfehle ich, selbst mit den Kommandos zu experimentieren (fast alle unterstützen eine Option --help!), und natürlich auch die Dokumentation zu Docker zu lesen.

Titelmotiv: Bild von ddzphoto auf Pixabay

Oliver Sturm

Schreibe einen Kommentar

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

Die von Ihnen hier erhobenen Daten werden von der Host Europe GmbH zur Veröffentlichung Ihres Beitrags in diesem Blog verarbeitet. Weitere Informationen entnehmen Sie bitte folgendem Link: www.hosteurope.de/AGB/Datenschutzerklaerung/