Docker und Docker Compose auf Debian und Ubuntu installieren

Veröffentlicht am 15 Min. Lesezeit

Warum docker.io auf Debian 12 zu alt ist, auf Ubuntu aber taugt, wie das offizielle Repo mit Keyring statt apt-key eingebunden wird, warum Compose ein Plugin ist und weshalb die Gruppe docker faktisch Root bedeutet.

Docker zu installieren dauert fünf Minuten. Docker so zu installieren, dass der Server ein Jahr später noch aktuelle Sicherheitsupdates bekommt, die Systemplatte nicht voll läuft und nicht versehentlich jeder Benutzer mit Root-Rechten unterwegs ist, dauert etwas länger. Dieser Artikel behandelt die zweite Variante, geprüft auf Debian 13 (Trixie), Debian 12 (Bookworm), Ubuntu 24.04 (Noble) und Ubuntu 22.04 (Jammy).

docker.io oder Docker CE: der Unterschied, den kaum jemand ehrlich erklärt

Es gibt zwei Wege, an Docker zu kommen. Das Paket docker.io stammt aus den Paketquellen der Distribution und wird von Debian beziehungsweise Ubuntu gebaut und gepflegt. Das Paket docker-ce stammt aus dem Repository von Docker selbst. Beide enthalten dieselbe Software, aber in sehr unterschiedlichem Alter.

Diese Versionen liegen aktuell in den Distributionsquellen (per apt-cache policy in frischen Containern nachgemessen):

Systemdocker.io in den Distributionsquellen
Debian 13 (Trixie)26.1.5
Debian 12 (Bookworm)20.10.24
Ubuntu 24.04 (Noble)29.1.3
Ubuntu 22.04 (Jammy)29.1.3

Das ist der eigentliche Punkt, und er wird in fast allen Anleitungen zu einer pauschalen Empfehlung verkürzt. Die Wahrheit ist differenzierter:

  • Ubuntu 24.04 und 22.04: docker.io liegt auf 29.1.3 und damit praktisch auf Höhe der aktuellen Upstream-Version. Wer keine besonderen Ansprüche hat, kann hier ohne schlechtes Gewissen das Distributionspaket nehmen. Sicherheitsupdates kommen dann über den normalen Ubuntu-Kanal.
  • Debian 13: 26.1.5 ist brauchbar, aber ein gutes Stück hinter Upstream. Für die meisten Anwendungsfälle reicht es.
  • Debian 12: 20.10.24 ist der Problemfall. Dieser Zweig ist upstream seit Jahren am Ende seines Lebenszyklus. Debian pflegt zwar Sicherheitspatches ein, aber viele moderne Funktionen fehlen schlicht, unter anderem eine aktuelle BuildKit-Version und einiges an Compose-Kompatibilität.

Dazu kommt ein praktischer Unterschied: docker-ce bringt Buildx und Compose als eigene Plugin-Pakete mit, die zur Engine passen. Bei docker.io müssen Sie sich diese Teile separat aus docker-buildx und docker-compose-v2 zusammensuchen, und docker-compose-v2 liegt ausschließlich in den Ubuntu-Quellen, unter Debian gibt es das Paket überhaupt nicht.

Was nicht geht: beides parallel. Das Paket containerd.io aus dem Docker-Repository steht im Konflikt mit dem Paket containerd aus der Distribution. Sie müssen sich entscheiden.

Faustregel: Auf Ubuntu ist docker.io eine legitime Wahl. Auf Debian 12 nicht. Für Server, die Compose-Stacks mit aktueller Syntax fahren, ist Docker CE überall die bessere Entscheidung.

Alte Pakete entfernen, bevor irgendetwas anderes passiert

Wenn schon ein Docker in irgendeiner Form vorhanden ist, muss es weg, sonst scheitert die Installation an Paketkonflikten. Die folgende Schleife entfernt alle üblichen Verdächtigen und fängt dabei Pakete ab, die gar nicht installiert sind oder in Ihrer Distribution überhaupt nicht existieren:

for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove -y $pkg || true; done

Das || true im Schleifenrumpf ist kein Schönheitsfehler, sondern notwendig. Auf Debian bricht apt-get beim Eintrag docker-compose-v2 mit E: Unable to locate package docker-compose-v2 und Exit-Code 100 ab, denn dieses Paket existiert ausschließlich in den Ubuntu-Quellen, nicht in bookworm oder trixie (und auch nicht in bullseye, wo zusätzlich podman-docker fehlt). Die Schleife läuft zwar weiter, hinterlässt aber einen Exit-Code ungleich 0, und genau daran stirbt ein Skript mit set -e oder eine Verkettung mit &&. Meldungen der Art "Unable to locate package" sind an dieser Stelle also normal und dürfen ignoriert werden, so hält es auch die offizielle Docker-Dokumentation.

Wichtig zu wissen: Dabei geht nichts verloren. Ihre Images, Container und Volumes liegen in /var/lib/docker, und dieses Verzeichnis rührt apt-get remove nicht an. Nach der Installation von Docker CE sind Ihre Container wieder da. Erst sudo rm -rf /var/lib/docker löscht wirklich, und das ist unwiderruflich.

Den Schlüssel richtig ablegen: apt-key ist Geschichte

Viele Anleitungen im Netz enthalten noch diese Zeile:

curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -

Das funktioniert auf keinem der vier hier behandelten Systeme mehr sinnvoll. apt-key ist abgekündigt und auf Debian 13 gar nicht mehr vorhanden. Der Grund ist nicht Kosmetik: ein Schlüssel in /etc/apt/trusted.gpg signiert alle Repositories, nicht nur das, für das er gedacht war. Ein kompromittierter Spiegelserver könnte Ihnen damit beliebige Pakete unterjubeln.

Richtig ist ein eigener Schlüsselbund unter /etc/apt/keyrings/, der per Signed-By genau einer Quelle zugeordnet wird.

sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings

Der folgende Befehl holt den passenden Schlüssel und funktioniert auf Debian wie auf Ubuntu, weil er die Distributions-ID aus /etc/os-release liest:

sudo curl -fsSL "https://download.docker.com/linux/$(. /etc/os-release && echo "$ID")/gpg" -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

Und jetzt der Schritt, den praktisch niemand beschreibt: prüfen Sie den Fingerabdruck, bevor Sie dem Schlüssel Ihr System anvertrauen.

gpg --show-keys /etc/apt/keyrings/docker.asc

Die Ausgabe muss den Fingerabdruck 9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88 und die Kennung Docker Release (CE deb) <docker@docker.com> enthalten. Stimmt das nicht überein, brechen Sie ab. Dann stimmt etwas mit Ihrer Verbindung oder mit der Quelle nicht.

Docker CE installieren, mit einem Snippet für alle vier Systeme

Die offizielle Dokumentation zeigt getrennte Blöcke für Debian und Ubuntu. Das ist unnötig. Der folgende Block schreibt die Paketquelle im modernen deb822-Format und ermittelt Distribution, Codename und Architektur selbst:

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

Zwei Details, die Zeit sparen. Erstens ${UBUNTU_CODENAME:-$VERSION_CODENAME}: auf Ubuntu-Abkömmlingen wie Linux Mint steht in VERSION_CODENAME der Name der Ableitung, nicht der von Ubuntu. Zweitens die Zeile Architectures: ohne sie beschwert sich apt auf Systemen mit aktivierter i386-Fremdarchitektur mit einer langen Warnung über nicht vorhandene Paketlisten.

Kontrollieren Sie das Ergebnis, bevor Sie weitermachen:

cat /etc/apt/sources.list.d/docker.sources

In Suites muss trixie, bookworm, noble oder jammy stehen. Steht dort etwas anderes, läuft der nächste Schritt in einen Fehler. Dann folgen Aktualisierung und Installation:

sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Die fünf Pakete sind: der Daemon, das Kommandozeilenwerkzeug, die Container-Laufzeit, der moderne Image-Builder und Compose.

Woran Sie erkennen, dass es wirklich läuft

Dass apt-get ohne Fehler durchlief, heißt nur, dass Dateien auf der Platte liegen. Die folgenden vier Prüfungen zeigen, ob das System tatsächlich arbeitet.

Erstens: erreicht der Client den Daemon?

docker version

Entscheidend ist nicht der Abschnitt Client, sondern dass darunter ein Abschnitt Server: Docker Engine - Community mit einer Versionsnummer erscheint. Fehlt er, läuft der Daemon nicht oder Sie dürfen nicht auf den Socket zugreifen.

Zweitens: welcher Speichertreiber ist aktiv?

docker info --format '{{.Driver}}'
docker info --format '{{.CgroupVersion}}'

Hier lauert eine Neuerung, die viele ältere Anleitungen falsch beantworten. Seit Docker Engine 29 ist bei Neuinstallationen der containerd-Image-Store voreingestellt. Der Treiber heißt dann overlayfs, nicht mehr overlay2. Beide Werte sind in Ordnung. Was Sie nicht sehen wollen, ist vfs: dieser Notfall-Treiber kopiert jede Schicht vollständig, frisst ein Vielfaches an Plattenplatz und ist quälend langsam. Er taucht typischerweise auf, wenn Docker in einer Umgebung ohne passende Kernel-Unterstützung läuft. Die Cgroup-Version muss auf allen vier Systemen 2 ergeben.

Falls Sie ein bestehendes System aktualisiert haben und plötzlich alle Images verschwunden scheinen: sie sind nicht gelöscht. Beim Wechsel des Image-Stores werden die Bestände der jeweils anderen Ablage nur ausgeblendet und tauchen beim Zurückschalten wieder auf. Zurückschalten geht über /etc/docker/daemon.json:

{
  "features": {
    "containerd-snapshotter": false
  }
}

Drittens: läuft wirklich ein Container?

docker run --rm hello-world

Viertens: funktioniert Netzwerk und Namensauflösung im Container? Dieser Test fehlt in fast jeder Anleitung, obwohl genau hier die meisten Folgeprobleme entstehen:

docker run --rm alpine:3 ping -c 2 1.1.1.1
docker run --rm alpine:3 nslookup deb.debian.org

Antwortet der Ping, aber die Namensauflösung scheitert, liegt es meist an einem DNS-Server, der nur auf 127.0.0.53 lauscht. Aus dem Container ist diese Adresse nicht erreichbar. Abhilfe schafft ein Eintrag in /etc/docker/daemon.json mit "dns": ["9.9.9.9"] und ein Neustart des Daemons.

Compose ist ein Plugin, kein eigenes Programm mehr

Das alte docker-compose mit Bindestrich war ein separates Python-Programm. Es ist ausgelaufen und wird nicht mehr ausgeliefert. Der Nachfolger ist ein in Go geschriebenes Plugin, das als Unterbefehl der Docker-CLI aufgerufen wird, also docker compose mit Leerzeichen.

docker compose version

Ein Hinweis zur Versionsnummer, weil das regelmäßig für Verwirrung sorgt: Der Ausdruck "Compose V2" bezeichnet die Neuentwicklung in Go, nicht die Versionsnummer. Die Ausgabe zeigt heute eine Version aus dem 5er-Zweig. Das ist korrekt und nicht etwa ein anderes Produkt.

Beim Umstieg fallen zwei Dinge auf. Zum einen ist der Schlüssel version: am Anfang von docker-compose.yml überflüssig geworden und erzeugt eine Warnung:

WARN[0000] docker-compose.yml: the attribute `version` is obsolete, it will be ignored, please remove it to avoid potential confusion

Löschen Sie die Zeile einfach. Zum anderen ändert sich die Benennung: Compose leitet den Projektnamen aus dem Verzeichnisnamen ab und erzeugt Container mit Bindestrich statt Unterstrich, also meinprojekt-web-1 statt meinprojekt_web_1. Skripte, die Container über feste Namen ansprechen, brechen dadurch. Setzen Sie in solchen Fällen den Projektnamen explizit über name: in der Compose-Datei oder über -p.

Wenn Sie bewusst bei den Distributionspaketen bleiben wollen, heißt das passende Paket docker-compose-v2 und liefert denselben Unterbefehl. Es steht allerdings nur in den Ubuntu-Quellen bereit. Prüfen Sie die verfügbare Version vorher:

apt-cache policy docker-compose-v2

Auf Ubuntu 24.04 und 22.04 erscheint eine Tabelle mit Installations- und Kandidatenversion. Auf Debian 13 und Debian 12 gibt der Befehl gar nichts aus, eine leere Ausgabe mit Exit-Code 0. Das ist kein Fehler, sondern die Antwort: Unter Debian gibt es dieses Paket nicht, dort führt der Weg zu Compose über docker-compose-plugin aus dem Docker-Repository.

Die Gruppe docker ist Root, nur mit einem Umweg

Damit ein normaler Benutzer Docker ohne sudo bedienen kann, wird er üblicherweise in die Gruppe docker aufgenommen:

sudo groupadd -f docker
sudo usermod -aG docker $USER

Die Gruppenmitgliedschaft wird erst bei einer neuen Anmeldung wirksam. Prüfen können Sie das nach dem erneuten Login mit id -nG. Wer nicht neu anmelden will, startet mit newgrp docker eine Shell mit der neuen Gruppe.

Jetzt der Teil, den Sie verstanden haben müssen: Mitgliedschaft in der Gruppe docker ist gleichbedeutend mit Root-Rechten auf dem gesamten Server. Das ist keine theoretische Bewertung, sondern eine unmittelbare Folge der Funktionsweise. Wer mit dem Docker-Socket sprechen darf, darf dem Daemon (der als Root läuft) beliebige Aufträge erteilen. Ein einziger Befehl genügt:

docker run -it -v /:/hostfs alpine:3 chroot /hostfs sh

Das Ergebnis ist eine Root-Shell auf dem Hostsystem, ohne sudo, ohne Passwortabfrage, ohne Eintrag in der sudo-Protokollierung. /etc/shadow lesen, SSH-Schlüssel hinterlegen, Dienste austauschen: alles möglich. Die Docker-Dokumentation formuliert es kurz und unmissverständlich: "The docker group grants root-level privileges to the user."

Praktische Konsequenzen für einen Server im Internet:

  • Nehmen Sie ausschließlich Konten in die Gruppe auf, denen Sie ohnehin Root anvertrauen würden.
  • Der Benutzer, unter dem eine Webanwendung oder ein CI-Runner läuft, gehört nicht dazu. Ein Einbruch in die Anwendung wäre sonst automatisch ein Einbruch in den Server.
  • Wenn Sie Nachvollziehbarkeit brauchen, verzichten Sie auf die Gruppe und rufen Docker über sudo docker auf. Dann taucht wenigstens der Aufruf im Protokoll auf.
  • Für echte Trennung gibt es den Rootless-Modus. Er wird über das Paket docker-ce-rootless-extras und das Werkzeug dockerd-rootless-setuptool.sh install eingerichtet und benötigt zusätzlich uidmap. Der Preis: Ports unterhalb 1024 lassen sich nicht ohne Zusatzkonfiguration belegen, und einige Netzwerkfunktionen verhalten sich anders.

Autostart: die Falle heißt docker.socket

Der Standardbefehl ist bekannt:

sudo systemctl enable --now docker.service
sudo systemctl enable --now containerd.service

Weniger bekannt ist, warum das Abschalten oft nicht wirkt. Docker bringt neben docker.service auch eine docker.socket mit. Diese Unit lauscht auf dem Socket und startet den Daemon beim ersten Zugriff automatisch. Wer also systemctl disable docker.service ausführt und danach feststellt, dass Docker trotzdem läuft, hat kein Gespenst gesehen: der erste docker ps hat den Daemon über die Socket-Unit wieder hochgezogen. Zum vollständigen Abschalten gehören beide:

sudo systemctl disable --now docker.service docker.socket

