Deployn

Docker für Anfänger: Installation, Container und Images verstehen

Docker Schritt für Schritt lernen: Begriffe wie Image und Container, Installation unter Debian und Ubuntu, ersten Webserver starten, Container verwalten und Docker aktualisieren.

Veröffentlicht am
Docker für Anfänger: Installation, Container und Images verstehen hero image
Inhalt
Getestet mit
Docker 29.9Docker Compose 5.7nginx 1.30Debian 13Ubuntu 26.04
Zuletzt geprüft am

Du hast ein Programm auf deinem Rechner zum Laufen gebracht, kopierst es auf einen Server, und dort geht plötzlich nichts mehr. Eine Bibliothek fehlt, die Version stimmt nicht, ein anderes Programm belegt denselben Port. Docker löst dieses Problem, indem es ein Programm samt allem, was es zum Laufen braucht, in ein einziges Paket steckt. Dieses Paket startet auf jedem Rechner mit Docker auf dieselbe Weise.

In diesem Beitrag installieren wir Docker auf einem Linux-Server und starten damit Schritt für Schritt einen Webserver.

Was du brauchst

  • Einen Linux-Server, am besten mit Debian oder Ubuntu. Ob Cloud-Server, Raspberry Pi oder Rechner im Heimnetz, spielt für die Docker-Befehle keine Rolle. Ich nutze im Folgenden Server mit Debian 13 und Ubuntu 26.04. Wie du einen Server auswählst und absicherst, steht in meiner Anleitung VPS für Anfänger. Wenn du ihn bei Hetzner anlegst, hilft dir der Cloud-Init-Generator beim Einrichten des Benutzers.
  • Eine Verbindung per SSH. Das ist der Weg, auf dem dein Computer Befehle an den Server schickt. Auch dazu findest du alles in der VPS-Anleitung.
  • Einen Benutzer, der sudo verwenden darf. Im Folgenden heißt er deployn. Wenn du als root angemeldet bist, lässt du bei allen Befehlen das Wort sudo weg.

Die Befehle in den grauen Kästen kopierst du in das Terminal und bestätigst mit Enter. Zeichen wie $ am Zeilenanfang gehören nicht dazu, ich schreibe sie auch nicht hin. Mit dem Terminal selbst fremdelst du noch? Dann lies vorher die wichtigsten Linux-Befehle.

Verbinde dich jetzt mit deinem Server:

Terminalbash
ssh {{username}}@{{server_ip}}

Du erkennst, dass es geklappt hat, an der Eingabezeile. Sie beginnt mit deployn@ und dem Namen deines Servers.

Die wichtigsten Begriffe

Bevor wir etwas installieren, klären wir vier Wörter, die in jeder Docker-Anleitung vorkommen. Die Reihenfolge ist: Aus einem Bauplan wird eine laufende Anwendung.

Begriff Bedeutung
Image Ein fertiges, unveränderliches Paket aus einem Programm und allem, was es braucht. Das Image ist der Bauplan.
Container Ein laufendes Programm, das aus einem Image gestartet wurde. Aus einem Image kannst du beliebig viele Container starten.
Registry Ein Lager für Images. Die bekannteste ist Docker Hub. Dort holt Docker Images ab, wenn sie noch nicht auf deinem Server liegen.
Dockerfile Eine Textdatei, in der steht, wie ein Image gebaut wird. Du brauchst sie erst, wenn du eigene Images erstellst. Hier kommt sie nicht vor.

Der Ablauf in einem Satz: Docker holt ein Image aus einer Registry und startet daraus einen Container.

Ist ein Container eine virtuelle Maschine?

Nein. Eine virtuelle Maschine bringt ein komplettes eigenes Betriebssystem mit. Ein Container teilt sich den Kern (Kernel) des Betriebssystems mit deinem Server und ist nur von den anderen Programmen abgeschottet. Stell dir ein Mehrfamilienhaus vor: Jede Wohnung hat eigene Türen und Möbel, aber alle teilen sich Fundament und Heizung. Deshalb starten Container in Sekunden und brauchen weniger Arbeitsspeicher als virtuelle Maschinen.

