Tutorial: So geht Docker
Lesen Sie, wie Sie mit Docker unter Linux, Windows und macOS arbeiten.
Aji Asmara | shutterstock.com
Container machen Anwendungs-Workloads portabel. Ähnlich wie eine virtuelle Maschine (VM), aber ohne deren Overhead. So ermöglicht die Technologie, Apps und Services zu verpacken und frei zwischen physischen, virtuellen und Cloud-basierten Umgebungen zu verschieben.
Docker macht sich die native Container-Funktionalität von Linux zunutze, um Container zu erstellen und zu managen. Diese stellt sie Endbenutzern über eine Befehlszeilenschnittstelle (Command-Line Interface, CLI) und eine Reihe von APIs zur Verfügung. Inzwischen sind diverse gängige Applikationskomponenten in Form vorgefertigter Docker-Container verfügbar. Das erleichtert es, Software-Stacks als entkoppelte Komponenten bereitzustellen.
In diesem Tutorial erfahren Sie nicht nur, wie Docker funktioniert, sondern unter anderem auch:
wie Sie die Software unter Linux, Windows und macOS einrichten,
wie Sie Docker-Container installieren, einrichten und erstellen,
wie Sie eine Apache-Webserver-Instanz in einem Docker-Container installieren und
wie Sie mit Dockerfiles Image-Builds automatisieren.
Ein Docker-Produkt wählen
Das Herzstück von Docker ist das Open-Source-Projekt Docker Engine. Dieses können Sie auch Standalone installieren und anschließend direkt über die Befehlszeile bedienen, allerdings ausschließlich unter Linux – oder über WSL unter Windows.
Die zweite Option ist Docker Desktop, eine praktische, GUI-basierte Anwendung, um mit Containern auf mehreren Plattformen zu arbeiten. Für Entwickler, die Microsoft Windows verwenden, ist das die bequemste Lösung. Der wichtigste Aspekt bei Docker Desktop ist die Lizenzierung: Für den privaten, nicht-kommerziellen Open-Source- und Bildungsbereich ist die Nutzung kostenlos. Für die kommerzielle Nutzung fallen jedoch Lizenzgebühren an. Deren Höhe variiert je nach Organisationsgröße.
Docker Desktop bietet eine übersichtliche grafische Benutzeroberfläche, die auch ein eingebettetes Konsolen-Interface beinhaltet.IDG
Darüber hinaus stehen auch Binary-Editionen der Docker Engine für Windows, macOS und Linux zur Verfügung. Weil Docker mehr als nur ein Artefakt ist, erfordert das jedoch, den gesamten Setup-Prozess manuell zu durchlaufen. Zudem verfügen die Standalone-Binaries nicht über einen Update-Mechanismus und lassen diverse Funktionen des vollständigen Docker-Produkts vermissen.
Docker unter Linux, Windows und macOS installieren
Linux
Unter Linux können Sie die wichtigsten Open-Source-Funktionen von Docker direkt in Form der Docker Engine nutzen. Diese einzurichten, erfordert allerdings für jede (große) Linux-Distribution ein anderes Verfahren. Gleiches gilt unter Linux auch für Docker Desktop.
Einmal installiert, bietet Docker Desktop unter Linux im Vergleich zur Befehlszeile bequemere Möglichkeiten, um ein Docker Setup zu managen.
Windows
Unter Windows kann Docker Desktop in einem von zwei Modi arbeiten:
mit dem nativen Hyper-V-Virtualisierungssystem von Windows oder
über eine Linux-Instanz in WSL2.
Beide Backends bieten die gleiche Funktionalität und legen identische Anforderungen an die Hardware an:
eine 64-Bit-CPU mit SLAT-Unterstützung,
mindestens 4 GB RAM und
BIOS-fähigen Support für Hardware-Virtualisierung.
Von den beiden Optionen ist WSL2 die schlankere. Hyper-V ist zudem anspruchsvoller und wird ausschließlich mit den Professional- oder Enterprise-Editionen von Windows 10 oder 11 ausgeliefert. Zu beachten ist dabei, dass Hyper-V ab Windows 11 und Windows Server 2022 erweiterte Funktionen bietet, um Prozesse zu isolieren. Das ist für Docker-Einsteiger aber auch nicht unbedingt erforderlich.
Falls Sie ein anderes VM- oder Hypervisor-System verwenden wollen, um Container auszuführen, benötigen Sie eine Business- oder Enterprise-Edition von Docker.
macOS
Docker Desktop auf macOS-Systemen zu installieren, funktioniert ähnlich wie bei jeder anderen Desktop-Anwendung:
Öffnen Sie die Docker.dmg-Datei per Doppelklick, um sie zu öffnen, und
ziehen Sie dann das Docker-Symbol in Ihren Anwendungsordner.
Es ist außerdem möglich, den Installationsvorgang über die Befehlszeile zu starten.
Mit der Docker-CLI arbeiten
Den Großteil Ihres Docker-„Daseins“ werden Sie sehr wahrscheinlich mit der docker-CLI-Utility verbringen. Sobald Docker installiert ist, können Sie docker über jede Konsole ausführen. Um alle verfügbaren Befehle einzusehen, genügt ein simpler docker-Befehl. Die offizielle Dokumentation des CLI-Client hält ausführliche Beschreibungen zu diesen bereit.
Ein weiterer grundlegender Befehl ist docker info. Dieser liefert Ihnen Basisinformationen über Ihre Docker-Installation, zum Beispiel die Anzahl der Container und Images.
Der (auszugweise) Output von ‚docker info‘.IDG
Zu beachten ist dabei, dass Sie docker-Befehlen unter Linux möglicherweise sudo voranstellen müssen (Dieser Hinweis gilt auch für alle anderen Befehlsbeispiele in diesem Artikel).
Der Docker-Desktop-Client ist übrigens nicht darauf konzipiert, die docker-CLI zu ersetzen. Vielmehr soll dieser eine Ergänzung darstellen, die eine praktische, grafische Benutzeroberfläche für alltägliche Container-Tasks bietet. Beispielsweise:
Container ausführen,
installierte Images untersuchen,
erstellte Volumes überprüfen,
Container-Image-Builds auflisten und
Extensions für Docker Desktop zu steuern.
Für direkten Konsolenzugriff bietet Docker Desktop außerdem einen eigenen, integrierten Konsolen-Host. Im Folgenden nutzen wir die Docker CLI als Standardmethode, um mit Docker zu interagieren.
Mit Docker-Containern und -Images arbeiten
Wie eingangs bereits erwähnt, sind Docker-Container deutlich effizienter als virtuelle Maschinen. Führt ein Container keinen Prozess aus, ist er vollständig inaktiv – und verbraucht (abgesehen von Speicherplatz) keine Ressourcen.
Um Container auszuführen, ist allerdings ein Image nötig – das standardmäßig nicht in der Installation vorhanden ist. Sie müssen dieses deshalb herunterladen und dem lokalen Image-Repository hinzufügen. Wie Sie im folgenden Beispiel sehen, geht das auch halbautomatisch.
Einen Docker-Container starten
Um ein Basis-Image für Ubuntu Linux zu starten und die bash-Shell auszuführen, nutzen Sie folgenden Befehl:
docker run -i -t ubuntu /bin/bash
Das Ergebnis sieht in etwa wie folgt aus:
PS C:\Users\serda> docker run -i -t ubuntu /bin/bash
Unable to find image 'ubuntu:latest' locally
latest: Pulling from library/ubuntu
dafa2b0c44d2: Pull complete
Digest: sha256:dfc10878be8d8fc9c61cbff33166cb1d1fe44391539243703c72766894fa834a
Status: Downloaded newer image for ubuntu:latest
root@16fd4752b26a:/#
Der Code zeigt an, wie Docker das Ubuntu-Image abruft und einen darauf basierenden Container startet. Die letzte Zeile stellt dabei den Prompt für die bash-Shell dar, die im Container ausgeführt wird und die Sie mit Befehlen füttern können. Zu beachten ist dabei, dass sich sämtliche Befehle, die an dieser Stelle einfließen, auf das Image beziehen – nicht auf das Gesamtsystem.
Laufende Container überprüfen
Mit dem Befehl docker ps können Sie aktive und inaktive Container anzeigen. Denken Sie daran, diesen Befehl über die eigentliche Systemkonsole auszuführen. Der erweiterte Befehl docker ps -a zeigt sämtliche Container im System an, unabhängig von ihrem Status.
Im Gegensatz dazu zeigt docker ps nur die laufenden Container an. Der folgende Output könnte etwa so aussehen:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
16fd4752b26a ubuntu "/bin/bash" 25 minutes ago Up 25 minutes stoic_gould
Jeder laufende Container wird mit einer ID verknüpft. In unserem Fall ist es die mit „16fd“ beginnende Zeichenfolge. Außerdem werden hier auch Informationen darüber angezeigt welches Image verwendet wurde, um den Container zu erstellen sowie dessen Anzeigename (stoic_gould). Letzter lässt sich manuell über den --name-Switch oder beim Start zufällig zuweisen.
Container abrufen
Mit dem Kommando docker run haben Sie automatisch ein Ubuntu-Container-Image vom Registry-Service Docker Hub abgerufen. In der Praxis werden Sie dieses jedoch bevorzugt vorab in Ihren lokalen Cache ziehen wollen. Dazu nutzen Sie:
docker pull ubuntu
Eine vollständige, durchsuchbare Auflistung aller verfügbarer Images und Repositories ist auf Docker Hub einsehbar.
Docker-Images vs. Container
An dieser Stelle werfen wir einen kurzen Blick darauf, wie Images, Container und der Pull-/Push-Prozess zusammenwirken.
Docker-Container werden aus Images erstellt, die im Wesentlichen Shells von Betriebssystemen sind. Sie enthalten die erforderlichen Binärdateien und Bibliotheken, um Applikationen in einem Container auszuführen.
Images werden mit Tags, im Wesentlichen Metadaten, gelabelt. Das erleichtert es, verschiedene Versionen eines Images zu speichern und abzurufen. Ein einzelnes Image kann dabei mit mehreren Tags verknüpft werden – etwa ubuntu:16.04, ubuntu:xenial-20171201, ubuntu:xenial, ubuntu:latest. Der bereits bekannte Befehl docker pull ubuntu ruft das Standard-Image aus dem Ubuntu-Repository ab, das mit dem Tag latest versehen ist. Der Befehl docker pull ubuntu entspricht also docker pull ubuntu:latest.
Der Befehl docker pull -a ubuntu hätte hingegen alle Bilder (das -a-Tag) im Ubuntu-Repository in das lokale System gezogen. Das ist praktisch, wenn Sie mit einer Vielzahl von Ubuntu-Images arbeiten wollen, ohne jedes einzeln abzurufen. Allerdings beansprucht das auch viel Speicherplatz auf lokaler Ebene. Im Regelfall greifen Sie jedoch entweder auf das Default-Image oder eine spezifische Version zu. Wollen Sie beispielsweise das Image für Ubuntu Saucy Salamander verwenden, würden Sie dieses mit docker pull -a ubuntu:saucy aus dem Repository abzurufen.
Die gleiche Logik, die hinter Repositories und Tags steht, gilt auch für andere Image-Manipulationen: Wenn Sie das Saucy-Image abgerufen und ausgeführt haben, können Sie mit docker image rm ubuntu das Ubuntu-Image entfernen, das mit latest getaggt ist. Um andere Images wie Saucy zu entfernen, müssen Sie das entsprechende Tag angeben. Der richtige Befehl lautet also: docker image rm ubuntu:saucy.
Docker-Images und Container-Workflows
Sobald Sie ein Image abgerufen haben, startet der Befehl docker run einen Live-Container mit dessen Inhalten.
Images sind grundsätzlich unveränderlich. Sie verändern sich also nicht, wenn Sie einen Container ausführen. Der Container ist zu Beginn im Wesentlichen eine Kopie des Image-Inhalts – wird er beendet, gehen auch sämtliche vorgenommenen Änderungen verloren. Um Änderungen an einem Image vorzunehmen, gibt es zwei Möglichkeiten:
Sie können das Dockerfile des Images modifizieren und auf dieser Grundlage ein neues Image erstellen, oder
Änderungen an einem laufenden Container vornehmen und mit dem Docker-Commit-Befehl ein neues Image erstellen, das diese enthält.
Wenn Sie eigene Images erstellen, werden nur die Änderungen, die Sie am Basis-Image vornehmen, im neuen Image gespeichert. Dieses ist mit dem Basis-Image verknüpft. Das ermöglicht es, Images zu erstellen, die eine virtuelle Größe von mehreren Hundert MB aufweisen, aber nur ein paar Megabyte Festplattspeicher belegen.
Vollständig konfigurierte Container können an ein zentrales Repository weitergeleitet werden, um an anderer Stelle in der Organisation verwendet oder auch öffentlich freigegeben zu werden.
Docker-Image aus Container erstellen
Nachdem wir die grundlegende Funktionsweise von Images und Containern behandelt haben, richten wir im folgenden Kapitel einen permanenten Apache-Webserver-Container ein.
Neuen Docker-Container erstellen
Dazu gilt es zuerst einen neuen Container zu erstellen. Um das zu tun, gibt es mehrere Möglichkeiten. Da Sie aber noch einige Befehle vor sich haben, empfiehlt es sich an dieser Stelle, eine Root-Shell in einem neuen Container zu starten. Dazu nutzen Sie folgenden Befehl:
docker run -i -t --name apache_web ubuntu /bin/bash
Nun haben Sie einen neuen Container mit einer eindeutigen ID und dem Namen apache_web erstellt. Außerdem erhalten Sie eine Root-Shell, weil Sie /bin/bash als auszuführenden Befehl angegeben haben. Anschließend installieren Sie den Apache-Webserver mit:
apt-get install apache2
In diesem Fall müssen Sie nicht auf sudo zurückgreifen, weil dieser innerhalb des Containers als root ausgeführt wird. Nötig ist allerdings apt-get update, weil die Package-Liste innerhalb des Containers nicht mit der außerhalb des Containers identisch ist. Sobald die Installation abgeschlossen ist, können Sie Apache starten, curl installieren und die Installation testen – alles innerhalb Ihres Containers:
service apache2 start
apt-get install curl
curl http://localhost
Würden Sie an dieser Stelle innerhalb einer Produktionsumgebung agieren, würden Sie im nächsten Schritt Apache gemäß Ihren Anforderungen konfigurieren und eine Anwendung installieren, die von diesem Server bereitgestellt werden soll. Dabei ermöglicht Docker, Verzeichnisse außerhalb eines Containers mit Pfaden innerhalb zu verknüpfen. Sie könnten also Ihre Web App in einem Verzeichnis auf dem Host speichern und diese für den Container über ein Mapping sichtbar machen.
Startskript für einen Docker-Container erstellen
Wie ebenfalls bereits erwähnt, wird ein Docker-Container nur so lange ausgeführt, wie sein Prozess oder seine Prozesse aktiv sind. Sobald der Prozess in den Hintergrund wechselt, den Sie ausgeführt haben um den Container zu starten (etwa ein System Daemon), stoppt Docker den Container. Sie müssen Apache zum Container-Launch also im Vordergrund ausführen, damit Ihr Container nicht sofort nach dem Start wieder beendet wird.
Dazu erstellen Sie ein Skript:
apt-get install nano
nano /usr/local/sbin/startapache.sh
Sie müssen dazu nicht den Nano-Editor verwenden, er ist an dieser Stelle aber praktisch.
Der Inhalt von startapache.sh:
#!/bin/bash
. /etc/apache2/envvars
/usr/sbin/apache2 -D FOREGROUND
Speichern Sie nun die Datei und machen Sie sie ausführbar mit:
chmod +x /usr/local/sbin/startapache.sh
Diese kleine Skriptdatei sorgt lediglich dafür, dass die entsprechenden Umgebungsvariablen für Apache bereitgestellt werden und der Apache-Prozess im Vordergrund gestartet wird.
Sie haben den Inhalt des Containers geändert und können diesen nun mit dem Befehl exit verlassen.
Container committen, um ein neues Docker-Image zu erstellen
Um die vorgenommenen Änderungen zu speichern, müssen Sie den Container „committen“. Das funktioniert mit:
docker commit apache_web local:apache_web
Der Commit speichert Ihren Container als neues Image und gibt eine eindeutige ID zurück. Das Argument local:apache_web bewirkt dabei, dass der Commit in einem lokalen Repository namens local mit dem Tag apache_web abgelegt wird.
Einsehen können Sie das mit dem Befehl docker images. Der resultierende Output sieht in etwa folgendermaßen aus:
REPOSITORY TAG IMAGE ID CREATED SIZE
local apache_web 540faa63535d 24 seconds ago 233MB
ubuntu latest b1e9cef3f297 4 weeks ago 78.1MB
Docker-Netzwerkgrundlagen
Nachdem Sie nun Ihr Image erstellt haben, können Sie Ihren Container starten und die Serving-Arbeit starten. Zuvor lohnt sich allerdings ein Blick darauf, wie Docker Netzwerke handhabt. Die Software ist in der Lage, verschiedene, virtuelle Netzwerke erstellen, die von Docker-Containern verwendet werden, um miteinander und mit der Außenwelt zu kommunizieren. Die drei (für den Anfang) wesentlichen sind:
Mit dem bridge-Netzwerk sind Docker-Container standardmäßig verbunden. Es ermöglicht Containern, direkt miteinander zu kommunizieren, jedoch nicht mit dem Host-System.
Im host-Netzwerk sind Container für den Host direkt sichtbar – so als würden alle darin enthaltenen Apps als lokale Netzwerkdienste ausgeführt.
Bei none handelt es sich im Wesentlichen um ein Null- oder Loopback-Netzwerk. Ein damit verbundener Container kann nur sich selbst sehen.
Wenn Sie einen Container starten möchten, der sowohl mit anderen Containern als auch mit der Außenwelt kommunizieren soll, müssen Sie dem Host die Ports von diesem Container manuell zuordnen. In unserem Beispiel können Sie das über die Befehlszeile bewerkstelligen, wenn Sie Ihren neu erstellten Container starten:
docker run -d -p 8080:80 --name apache local:apache_web /usr/local/sbin/startapache.sh
Für die Portzuordnung kommt in diesem Beispiel der -p-Switch zum Einsatz. Dabei wird Port 8080 auf dem Host dem Port 80 im Container zugeordnet. Sobald Sie diesen Befehl ausführen, sollten Sie die Standardseite des Apache-Webservers über einen Webbrowser abrufen können.
Den Status Ihres Containers und seine TCP-Portzuordnungen zeigen Sie mit dem Befehl docker ps an.
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS
NAMES
81d8985d0197 local:apache_web "/usr/local/sbin/sta…" 13 minutes ago Up 12 minutes 0.0.0.0:8080->80/tcp apache
Zudem können Sie Netzwerkzuordnungen auch mit dem Befehl docker port abrufen, in diesem Fall docker port apache.
80/tcp -> 0.0.0.0:8080
Nun haben Sie einen voll funktionsfähigen Docker-Container, in dem Ihr Apache-Prozess ausgeführt wird. Wenn Sie den Container anhalten, verbleibt er im System und kann jederzeit mit dem Befehl docker restart neu gestartet werden.
Mit Dockerfiles automatisieren
So lehrreich es auch ist, Docker-Container manuell zu erstellen – so sehr verliert es auch mit jeder Wiederholung seinen Reiz. Um diesen Prozess einfach, konsistent und wiederholbar zu gestalten, bietet Docker auch eine Automatisierungsfunktion, um Images zu erstellen – die sogenannten Dockerfiles.
Dabei handelt es sich um Textdateien, die zusammen mit Docker-Images in einem Repository gespeichert werden. Sie beschreiben, wie ein bestimmter Container erstellt wird, was Docker ermöglicht, diesen Prozess zu automatisieren.
Nachfolgend ein Dockerfile-Beispiel für einen minimalen Container:
FROM ubuntu:latest
RUN apt-get update
RUN apt-get install -y curl
ENTRYPOINT ["/bin/bash"]
Wenn Sie diese Datei als dftest in Ihrem lokalen Verzeichnis speichern, können Sie daraus ein Image namens ubuntu:testing erstellen. Dazu genügt folgender Befehl:
docker build -t ubuntu:testing - < dftest
In PowerShell würden Sie dieses Kommando verwenden:
cat .\dftest | docker build -t ubuntu:testing –
Das veranlasst Docker ein neues Image auf der Grundlage von ubuntu:latest zu erstellen. Anschließend führt es innerhalb des Containers ein apt-get update aus und verwendet apt-get, um curl zu installieren. Schließlich wird der Standardbefehl, der beim Start des Containers ausgeführt werden soll, auf /bin/bash festgelegt. Nun können Sie folgenden Befehl ausführen:
docker run -i -t ubuntu:testing
Im Resultat erhalten Sie eine Root-Shell auf einem neuen Container, der nach diesen Spezifikationen erstellt wurde. Diesen könnten Sie auch starten mit:
docker run -i -t dftest
Für Dockerfiles stehen zahlreiche Operatoren zur Verfügung, beispielsweise um:
Host-Verzeichnisse auf Container zu mappen,
Umgebungsvariablen festzulegen, oder
Trigger zu definieren, die in zukünftigen Builds verwendet werden sollen.
Eine vollständige Auflistung finden Sie hier.
Docker bietet noch weitaus mehr Möglichkeiten, als wir in diesem Tutorial behandelt haben. Sie sollten nun jedoch ein grundlegendes Verständnis für die Funktionsweise von Docker und seinen wichtigsten Konzepten erlangt haben und funktionale Container erstellen können. Die Docker-Webseite hält weitere Informationen bereit – inklusive eines tiefgehenden Online-Tutorials. (fm)
Sie wollen weitere interessante Beiträge zu diversen Themen aus der IT-Welt lesen? Unsere kostenlosen Newsletter liefern Ihnen alles, was IT-Profis wissen sollten – direkt in Ihre Inbox!
Hier finden Sie den kompletten Artikel: