Docker è fantastico, ma occhio allo spazio!
Docker ha rivoluzionato il modo di sviluppare e distribuire applicazioni, ammetto che da quando abbiamo iniziato ad utilizzarlo non ne facciamo più a meno. Grazie ai container, possiamo impacchettare tutto il necessario e far girare servizi ovunque in modo consistente. Tuttavia, Docker tende a divorare spazio su disco con il passare del tempo se non ce ne prendiamo cura. Immagini di container, livelli di cache e volumi orfani possono accumularsi silenziosamente, occupando decine di gigabyte di storage.
La mia esperienza con il “disco divorato”
Confesso che mi è successo 😅: un bel giorno, agli inizi, il mio SSD era misteriosamente pieno. Dopo qualche indagine ho scoperto il colpevole: Docker aveva lasciato in giro decine di immagini inutilizzate e container fermi che non avevo mai ripulito. Lo stesso tipo di problema l’ho riscontrato nelle pipeline CI/CD: build dopo build, senza una strategia di pulizia, il server di CI finiva per saturare lo spazio a disposizione.
Qualche soluzione pratica
Prima di tutto fatevi una panoramica attuale del disco, un bel docker system df vi darà un’idea della vostra situazione attuale:
❯ docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 21 19 9.32GB 756.7MB (8%)
Containers 53 0 361.2MB 361.2MB (100%)
Local Volumes 76 31 12.09GB 4.073GB (33%)
Build Cache 40 0 12.92kB 12.92kB
Qui potrete capire subito la situazione attuale, fortunatamente Docker fornisce comandi per tenere sotto controllo l’utilizzo del disco. Ecco alcune pratiche utili per evitare accumuli di dati inutilizzati:
- Rimuovere le immagini non utilizzate: Il comando docker image prune elimina le immagini inutilizzate. Di default rimuove solo quelle dangling (immagini senza tag e non referenziate da alcun container). Con l’opzione -a estende la pulizia a tutte le immagini non usate da almeno un container. Possiamo anche filtrare per data, ad esempio –filter “until=24h” per considerare solo immagini più vecchie di 24
- Eliminare container e volumi fermi: I container stoppati occupano ancora spazio (i layer scrivibili restano su disco finché non li rimuovi). Per pulire rapidamente, docker container prune cancella tutti i container terminati. Allo stesso modo docker volume prune elimina i volumi non utilizzati da alcun container attivo. (Docker non rimuove mai automaticamente i volumi, per evitare di cancellare dati importanti).
- Pulire la cache di build Docker: La cache di build è un’arma a doppio taglio: velocizza i build, ma col tempo può accumulare molti dati (anche diversi gigabyte). Per recuperare spazio c’è docker builder prune, che rimuove la cache di build non più in uso. Questo comando è un salvavita dopo tante build frequenti!
- Usare la “scopa” generale se serve: In situazioni drastiche puoi utilizzare docker system prune per ripulire in un colpo solo immagini, container e network inutilizzati. Aggiungendo anche –volumes estendi la pulizia ai volumi orfani. NB: questo comando è molto aggressivo (rimuove tutto ciò che non è attualmente in uso), quindi usalo con cautela e magari dopo aver verificato in anticipo cosa verrà eliminato con docker system df o con i comandi di prune specifici.
- Automatizzare la manutenzione periodica: L’ideale è non doversi ricordare di pulire a mano. Puoi schedulare uno script periodico sulla tua macchina di sviluppo, oppure inserire uno stage dedicato di cleanup nelle pipeline CI/CD dopo i build. In questo modo Docker farà le “pulizie di casa” da solo, regolarmente, evitandoti brutte sorprese.
Dove si nasconde il pericolo?
Il pericolo fondamentale è dovuto alla rimozione dei contenitori o volumi non in esecuzione, fermi, e se usate docker come sistema di sviluppo, questo potrebbe essere la normalità, quando si sviluppa, magari si tiene attivo solo il progetto corrente e spenti gli altri. Ecco un esempio molto pericoloso in questo scenario potrebbe essere:
docker system prune -a --volumes
Perché è pericoloso?
docker system prune di base pulisce:
- container fermi
- immagini dangling (senza tag)
- network non usati
- build cache
Con -a (alias --all) e –volumes estende:
- Rimuove tutte le immagini non in uso da un container attivo.
- Elimina volumi non montati da container attivi (magari contenenti dati importanti come database o storage persistente).
⚠️ Se il tuo container è stoppato (non running), Docker considera le sue immagini “non in uso” e te le butta via. Alla prossima ripartenza ti toccherà ribuildare o ripullare tutto.
Rischio concreto:
Immagina:
- Progetto con database PostgreSQL in volume stoppato per 2 giorni.
- Fai un innocente
docker system prune -a --volumesper pulire un po’… - Addio database.
Esempi di ottimizzazione
Questo è uno esempio di script che potresti schedulare nella tua macchina:
#!/bin/bash
# Script per pulire la cache di build Docker più vecchia di 1 giorno
# Pulisce la cache di build non utilizzata da almeno 24 ore
docker builder prune --filter "until=24h" --force
# Pulisce immagini non utilizzate da almeno 24 ore
docker image prune --all --filter "until=24h" --force
Se parliamo invece di CI, ad esempio, ecco uno snippet reale (Groovy per Jenkins) di uno stage CI che esegue la pulizia automatica delle immagini e della cache di build più vecchie di 4 giorni:
// Clean up docker images
stage('Cleanup images') {
steps {
script {
// Remove unused Docker images older than a week
sh """
docker image prune --all --force --filter "until=96h"
docker builder prune --filter "until=96h"
"""
}
}
}
Questi sono piccoli accorgimenti che mi hanno salvato da più di un grattacapo dovuto al disco pieno 🚀. Così posso godermi i vantaggi di Docker senza ritrovarmi l’hard disk occupato all’inverosimile.
🧠 Consiglio pratico:
- Evita
-ae--volumesse non sei sicuro. - Usa comandi più selettivi tipo:
docker container prune # Solo container fermati
docker image prune # Solo immagini dangling
docker volume prune # Solo volumi non referenziati (MA ATTENTO anche qui!)
docker builder prune # Solo cache build