Prüfen lässt sich der Zustand mit systemctl is-enabled docker.service, was enabled ausgeben muss.

Der zweite Punkt betrifft Ihre Container. Ob ein Container nach einem Neustart wiederkommt, entscheidet nicht systemd, sondern die Restart-Policy. Und dabei gibt es einen Unterschied, der regelmäßig überrascht: always startet einen Container auch dann wieder, wenn Sie ihn vor dem Neustart bewusst gestoppt haben. unless-stopped respektiert Ihren manuellen Stopp über den Neustart hinweg. Für Server ist unless-stopped in aller Regel die richtige Wahl:

services:
  web:
    image: nginx:stable
    restart: unless-stopped

Der Test dafür ist nicht docker ps, sondern ein echter Neustart des Servers mit anschließender Kontrolle.

Logrotation: der häufigste Grund für eine volle Systemplatte

Docker schreibt die Ausgabe jedes Containers standardmäßig in eine JSON-Datei unter /var/lib/docker/containers/. Diese Datei wächst per Voreinstellung unbegrenzt. Ein gesprächiger Reverse Proxy kann so über Monate zweistellige Gigabyte-Beträge ansammeln, bis der Server mit no space left on device stehen bleibt. Der Schuldige ist dann schwer zu finden, weil du im Anwendungsverzeichnis nichts Auffälliges zeigt.

Die Lösung gehört auf jeden Server, und zwar bevor das erste Problem auftritt:

sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json > /dev/null <<'EOF'
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}
EOF

Falls schon eine daemon.json existiert, überschreibt dieser Befehl sie. Sehen Sie vorher nach und fügen Sie die Schlüssel gegebenenfalls von Hand ein. Danach:

sudo systemctl restart docker

Drei Punkte, an denen es trotzdem schiefgeht:

  • Die Werte müssen als Zeichenketten in Anführungszeichen stehen. "max-file": 3 ohne Anführungszeichen lässt den Daemon nicht mehr starten.
  • Die Einstellung gilt nur für neu erstellte Container. Bestehende behalten ihre alte Konfiguration, bis sie neu erzeugt werden, bei Compose also über docker compose up -d --force-recreate.
  • Eine überlaufene Logdatei mit rm zu löschen bringt keinen Plattenplatz zurück, weil der Daemon die Datei noch offen hält. Verwenden Sie stattdessen sudo truncate -s 0 <pfad>.

Ob die Einstellung bei einem konkreten Container greift, prüfen Sie so:

docker inspect --format '{{json .HostConfig.LogConfig}}' meincontainer

Aufräumen mit docker system prune, ohne Daten zu verlieren

Ungenutzte Images, abgebrochene Builds und der BuildKit-Cache summieren sich. Erst einmal nachsehen, wohin der Platz geht:

docker system df
docker system df -v

Der Standardbefehl zum Aufräumen entfernt gestoppte Container, ungenutzte Netzwerke, Images ohne Namen und den Build-Cache:

docker system prune

Zwei Schalter verdienen Respekt. -a löscht zusätzlich alle Images, die gerade von keinem Container verwendet werden, also auch sorgsam gepflegte Basis-Images. Auf einem Server mit schmaler Anbindung kann das Nachladen anschließend dauern. Deutlich gefährlicher ist --volumes: dieser Schalter entfernt benannte Volumes ohne zugehörigen Container. Wenn Ihr Datenbank-Container gerade gelöscht wurde, das Volume aber noch die Daten enthält, sind diese danach weg. Es gibt keinen Papierkorb.

Setzen Sie --volumes niemals in einem automatischen Aufräumjob ein.

Sinnvoll ist eine zeitliche Schonfrist, damit nur wirklich altes Material verschwindet:

docker system prune -a --filter "until=168h"
docker builder prune --filter "until=168h"

Als wöchentlicher Job, ressourcenschonend nachts und ohne Volume-Löschung, genügt eine Zeile in /etc/cron.d/docker-prune:

15 4 * * 0 root /usr/bin/docker system prune -af --filter "until=168h" > /dev/null 2>&1

