Docker schijfruimte vrijmaken op een VPS
Uw VPS schijf zit vol door Docker? Ontdek hoe u met docker system df de boosdoener vindt en veilig containers, images of volumes verwijdert zonder onbedoeld dataverlies.
Bepaal wat schijfruimte verbruikt voordat u gegevens verwijdert
Docker verbruikt schijfruimte op een VPS op vier plaatsen: images, gestopte containers, build-cache en lokale volumes. Voer eerst docker system df uit om te achterhalen waar de ruimte wordt verbruikt en voer daarna de meest specifieke prune-opdracht uit om dit op te lossen. De volgorde is van belang, omdat de laatste opdracht in deze handleiding, docker volume prune -a, gegevens verwijdert die niet ongedaan kunnen worden gemaakt.
Begin bij het bestandssysteem, niet bij Docker.
df -h /
sudo du -xh --max-depth=1 /var/lib/docker | sort -hdf geeft aan hoe groot het probleem is. du laat zien waar de ruimte is gebleven. De vlag -x zorgt ervoor dat du op één bestandssysteem blijft, zodat het geen mount naar een apart volume volgt en deze dubbel telt. Vijf mappen zijn hier van belang: overlay2 bevat image- en container-layers, volumes bevat volume-data, containers bevat container-metadata en logbestanden, buildkit bevat de build-cache en image bevat layer-metadata.
Een opmerking over sudo en shell-wildcards, omdat dit vaak veel tijd kost. /var/lib/docker is eigendom van root en is niet leesbaar voor uw normale gebruiker, waardoor ls /var/lib/docker de melding Permission denied geeft. Een opdracht zoals sudo du -sh /var/lib/docker/* faalt om dezelfde reden, omdat uw shell de * uitbreidt voordat sudo wordt uitgevoerd, en uw shell die map niet kan lezen. Elke onderstaande opdracht gebruikt daarom find of --max-depth in plaats van een wildcard.
Nu het overzicht vanuit Docker zelf.
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.87GBDeze cijfers zijn afkomstig van één machine en zeggen niets over die van u. Kijk naar de verhoudingen. TOTAL telt objecten, ACTIVE telt de objecten die momenteel in gebruik zijn, en RECLAIMABLE is de schatting van Docker van hoeveel ruimte een prune-opdracht per rij kan vrijmaken.
Twee zaken met betrekking tot RECLAIMABLE zorgen vaak voor verwarring. Het telt gedeelde image-layers één keer voor elke image die ze gebruikt, waardoor de rij voor images meestal meer ruimte belooft dan er daadwerkelijk vrijkomt. Bovendien worden container-logbestanden nooit meegerekend, omdat Docker een logbestand niet als een verwijderbaar object beschouwt. Wanneer du een map rapporteert die veel groter is dan docker system df aangeeft, zijn logbestanden de oorzaak; hierover vindt u verderop een sectie.
Voeg -v toe voor een uitsplitsing per object.
docker system df -vDit splitst het overzicht in één sectie per objecttype. De image-sectie voegt de kolommen SHARED SIZE en UNIQUE SIZE toe, zodat u kunt zien wat een enkele image daadwerkelijk verbruikt. De volume-sectie voegt een LINKS-telling toe, wat het aantal containers is dat aan dat volume is gekoppeld. Onthoud LINKS, aangezien een waarde van 0 de volledige voorwaarde is waaraan de volume-prune-opdrachten voldoen.
Dangling images versus ongebruikte images
Deze twee termen lijken uitwisselbaar, maar dat zijn ze niet. De filters gedragen zich verschillend omdat de objecten verschillend zijn.
Een dangling image is een image zonder tag. Deze wordt weergegeven als <none> in docker images. U creëert er een bij elke rebuild: docker build -t myapp:latest . verplaatst de myapp:latest tag naar de nieuwe image, en de oude image behoudt al zijn lagen maar verliest zijn naam. Niets verwijst ernaar en niets ruimt het automatisch op.
Een ongebruikte image is elke image, met of zonder tag, waarnaar momenteel geen container verwijst. Een postgres:16 die u vorige maand hebt binnengehaald en die nu niet draait, is ongebruikt en is niet dangling.
docker image prune # dangling images only
docker image prune -a # every image no container refers toDe tweede optie vraagt eerst om bevestiging.
WARNING! This will remove all images without at least one container associated to them.
Are you sure you want to continue? [y/N]Lees die prompt zorgvuldig. "Associated to them" betekent een bestaand containerobject, ongeacht of deze draait of gestopt is. Als u docker compose down hebt uitgevoerd, zijn de containers verdwenen; elke image die die services gebruikten is nu ongebruikt, en -a verwijdert ze allemaal. Er gaat niets verloren dat u niet kunt terughalen, maar de volgende docker compose up -d haalt of bouwt alles opnieuw, wat bandbreedte en bouwtijd kost op een kleine VPS. Dat is een praktische reden om te weten wat docker compose down verwijdert en wat stop laat draaien voordat u iets opschoont.
Een filter houdt recente images buiten het bereik.
docker image prune -a --filter "until=240h"Dit verwijdert ongebruikte images die meer dan 240 uur (10 dagen) geleden zijn aangemaakt en laat nieuwere images met rust. De waarde until accepteert een Go duration-string zoals 240h, of een absolute tijdstempel zoals 2026-08-01T00:00:00.
Wat de build cache is en waarom deze onbeperkt groeit
BuildKit is de builder die Docker standaard gebruikt voor docker build en docker compose build sinds Docker Engine 23.0. Het slaat het resultaat van elke stap van elke Dockerfile die wordt uitgevoerd op in een cache, en bewaart deze cache in /var/lib/docker/buildkit. Dankzij deze cache is uw tweede build binnen enkele seconden voltooid; het systeem doet dus zijn werk. Het probleem is dat er standaard geen verloopdatum is voor oude items. Als u vijftig keer dezelfde image bouwt met een COPY-stap die telkens wijzigt, behoudt u vijftig sets aan lagen.
De build cache is onzichtbaar voor docker image prune. Het is een afzonderlijk objecttype met een eigen commando.
docker builder prune # dangling cache
docker builder prune -a # all unused cache
docker builder prune --filter until=168h # cache untouched for 7 daysGeen van deze commando's heeft invloed op uw images of uw data. De enige consequentie van het legen van de build cache is dat de eerstvolgende build eenmalig langzamer verloopt. Op een VPS waar regelmatig images worden herbouwd, is Build Cache vaak de grootste regel in docker system df, wat het de veiligste grote post maakt om te verwijderen.
De prune-commando's, gerangschikt van veilig naar destructief
Werk deze lijst af en stop zodra df -h / er weer gezond uitziet. Elk commando toont een Total reclaimed space:-regel wanneer het is voltooid.
docker container pruneverwijdert gestopte containers. Hun beschrijfbare lagen worden ook verwijderd, dus alles wat een container buiten een volume heeft geschreven, wordt daarmee gewist. Volumes worden niet aangeraakt.docker image pruneverwijdert alleen zwevende (dangling) images. Dit is het veiligste image-commando dat er is.docker builder pruneverwijdert zwevende build-cache. De prijs hiervan is één trage build.docker image prune -averwijdert elke image waarnaar geen enkele container verwijst. De prijs hiervan is een nieuwe pull of een nieuwe build.docker system prunevoert de eerste drie acties tegelijk uit en voegt ongebruikte netwerken toe.docker volume pruneverwijdert ongebruikte anonieme volumes.docker volume prune -averwijdert ongebruikte volumes, inclusief benoemde volumes. Dit is het commando dat databases verwijdert.
docker system prune vermeldt zijn eigen bereik voordat het wordt uitgevoerd.
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 ontbreken bewust in die lijst. Het toevoegen van --volumes brengt anonieme volumes terug in het bereik. Het toevoegen van -a verbreedt de image-stap van zwevende images naar alle ongebruikte images. Een volledige docker system prune -a --volumes -f op een productiehost is de manier waarop mensen data verliezen terwijl ze proberen ruimte vrij te maken.
Waarom het opschonen van volumes uw database verwijdert
Dit is de sectie die u twee keer moet lezen.
Een volume wordt als ongebruikt beschouwd wanneer er geen container aan gekoppeld is. Dat is de enige voorwaarde. Docker controleert niet of het volume leeg is, of een compose-bestand het nog declareert, of dat het de enige kopie van uw database bevat. LINKS 0 in docker system df -v betekent dat het opgeschoond kan worden, en niets anders.
Voer nu twee normale acties achter elkaar uit. U voert docker compose down uit om een stack schoon te herstarten. Dat verwijdert de containers en laat de named volumes staan, wat precies is wat de documentatie voorschrijft. Uw Postgres-volume is nu aan niets gekoppeld. Tien minuten later voert u docker volume prune -a uit om ruimte vrij te maken, en de database is verdwenen. Beide commando's gedroegen zich correct. De reeks acties heeft de data vernietigd.
Sinds Docker Engine 23.0 (API-versie 1.42) is het standaardcommando beperkter dan voorheen.
WARNING! This will remove anonymous local volumes not used by at least one container.Een anoniem volume is een volume dat Docker voor u heeft aangemaakt, meestal omdat een image VOLUME declareert en u het nooit een naam heeft gegeven. Deze bevatten normaal gesproken data waarvan u niet vroeg om deze te bewaren. Een named volume, het type dat u in uw compose-bestand heeft geschreven, wordt alleen verwijderd wanneer u -a toevoegt. Oudere Docker-versies verwijderden beide met het standaardcommando, dus vertrouw niet op gewoontes die zijn gevormd op een systeem dat u sindsdien heeft geüpgraded. Het verschil is pas logisch als u weet hoe named volumes verschillen van bind mounts, omdat een bind mount helemaal geen Docker-volume is en geen enkel prune-commando deze ooit zal aanraken.
Kijk voordat u verwijdert. Vervang myapp_pgdata door de naam van het volume dat u controleert.
docker volume ls -f dangling=true
docker volume inspect myapp_pgdata
sudo ls -la /var/lib/docker/volumes/myapp_pgdata/_dataHet dangling=true-filter op een volume betekent niet-gekoppeld, niet leeg. Het weergeven van _data laat u zien wat er daadwerkelijk in staat. Als u daar een pgdata- of mysql-directory aantreft, stop dan en maak een kopie voordat u verder gaat. Dezelfde vernietiging vindt plaats via docker compose down -v, die elk volume verwijdert dat het compose-bestand declareert zonder u eerst om bevestiging te vragen.
Een volume is het enige op een Docker-host dat een rebuild niet kan herstellen. Daarom hoort volume-data thuis in een restic-back-up die buiten de server draait, waar een verkeerd getypte flag er niet bij kan.
Wanneer niets wordt opgeschoond: de container-logbestanden
U heeft alles opgeschoond, docker system df toont vrijwel niets dat kan worden teruggewonnen, en de schijf is nog steeds vol. Controleer de logs.
sudo find /var/lib/docker/containers -name '*-json.log' -exec du -h {} + | sort -h | tail -10Elke container schrijft zijn standaarduitvoer en standaardfout naar een JSON-bestand onder /var/lib/docker/containers/. Bij een standaardinstallatie is max-size niet ingesteld, wat betekent dat er geen limiet is. Een container die vastzit in een crash-loop schrijft dus door totdat de partitie vol is. Geen enkel prune-commando verwijdert deze bestanden, omdat de containers die ze produceren actief zijn; ze zijn per definitie niet prune-baar.
Verwijder het bestand niet. Het uitvoeren van rm op een geopend logbestand maakt geen ruimte vrij, omdat de Docker-daemon nog steeds een open bestandsdescriptor heeft en de kernel die blokken toegewezen houdt totdat die handle wordt gesloten. df zal in het geheel niet veranderen. Gebruik in plaats daarvan truncate, waardoor de inode behouden blijft en de daemon kan blijven schrijven.
sudo find /var/lib/docker/containers -name '*-json.log' -exec truncate -s 0 {} +
df -h /Dat is een tijdelijke oplossing. docker logs voor die containers geeft nu niets meer terug, en de bestanden beginnen direct weer te groeien. De definitieve oplossing is rotatie, wat in de volgende sectie wordt behandeld.
Meet altijd voor en na de actie
Gok nooit wat een prune-opdracht heeft opgeleverd. Noteer de status, voer één commando uit en noteer de status opnieuw.
df -h /
docker system df
docker builder prune -f --filter until=168h
docker image prune -f
docker system df
df -h /Vergelijk de twee df-outputs. Dat is het enige getal dat bepaalt of uw server operationeel blijft. docker system df geeft vervolgens aan welke rij daadwerkelijk is verplaatst en elke prune toont zijn eigen Total reclaimed space:-cijfer.
Als df niet is veranderd maar docker system df aangeeft dat er ruimte is vrijgekomen, houdt een open bestands-handle verwijderde blokken vast; dit is het eerder genoemde logbestandprobleem. Als beide waarden zijn veranderd en de schijf binnen een dag weer volloopt, heeft u een groeiprobleem in plaats van een opschoonprobleem. De oplossing is dan rotatie in combinatie met een geplande taak.
Hoe u voorkomt dat de schijf opnieuw volloopt
Begrens de loggrootte. Maak of bewerk /etc/docker/daemon.json.
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}Hiermee wordt elke container beperkt tot 30 MB aan logs. Elke waarde onder log-opts moet een string zijn, ook de numerieke waarden. Controleer of het bestand correct wordt geparseerd voordat u opnieuw opstart, want een onjuist geformatteerd daemon.json zorgt ervoor dat de daemon helemaal niet start en haalt daarmee alle containers offline.
python3 -m json.tool /etc/docker/daemon.json
sudo systemctl restart docker
docker info | grep -i 'logging driver'docker info zou nu Logging Driver: json-file moeten rapporteren. De limieten zelf zijn zichtbaar in de sectie LogConfig van docker inspect bij een container die na de herstart is aangemaakt; dit is een belangrijk detail: deze instelling is alleen van toepassing op nieuwe containers. Bestaande containers behouden de configuratie waarmee ze zijn gebouwd, dus u moet deze opnieuw aanmaken.
docker compose up -d --force-recreateDezelfde limiet kan per service in een compose-bestand worden ingesteld; dit is de betere keuze wanneer één luidruchtige service een eigen waarde nodig heeft.
services:
app:
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"Plan een gerichte opschoonactie. Voer wekelijks een opschoonactie uit, beperkt tot zwevende images en oude build-cache. Gebruik nooit -a of --volumes in een geplande taak, omdat een taak die wordt uitgevoerd terwijl een stack offline is, de images van die stack zal verwijderen, en met --volumes begint het proces direct met uw data.
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-pruneDe laatste regel voert het script eenmalig handmatig uit, zodat u de output ziet voordat het onbeheerd draait. Het bestand moet uitvoerbaar zijn en de naam mag geen punt bevatten, omdat run-parts alles overslaat wat niet uitvoerbaar is of een extensie heeft.
Stel een alarm in voor vrije schijfruimte. Een opschoonactie die u uitvoert nadat de schijf vol is, is herstel. Een waarschuwing bij 80 procent is preventie.
usage=$(df --output=pcent / | tr -dc '0-9')
[ "$usage" -ge 80 ] && echo "root filesystem at ${usage} percent full"Plaats dit in cron met de notificatiemethode die u al gebruikt. Vrije schijfruimte is slechts de helft van het verhaal, dus combineer het alarm met schijfgezondheidsmonitoring op uw VPS, omdat een falende schijf en een volle schijf beide uw containers stoppen, maar beide een andere oplossing vereisen.
Alles hierboven gaat uit van een standaardinstallatie met de data-root op /var/lib/docker. Als u deze heeft verplaatst met de sleutel data-root in daemon.json, vervang dan uw eigen pad in elk commando. Het correct inrichten van die structuur op een nieuwe server is onderdeel van het instellen van Docker op een VPS, en het is veel eenvoudiger om dit te bepalen voordat u 40 GB aan containers op de verkeerde partitie heeft staan.
FAQ
Verwijdert docker system prune mijn volumes?
Nee. Het standaardcommando verwijdert gestopte containers, ongebruikte netwerken, zwevende images en ongebruikte build-cache; de bevestigingsvraag toont precies deze selectie. Volumes worden pas meegenomen wanneer u --volumes toevoegt. Sinds Docker Engine 23.0 heeft deze vlag betrekking op anonieme volumes in plaats van benoemde volumes. Benoemde volumes worden verwijderd met docker volume prune -a en met docker compose down -v. Wees met deze twee commando's voorzichtig.
Waarom is mijn schijf nog steeds vol na het uitvoeren van docker prune?
Er zijn twee gebruikelijke oorzaken. De eerste zijn container-logbestanden onder /var/lib/docker/containers/; geen enkel prune-commando verwijdert deze en ze groeien onbeperkt totdat u max-size instelt. De tweede oorzaak is een verwijderd bestand dat nog door een proces open wordt gehouden: als u een logbestand verwijderde met rm terwijl de container draaide, behoudt de daemon de file descriptor en geeft de kernel de blokken niet vrij, waardoor df geen verandering rapporteert. Vergelijk sudo du -xh --max-depth=1 /var/lib/docker met docker system df om te zien met welke situatie u te maken heeft.
Wat is het verschil tussen docker image prune en docker image prune -a?
Het standaardcommando verwijdert alleen zwevende images, oftewel images die hun tag zijn verloren, meestal door een nieuwe build. De vorm -a verwijdert elke image waarnaar geen bestaande container verwijst, inclusief getagde images die u bewust heeft binnengehaald. Na een docker compose down zijn de containers weg, dus -a zal de images van die stack meenemen. Niets is permanent verloren, omdat de volgende start ze opnieuw ophaalt of bouwt, maar op een trage verbinding duurt dit lang.
Hoe voorkom ik dat Docker-logs de schijf vullen?
Stel max-size en max-file in onder log-opts in /etc/docker/daemon.json en herstart daarna de daemon met sudo systemctl restart docker. De instelling is alleen van toepassing op containers die na die herstart zijn aangemaakt; maak de draaiende containers daarom opnieuw aan met docker compose up -d --force-recreate. U kunt dezelfde twee opties per service instellen in een compose-bestand onder een logging-sleutel; dit is de juiste methode wanneer één service aanzienlijk meer logt dan de rest.
Is het veilig om docker system prune in een cron-job uit te voeren?
Het standaardcommando docker system prune -f is veilig op een host waar elke stack actief blijft, maar het verwijdert gestopte containers. Hierdoor verwijdert het ook een container die u bewust heeft gestopt en later weer wilde opstarten. Een veiligere geplande taak is docker image prune -f plus docker builder prune -f --filter until=168h; dit maakt de twee categorieën vrij die het snelst groeien en kan geen volumes raken. Plan nooit -a of --volumes in.