Docker installieren

Debian bietet Docker im eigenen Paketarchiv an, aber die Version ist dort nicht aktuell. Wir nehmen deshalb die Paketquelle, die Docker selbst pflegt. Sie besteht aus fünf kleinen Schritten.

Schritt 1: Alte Docker-Pakete entfernen

Auf einem frisch angelegten Server hast du nichts zu entfernen. Der Befehl schadet trotzdem nicht. Er entfernt nur Pakete, die mit Docker aus der offiziellen Quelle kollidieren würden:

bash

Debian

sudo apt remove $(dpkg --get-selections docker.io docker-compose docker-doc docker-buildx podman-docker containerd runc | cut -f1)

Ubuntu

sudo apt remove $(dpkg --get-selections docker.io docker-compose docker-compose-v2 docker-doc docker-buildx podman-docker containerd runc | cut -f1)

Meldungen wie dpkg: no packages found matching docker-compose bedeuten nur, dass dieses Paket nicht installiert war. Container und Images, die bereits auf dem Server liegen, bleiben erhalten.

Schritt 2: Den Schlüssel von Docker speichern

Linux prüft installierte Pakete mit einem digitalen Schlüssel, damit niemand dir veränderte Software unterschieben kann. Diesen Schlüssel holen wir uns jetzt. Wähle den Tab zu deinem System:

bash

Debian

sudo apt update
sudo apt install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

Ubuntu

sudo apt update
sudo apt install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

Schritt 3: Die Paketquelle eintragen

Jetzt sagst du dem System, wo es die Docker-Pakete findet. Kopiere den gesamten Block, auch die letzte Zeile EOF:

bash

Debian

sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/debian
Suites: $(. /etc/os-release && echo "$VERSION_CODENAME")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF

Ubuntu

sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF

Der Befehl schreibt eine kleine Textdatei und gibt ihren Inhalt noch einmal aus. In der Zeile Suites: steht der Name deiner Version, auf Debian 13 zum Beispiel trixie, auf Ubuntu 26.04 resolute.

Terminalbash
sudo apt update

In der Ausgabe taucht jetzt eine Zeile mit download.docker.com auf. Dann kennt dein Server die neue Quelle.

Schritt 4: Docker installieren

Terminalbash
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Das sind mehrere Pakete in einem Befehl: die Docker Engine (docker-ce), das Befehlszeilenprogramm (docker-ce-cli), eine Hilfskomponente (containerd.io) und zwei Erweiterungen. Eine davon, docker-compose-plugin, brauchst du später für Docker Compose.

Debian zeigt eine Liste der Pakete und fragt Do you want to continue? [Y/n]. Mit Enter bestätigst du den Vorgang. Das große Y zeigt, dass „Ja” die Voreinstellung ist. Die Installation dauert ein bis zwei Minuten.

Schritt 5: Installation prüfen

Terminalbash
sudo docker --version
sudo docker compose version
Docker version 29.9.3, build 5457199
Docker Compose version v5.7.0

Bei dir können die Nummern höher sein. Wichtig ist, dass überhaupt Versionen erscheinen. Dass der Docker-Dienst im Hintergrund läuft und beim Start des Servers automatisch hochfährt, kannst du ebenfalls prüfen:

Terminalbash
systemctl is-active docker
systemctl is-enabled docker
active
enabled

Falls hier etwas anderes steht, startest du den Dienst mit sudo systemctl start docker und schaltest den Autostart mit sudo systemctl enable docker ein.

Warum steht vor jedem Befehl sudo?

Docker greift tief in das System ein und braucht dafür Administratorrechte. Ohne sudo bekommst du diese Meldung:

permission denied while trying to connect to the docker API at unix:///var/run/docker.sock

Du kannst deinen Benutzer in die Gruppe docker aufnehmen, dann entfällt sudo. Ich empfehle das nicht. Ein Benutzer in dieser Gruppe darf einen Container starten, der Ordner des Servers einbindet. Bindet er zum Beispiel den Ordner /etc des Servers ein, kann der Container die Datei /etc/shadow sehen, in der die Passwort-Prüfsummen stehen. Der Benutzer selbst darf sie auf dem Server nicht lesen (cat /etc/shadow meldet Permission denied).

