consigli-software software

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 --volumes per 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 -a e --volumes se 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