I container raramente sono lenti o instabili a causa di “Docker in sé” – molto spesso la vera causa è il setup di storage sottostante. Questo troubleshooting dello storage per container si concentra su tre aree classiche di problemi in esercizio: OverlayFS (di solito usato come overlay2), device-mapper (devicemapper/thin provisioning) e le particolarmente insidiose configurazioni loopback. L’obiettivo è un runbook che possiate usare anche sotto pressione: classificare i sintomi, restringere le cause, verificarle con passaggi di controllo affidabili e applicare modifiche mantenendo un percorso di rollback.
Importante: molti problemi di storage inizialmente sembrano “errori dell’app” (timeout, 500, build che fallisce), ma in realtà sono latenza I/O, colli di bottiglia sui metadati o una combinazione errata di driver/filesystem. Separare chiaramente questi ambiti fa risparmiare ore nelle call di incident.
Come funziona internamente lo storage dei container (breve panoramica per il troubleshooting)
I motori per container come Docker memorizzano le immagini e i layer di scrittura dei container in un storage backend. Il storage driver decide come vengono implementati i “layer” (strati immagine di sola lettura) e lo strato scrivibile del container. In Linux overlay2 (OverlayFS) è oggi lo standard; setup più datati usano talvolta devicemapper. In aggiunta esistono i Volumes (dati persistenti, di solito come percorso host o tramite plugin di volume), che sono indipendenti dal layer delle immagini.
Per il troubleshooting è centrale la distinzione:
- Image-/Container-Layer (storage driver): build, pull/push, tempi di avvio, “copy-on-write”.
- Volumes/Bind-Mounts: database, upload, code di messaggi, directory di log – spesso il punto caldo delle prestazioni.
- Filesystem & Blockdevice: XFS/ext4, LVM, RAID, SAN, virtio, NVMe – qui emergono picchi di latenza e limiti sui metadati.
Sintomi: Come riconoscere precocemente problemi di storage
I segnali tipici in esercizio sono sorprendentemente ricorrenti. Prestate particolare attenzione a questi pattern:
- “no space left on device”, anche se df -h mostra ancora spazio (spesso inode esauriti, thin-pool pieno o metadati di Overlay pieni).
- Build estremamente lenti con molti file piccoli (operazioni sui metadati, costi di copy-up con OverlayFS).
- Avvio dei container ritardato o blocchi durante fasi di inizializzazione intensive in I/O.
- Elevata iowait sull’host, accompagnata da timeout nelle applicazioni.
- Errori poco chiari nei log del Docker daemon relativi a mount, “failed to mount overlay”, “Invalid argument”.
- Improvviso calo di prestazioni dopo upgrade del kernel/distribuzione o migrazione del filesystem (es. opzioni XFS, d_type/ftype).
Prima valutazione: quale configurazione di storage è in uso?
Prima di eseguire il debug dei dettagli, stabilite una baseline: driver di storage, Root-Dir, filesystem, opzioni di mount e se sono interessati volumi o layer.
Controllare Docker-Info e i percorsi
docker info --format 'Driver={{.Driver}}
DockerRootDir={{.DockerRootDir}}
BackingFilesystem={{.BackingFilesystem}}
SupportsDType={{.DriverStatus}}'
docker info | sed -n '/Storage Driver/,$p' | sed -n '1,80p'Perché questo aiuta: Il driver di storage delimita la classe di problemi. DockerRootDir mostra dove risiedono i dati (predefinito: /var/lib/docker). Il filesystem sottostante determina se OverlayFS funziona correttamente.
Filesystem e opzioni di mount su DockerRootDir
DOCKER_DIR=$(docker info --format '{{.DockerRootDir}}')
df -Th "$DOCKER_DIR"
findmnt -no SOURCE,FSTYPE,OPTIONS -T "$DOCKER_DIR"
# Inodes: wichtig bei "no space left" trotz freiem Speicher
df -ih "$DOCKER_DIR"Interpretazione: Con OverlayFS sono comuni XFS o ext4. XFS deve supportare d_type (storicamente visibile in Docker come ftype=1). Gli inode sono spesso il vero collo di bottiglia in presenza di molti file piccoli e layer.
OverlayFS/overlay2: cause comuni, passaggi di verifica, rimedi
OverlayFS è un meccanismo del kernel che „sovrappone“ due livelli di directory: una catena lowerdir (image layer, sola lettura) e un upperdir (strato di scrittura del container). Quando un container modifica un file proveniente da un layer inferiore avviene un Copy-up: il file viene copiato nel layer superiore e lì modificato. Questo è funzionalmente robusto, ma presenta chiare caratteristiche in termini di performance e metadati.
Insidia 1: XFS senza d_type (ftype=0) o «Invalid argument»
Un classico: Docker si avvia, ma in alcune operazioni compaiono errori di mount o il lancio dei container fallisce. Motivo: OverlayFS richiede d_type (Directory Entry Type) per riconoscere in modo affidabile i tipi di file. Su XFS è un’opzione di formattazione; su ext4 nella pratica è per lo più irrilevante.
# Nur sinnvoll, wenn das Backing-FS XFS ist:
# Ausgabe: ftype=1 ist gut; ftype=0 ist problematisch.
XFS_DEV=$(findmnt -no SOURCE -T "$(docker info --format '{{.DockerRootDir}}')")
# xfs_info erwartet das Blockdevice oder den Mountpoint
xfs_info "$(findmnt -no TARGET -T "$(docker info --format '{{.DockerRootDir}}')")" | tr ' ' 'n' | grep -E '^ftype=' || trueRealità delle correzioni: ftype non è modificabile. Se XFS è stato formattato con ftype=0, l’unica opzione è migrare su un filesystem formattato correttamente (per es. un nuovo XFS con ftype=1 o ext4) e quindi ricreare il Docker data root. Pianificate obbligatoriamente downtime e un repull delle immagini (vedere la sezione «Migrazione e strategia di rollback»).
Problema 2: «no space left» causato da esaurimento di inode o colli di bottiglia sui metadati
Overlay2 crea molte directory e metadati per layer. Nei carichi CI o sugli host di build l’esaurimento degli inode è più frequente della reale carenza di capacità.
DOCKER_DIR=$(docker info --format '{{.DockerRootDir}}')
df -h "$DOCKER_DIR"
df -ih "$DOCKER_DIR"
# Hotspot-Suche: wo liegen besonders viele Einträge?
# (Kann dauern, bei Bedarf außerhalb der Peak-Zeit laufen lassen.)
sudo du -x -d 2 -h "$DOCKER_DIR" 2>/dev/null | sort -h | tail -n 30Perché fallisce: Su alcuni file system/partizioni gli inode sono assegnati in modo fisso. Anche se ci sono 200 GB liberi, un contingente inode esaurito può bloccare rigidamente le operazioni di scrittura. Inoltre, meccanismi di thin provisioning o di quota a livello VM/SAN possono generare effetti analoghi.
Trappola 3: cali di prestazioni dovuti a copy-up e „chown -R“ nelle immagini
Molti amministratori individuano inizialmente il problema nell’applicazione. Tipico è però un’immagine/entrypoint che all’avvio imposta ricorsivamente i permessi o modifica grandi directory. Su OverlayFS questo attiva copy-up e aggiornamenti dei metadati — su molte piccole file è costoso.
Verifichi se l’hotspot si trova nello strato del container o nei volumi. Un indicatore rapido è il carico I/O all’avvio e se i percorsi si trovano all’interno di bind-mount. Negli ambienti produttivi vale: le directory dati (p.es. database) devono stare nei volumi, non nello strato di scrittura del container.
Controlli di OverlayFS che aiutano realmente durante un incidente
# Kernel- und OverlayFS-Sichtbarkeit
uname -r
lsmod | grep -i overlay || true
# Docker-Daemon-Logs (systemd)
sudo journalctl -u docker --since "-2h" | tail -n 200
# Aktive Mounts: Overlay-Mounts zeigen lowerdir/upperdir/workdir
mount | grep -E ' type overlay ' | head -n 20Interpretazione: Spesso vedrete direttamente „failed to mount overlay“ o errori del kernel che indicano opzioni incompatibili, catene lowerdir troppo lunghe (oggi raro) o metadati danneggiati. Se i mount aumentano massicciamente, vale anche la pena esaminare i container leak (container che non vengono rimossi, builder temporanei che si saturano).
device-mapper/devicemapper: Thin-Pool, metadati e insidie operative
device-mapper è un Linux-sottosistema del kernel che virtualizza i block device. Nel contesto Docker devicemapper è spesso implementato come thin provisioning: dati e metadati sono gestiti in un Thin-Pool. Questo può funzionare in modo stabile, ma è sensibile a una errata provisioning (Pool/Meta pieni), a lacune nel monitoring e — soprattutto — a configurazioni in loopback.
Importante: il loopback con devicemapper è quasi sempre un Anti-Pattern
Con loopback i „virtuale Blockdevices“ risiedono come file su un filesystem. Su questi viene poi costruito devicemapper. Questo aggiunge latenza, effetti di cache e modalità di guasto. È accettabile nei test, ma in esercizio continuo è una causa frequente di problemi di prestazioni, spike di I/O e difficilmente spiegabili errori „Device is busy“.
Leggere lo stato di devicemapper da Docker
docker info | sed -n '/Storage Driver: devicemapper/,$p' | sed -n '1,120p'Prestate attenzione qui a termini come Pool Name, Data file/Metadata file (indicazione di loopback) nonché Deferred Removal/Deferred Deletion.
Controllare il riempimento del thin pool e i metadati (lvs)
Se devicemapper gira su LVM (frequente), i LVM-Thin-Pools sono il nucleo. Importante non è solo la parte dati, ma anche i metadati (tabelle di mapping). Metadati pieni significa: stop alle scritture, spesso in modo improvviso.
# Übersicht über LVM Thin Pools und deren Auslastung
sudo lvs -a -o +devices,lv_size,data_percent,metadata_percent,segtype,lv_attr,origin,pool_lvInterpretazione: data_percent vicino al 100% è critico. metadata_percent vicino al 100% è spesso ancora più critico, perché anche modifiche «apparentemente piccole» falliscono. Pianificate monitoring/alert per entrambi i valori.
Verificare direttamente con dmsetup (se le informazioni LVM non sono sufficienti)
sudo dmsetup status
sudo dmsetup ls --treePerché aiuta: dmsetup mostra anche stati che non sono visibili in Docker (p.es. accumulo di deferred deletion). Con un elevato churn di container, la „deferred deletion“ può dare l’illusione che lo spazio non venga mai liberato.
Tipici scenari di errore con devicemapper
- Pool/Meta pieni: i container non si avviano, i pull falliscono, „no space left“ nonostante la partizione host libera.
- Latenza da loopback: timeout sporadici, alto iowait, specialmente durante build paralleli.
- Inaspettato „Device is busy“: le operazioni di pulizia si bloccano quando i device sono ancora referenziati.
Rilevare e valutare i rischi specifici del loopback
Il loopback non è solo „più lento“ – altera anche la diagnosi degli errori. Si creano due livelli in cui lo spazio può scarseggiare: il filesystem che contiene i file di loopback e il thin pool sovrastante. Inoltre, frammentazione e journaling del filesystem possono aumentare la latenza.
È davvero loopback?
docker info | sed -n '/Storage Driver/,$p' | sed -n '1,160p'
# Loop-Devices auf dem Host sichtbar?
losetup -a || true
lsblk -o NAME,TYPE,SIZE,FSTYPE,MOUNTPOINTS | sed -n '1,120p'Interpretazione: Se vedete molti /dev/loop* e Docker usa devicemapper, la probabilità che sia coinvolto loopback è alta. Con overlay2 il loopback di norma non è rilevante (a meno che non eseguiate Docker su un sottostante basato su loopback, p.es. setup di laboratorio annidati).
Decisione: misura immediata vs correzione duratura
In un incidente l’obiettivo è spesso stabilizzare: alleggerire la pressione sul sistema prima di migrare. A lungo termine quasi sempre la soluzione è: eliminare il loopback, standardizzare il storage driver e collocare i dati Docker su un block device adeguato.
Runbook: sequenza di passaggi per un troubleshooting riproducibile dello storage dei container
La seguente sequenza di controlli è strutturata in modo da permettervi di decidere rapidamente se si tratta di cleanup, capacità oppure di una migrazione strutturale.
1) Chiarire l’ambito: Layer-Storage oder Volume-Storage?
# Welche Container schreiben besonders viel? (Grobindikator über Log/IO nicht direkt sichtbar)
# Hilft, Kandidaten zu identifizieren.
docker ps --format 'table {{.Names}}t{{.Image}}t{{.Status}}'
# Volumes und Mounts eines auffälligen Containers anzeigen
C=<container_name_or_id>
docker inspect "$C" --format '{{json .Mounts}}' | jq .Perché questo aiuta: Se un problema è principalmente nei volumi (ad es. NFS, CIFS/SMB, iSCSI), la messa a punto del driver di storage offre poco vantaggio. Viceversa, „pull dell’immagine lento“ o „build bloccato“ sono spesso questioni relative al Layer-Storage.
2) Capacità dell’host, Inodes, principali responsabili
DOCKER_DIR=$(docker info --format '{{.DockerRootDir}}')
df -Th "$DOCKER_DIR"
df -ih "$DOCKER_DIR"
# Größte Docker-Verzeichnisse
sudo du -x -d 1 -h "$DOCKER_DIR" 2>/dev/null | sort -h3) Docker-Objekte: Wie viel ist wirklich belegbar?
docker system df
docker system df -v | sed -n '1,200p'Interpretazione: Alti valori etichettati come „Reclaimable“ indicano potenziale per la pulizia. Attenzione: „Reclaimable“ non equivale a „sicuro da eliminare“. La cancellazione può rimuovere cache di build e aumentare il carico di pull.
4) Safe Cleanup (mit klaren Grenzen)
Se è necessario liberare spazio a breve termine, procedete in modo conservativo. Considerate che i container in esecuzione non verranno rimossi, mentre le risorse non utilizzate sì.
# Unbenutzte Images, Container (stopped), Netzwerke, Build-Cache entfernen
# Vorsicht in CI-Umgebungen: Build-Cache-Verlust kann Builds verlangsamen.
docker system prune
# Aggressiver: auch unbenutzte Images entfernen
docker system prune -a
# Volumes nur entfernen, wenn Sie absolut sicher sind
docker volume ls
# docker volume prunePerché funziona: Molti host „pieni“ sono semplicemente il risultato dell’assenza di regole di lifecycle. Quando fallisce: Se il collo di bottiglia non è la capacità, ma gli inode, i metadati del thin-pool o la latenza I/O. Oppure se lo spazio non viene liberato immediatamente a causa della cancellazione differita (devicemapper).
5) I/O-Latenz sichtbar machen (Host-Perspektive)
Per i problemi di storage non è rilevante solo „%util“, ma soprattutto la latenza. A seconda della distribuzione sono disponibili strumenti diversi; iostat è spesso rapidamente disponibile.
# Pakete ggf. installieren: sysstat
# sudo apt-get install -y sysstat | sudo yum install -y sysstat
iostat -x 1 10
# Grobe Prozesssicht, um I/O-Wait zu erkennen
vmstat 1 10Interpretazione: Alti valori di await o svctm (a seconda della versione) e un utilizzo costantemente elevato indicano colli di bottiglia a livello di block device. In questi casi le misure di pulizia sono spesso solo un palliativo.
Migration: Storage-Driver wechseln oder DockerRootDir verlagern (mit Rückfallstrategie)
Se la diagnosi è chiara (ad es. devicemapper loopback in funzione permanente, XFS senza ftype, IOPS permanentemente insufficienti), una modifica strutturale è più pulita rispetto a „più spazio“. Per gli operatori è importante: un cambio del storage driver di norma comporta che le immagini/layer locali esistenti nel DockerRootDir debbano essere ricostruiti. I dati persistenti devono comunque risiedere nei volumi; tutto il resto è sostituibile.
Vorbereitung: Was muss gesichert werden?
- Definizioni Compose/Stack, unità systemd, file environment: in modo da poter avviare i container in modo riproducibile.
- Accessi alla registry (credenziali, mirror): affinché un repull funzioni.
- Volumi: a seconda dell’implementazione si trovano sotto DockerRootDir o come mount separati. Verifichi la posizione effettiva di memorizzazione.
Piano di downtime (generico, senza orchestratore)
# 1) Laufende Container geordnet stoppen
docker ps -q | xargs -r docker stop
# 2) Docker-Dienst stoppen
sudo systemctl stop docker
# 3) Datenverzeichnis sichern (Rollback-Pfad)
DOCKER_DIR=$(docker info --format '{{.DockerRootDir}}' 2>/dev/null || echo /var/lib/docker)
# Hinweis: Bei großen Verzeichnissen dauert das. Alternativ: Snapshot auf Storage-Ebene.
sudo tar -C "$(dirname "$DOCKER_DIR")" -cpf /root/docker-rootdir-backup.tar "$(basename "$DOCKER_DIR")"
# 4) Neues Filesystem/Blockdevice mounten und als DockerRootDir konfigurieren
# (Konkrete Mount-/mkfs-Schritte sind umgebungsspezifisch.)
# 5) Docker mit neuer Konfiguration starten
sudo systemctl start docker
# 6) Images neu ziehen und Workloads starten
# docker compose up -d (falls genutzt)Perché un backup tar come percorso di rollback? Non perché vogliate ripristinarlo „sempre“, ma perché vi offre un’opzione se ci sono dipendenze inattese nel vecchio root (p.es. immagini locali senza registry, dati dimenticati nello strato di scrittura). In ambienti più grandi uno snapshot a livello storage (LVM, SAN, snapshot VM con cautela) è spesso più pratico.
Impostare DockerRootDir tramite daemon.json
Molti team usano una partizione dedicata per Docker, per isolare capacità, inode e IOPS. Questo si configura in /etc/docker/daemon.json.
{
"data-root": "/var/lib/docker",
"storage-driver": "overlay2"
}Importante: Non modifichi il storage-driver „a cuor leggero“ su un host con layer locali in produzione, senza pianificare la ricostruzione. E: dopo uno spostamento controlli i contesti SELinux/AppArmor e le opzioni di mount, altrimenti possono verificarsi errori consecutivi (p.es. Permission Denied su sistemi basati su label).
Best practice per un’operatività stabile (per evitare di ritrovarsi di nuovo in un incidente)
1) La capacità non sono solo GB: inode, metadati, IOPS
Pianifichi il monitoraggio su almeno tre assi: spazio occupato, utilizzo degli inode e latenza I/O. Soprattutto i build-host con molti layer richiedono riserve di inode.
2) Posizionare e separare i Volumi in modo consapevole
I workload intensivi di dati (database, repository di artefatti, log) non dovrebbero risiedere sul layer di scrittura del container. Utilizzi Volumi o bind-mount su filesystem progettati per questo scopo. Riduce il copy-up e rende le prestazioni più prevedibili.
3) Definire una strategia di pulizia invece del „prune“ manuale
La manutenzione regolare è preferibile rispetto a cancellazioni ad-hoc durante un incidente. Definisca regole su quanto a lungo cache di build, dangling images e container obsoleti possono rimanere sull’host. In ambienti CI la routine operativa include runner-host dedicati e un approccio controllato al caching.
4) Trattare le modifiche al kernel/filesystem come deployment
Un aggiornamento del kernel può modificare il comportamento di OverlayFS; una migrazione del filesystem può influenzare d_type/opzioni. Testi tali modifiche su un host di staging con build rappresentativi e carichi I/O prima di estenderle su più sistemi.
Conclusione: i problemi di storage raramente sono „misteriosi“, ma spesso a più livelli
OverlayFS, device-mapper e loopback nel quotidiano possono sembrare dettagli interni – in caso di incidente però determinano stabilità, prestazioni e la velocità del vostro recovery. Un accurato Container-Storage-Troubleshooting inizia con una baseline chiara (Driver, Filesystem, DockerRootDir), distingue i problemi di layer da quelli di volume e verifica in modo consequenziale inode, metadati del thin pool e latenza I/O. Se loopback o un filesystem non adatto sono la causa, una migrazione pianificata è di norma più conveniente rispetto a una „pulizia“ permanente sotto pressione.
Se volete standardizzare l’argomento nel vostro ambiente, predisponete un breve runbook con sequenza di verifiche, soglie e una procedura di rollback testata – così il prossimo incidente di storage diventerà un intervento di manutenzione controllabile.
Per questo tema sono inoltre importanti Overlayfs Docker e Device-Mapper Docker. L’articolo inquadra questi aspetti in modo comprensibile e mostra su cosa occorre concentrarsi nella pratica quotidiana.