Terminalbash
docker run --rm -v /etc:/host alpine ls -l /host/shadow
-rw-r-----    1 root     shadow         634 Nov  7 06:17 /host/shadow

Die Gruppe docker ist also praktisch gleichbedeutend mit Administratorrechten. Ich bleibe hier bei sudo.

Der erste Container: hello-world

Jetzt starten wir den ersten Container. Das Image hello-world ist ein winziger Test, der nur einen Text ausgibt:

Terminalbash
sudo docker run hello-world

Auf deinem Server passiert dabei Folgendes:

  1. Docker sucht das Image hello-world auf dem Server und findet es nicht. Du siehst die Meldung Unable to find image 'hello-world:latest' locally.
  2. Docker lädt das Image aus Docker Hub herunter (Pulling und Pull complete).
  3. Docker startet daraus einen Container. Er gibt einen Text aus, der mit Hello from Docker! beginnt.
  4. Der Container hat nichts weiter zu tun und beendet sich selbst.

Wenn du den Text Hello from Docker! siehst, funktioniert deine Installation. Den Container gibt es jetzt noch, nur läuft er nicht mehr. Das siehst du gleich bei der Verwaltung.

Der zweite Container: ein Webserver

Das war ein Test. Jetzt starten wir etwas, das du im Browser sehen kannst. nginx ist ein Webserver, also ein Programm, das Webseiten ausliefert.

Terminalbash
sudo docker run nginx

Docker lädt das Image nginx und startet den Container. Danach scrollen einige Zeilen durch, und die Eingabezeile kommt nicht zurück:

/docker-entrypoint.sh: Configuration complete; ready for start up

Das ist gewollt. Ein Webserver hat keine Aufgabe, die irgendwann endet, er läuft weiter und wartet auf Besucher. Das Terminal zeigt dir seine Ausgabe, deshalb ist es blockiert. Mit Strg + C stoppst du den Container.

Es bleiben drei Probleme. Das Terminal ist blockiert. Du kannst den Webserver nicht im Browser erreichen, weil er von der Außenwelt abgeschottet ist. Und welche nginx-Version läuft, weißt du auch nicht. Den Befehl verbessern wir jetzt Schritt für Schritt.

Der vollständige Befehl

Terminalbash
sudo docker run -d -p 8080:80 --name mein-webserver nginx:1.30

Das sieht länger aus, besteht aber nur aus fünf Teilen:

Teil Bedeutung
docker run Starte einen neuen Container.
-d „Detached”: Der Container läuft im Hintergrund, das Terminal bleibt frei.
-p 8080:80 Leite Anfragen an Port 8080 deines Servers an Port 80 im Container weiter. Mehr dazu gleich.
--name mein-webserver Gib dem Container einen Namen. Ohne Namen vergibt Docker einen zufälligen wie musing_elbakyan.
nginx:1.30 Das Image: links vom Doppelpunkt der Name, rechts der Tag. Der Tag legt die Version fest.

Die Ausgabe ist beim ersten Mal lang, weil das Image heruntergeladen wird. Am Ende steht eine lange Zeichenfolge, die Kennung des neuen Containers.

Was bedeutet 8080:80?

Ein Rechner hat viele Ports, nummerierte Eingänge, über die Programme Anfragen entgegennehmen. Der Browser sendet Anfragen für normale Webseiten standardmäßig an Port 80 (HTTP) und 443 (HTTPS). Der nginx-Webserver im Container wartet auf Port 80. Dieser Port gilt aber nur innerhalb des Containers, von außen kommt niemand heran.

Mit -p 8080:80 baust du eine Verbindung: Was auf dem Server an Port 8080 ankommt, landet im Container an Port 80. Die Zahl links gehört dem Server, die Zahl rechts dem Container. Die rechte Zahl ist durch nginx vorgegeben. Die linke kannst du frei wählen, solange der Port noch frei ist.

Im Browser ansehen

