Docker

Nach Bearbeitung dieses Kapitels können Sie ...

  • ... den Unterschied zwischen Container- und Betriebssystem-Virtualisierung erklären
  • ... Container starten und mit Volumes verbinden
  • ... mehrere Container starten, die untereinander in Abhängigkeit stehen

Docker ist eine Software, mit der Server-Dienste in Containern virtualisiert werden können und getrennt voneinander laufen. Der Container beinhaltet ein Programm mit all seinen Abhängigkeiten, wodurch er sich in allen Umgebungen identisch verhält, was seine Portierung stark vereinfacht. Dabei nutzen die Container gemeinsam das Host-Betriebssystem. Es besteht die Möglichkeit, fertige Images zu nutzen oder diese selbst zusammen zu stellen.

Warum man unbedingt Docker lernen muss:[3]

1 Begriffe[1]

Image
ein Speicherabbild eines Containers. Das Image selbst besteht aus mehreren Layern, die schreibgeschützt sind und somit nicht verändert werden können. Ein Image ist portabel, kann in Repositories gespeichert und mit anderen Nutzern geteilt werden. Aus einem Image können immer mehrere Container gestartet werden.
Container
als Container wird die aktive Instanz eines Images bezeichnet. Der Container wird also gerade ausgeführt und ist beschäftigt. Sobald der Container kein Programm ausführt oder mit seinem Auftrag fertig ist, wird der Container automatisch beendet.
Layer
ein Layer ist Teil eines Images und enthält einen Befehl oder eine Datei, die dem Image hinzugefügt wurde. Anhand der Layer kann die ganze Historie des Images nachvollzogen werden.
Dockerfile
eine Textdatei, die mit verschiedenen Befehlen ein Image beschreibt. Diese werden bei der Ausführung abgearbeitet und für jeden Befehl ein einzelner Layer angelegt.
Repository
ein Repository ist ein Satz gleichnamiger Images mit verschiedenen Tags, zumeist Versionen.
Registry
eine Registry, wie zum Beispiel Docker Hub oder Artifactory, dient der Verwaltung von Repositories.
libcontainer
eine Schnittstelle zu den Grundfunktionen von Docker.
libswarm
eine Schnittstelle, um Docker-Container zu steuern.
libchan[2]
ermöglicht eine einfache („light weighted“) Kommunikation zwischen Prozessteilen und Prozessen.

2 Docker installieren

Docker steht für die gängigen Plattformen - Linux, Raspberry Pi, Windows, Mac - zur Verfügung[4]. Wenn Docker unter Windows installiert wird, muss auch das Windows-Subsystem Linux (WSL 2) installiert werden[5]. Docker kann nicht in einer Virtuellen Maschine installiert werden.

Unter Linux sollte man den eigenen Benutzer mit sudo usermod -aG docker $USER zur Gruppe 'docker' hinzufügen, damit nicht bei jedem Befehl 'sudo' angegeben werden muss[6]. Dieser Eintrag wird nach erneuter Anmeldung wirksam.

Play with Docker[7] stellt neben zahlreichen Tutorials auch eine Testumgebung bereit.

3 Wichtige Befehle[3]

Befehl Funktion
docker version zeigt die installierte Docker-Version an
docker run <Image> startet einen Container und lädt das Image aus dem Docker-Hub[8]
docker ps zeigt alle laufenden Container
docker ps -a zeigt alle Container, auch nicht laufende
docker stop <Container> stoppt einen Container
docker restart <Container> startet einen Container neu
docker inspect <Container> zeigt umfangreiche Informationen über den angegebenen Container
docker image ls zeigt heruntergeladene Images
docker image prune löscht nicht verwendete Images
docker volume create <VolName> erzeugt ein Volume[9]
docker volume prune löscht nicht verwendete Volumes (Vorsicht ist geboten)
docker stop $(docker ps -a -q) hält alle Container an
docker rm $(docker ps -a -q) löscht alle Container

4 Image verwenden

Das Docker-Image, wie man es z.B. aus dem Docker-Hub[10] herunterladen kann, ist die Grundlage für den Container. Neben dem eigentlichen Programm enthält es alle Abhängigkeiten, daher verhalten sich Container auf allen Systemen gleich.