Der Erfolgsnachweis ist ein erneutes docker system df mit gesunkener Spalte "RECLAIMABLE".

Fehlermeldungen im Wortlaut und was dahintersteckt

permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock
Der Benutzer ist nicht in der Gruppe docker, oder die Gruppenmitgliedschaft ist in der aktuellen Sitzung noch nicht wirksam. Neu anmelden oder newgrp docker.

Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
Der Daemon läuft nicht. Ursache und Wortlaut liefert systemctl status docker und ausführlicher journalctl -u docker -n 50 --no-pager. Sehr häufig steckt dahinter eine fehlerhafte /etc/docker/daemon.json. Diese Datei muss gültiges JSON sein, ein einziges überzähliges Komma reicht.

docker: 'compose' is not a docker command.
Das Plugin fehlt. Entweder docker-compose-plugin aus dem Docker-Repository oder, nur unter Ubuntu, docker-compose-v2 aus der Distribution nachinstallieren.

E: Conflicting values set for option Signed-By regarding source https://download.docker.com/linux/debian/ trixie: /etc/apt/keyrings/docker.asc != /etc/apt/keyrings/docker.gpg
Der Klassiker nach dem Durcharbeiten mehrerer Anleitungen: es existieren gleichzeitig eine alte /etc/apt/sources.list.d/docker.list und die neue docker.sources. Löschen Sie die alte Datei und wiederholen Sie sudo apt-get update. Verschaffen Sie sich mit ls -l /etc/apt/sources.list.d/ einen Überblick.

The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 8D81803C0EBFCD88
Der Schlüssel liegt nicht dort, wo Signed-By ihn erwartet, oder die heruntergeladene Datei ist unvollständig (etwa weil ein Proxy eine HTML-Fehlerseite geliefert hat). gpg --show-keys /etc/apt/keyrings/docker.asc zeigt sofort, ob überhaupt ein Schlüssel darin steckt.

E: The repository 'https://download.docker.com/linux/debian trixie Release' does not have a Release file.
Der Codename passt nicht zur Quelle. Das passiert auf abgeleiteten Distributionen und wenn Debian- und Ubuntu-Anleitungen vermischt werden. Kontrollieren Sie die Zeilen URIs und Suites in docker.sources.

Bind for 0.0.0.0:80 failed: port is already allocated
Ein anderer Dienst belegt den Port, oft ein direkt installierter Webserver. sudo ss -tulpn | grep :80 nennt den Verursacher.

Docker und die Firewall: ein Wort zur Sicherheit

Eine Eigenheit, die auf einem öffentlich erreichbaren Server teuer werden kann: Docker trägt seine Weiterleitungsregeln in der NAT-Tabelle ein und umgeht damit die Regeln, die Sie in ufw gepflegt haben. Ein Container, der mit -p 5432:5432 gestartet wurde, ist aus dem Internet erreichbar, auch wenn ufw status den Port nirgends erlaubt. Das gilt weiterhin, obwohl Docker Engine 28 das Netzwerkverhalten insgesamt gehärtet und den Zugriff auf nicht veröffentlichte Ports von außen unterbunden hat.

Die einfachste und zuverlässigste Gegenmaßnahme ist, Dienste, die nur lokal gebraucht werden, ausdrücklich an die Loopback-Adresse zu binden:

services:
  db:
    image: postgres:17
    ports:
      - "127.0.0.1:5432:5432"
    restart: unless-stopped

Noch besser: veröffentlichen Sie solche Ports gar nicht und lassen Sie die Container über ein gemeinsames Docker-Netzwerk miteinander sprechen. Prüfen lässt sich das Ergebnis am ehesten von einem zweiten Rechner aus, denn ein Test vom Server selbst beantwortet die entscheidende Frage nicht.

Kurz zusammengefasst