Öffne in deinem Browser diese Adresse:

http://{{server_ip}}:8080

Du siehst die Seite „Welcome to nginx!“. Du hast gerade einen Webserver gestartet, ohne ihn zu installieren.

Zur Kontrolle auf dem Server selbst:

Terminalbash
curl -s localhost:8080 | head -n 8
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>

Mehrere Webserver nebeneinander

Weil jeder Container abgeschottet ist, kannst du mehrere gleichzeitig laufen lassen, auch in verschiedenen Versionen. Starte zwei weitere:

Terminalbash
sudo docker run -d -p 8081:80 --name mein-webserver-2 nginx:1.30
sudo docker run -d -p 8082:80 --name mein-webserver-3 nginx:1.28

Jetzt laufen drei Webserver, erreichbar unter den Ports 8080, 8081 und 8082, zwei davon in Version 1.30 und einer in Version 1.28. Ohne Docker müsstest du dafür drei Installationen auseinanderhalten.

Was passiert, wenn du einen Fehler machst? Wiederhole den ersten Befehl mit einem anderen Namen, aber demselben Port:

Terminalbash
sudo docker run -d -p 8080:80 --name zweiter nginx:1.30
docker: Error response from daemon: ... Bind for 0.0.0.0:8080 failed: port is already allocated

Port 8080 ist schon vergeben. Wähle einen anderen. Und wenn du einen Namen doppelt verwendest:

docker: Error response from daemon: Conflict. The container name "/mein-webserver" is already in use by container "...". You have to remove (or rename) that container to be able to reuse that name.

Jeder Name darf nur einmal vorkommen. Beachte außerdem, dass der fehlgeschlagene Start trotzdem einen Container mit dem Status Created hinterlässt. Er taucht in der Liste auf (sudo docker ps -a), und du entfernst ihn mit sudo docker rm zweiter. Wie das geht, zeige ich im nächsten Abschnitt.

Container verwalten

Ein Webserver ist erst nützlich, wenn du ihn auch wieder anhalten, ansehen und löschen kannst. Dafür brauchst du sieben Befehle.

Laufende Container anzeigen

Terminalbash
sudo docker ps
CONTAINER ID   IMAGE        COMMAND                  CREATED         STATUS         PORTS                                     NAMES
e8e360e0586c   nginx:1.28   "/docker-entrypoint.…"   2 seconds ago   Up 2 seconds   0.0.0.0:8082->80/tcp, [::]:8082->80/tcp   mein-webserver-3
276fdfb7fef4   nginx:1.30   "/docker-entrypoint.…"   6 seconds ago   Up 6 seconds   0.0.0.0:8081->80/tcp, [::]:8081->80/tcp   mein-webserver-2
758f8ae64784   nginx:1.30   "/docker-entrypoint.…"   6 seconds ago   Up 6 seconds   0.0.0.0:8080->80/tcp, [::]:8080->80/tcp   mein-webserver

Jede Zeile ist ein Container. Wichtig sind für dich vier Spalten: die ID (CONTAINER ID), das Image, der Status (Up heißt: läuft) und der Name ganz rechts. 0.0.0.0:8080->80/tcp bedeutet, dass Port 8080 des Servers auf Port 80 des Containers zeigt. Die zweite Angabe mit [::] ist dieselbe Weiterleitung für IPv6, die neuere Form der Internetadressen.

Ein Befehl mit gleicher Wirkung ist sudo docker container ls. Er ist ausführlicher, docker ps ist kürzer und verbreiteter.

Nur die IDs, ohne Tabelle, gibt dir das Flag -q („quiet”):

Terminalbash
sudo docker ps -q

Welche Flags es zu einem Befehl gibt, verrät dir --help, zum Beispiel sudo docker ps --help.

Container anhalten und wieder starten

Einen Container hältst du mit seinem Namen an:

Terminalbash
sudo docker stop mein-webserver-3

Docker gibt zur Bestätigung den Namen aus. Die Seite auf Port 8082 lädt jetzt nicht mehr. Statt des Namens kannst du auch die ID nehmen, und es genügen die ersten Zeichen, solange sie eindeutig sind, also etwa bf7.