Jeder, der ein Konto auf dem Docker-Hub anlegt, kann dort Images ablegen. Da hierbei keine weiteren Kontrollen stattfindet, können diese Images auch Schadsoftware enthalten. Daher sollte man zu Beginn nur offiziellen Images vertrauen und die Dokumentation sorgfältig lesen.

4.1 Einzelnen Container starten

Der Docker-Hub[11] stellt zahlreiche fertige images bereit. Da ein Container den Kernel des Betriebssystems benutzt, muss bei der Auswahl eines fertigen Images dieses eingestellt werden.

Das folgende Beispiel lädt das Images für den Webserver nginx herunter, startet ihn als Hintergrunddienst (-d), der auf Port 8080 hört und diesen an den Port 80 im Container weiter leitet. Der Container erhält den Namen mein-nginx:
docker run --name mein-nginx -d -p 8080:80 nginx

Wenn man auf die Shell innerhalb des Containers zugreifen will: (hierfür muss das Image eine Shell bereitstellen)
docker exec -it mein-nginx bash

Der Container kann mit docker stop mein-nginx angehalten und mit docker rm mein-ngingx gelöscht werden.

4.2 Daten persistent speichern

Ein Container existiert nur temporär und kann keine Daten dauerhaft speichern. Um das persistente Speichern und Bereitstellen von Daten zu ermöglichen, werden beim Starten des Containers Volumes verbunden[12]. Dort bleiben die Daten auch nach dem Löschen des Containers erhalten.

Man unterscheidet drei Arten von Volumes:

Host Volumes
man legt selbst fest, welches Verzeichnis des Host-Computer mit welchem Verzeichnis in dem Container verbunden werden soll.
docker run -v <Host-directory>:<Container-directory> <Image>
Anonymous Volumes
hier wird nur das Verzeichnis im Container angegeben. Das Verzeichnis auf dem Host-Computer wird von Docker automatisch festgelegt.
docker run - v <Container directory> <Image>
Named Volumes
für das Volume auf dem Host-Computer wird ein Name vergeben und das Verzeichnis im Container angegeben. Der genaue Ort des Volumes wird ebenfalls von Docker festgelegt.
docker run -v <Name>:<Container directory> <Image>

Die Volumes werden dann beim Starten des Containers automatisch angelegt, Named Volumes können aber auch mit dem Befehl docker volume create <Volume-Name> angelegt werden.

Docker speichert die Inhalte der Volumes im Verzeichnis[4]:

  • Linux: /var/lib/docker
  • Windows: C:\ProgramData\DockerDesktop
  • MacOS: ~/Library/Containers/com.docker.docker/Data/vms/0/

Arbeitsauftrag:

  1. Verbinden Sie ein Host-Volume mit einem Container:
    1. Legen Sie ein Verzeichnis lokal auf Ihrem PC an und und speichern Sie darin eine Datei 'index.html', die Sie mit einem beliebigen Inhalt füllen.
    2. Starten Sie anschließend den nginx[13]-Container und verbinden Sie das Verzeichnis als Host-Volume mit dem Container.
      Als Ergebnis muss im Browser die von Ihnen erstellte Seite angezeigt werden.
    3. Dokumentieren Sie die Vorgehensweise und das Ergebnis.

4.3 Mehrere Container starten

Wenn mehrere Container gestartet werden sollen, empfiehlt es sich unbedingt, die Einstellungen für diese Container einen Stack in einer Yaml-Datei[14] zu erstellen und diese mit docker-compose[5] auszuführen. Die Parameter, die mit docker run ... angegeben werden, müssen strukturiert in der Datei gesammelt werden[15]. Die Einrückungen in der Datei müssen unbedingt korrekt strukturiert sein. Die Datei kann vorab überprüft werden, z.B. mit https://yamlvalidator.com/

Die Reihenfolge der Parameter ist für die Funktionalität nicht entscheidend. Es erhöht allerdings die Übersichtlichkeit deutlich, wenn man für alle Container in der Datei die selbe Reihenfolge der Parameter wählt.

Zunächst muss ein Ordner erstellt werden, in dem die Datei docker-compose.yml angelegt wird. Diese Datei hat eine festgelegte Struktur, die sehr gut in [16] und [17] beschrieben wird.

In der ersten Zeile steht die Angabe version:. Diese hängt von der Version der installierten Docker-Engine ab[18]. Anschließend werden unter services: alle zu startenden Container mit den erforderlichen Parametern aufgelistet.

