Docker auf VPS bereinigen und Speicherplatz freigeben
Ist die VPS-Festplatte voll? Ermitteln Sie mit Docker-Übersicht und du gezielt Images, Container, Build-Cache oder Volumes, ohne Daten versehentlich zu löschen.
Ermitteln Sie, was den Speicherplatz belegt, bevor Sie etwas bereinigen
Docker belegt auf einem VPS an vier Stellen Speicherplatz: Images, gestoppte Container, Build-Cache und lokale Volumes. Führen Sie zuerst docker system df aus, um festzustellen, welcher Bereich den Speicherplatz belegt. Führen Sie anschließend die engste Bereinigung aus, die ihn freigibt. Die Reihenfolge ist wichtig, weil der letzte Befehl in diesem Leitfaden, docker volume prune -a, Daten löscht und nicht rückgängig gemacht werden kann.
Beginnen Sie mit dem Dateisystem, nicht mit Docker.
df -h /
sudo du -xh --max-depth=1 /var/lib/docker | sort -hdf zeigt, wie kritisch die Belegung ist. du zeigt, wohin der Speicherplatz gegangen ist. Das Flag -x beschränkt du auf ein Dateisystem. Dadurch folgt der Befehl keinem Mount in ein separates Volume und zählt den Speicherplatz nicht doppelt. Hier sind fünf Verzeichnisse relevant: overlay2 enthält Image- und Container-Layer, volumes enthält Volume-Daten, containers enthält Container-Metadaten und Logdateien, buildkit enthält den Build-Cache und image enthält Layer-Metadaten.
Ein Hinweis zu sudo und Shell-Wildcards, da dies häufig viel Zeit kostet. /var/lib/docker gehört root und ist für Ihren normalen Benutzer nicht lesbar. Daher gibt ls /var/lib/docker Permission denied zurück. Auch ein Befehl wie sudo du -sh /var/lib/docker/* schlägt fehl, weil Ihre Shell * erweitert, bevor sudo überhaupt ausgeführt wird, und Ihre Shell dieses Verzeichnis nicht lesen kann. Jeder folgende Befehl verwendet aus genau diesem Grund find oder --max-depth anstelle eines Wildcards.
Nun die Sicht von Docker.
docker system dfTYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 24 6 12.4GB 8.91GB (71%)
Containers 31 6 1.42GB 1.39GB (97%)
Local Volumes 14 5 6.03GB 4.11GB (68%)
Build Cache 212 0 9.87GB 9.87GBDiese Werte stammen von einem einzelnen System und sagen nichts über Ihr System aus. Achten Sie stattdessen auf die Struktur. TOTAL zählt Objekte, ACTIVE zählt die derzeit verwendeten Objekte, und RECLAIMABLE ist Dockers Schätzung, wie viel Speicherplatz eine Bereinigung aus dieser Zeile freigeben könnte.
Bei RECLAIMABLE führen zwei Dinge häufig zu falschen Erwartungen. Gemeinsame Image-Layer werden für jedes Image gezählt, das sie verwendet. Daher verspricht die Image-Zeile normalerweise mehr Speicherplatz, als tatsächlich freigegeben wird. Außerdem enthält sie niemals Container-Logdateien, weil Docker eine Logdatei nicht als freigebbares Objekt behandelt. Wenn du ein deutlich größeres Verzeichnis meldet, als docker system df ausweist, sind Logdateien der Grund dafür. Weiter unten gibt es dazu einen eigenen Abschnitt.
Fügen Sie -v hinzu, um die Aufschlüsselung nach einzelnen Objekten anzuzeigen.
docker system df -vDadurch wird die Zusammenfassung in einen Abschnitt pro Objekttyp aufgeteilt. Der Image-Abschnitt enthält zusätzlich die Spalten SHARED SIZE und UNIQUE SIZE. Damit sehen Sie, wie viel Speicherplatz ein einzelnes Image tatsächlich belegt. Der Volume-Abschnitt enthält zusätzlich die Anzahl LINKS. Sie gibt an, wie viele Container an dieses Volume angebunden sind. Merken Sie sich LINKS, denn der Wert 0 ist die einzige Bedingung, die die Volume-Bereinigungsbefehle prüfen.
Dangling Images und ungenutzte Images
Diese beiden Begriffe wirken austauschbar, sind es aber nicht. Die Filter verhalten sich unterschiedlich, weil es sich um unterschiedliche Objekte handelt.
Ein Dangling Image ist ein Image ohne Tag. In docker images wird es als <none> angezeigt. Bei jedem Rebuild entsteht eines: docker build -t myapp:latest . verschiebt den Tag myapp:latest auf das neue Image, während das alte Image alle Layer behält, aber seinen Namen verliert. Nichts referenziert es, und es wird nicht automatisch entfernt.
Ein ungenutztes Image ist jedes Image, mit oder ohne Tag, auf das derzeit kein Container verweist. Ein postgres:16, das Sie letzten Monat abgerufen haben und das momentan nicht ausgeführt wird, ist ungenutzt, aber nicht Dangling.
docker image prune # dangling images only
docker image prune -a # every image no container refers toDie zweite Abfrage fragt zuerst nach einer Bestätigung.
WARNING! This will remove all images without at least one container associated to them.
Are you sure you want to continue? [y/N]Lesen Sie diese Eingabeaufforderung genau. „Associated to them“ bezeichnet ein vorhandenes Container-Objekt, unabhängig davon, ob es läuft oder gestoppt ist. Wenn Sie docker compose down ausgeführt haben, sind die Container entfernt. Damit ist jedes von diesen Services verwendete Image ungenutzt, und -a löscht sie alle. Es geht nichts verloren, was sich nicht wiederherstellen lässt. Der nächste Aufruf von docker compose up -d ruft jedoch alles erneut ab oder baut es neu. Auf einem kleinen VPS kostet das Bandbreite und Build-Zeit. Das ist ein praktischer Grund, vor dem Aufräumen zu wissen, was docker compose down entfernt und was stop weiterlaufen lässt.
Ein Filter nimmt neuere Images aus dem Anwendungsbereich aus.
docker image prune -a --filter "until=240h"Damit werden ungenutzte Images entfernt, die vor mehr als 240 Stunden (10 Tagen) erstellt wurden. Neuere Images bleiben erhalten. Der Wert until verwendet eine Go-Dauerzeichenfolge wie 240h oder einen absoluten Zeitstempel wie 2026-08-01T00:00:00.
Was der Build-Cache ist und warum er unbegrenzt wächst
BuildKit ist der Builder, den Docker seit Docker Engine 23.0 standardmäßig für docker build und docker compose build verwendet. Er cached das Ergebnis jedes Schritts jeder ausgeführten Dockerfile und speichert diesen Cache in /var/lib/docker/buildkit. Der Cache sorgt dafür, dass der zweite Build in wenigen Sekunden abgeschlossen ist. Damit erfüllt er seinen Zweck. Das Problem ist, dass alte Einträge standardmäßig nicht ablaufen. Wenn Sie dasselbe Image 50-mal mit einem COPY-Schritt bauen, der sich bei jedem Durchlauf ändert, behalten Sie 50 Layer-Sätze.
Der Build-Cache ist für docker image prune unsichtbar. Er ist ein eigener Objekttyp mit einem eigenen Befehl.
docker builder prune # dangling cache
docker builder prune -a # all unused cache
docker builder prune --filter until=168h # cache untouched for 7 daysKeiner dieser Befehle verändert Ihre Images oder Ihre Daten. Das Löschen des Build-Caches kostet nur den nächsten Build, der einmalig länger läuft. Auf einem VPS, der regelmäßig Images neu baut, ist Build Cache häufig der größte Eintrag in docker system df. Deshalb können Sie diesen Bereich am sichersten löschen.
Bereinigungskommandos, geordnet von sicher bis destruktiv
Arbeiten Sie diese Liste von oben nach unten ab. Beenden Sie den Vorgang, sobald df -h / wieder einen unauffälligen Zustand anzeigt. Nach Abschluss jedes Kommandos wird eine Zeile mit Total reclaimed space: ausgegeben.
docker container pruneentfernt beendete Container. Dabei werden auch deren beschreibbare Layer entfernt. Alles, was ein Container außerhalb eines Volumes geschrieben hat, wird dadurch gelöscht. Volumes werden nicht verändert.docker image pruneentfernt nur verwaiste Images. Dies ist das sicherste Kommando für Images.docker builder pruneentfernt den verwaisten Build-Cache. Der Preis dafür ist ein einmalig langsamer Build.docker image prune -aentfernt jedes Image, das von keinem Container referenziert wird. Danach müssen Images erneut geladen oder neu erstellt werden.docker system pruneführt die ersten drei Schritte gemeinsam aus und entfernt zusätzlich ungenutzte Netzwerke.docker volume pruneentfernt ungenutzte anonyme Volumes.docker volume prune -aentfernt ungenutzte Volumes einschließlich benannter Volumes. Mit diesem Kommando werden Datenbanken gelöscht.
docker system prune gibt seinen eigenen Geltungsbereich aus, bevor das Kommando ausgeführt wird.
WARNING! This will remove:
- all stopped containers
- all networks not used by at least one container
- all dangling images
- unused build cache
Are you sure you want to continue? [y/N]Volumes sind bewusst nicht in dieser Liste enthalten. Durch das Hinzufügen von --volumes werden anonyme Volumes ebenfalls berücksichtigt. Durch das Hinzufügen von -a wird der Schritt für Images von verwaisten Images auf alle ungenutzten Images erweitert. Ein vollständiges docker system prune -a --volumes -f auf einem Produktionshost führt dazu, dass Daten verloren gehen, während Speicherplatz freigegeben werden soll.
Warum das Bereinigen von Volumes Ihre Datenbank löscht
Diesen Abschnitt sollten Sie zweimal lesen.
Ein Volume gilt als ungenutzt, wenn kein Container daran gebunden ist. Das ist die gesamte Prüfung. Docker prüft nicht, ob das Volume leer ist, ob eine Compose-Datei es weiterhin deklariert oder ob es die einzige Kopie Ihrer Datenbank enthält. LINKS 0 in docker system df -v bedeutet, dass das Volume bereinigt werden kann. Mehr bedeutet es nicht.
Führen Sie nun zwei gewöhnliche Aktionen nacheinander aus. Sie verwenden docker compose down, um einen Stack sauber neu zu starten. Dabei werden die Container entfernt, während benannte Volumes bestehen bleiben. Genau so ist der Befehl dokumentiert. Ihr Postgres-Volume ist nun an keinen Container gebunden. Zehn Minuten später verwenden Sie docker volume prune -a, um Speicherplatz freizugeben, und die Datenbank ist gelöscht. Beide Befehle haben korrekt funktioniert. Die Abfolge hat die Daten zerstört.
Seit Docker Engine 23.0 (API-Version 1.42) ist der einfache Befehl enger gefasst als früher.
WARNING! This will remove anonymous local volumes not used by at least one container.Ein anonymes Volume wird von Docker erstellt. Das geschieht normalerweise, weil ein Image VOLUME deklariert und Sie keinen Namen vergeben haben. Solche Volumes enthalten normalerweise Daten, die Sie nicht dauerhaft behalten wollten. Ein benanntes Volume, also ein Volume aus Ihrer Compose-Datei, wird nur entfernt, wenn Sie -a hinzufügen. Ältere Docker-Versionen entfernten mit dem einfachen Befehl beide Arten. Verlassen Sie sich daher nicht auf Gewohnheiten von einem System, das Sie inzwischen aktualisiert haben. Der Unterschied wird erst verständlich, wenn Sie wissen, wie sich benannte Volumes von Bind-Mounts unterscheiden, denn ein Bind-Mount ist überhaupt kein Docker-Volume. Kein Prune-Befehl kann ihn entfernen.
Prüfen Sie das Volume, bevor Sie es löschen. Ersetzen Sie myapp_pgdata durch den Namen des Volumes, das Sie überprüfen.
docker volume ls -f dangling=true
docker volume inspect myapp_pgdata
sudo ls -la /var/lib/docker/volumes/myapp_pgdata/_dataDer Filter dangling=true für ein Volume bedeutet, dass es nicht referenziert wird, nicht dass es leer ist. Mit _data sehen Sie, welche Daten tatsächlich enthalten sind. Wenn Sie darin ein Verzeichnis pgdata oder mysql finden, halten Sie an und erstellen Sie eine Kopie, bevor Sie fortfahren. Dieselbe Zerstörung kann über docker compose down -v erfolgen. Dieser Befehl entfernt jedes Volume, das die Compose-Datei deklariert, und fragt vorher nicht nach.
Ein Volume ist das einzige Element auf einem Docker-Host, das ein Neuaufbau nicht wiederherstellen kann. Deshalb gehören Volume-Daten in ein Restic-Backup, das außerhalb des Servers ausgeführt wird, damit ein falsch gesetztes Flag sie nicht erreichen kann.
Wenn nichts bereinigt wird: Container-Logdateien
Sie haben alles bereinigt, docker system df zeigt kaum noch freigebbaren Speicher an, und die Festplatte ist weiterhin voll. Prüfen Sie die Logs.
sudo find /var/lib/docker/containers -name '*-json.log' -exec du -h {} + | sort -h | tail -10Jeder Container schreibt seine Standardausgabe und seinen Standardfehler in eine JSON-Datei unter /var/lib/docker/containers/. Bei einer Standardinstallation ist max-size nicht gesetzt. Das bedeutet, dass keine Begrenzung gilt. Ein einzelner Container in einer Crash-Schleife kann daher so lange schreiben, bis die Partition voll ist. Kein Prune-Befehl entfernt diese Dateien, weil die Container, die sie erzeugen, laufen. Per Definition können sie daher nicht bereinigt werden.
Löschen Sie die Datei nicht. rm für eine geöffnete Logdatei gibt keinen Speicher frei, weil der Docker-Daemon weiterhin einen offenen Dateideskriptor hält. Der Kernel behält die zugehörigen Blöcke belegt, bis dieser Handle geschlossen wird. df bewegt sich überhaupt nicht. Kürzen Sie die Datei stattdessen. Dabei bleibt derselbe Inode erhalten, und der Daemon kann weiter schreiben.
sudo find /var/lib/docker/containers -name '*-json.log' -exec truncate -s 0 {} +
df -h /Das ist nur eine vorübergehende Lösung. docker logs für diese Container liefert jetzt nichts zurück, und die Dateien wachsen sofort wieder. Die eigentliche Lösung ist die Rotation. Sie wird im nächsten Abschnitt behandelt.
Vorher und nachher messen, jedes Mal
Vermuten Sie nie, was ein Prune bewirkt hat. Erfassen Sie zuerst einen Messwert, führen Sie einen Befehl aus und erfassen Sie anschließend einen weiteren Messwert.
df -h /
docker system df
docker builder prune -f --filter until=168h
docker image prune -f
docker system df
df -h /Vergleichen Sie die beiden df-Ausgaben. Nur diese Zahl entscheidet, ob Ihr Server weiterhin Anfragen verarbeitet. docker system df zeigt anschließend, welche Zeile sich tatsächlich geändert hat, und jeder Prune gibt eine eigene Total reclaimed space:-Angabe aus.
Wenn sich df nicht geändert hat, docker system df aber meldet, dass Speicherplatz freigegeben wurde, hält ein offener Dateideskriptor gelöschte Blöcke fest. Das ist das oben beschriebene Problem mit der Logdatei. Wenn sich beide Werte geändert haben und der Datenträger innerhalb eines Tages erneut voll ist, liegt ein Wachstumsproblem und kein Bereinigungsproblem vor. Die Lösung besteht dann aus Rotation und einem geplanten Job.
So verhindern Sie, dass sich die Festplatte erneut füllt
Begrenzen Sie die Loggröße. Erstellen oder bearbeiten Sie /etc/docker/daemon.json.
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}Damit wird jeder Container auf 30 MB Logs begrenzt. Jeder Wert unter log-opts muss eine Zeichenfolge sein, auch numerische Werte. Prüfen Sie, ob die Datei korrekt eingelesen werden kann, bevor Sie den Dienst neu starten. Eine fehlerhafte daemon.json verhindert den Start des Daemons vollständig und reißt alle Container mit.
python3 -m json.tool /etc/docker/daemon.json
sudo systemctl restart docker
docker info | grep -i 'logging driver'docker info sollte jetzt Logging Driver: json-file melden. Die eigentlichen Begrenzungen werden im Abschnitt LogConfig von docker inspect für einen Container angezeigt, der nach dem Neustart erstellt wurde. Das ist der entscheidende Punkt: Diese Einstellung gilt nur für neue Container. Vorhandene Container behalten die Konfiguration, mit der sie erstellt wurden. Erstellen Sie sie daher neu.
docker compose up -d --force-recreateDieselbe Begrenzung kann in einer Compose-Datei pro Dienst festgelegt werden. Das ist die bessere Wahl, wenn ein Dienst mit hohem Logaufkommen einen eigenen Wert benötigt.
services:
app:
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"Planen Sie ein gezieltes Aufräumen. Führen Sie es wöchentlich aus und beschränken Sie es auf verwaiste Images und alten Build-Cache. Verwenden Sie -a oder --volumes niemals in einem geplanten Job. Wenn der Job läuft, während ein Stack gestoppt ist, löscht er die Images dieses Stacks. Mit --volumes beginnt er außerdem mit Ihren Daten.
sudo tee /etc/cron.weekly/docker-prune >/dev/null <<'EOF'
#!/bin/sh
docker image prune -f
docker builder prune -f --filter until=168h
EOF
sudo chmod +x /etc/cron.weekly/docker-prune
sudo /etc/cron.weekly/docker-pruneDie letzte Zeile führt das Script einmal manuell aus. So sehen Sie die Ausgabe, bevor es unbeaufsichtigt läuft. Die Datei muss ausführbar sein. Ihr Name darf keinen Punkt enthalten, weil run-parts nicht ausführbare Dateien und Dateien mit einer Erweiterung überspringt.
Überwachen Sie den freien Speicherplatz. Ein Aufräumen nach einer vollen Festplatte ist eine Wiederherstellung. Ein Alarm bei 80 Prozent verhindert das Problem.
usage=$(df --output=pcent / | tr -dc '0-9')
[ "$usage" -ge 80 ] && echo "root filesystem at ${usage} percent full"Tragen Sie dies mit dem Benachrichtigungsdienst, den Sie bereits verwenden, in cron ein. Der freie Speicherplatz ist nur eine Hälfte des Problems. Kombinieren Sie den Alarm daher mit der Überwachung des Festplattenzustands auf Ihrem VPS, weil sowohl eine ausfallende als auch eine volle Festplatte Ihre Container stoppt. Beide Probleme erfordern unterschiedliche Maßnahmen.
Alle obigen Angaben setzen eine Standardinstallation mit dem Datenstamm unter /var/lib/docker voraus. Wenn Sie ihn mit dem Schlüssel data-root in daemon.json verschoben haben, ersetzen Sie den Pfad in jedem Befehl. Die Verzeichnisstruktur auf einem neuen System korrekt festzulegen, gehört zur Einrichtung von Docker auf einem VPS. Diese Entscheidung lässt sich deutlich einfacher treffen, bevor 40 GB Container auf der falschen Partition liegen.
FAQ
Löscht docker system prune meine Volumes?
Nein. Der einfache Befehl entfernt gestoppte Container, nicht verwendete Netzwerke, verwaiste Images und nicht verwendeten Build-Cache. Die Bestätigungsabfrage listet genau diese Elemente auf. Volumes werden erst berücksichtigt, wenn Sie --volumes hinzufügen. Seit Docker Engine 23.0 gilt dieses Flag für anonyme Volumes, nicht für benannte Volumes. Benannte Volumes werden durch docker volume prune -a und docker compose down -v entfernt. Bei diesen beiden Befehlen ist besondere Vorsicht erforderlich.
Warum ist meine Festplatte nach docker prune weiterhin voll?
Dafür gibt es zwei typische Ursachen. Die erste sind Container-Logdateien unter /var/lib/docker/containers/. Kein prune-Befehl erfasst diese Dateien. Sie wachsen unbegrenzt, bis Sie max-size setzen. Die zweite Ursache ist eine gelöschte Datei, die ein Prozess weiterhin geöffnet hält. Wenn Sie ein Log mit rm gelöscht haben, während der Container lief, behält der Daemon den Dateideskriptor. Der Kernel gibt die belegten Blöcke deshalb nicht frei, und df zeigt keine Änderung. Vergleichen Sie sudo du -xh --max-depth=1 /var/lib/docker mit docker system df, um die Ursache zu ermitteln.
Was ist der Unterschied zwischen docker image prune und docker image prune -a?
Der einfache Befehl entfernt nur verwaiste Images. Das sind Images, deren Tag entfernt wurde, fast immer durch einen erneuten Build. Die Form -a entfernt jedes Image, auf das kein vorhandener Container verweist. Dazu gehören auch getaggte Images, die Sie bewusst heruntergeladen haben. Nach einem docker compose down sind die Container entfernt. Deshalb entfernt -a auch die Images dieses Stacks. Dauerhaft geht nichts verloren, da der nächste Start die Images erneut herunterlädt oder erstellt. Bei einer langsamen Verbindung kann das jedoch lange dauern.
Wie verhindere ich, dass Docker-Logs die Festplatte füllen?
Setzen Sie max-size und max-file unter log-opts in /etc/docker/daemon.json. Starten Sie den Daemon anschließend mit sudo systemctl restart docker neu. Die Einstellung gilt nur für Container, die nach diesem Neustart erstellt werden. Erstellen Sie die laufenden Container deshalb mit docker compose up -d --force-recreate neu. Sie können dieselben beiden Optionen pro Service in einer Compose-Datei unter einem logging-Schlüssel festlegen. Das ist sinnvoll, wenn ein Service deutlich mehr Logs erzeugt als die übrigen.
Ist es sicher, docker system prune in einem Cronjob auszuführen?
Das einfache docker system prune -f ist auf einem Host sicher, auf dem alle Stacks dauerhaft laufen. Es entfernt jedoch gestoppte Container. Daher wird auch ein Container gelöscht, den Sie absichtlich gestoppt haben und später wieder starten wollten. Der sicherere geplante Job ist docker image prune -f zusammen mit docker builder prune -f --filter until=168h. Damit geben Sie die beiden am schnellsten wachsenden Speicherbereiche frei, ohne ein Volume zu verändern. Planen Sie niemals -a oder --volumes ein.