Der Container ist nicht weg. docker ps zeigt nur laufende Container, mit -a („all”) siehst du auch die angehaltenen:

Terminalbash
sudo docker ps -a
CONTAINER ID   IMAGE        COMMAND                  CREATED         STATUS                              PORTS                                     NAMES
e8e360e0586c   nginx:1.28   "/docker-entrypoint.…"   2 seconds ago   Exited (0) Less than a second ago                                             mein-webserver-3
276fdfb7fef4   nginx:1.30   "/docker-entrypoint.…"   6 seconds ago   Up 6 seconds                        0.0.0.0:8081->80/tcp, [::]:8081->80/tcp   mein-webserver-2
758f8ae64784   nginx:1.30   "/docker-entrypoint.…"   6 seconds ago   Up 6 seconds                        0.0.0.0:8080->80/tcp, [::]:8080->80/tcp   mein-webserver

Auf deinem Server stehen in dieser Liste außerdem der hello-world-Container und der erste nginx-Container mit ihren zufälligen Namen, beide mit dem Status Exited. Einen angehaltenen Container startest du wieder mit:

Terminalbash
sudo docker start mein-webserver-3

Container entfernen

Mit docker rm löschst du einen Container endgültig:

Terminalbash
sudo docker rm mein-webserver-3

Ein laufender Container lässt sich nicht löschen. Docker meldet dann cannot remove container "mein-webserver-3": container is running: stop the container before removing or force remove. Erst stop, dann rm. Dasselbe in einem Schritt macht sudo docker rm -f mein-webserver-3.

Alle angehaltenen Container entfernst du auf einmal mit:

Terminalbash
sudo docker container prune

Docker fragt vorher nach (Are you sure you want to continue? [y/N]). Hier ist N die Voreinstellung. Du musst also y eingeben, ein bloßes Enter bricht ab.

Was beim Löschen mit den Dateien im Container passiert

Das ist die wichtigste Eigenschaft von Containern und ein häufiger Anfängerfehler. Probiere es aus. Erstelle im laufenden Container mein-webserver eine Datei:

Terminalbash
sudo docker exec mein-webserver sh -c "echo hallo > /usr/share/nginx/html/test.html"
curl -s localhost:8080/test.html
hallo

docker exec führt einen Befehl in einem laufenden Container aus. Hier legt er eine Datei an, die nginx sofort ausliefert. Anhalten und wieder starten ändert daran nichts. Die Datei ist danach noch da. Jetzt löschen wir den Container und starten einen neuen aus demselben Image:

Terminalbash
sudo docker stop mein-webserver
sudo docker rm mein-webserver
sudo docker run -d -p 8080:80 --name mein-webserver nginx:1.30
curl -s -o /dev/null -w "%{http_code}\n" localhost:8080/test.html
404

Der Statuscode 404 heißt „nicht gefunden”. Die Datei ist weg. Ein Container ist wie ein Wegwerfprodukt, das jederzeit aus dem Image neu entsteht. Alles, was du in ihm veränderst, geht beim Entfernen verloren. Programme, die Daten behalten sollen, wie Datenbanken oder Fotosammlungen, legen diese deshalb außerhalb des Containers ab. Dafür gibt es Volumes und Bind-Mounts, ein eigenes Thema.

Logs ansehen

Wenn etwas nicht funktioniert, schaust du zuerst in die Logs. Das sind die Meldungen, die ein Programm über seine Arbeit schreibt:

Terminalbash
sudo docker logs --tail 2 mein-webserver
2026/11/07 06:25:27 [error] 30#30: *1 open() "/usr/share/nginx/html/test.html" failed (2: No such file or directory), client: 172.17.0.1, server: localhost, request: "GET /test.html HTTP/1.1", host: "localhost:8080"
172.17.0.1 - - [07/Nov/2026:06:25:27 +0000] "GET /test.html HTTP/1.1" 404 153 "-" "curl/8.14.1" "-"