Nehmen Sie auf Debian 12 auf jeden Fall Docker CE, auf Ubuntu dürfen Sie zwischen docker.io und Docker CE wählen. Binden Sie das Repository mit einem eigenen Keyring und geprüftem Fingerabdruck ein, nicht mit apt-key. Verwenden Sie docker compose mit Leerzeichen. Behandeln Sie die Gruppe docker wie eine Root-Freigabe, weil sie genau das ist. Und richten Sie Logrotation sowie einen wöchentlichen Prune-Job ein, bevor der Server zum ersten Mal an einer vollen Platte scheitert.

Passend dazu: UFW-Firewall auf Debian und Ubuntu einrichten und Nginx auf Debian und Ubuntu installieren.

Häufige Fragen

Soll ich docker.io oder docker-ce installieren?
Auf Debian 12 klar Docker CE, weil das Distributionspaket dort auf 20.10.24 steht und dieser Zweig upstream ausgelaufen ist. Auf Debian 13 liefert docker.io 26.1.5, auf Ubuntu 24.04 und 22.04 sogar 29.1.3 und damit praktisch den aktuellen Stand. Dort ist das Distributionspaket eine legitime Wahl, sofern Sie Buildx und Compose separat nachinstallieren. Das Paket docker-compose-v2 gibt es allerdings nur in den Ubuntu-Quellen, unter Debian führt der Weg zu Compose über docker-compose-plugin aus dem Docker-Repository.
Warum funktioniert docker-compose mit Bindestrich nicht mehr?
Das alte docker-compose war ein eigenständiges Python-Programm und wird nicht mehr ausgeliefert. Der Nachfolger ist ein Go-Plugin der Docker-CLI und wird als docker compose mit Leerzeichen aufgerufen. Es steckt im Paket docker-compose-plugin (Docker-Repository) oder, nur unter Ubuntu, in docker-compose-v2 aus der Distribution. Prüfen mit: docker compose version.
Ist die Gruppe docker wirklich so gefährlich wie behauptet?
Ja. Wer auf den Docker-Socket zugreifen darf, kann dem als Root laufenden Daemon beliebige Aufträge erteilen, etwa das Wurzelverzeichnis des Hosts in einen Container einhängen und darin eine Root-Shell öffnen. Die Docker-Dokumentation formuliert es als root-level privileges. Nehmen Sie nur Konten auf, denen Sie ohnehin Root anvertrauen, oder nutzen Sie den Rootless-Modus.
Warum sagt docker info bei mir overlayfs statt overlay2?
Seit Docker Engine 29 ist bei Neuinstallationen der containerd-Image-Store voreingestellt. Dessen Snapshotter heißt overlayfs. Das ist korrekt und kein Fehler. Problematisch wäre nur der Wert vfs, der auf fehlende Kernel-Unterstützung hindeutet und sehr viel Plattenplatz verbraucht.
Meine Images sind nach einem Update verschwunden, sind sie gelöscht?
In aller Regel nein. Beim Wechsel zwischen klassischem Image-Store und containerd-Image-Store werden die Bestände der jeweils anderen Ablage nur ausgeblendet, die Daten bleiben auf der Platte. Schalten Sie testweise über features containerd-snapshotter in /etc/docker/daemon.json zurück, dann tauchen sie wieder auf.
Wie verhindere ich, dass Container-Logs die Platte volllaufen lassen?
Der Treiber json-file rotiert per Voreinstellung nicht. Tragen Sie in /etc/docker/daemon.json log-opts mit max-size 10m und max-file 3 ein, die Werte müssen als Zeichenketten in Anführungszeichen stehen. Nach systemctl restart docker gilt das nur für neu erstellte Container, bestehende müssen mit docker compose up -d --force-recreate neu erzeugt werden.
Ist docker system prune gefahrlos?
Ohne Schalter weitgehend ja, es entfernt gestoppte Container, ungenutzte Netzwerke, namenlose Images und Build-Cache. Der Schalter -a löscht zusätzlich alle gerade nicht verwendeten Images. Gefährlich ist --volumes, weil damit benannte Volumes ohne zugehörigen Container verschwinden, also möglicherweise Ihre Datenbank. In automatischen Jobs gehört --volumes nie hinein.

Docker Docker Compose Debian Ubuntu Linux Server containerd apt Serveradministration