Einführung
In diesem Tutorial wird erklärt, wie man ein Docker Image entweder selbst aus einer Dockerfile erstellt oder von Docker Hub importiert, wie man aus einem Image einen Container erstellt und wie man ein Image und einen Container löscht. Docker muss dafür bereits auf dem Server installiert sein (siehe Docker installieren unter Ubuntu/Debian).
Wenn Sie einen neuen Hetzner Cloud Server erstellen und die Hetzner Cloud App Docker auswählen, wird
docker-ce
automatisch für Sie auf dem Server vorinstalliert.
Container
Docker Container werden aus einem sogenannten Image erstellt. Das Image definiert, was der Container genau enthalten soll. Das können bestimmte Dokumente sein, Befehle, die ausgeführt werden sollen oder andere Vorgaben. Ein Image kann man entweder als fertige Vorlage von Docker Hub importieren oder über eine Dockerfile selbst erstellen.
Dockerfile
Eine Dockerfile ist eine Datei, in der über mehrere Anweisungen definiert wird, was genau der Container einmal beinhalten soll. Aus dieser Dockerfile kann man ein Image erstellen, welches später als Basis für den definierten Container dient. Wenn man ein Image aus einer Dockerfile erstellt, wird für jede neue Anweisung innerhalb dieser Dockerfile ein eigenes Image erstellt. Dabei enthält jedes neuerstellte Image alle Images, die für darüberstehende Anweisungen erstellt wurden als sogenannte Layer. Ausschließlich das finale Image, also das Image, das mit der letzten Anweisung innerhalb der Dockerfile erstellt wird, besitzt einen eigenen Namen. Alle anderen Images sind sogenannte Intermediate Images mit dem Namen <none>
.
Mit docker history <image>
ist es möglich sich die verschiedenen Layer anzeigen zu lassen, die in einem Image enthalten sind. Da Intermediate Images keinen eigenen Namen besitzen, werden die Layer über die Image-ID unterschieden.
Intermediate Images
Der Zweck von Intermediate Images liegt mitunter vor allem darin, dass diese für mehrere Images verwendet werden können. Wenn also beispielsweise ein zweites Image genannt NEU
erstellt wird, welches in den ersten beiden Anweisungen direkt mit einem bereits zuvor erstellten Image genannt ALT
übereinstimmt, ist es möglich die entsprechenden Intermediate Images wiederzuverwenden. Das heißt, die ersten beiden Layer des Images NEU
müssen nicht neu erstellt werden. Stattdessen werden direkt die bereits vorhandenen Intermediate Images über ihre Image-ID genutzt und der Erstellungsprozess des Images NEU
kann schneller beendet werden. Da auf dem System keine zweiten Layer mit selbem Inhalt erstellt werden müssen, wird zusätzlich weniger Speicher vom Host benötigt.
Container
Docker Container bestehen im Wesentlichen aus zwei Teilen:
- (Mehrere) schreibgeschützte Image Layer
- Eine Container Layer
Ein einzelnes Image kann für mehrere Container verwendet werden. Wenn innerhalb eines Containers eine Änderung vorgenommen wird, die eines der Image Layer betrifft, wird dieses Image Layer nicht verändert. Stattdessen wird die Änderung in der Container Layer festgehalten.
Images
Im obenstehenden Bild wird ein neues Image aus einer Dockerfile mit folgenden Anweisungen erstellt:
FROM ubuntu:latest
WORKDIR /new-dir
COPY file.txt .
CMD ["sleep", "60m"]
An erster Stelle steht immer FROM
. Hier wird angegeben, worauf das neue Image aufbauen soll. In den meisten Fällen wird ein bereits existierendes Image verwendet. Da das nach FROM
angegebene Image als Basis für das neue Image dient, wird dieses auch Parent Image genannt.
Das bei FROM
angegebene Image wird erst auf dem System gesucht. In diesem Bild ist die aktuellste Version vom Image ubuntu
bereits vorhanden und kann direkt verwendet werden. Wenn das Image nicht vorhanden ist, wird die Suche auf Docker Hub fortgesetzt und das Image wird automatisch importiert.
Wenn man kein Parent Image verwenden möchte, kann man auch
FROM scratch
angeben. In diesem Fall wird auf das leerescratch
-Image von Docker Hub verwiesen. Da das Image nichts enthält, ist in den folgenden Intermediate Images und im finalen Image keine Layer für dieFROM
-Anweisung vorhanden. Diese Option eignet sich allerdings wenig für Anfänger. Images, die mit der AnweisungFROM scratch
erstellt werden, werden Base Image genannt.
Voraussetzungen
- Grundlegende Kenntnisse über Server
- Docker ist bereits installiert (z. B. über die Hetzner App Docker CE oder das Tutorial Docker installieren unter Ubuntu/Debian)
- Zugriff auf den root-Benutzer, einen Benutzer mit sudo-Rechten oder einen Benutzer in der Docker-Gruppe
- Kommandozeile
- Dieses Tutorial wurde anhand von Ubuntu 22.04 erstellt
Wenn Ihr Benutzer bisher noch nicht der Docker-Gruppe hinzugefügt wurde, können Sie beispielsweise dem zweiten Schritt im Tutorial zum Installieren von Docker folgen.
Beispiel-Benennungen
- Image-Name/ID:
<image>
- Container-Name/ID:
<container>
Beachten Sie, dass in allen Beispiel-Befehlen <image>
mit dem eigenen Image-Namen oder der eigenen Image-ID und container
mit dem eigenen Container-Namen oder der eigenen Container-ID ersetzt werden muss.
Schritt 1 - Docker Image erstellen
Wie oben bereits erklärt, benötigt jeder Docker Container ein Docker Image als Basis. Das heißt, bevor der erste Container erstellt werden kann, muss zunächst ein Image bereitgestellt werden. Dabei gibt es drei Möglichkeiten:
- Option 1 - Fertiges Image von Docker Hub importieren
empfohlen
- Option 2 - Image manuell aus Dockerfile erstellen
- Option 3 - Neues Image aus einem bestehenden Container erstellen
Folgend werden alle drei Optionen einzeln erklärt.
Für Anfänger eignet sich Option 1 am besten, ein Image von Docker Hub importieren.
Wenn Sie selbst bestimmen möchten, welche Änderungen im Dateisystem des Containers vorgenommen werden, können Sie Option 2 nutzen.
Option 1 - Fertiges Image von Docker Hub importieren
Beim Erstellen eines Containers aus einem Image von Docker Hub gibt es im Allgemeinen zwei wesentliche Befehle, docker pull
und docker run
.
- Mit
docker pull <image-name>
ist es möglich ein beliebiges Image von Docker Hub zu importieren. Mit diesem Befehl wird noch kein Container erstellt. - Mit
docker run <image-name>
ist es möglich einen Container aus einem Image zu erstellen. Das im Befehl angegebene Image wird erst auf dem System gesucht. Wenn es dort nicht gefunden wird, wird die Suche anschließend auf Docker Hub fortgesetzt. Wenn dort ein passendes Image gefunden wird, wird es automatisch importiert. Anschließend wird aus diesem Image der neue Container erstellt.
Sie können also entweder erst docker pull
nutzen, um das Image von Docker Hub zu importieren und daraus anschließend mit docker run
einen oder mehrere neue Container erstellen oder Sie nutzen direkt docker run
und führen damit beide Schritte mit einem Befehl aus:
docker run hello-world
Output:
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
...
Hello from Docker!
This message shows that your installation appears to be working correctly.
...
Im Output ist zu sehen, dass ein Image namens hello-world
wie zuvor erwähnt erst auf dem System gesucht wurde. Nachdem keines gefunden wurde, wurde es automatisch von Docker Hub importiert. Sobald das Image auf dem System war, wurde daraus der neue Container erstellt.
Als nächstes können Sie mit dem Schritt Container starten und stoppen fortfahren. Falls Sie eine Terminal-Sitzung starten möchten, beachten Sie, dass das Image hello-world
keine dauerhaft laufenden Prozesse beinhaltet.
Option 2 - Image manuell aus Dockerfile erstellen
Mit dieser Option legen Sie selbst fest, welche Layer Ihr Image besitzen soll und welche Konfigurationen und Einstellungen auf Ihrem Container vorgenommen werden sollen.
Um einen möglichst breiten Überblick über die verschiedenen Anweisungen zu geben, wird folgend ein Image für einen Container erstellt, welcher beim Erstellen:
ping
installiert- Einen Ordner und eine Datei vom Host in den Container kopiert
- Einen neuen Ordner und eine neue Datei im Container erstellt
- Einen
sleep
-Befehl ausführt
Als ersten Schritt empfiehlt es sich einen neuen Ordner anzulegen. Hier können dann alle Dateien hinterlegt werden, die für das Erstellen des Containers relevant sind.
-
Neuen Ordner für das Image erstellen
mkdir first-docker-image
-
Dateien anlegen, die kopiert werden sollen
Öffnen Sie den neuen Ordner und erstellen Sie darin einen weiteren Ordner und eine Datei, die später in den Container kopiert werden sollen.cd first-docker-image mkdir copy-dir touch copy-file
-
Dateien anlegen, die nicht kopiert werden sollen
In der Dockerfile müssen die Dateien nicht einzeln angegeben werden. Stattdessen kann mit einer Anweisung bestimmt werden, dass alle Dateien aus einem bestimmten Ordner kopiert werden sollen. Das wird praktisch, sobald man ein echtes Projekt mit wesentlich mehr als zwei Dateien erstellt. Für den Fall, dass eine der Dateien aber nicht kopiert werden soll, gibt es die.dockerignore
-Datei. Alle Dateien, die darin gelistet sind, werden ignoriert und nicht in den Container kopiert.Testen Sie die
.dockerignore
-Datei, indem Sie eine Datei erstellen, die nicht kopiert werden soll:touch do-not-copy
Erstellen Sie nun die
.dockerignore
-Datei und geben Sie alle Dateien an, die nicht kopiert werden sollen.nano .dockerignore
Fügen Sie folgende Dateien hinzu:
.dockerignore Dockerfile do-not-copy
Anstatt alle Dokumente zu kopieren und in der
.dockerignore
-Datei die Ausnahmen zu listen, ist es auch möglich in der.dockerignore
-Datei festzulegen, dass alle Dateien ignoriert werden sollen und Ausnahmen zu bestimmen. Dies würde dann so aussehen:* !copy-dir !copy-file
Mit
*
wird angegeben, dass alle Dateien ignoriert und damit nicht kopiert werden sollen. Mit!
ist es möglich Ausnahmen zu bestimmen. In diesem Fall bedeutet das, dass ausschließlich die Dateiencopy-dir
undcopy-file
kopiert werden.Sobald Sie fertig sind, können Sie die Datei mit
CTRL
+X
schließen, mitY
speichern und mitENTER
bestätigen. -
Dockerfile anlegen
nano Dockerfile
Fügen Sie folgenden Text der Datei hinzu:
FROM ubuntu:latest RUN apt update && apt install -y iputils-ping WORKDIR /new-workdir COPY . . RUN touch new-file RUN mkdir new-dir CMD ["sleep", "60m"]
Sobald Sie fertig sind, können Sie die Datei mit
CTRL
+X
schließen, mitY
speichern und mitENTER
bestätigen.Hinweis: Nach
FROM
wird angegeben, worauf das neue Image aufbauen soll. In diesem Beispiel, wird die aktuellste Version von Ubuntu verwendet. Wenn das Image noch nicht auf dem System ist, wird es automatisch von Docker Hub importiert.
NachCOPY
wird angegeben, welche Datei oder welcher Ordner kopiert werden soll. Anschließend wird der Pfad angegeben, unter dem die kopierte Datei auf dem Container gespeichert werden soll. Der erste.
bedeutet, dass die Dateien aus dem Pfad kopiert werden sollen, unter dem man den Befehl ausführt. Der zweite.
bedeutet, dass die Dateien unter dem Pfad gespeichert werden sollen, unter dem die Befehle auf dem Container ausgeführt werden. In diesem Fall ist das der Pfad/new-workdir
, der zuvor mitWORKDIR
festgelegt wurde.WORKDIR
in einer Dockerfile kann mitcd
in einer Kommandozeile verglichen werden. -
Image aus Dockerfile erstellen
Nutzen Sie nun folgenden Befehl, um aus der eben erstellten Dockerfile ein neues Image zu erstellen:docker build -t <image-name>:latest .
Beachten Sie, dass
<image-name>
mit einem beliebigen Namen für das Image ersetzt werden muss. Mit der Option-t
kann man einen Tag festlegen, im Formatname:version
. Zuletzt wird der Pfad angegeben, unter dem die Dockerfile zu finden ist, wobei.
bedeutet, dass sich die Datei in dem Pfad befindet unter dem man gerade den Befehl ausführt. -
Images listen
Nutzen Sie folgenden Befehl, um sich ihr neues Image listen zu lassen:docker image ls
Das neue Image kann nun genutzt werden, um einen neuen Container zu erstellen.
-
Container aus diesem Image erstellen
Fahren Sie nun mit dem Schritt Container erstellen fort, um aus dem Image einen Container zu erstellen. Beachten Sie hierbei, dass in der Dockerfile einsleep
-Befehl enthalten ist, der direkt ausgeführt wird. Damit besitzt der Container nach dem Erstellen für 60 Minuten einen laufenden Prozess. Sobald dersleep
-Befehl endet, wird der Container automatisch gestoppt. Wenn Sie den Container neustarten, wird auch der Befehl erneut ausgeführt.
Nachdem der Container erstellt wurde, können Sie auf diesem eine Terminal-Sitzung starten. Wenn Sie sich anschließend mitls
alle Dokumente innerhalb Ihres Containers listen lassen, sollten die kopierten Dateiencopy-dir
undcopy-file
angezeigt werden, sowie die im Erstellungsprozess des Containers neu hinzugefügten Dateiennew-file
undnew-dir
.
Option 3 - Neues Image aus einem bestehenden Container erstellen
Ein einzelnes Image kann zum Erstellen mehrere Container verwendet werden. Änderungen, die innerhalb eines Containers vorgenommen werden, wirken sich nie auf andere Container aus. Um neue Container erstellen zu können, welche neben den Layern eines bestimmten Images auch die Änderungen beinhalten, die innerhalb eines Containers vorgenommen wurden, muss aus diesem Container zunächst ein neues Image erstellt werden. Das neue Image besitzt dann eine zusätzliche Layer, welche alle Änderungen enthält, die auf dem Container vorgenommen wurden.
-
Container listen
docker container ls -a
Kopieren Sie die ID oder den Namen des Containers aus dem Sie das Image erstellen wollen.
-
Image aus Container erstellen
docker commit <container>
Beachten Sie, dass
<container>
mit dem Container-Namen oder der Container-ID aus dem vorangegangenen Schritt ersetzt werden muss. -
Images listen
docker image ls
Das eben erstellte Image sollte nun gelistet werden. Entnehmen Sie dem Output die dazugehörige ID, um dem Image im nächsten Schritt einen Namen geben zu können.
-
Image benennen
docker tag <image-id> <name>
Beachten Sie, dass
<image-id>
mit der ID des eben erstellten Images ersetzt werden muss und<name>
mit einem selbst gewählten Namen, der dem Image nun zugewiesen werden soll.
Das eben erstellte Image kann nun wie alle anderen Images verwendet werden, um einen neuen Container zu erstellen.
Schritt 2 - Container erstellen
Ein einzelnes Image kann zum Erstellen von mehreren Containern genutzt werden. Solange zu einem bestimmten Image mindestens ein Container existiert, kann dieses Image nicht gelöscht werden.
-
Images listen
docker image ls
Kopieren Sie die ID oder den Namen des Images, aus dem der Container erstellt werden soll.
-
Container erstellen
Bestehende Container können den Status laufend oder gestoppt besitzen.
Solange auf einem Container mindestens ein Prozess läuft, besitzt dieser den Status "laufend". Sobald auf einem Container der letzte Prozess beendet wird, wird der Container ebenfalls automatisch "gestoppt". Dies ist dann relevant, wenn Sie auf Ihrem Container eine Terminal-Sitzung starten möchten. Denn eine Terminal-Sitzung kann ausschließlich auf einem Container mit laufenden Prozessen gestartet werden.
Folgend werden 2 Optionen zum Erstellen eines Containers erklärt.- Option 1 eignet sich für die meisten Fälle und ist die empfohlene Option. Mit dieser Option wird der Container erst aus einem Image erstellt und anschließend direkt gestartet.
- Option 2 eignet sich ausschließlich, wenn Sie auf Ihrem Container eine Terminal-Sitzung starten müssen und der Container nach dem Erstellen keine laufenden Prozesse besitzen würde. Damit Sie dennoch eine Terminal-Sitzung starten können, wird mit Option 2 bereits beim Erstellen des Containers ein erster Prozess gestartet.
Option 1: Container aus Image erstellen und starten
empfohlen
Option 2: Container aus Image erstellen und gleichzeitig einen neuen Prozess startenOption 1 - Container aus Image erstellen und starten
-
Container erstellen
docker run -d <image>
Beachten Sie, dass
<image>
mit dem zuvor kopierten Namen oder der ID Ihres Images ersetzt werden muss. Mit der Option-d
wird angegeben, dass der Container im Hintergrund laufen soll, und dass die Container-ID angezeigt werden soll.Das im Befehl angegebene Image wird erst auf dem System gesucht. Wenn es dort nicht gefunden wird, wird die Suche anschließend auf Docker Hub fortgesetzt. Wenn dort ein passendes Image gefunden wird, wird es automatisch importiert. Anschließend wird aus dem angegebenen Image der neue Container erstellt und gestartet.
Option 2 - Container aus Image erstellen und gleichzeitig einen neuen Prozess starten
Damit der Container nach dem Erstellen nicht automatisch gestoppt wird, kann im Befehl zum Erstellen des Containers gleichzeitig ein erster Prozess gestartet werden. Dabei gibt es unter anderem diese beiden Möglichkeiten:
-
Container erstellen und einen zeitlich begrenzten Prozess starten
docker run -it <image>
Mit dem obenstehenden Befehl wird direkt beim Erstellen des Containers eine Terminal-Sitzung geöffnet. Diese Sitzung ist ein eigener laufender Prozess.
In der Befehlseingabe sollte nun nicht mehr der Hostname angeben werden, sondern die Container-ID oder der Container-Hostname. Alle Befehle werden nun auf dem Container ausgeführt. Um die Sitzung zu beenden, können Sieexit
ausführen. Wenn Sie während der Sitzung keine weiteren Prozesse gestartet haben und die Sitzung beenden, wird der Container automatisch gestoppt. Um den Container anschließend wieder starten zu können, müssen Siedocker start -ai <container>
ausführen und damit erneut eine Terminal-Sitzung starten. Dieser Befehl funktioniert nur bei gestoppten Containern, die wie in diesem Schritt mit den Optionen-it
erstellt wurden. -
Container erstellen und einen dauerhaften Prozess starten
docker run -d <image> sleep infinity
Mit der Option
-d
wird angegeben, dass der Container im Hintergrund laufen soll, und dass die Container-ID angezeigt werden soll.Mit dem obenstehenden Befehl wird direkt beim Erstellen des Containers ein
sleep
-Befehl ausgeführt. Solange dieser Prozess läuft, wird auch der Container nicht gestoppt.
Schritt 3 - Terminal-Sitzung im Container starten
Um eine neue Terminal-Sitzung in einem Container starten zu können, darf dieser nicht gestoppt sein. Wie in Schritt 2 bereits erklärt, bedeutet das, dass der Container mindestens einen laufenden Prozess besitzen muss.
-
Laufende Container listen
docker container ls
Wenn Sie im Befehl die Option
-a
ergänzen, werden zusätzlich auch alle gestoppten Container gelistet.Entnehmen Sie dem Output die ID oder den Namen des Containers, auf den Sie gerne zugreifen würden.
-
Terminal-Sitzung im Container starten
docker exec -it <container> /bin/bash
Sobald die Sitzung gestartet wurde, sollte in der Befehlseingabe nicht mehr der Name des Hosts angegeben werden, sondern die ID bzw. der Hostname Ihres Containers. Alle Befehle, die Sie in der Befehlseingabe eingeben, werden nun auf dem Container ausgeführt. Um das zu prüfen, können Sie sich mit
ls -al
beispielsweise alle Dateien des Containers anzeigen lassen. Mithostname -I
können Sie sich die IP-Adresse(n) des Containers anzeigen lassen. -
Terminal-Sitzung im Container beenden
exit
Die Sitzung sollte nun beendet sein und in der Befehlseingabe sollte nun wieder der Name Ihres Hosts angegeben werden.
Schritt 4 - Container starten und stoppen
Einen Container zu starten bedeutet im Wesentlichen die im Container, bzw. dem dazugehörigen Image, enthaltenen Prozesse zu starten. Den Container zu stoppen bedeutet hingegen für alle laufenden Prozesse im Container den Stop zu erzwingen.
-
Container listen
docker container ls -a
Kopieren Sie die ID oder den Namen des Containers, den Sie starten oder stoppen wollen.
-
Container starten
docker start <container>
Beachten Sie, dass
<container>
mit dem eigenen Container-Namen oder der eigenen Container-ID ersetzt werden muss. -
Container stoppen
docker stop <container>
Beachten Sie, dass
<container>
mit dem eigenen Container-Namen oder der eigenen Container-ID ersetzt werden muss.
Schritt 5 - Image oder Container löschen
-
Alle Images oder Container listen
docker image ls
docker container ls -a
Kopieren Sie die ID oder den Namen des Images oder des Containers, den Sie löschen wollen.
-
Container löschen
docker container rm <container>
Beachten Sie, dass
<container>
mit dem eigenen Container-Namen oder der eigenen Container-ID ersetzt werden muss. -
Image löschen
docker image rm <image>
Beachten Sie, dass
<image>
mit mit dem eigenen Image-Namen oder der eigenen Image-ID ersetzt werden muss.Beachten Sie, dass ein Image nur dann gelöscht werden kann, wenn keine vorhandenen Container auf diesem Image basieren. Sollte ein Container dieses Image nutzen, muss der Container gelöscht werden, bevor das Image gelöscht werden kann.
Ergebnis
Im vorangegangenen Tutorial haben Sie gelernt wie Sie ein Image aus einer Dockerfile erstellen oder von Docker Hub importieren, einen Container erstellen, eine Terminal-Sitzung in einem Container starten und wie Sie ein Image oder einen Container löschen. Als nächsten Schritt können Sie beispielsweise mit dem Tutorial IPv6 on Docker securely (EN) oder Run multiple Docker Compose services on Debian/Ubuntu (EN) fortfahren.