Du siehst, dass der Aufruf von /test.html mit 404 beantwortet wurde, und den Grund dazu: No such file or directory. --tail 2 zeigt nur die letzten zwei Zeilen. Mit -f („follow”) bleibt das Terminal offen und zeigt neue Einträge laufend an. Beenden kannst du das mit Strg + C.

In einen Container hineinschauen

Mit exec und einer Shell öffnest du ein Terminal im Container:

Terminalbash
sudo docker exec -it mein-webserver bash

-i hält die Eingabe offen, -t sorgt für ein ordentliches Terminal. Die Eingabezeile ändert sich:

root@06fa4833f3b5:/#

Du bist jetzt im Container. Der Name nach dem @ ist die Container-ID. Hier kannst du ls /usr/share/nginx/html ausführen und siehst 50x.html und index.html. Mit exit kehrst du zum Server zurück.

Manche Images haben keine Shell namens bash. Dann kommt exec: "bash": executable file not found in $PATH, und du versuchst es mit sh. Das trifft besonders schlanke Images, wie du im nächsten Abschnitt siehst.

Images und Tags

Beim Start hat Docker das Image heruntergeladen und gespeichert. Diese Liste zeigt dir, was auf deinem Server liegt:

Terminalbash
sudo docker image ls
IMAGE        ID             DISK USAGE   CONTENT SIZE   EXTRA
nginx:1.28   fda7399e8104        161MB             0B   U
nginx:1.30   53d8f012a1a7        163MB             0B   U

Der Teil vor dem Doppelpunkt ist der Name, der Teil danach der Tag. Der Tag legt fest, welche Version du bekommst. Das U in der letzten Spalte bedeutet, dass ein Container dieses Image gerade nutzt.

Zwei Images mit demselben Namen, aber unterschiedlichem Tag sind verschiedene Images. Die Image-ID unterscheidet sie. Bei Docker ist gleiche ID gleicher Inhalt: Hätten zwei Tags dieselbe ID, belegen sie den Speicherplatz nur einmal.

Warum du latest vermeiden solltest

Lässt du den Tag weg, ergänzt Docker latest. sudo docker run nginx ist also dasselbe wie sudo docker run nginx:latest. Der Name klingt nach „die neueste Version”, ist aber nur ein Tag wie jeder andere. Der Entwickler des Images entscheidet, worauf er zeigt, und kann ihn jederzeit auf eine neue Version umstellen.

Zum Zeitpunkt dieses Beitrags zeigte nginx:latest auf nginx 1.31.8, während nginx:1.30 genau die Version 1.30 lieferte. Wer latest benutzt und seinen Container neu erstellt, bekommt irgendwann eine andere Version als zuvor, zum Beispiel mit anderen Einstellungen. Deshalb gebe ich bei jedem Projekt einen festen Tag an. Dann weiß ich, was läuft.

Versionsnummern lesen

Die meisten Programme nummerieren ihre Versionen nach dem Muster Haupt.Neben.Patch, also etwa 1.30.2. Das nennt sich semantische Versionierung. Es hilft dir beim Abschätzen, wie riskant ein Update ist:

Ändert sich Beispiel Bedeutung
Die letzte Zahl 1.30.1 → 1.30.2 Fehlerbehebung. Das Update ist in der Regel unproblematisch.
Die mittlere Zahl 1.30.2 → 1.31.0 Neue Funktionen, die alte weiterhin unterstützen sollten.
Die erste Zahl 1.31.0 → 2.0.0 Große Änderung. Vorhandene Einstellungen können danach nicht mehr funktionieren.

Bei Docker-Images kann ein Tag grob oder fein sein. nginx:1.30 hält dich auf der Version 1.30 und lädt Fehlerbehebungen nach. nginx:1 macht innerhalb von Version 1 auch größere Sprünge mit. Zum Zeitpunkt meines Tests lieferte dieser Tag nginx 1.31.8. Welche Tags es gibt und was sie bedeuten, entscheidet jedes Projekt selbst. Eine Übersicht findest du im Reiter „Tags” des Images auf Docker Hub.

Der Tag alpine