Alle Container, die über eine Datei gestartet werden, befinden sich im selben Netzwerk, das mit dem Namen <Ordnername>_default automatisch erstellt wird. Docker stellt in diesem Netzwerk auch einen internen DNS bereit.

Wenn ein Container den Dienst eines anderen dringend benötigt - wie z.B. WordPress die Datenbank - kann dies unter depends_on: eingetragen werden, damit der WordPress-Container erst gestartet wird, wenn der Datenbank-Container läuft.

Unter environment: können die Umgebungsvariablen für die Konfiguration des Containers eingetragen werden[6]. Welche Variablen benötigt werden, erfährt man in der Dokumentation des Images.

Befehl Funktion
docker-compose up -d startet alle in der Compose-Datei festgelegten Container als Dienst.
Falls restart: always gesetzt ist, wird der Container auch noch Neustart des Hosts wieder gestartet.
docker-compose restart startet alle Container neu
docker-compose stop stoppt vorübergehend alle laufenden Container
docker-compose down stoppt alle Container und löscht sie

Wenn nur einzelne Container gestartet oder beendet werden sollen, muss der Name, der unter 'services:' angeben wurde, angehängt werden.

Wenn ein Named-Volume von mehreren Container gemeinsam genutzt werden soll, muss es unter 'volumes:' in der Yaml-Datei aufgelistet werden.

Alle Angaben können auch in einer beliebigen Datei gespeichert werden. Deren Name kann beim Starten mitgegeben werden: docker-compose -f <Datei>.yml up -d

Arbeitsauftrag

  1. Erstellen Sie eine Yaml-Datei, die alle Einträge enthält, um den nginx-Webserver mit dem Volume zu verbinden und zu starten.
    Kommentieren Sie jede Zeile in Datei mit #.
  2. Erstellen Sie eine Yaml-Datei, mit der Sie eine MySQL-Datenbank[19] starten und mit dem phpmyadmin[20], [21] verwalten können.
    1. Dabei sollen alle Daten der Datenbank und die Konfiguration des phpmyadmins lokal in einem Volume abgelegt werden.
    2. Kommentieren Sie auch hier jede Zeile.
    3. Importieren Sie die Nordwind-Datenbank[22]
  3. Starten Sie mit der Yaml-Datei einen Wordpress-Container[23], der ...
    1. ... den vorhandenen MySQL-Container nutzt und hierin eine eigene Datenbank anlegt. Stellen Sie die Verbindung über die entsprechenden Umgebungsvariablen her.
    2. ... einen eigenen Benutzer für den Datenbank-Zugriff nutzt, der ebenfalls in den Umgebungsvariablen eingetragen wird.
    3. ... Dateien für Themes und Uploads in einem eigenen Volume ablegt.
    4. Kommentieren Sie auch hier jede Zeile.
  4. Ergänzen Sie die Yaml-Datei um die notwendigen Einträge, die mediawiki[24] starten.
    1. Hierbei sollen im Wiki hochgeladene Dateien und Bilder in einem Volume auf dem Host abgelegt werden.
    2. Binden Sie als Datenbank-Server den MySQL-Container an. Für das Wiki soll hierin eine eigene Datenbank angelegt und ein Benutzer hierfür festgelegt werden.
    3. Installieren Sie das Wiki vollständig und legen Sie einen Admin-Benutzer hierfür an.
    4. Kommentieren Sie auch hier jede Zeile.


5 Verschiedenes

  1. für die Installation auf einem Raspberry Pi empfehle ich:
    1. mit log2ram werden die log-Datei nicht ständig sondern in festgelegten Zyklen auf die SD-Karte geschrieben.
    2. swap-Datei abschalten[25]

6 Links


  1. Quelle: https://de.wikipedia.org/wiki/Docker_(Software)#Begriffe
  2. LinuxMagazinBegriffe, Autor: Michael Unke http://www.linux-magazin.de/ausgaben/2014/09/container/ 2014-09-01
  3. Quelle: c't Wissen - Docker 2020[1] - Seite 15
  4. Quelle: https://www.freecodecamp.org/news/where-are-docker-images-stored-docker-container-paths-explained/ - 17.05.2021 - 23:30
  5. Unter Umständen muss docker-compose noch installiert werden.[2]
  6. Es ist ebenso möglich, diese in einer separaten Datei im selben Verzeichnis zu speichern.