Auf Docker Hub gibt es viele Images mit einem Zusatz im Tag, etwa nginx:1.30-alpine. Alpine ist ein Linux, das auf geringe Größe getrimmt ist. Lade das Image herunter und vergleiche:

Terminalbash
sudo docker pull nginx:1.30-alpine
sudo docker image ls nginx
IMAGE               ID             DISK USAGE   CONTENT SIZE   EXTRA
nginx:1.28          fda7399e8104        161MB             0B   U
nginx:1.30          53d8f012a1a7        163MB             0B   U
nginx:1.30-alpine   1390db6b01a8       62.4MB             0B

Die Alpine-Variante belegt nur etwa ein Drittel (62,4 MB gegenüber 163 MB). Kleinere Images sind schneller heruntergeladen, brauchen weniger Platz und enthalten weniger Programme, die Sicherheitslücken haben könnten. Der Preis ist, dass manches fehlt. Starte einen Container aus dem Alpine-Image und versuche, hineinzuschauen:

Terminalbash
sudo docker run -d --name alp nginx:1.30-alpine
sudo docker exec alp bash
OCI runtime exec failed: exec failed: unable to start container process: exec: "bash": executable file not found in $PATH

Das Image hat kein bash. Mit sh klappt es:

Terminalbash
sudo docker exec -it alp sh

Entferne diesen Testcontainer danach mit sudo docker rm -f alp.

Images löschen

Ein Image löschst du mit docker image rm. Solange ein Container es verwendet, verweigert Docker das:

Error response from daemon: conflict: unable to remove repository reference "nginx:1.30-alpine" (must force) - container 6bf29c9edd00 is using its referenced image 1390db6b01a8

Entferne zuerst den Container, dann geht es:

Terminalbash
sudo docker rm -f alp
sudo docker image rm nginx:1.30-alpine

Aufräumen

Zum Schluss räumen wir alles weg, was wir in diesem Beitrag gestartet haben. Wie viel Platz Docker auf deinem Server belegt, zeigt dir:

Terminalbash
sudo docker system df
TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
Images          2         2         323.4MB   0B (0%)
Containers      3         3         3.285kB   0B (0%)
Local Volumes   0         0         0B        0B
Build Cache     0         0         0B        0B

Entferne die Container, und danach alle Images, die kein Container mehr benutzt:

Terminalbash
sudo docker rm -f mein-webserver mein-webserver-2 mein-webserver-3
sudo docker image prune -a

image prune -a fragt nach (y/N) und löscht dann jedes Image ohne Container. Das ist praktisch zum Aufräumen. Auf einem Server mit laufenden Anwendungen schaust du vorher kurz nach, ob sie alle laufen, sonst werden Images gelöscht, die du später wieder herunterladen musst.

Docker aktualisieren

Du musst Docker für ein Update nicht deinstallieren. Docker kommt aus einer Paketquelle, und die aktualisierst du wie alles andere auf Debian:

Terminalbash
sudo apt update
sudo apt install --only-upgrade docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Alternativ aktualisiert sudo apt upgrade das ganze System und damit auch Docker.

Aktualisiert Docker sich, startet der Docker-Dienst neu, und die Container werden dabei gestoppt. Container, die du mit --restart unless-stopped gestartet hast, fahren von selbst wieder hoch. Alle anderen bleiben auf Exited stehen, bis du sie mit docker start startest. Nach einem Neustart des Docker-Dienstes (sudo systemctl restart docker) stehen Container ohne diese Einstellung auf Exited. Plane Updates deshalb nicht in einem Moment ein, in dem jemand deinen Dienst nutzt. Die Daten selbst liegen in /var/lib/docker und bleiben unberührt. Wenn dir deine Daten wichtig sind, sicherst du sie vorher trotzdem. Den Ordner /var/lib/docker zeigt dir sudo docker info, er heißt dort „Docker Root Dir”.

Das Docker-Update ersetzt nicht die Images deiner Container. Ein Container läuft weiter mit dem Image, aus dem er gestartet wurde. Für eine neuere Version eines Programms holst du das neue Image (sudo docker pull nginx:1.30 lädt Fehlerbehebungen nach, falls es welche gibt) und erstellst den Container neu. Mit Docker Compose geht das mit zwei Befehlen.

Häufige Fehler

Meldung Ursache und Lösung
docker: command not found Docker ist nicht installiert, oder es wurde docker.io installiert. Folge den Schritten oben.
permission denied while trying to connect to the docker API Du hast sudo vergessen.
port is already allocated Der Port links von : wird bereits benutzt. Wähle einen anderen oder entferne den Container, der ihn belegt.
The container name ... is already in use Der Name ist vergeben. Wähle einen anderen oder entferne den alten Container mit docker rm.
cannot remove container ...: container is running Erst docker stop, dann docker rm, oder docker rm -f.
exec: "bash": executable file not found in $PATH Das Image hat kein bash. Verwende sh.
Die Seite im Browser lädt nicht Mit sudo docker ps prüfen, ob der Container läuft und welcher Port eingetragen ist. Dann sudo docker logs.

Fazit

Mit sechs Befehlen kommst du schon weit: docker run startet einen Container, docker ps zeigt, was läuft, docker logs verrät, was schiefgeht, docker stop und docker rm halten ihn an und entfernen ihn, und docker image ls zeigt die heruntergeladenen Images. Entscheidend sind drei Gedanken: Aus einem Image entstehen Container, Dateien im Container verschwinden mit ihm, und feste Tags statt latest halten deine Installation reproduzierbar.

Langfristig willst du solche Befehle nicht mehr jedes Mal von Hand tippen. Dafür gibt es Docker Compose: Du schreibst alle Einstellungen einmal in eine Datei. Du siehst Compose in meinen Anleitungen zu Uptime Kuma oder Vaultwarden im Einsatz.

Bei welchem Schritt hast du am längsten gebraucht? Schreib es gerne in die Kommentare, dann ergänze ich die Stelle.

FAQ

Häufige Fragen

Was ist der Unterschied zwischen einem Image und einem Container?

Ein Image ist die Vorlage: ein fertiges Paket aus Programm und Zubehör, das sich nicht verändert. Ein Container ist ein laufendes Programm, das aus dem Image gestartet wurde. Aus einem Image lassen sich beliebig viele Container starten.

Ist ein Docker-Container eine virtuelle Maschine?

Nein. Eine virtuelle Maschine bringt ein komplettes Betriebssystem mit. Ein Container teilt sich den Kernel mit dem Server und ist nur von anderen Programmen abgeschottet. Deshalb startet er schneller und braucht weniger Arbeitsspeicher.

Warum installiere ich Docker nicht mit apt install docker.io?

Das Debian-Paket docker.io liegt mehrere Hauptversionen hinter der aktuellen zurück. Auf Debian 13 ist es Version 26.1.5, die offizielle Version ist 29.9.3.

Wie aktualisiere ich Docker, ohne Daten zu verlieren?

Mit sudo apt update und sudo apt install --only-upgrade docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin. Deinstallieren ist nicht nötig. Container und Volumes bleiben erhalten, die Container werden beim Update aber kurz neu gestartet.

Ist Docker Desktop kostenlos?

Für Privatpersonen, Bildung, Open-Source-Projekte und kleine Unternehmen ja. Die Grenze liegt laut Docker bei weniger als 250 Mitarbeitern und weniger als 10 Millionen US-Dollar Jahresumsatz. Die Docker Engine, die du auf einem Linux-Server installierst, ist davon nicht betroffen.

Warum läuft mein Container nicht, obwohl der Befehl keinen Fehler zeigt?

Schau mit sudo docker ps -a nach dem Status und mit sudo docker logs NAME nach der Ursache. Steht der Container auf Exited, ist das Programm im Container beendet. Der Grund steht in den Logs.

Muss ich bei Rückfragen immer y eintippen?

Nicht bei apt. Bei der Rückfrage [Y/n] ist Ja voreingestellt (großes Y), ein Enter genügt. Bei docker container prune oder docker image prune -a steht [y/N]: Dort ist Nein voreingestellt, du musst y eingeben.