IT-Admin.tech

Dépannage du stockage des conteneurs : OverlayFS, device-mapper et pièges liés au loopback

Operator analysiert ein textfreies Diagramm zu Container-Storage mit OverlayFS-Layern, device-mapper Thin-Pool und...
Das Storage-Backend entscheidet oft über Performance und „no space left“-Fehler – besonders bei OverlayFS-Layern, Thin-Pools und Loopback-Setups.

Les conteneurs ralentissent rarement « à cause de Docker lui‑même » ou deviennent instables — dans de nombreux cas, c’est la configuration de stockage sous‑jacente qui en est la véritable cause. Ce dépannage du stockage des conteneurs se concentre sur trois domaines classiques en exploitation : OverlayFS (généralement utilisé sous overlay2), device-mapper (devicemapper/thin provisioning) et les configurations particulièrement sournoises en loopback. L’objectif est un runbook que vous pouvez utiliser même sous pression : classer les symptômes, circonscrire les causes, vérifier par des étapes d’audit fiables et appliquer les modifications en prévoyant une voie de retour.

Important : de nombreux problèmes de stockage se manifestent d’abord comme des « erreurs applicatives » (timeouts, erreurs 500, build qui échoue), alors qu’il s’agit en réalité de latence I/O, de goulets d’étranglement sur les métadonnées ou d’une combinaison pilote/système de fichiers défectueuse. Qui sépare proprement ces niveaux gagne des heures lors des appels d’incident.

Comment fonctionne le stockage des conteneurs en interne (aperçu pour le dépannage)

Les moteurs de conteneurs comme Docker stockent les images et les couches d’écriture des conteneurs dans un Storage-Backend. Le Storage-Driver détermine la manière dont les « Layer » (couches d’image en lecture seule) et la couche d’écriture du conteneur sont réalisées. Sur Linux le overlay2 (OverlayFS) est aujourd’hui le standard ; les environnements plus anciens utilisent parfois le devicemapper. On trouve en complément des Volumes (données persistantes, généralement sous forme de chemin hôte ou via des plugins de volume), indépendants du mécanisme de layering des images.

Pour le dépannage, la distinction est centrale :

  • Couches image/conteneur (Storage-Driver) : builds, pull/push, temps de démarrage, « copy-on-write ».
  • Volumes/Bind-Mounts : bases de données, uploads, files d’attente, répertoires de logs — souvent le point chaud de performance.
  • Système de fichiers & périphérique bloc : XFS/ext4, LVM, RAID, SAN, virtio, NVMe — c’est là que naissent les pics de latence et les limites liées aux métadonnées.

Symptômes : comment détecter tôt les problèmes de stockage

Les signaux d’alerte typiques en exploitation de conteneurs sont étonnamment répétables. Surveillez particulièrement ces schémas :

  • « no space left on device », alors que df -h affiche encore de l’espace (souvent inodes, Thin-Pool plein, ou métadonnées Overlay).
  • Builds extrêmement lents avec de nombreux petits fichiers (opérations sur les métadonnées, coûts de copy-up avec OverlayFS).
  • Démarrage des conteneurs retardé ou blocages lors d’étapes d’initialisation intensives en I/O.
  • iowait élevé sur l’hôte, accompagné de timeouts dans les applications.
  • Erreurs peu explicites dans le journal du daemon Docker autour des mounts, « failed to mount overlay », « Invalid argument ».
  • Baisse de performance soudaine après une mise à jour du noyau ou de la distribution, ou une migration de système de fichiers (p. ex. options XFS, d_type/ftype).

Première évaluation : quelle configuration de stockage est en place ?

Graphique sans texte : chemins de données du périphérique bloc et du système de fichiers vers DockerRootDir et les drivers de stockage overlay2 et...
Vérification rapide : où se trouvent les données Docker et quel driver y est rattaché ?

Avant de déboguer les détails, établissez une référence : le pilote de stockage, le répertoire racine, le système de fichiers, les options de montage et si des volumes ou des layers sont concernés.

Vérifier Docker-Info et les chemins

Shell
docker info --format 'Driver={{.Driver}}
DockerRootDir={{.DockerRootDir}}
BackingFilesystem={{.BackingFilesystem}}
SupportsDType={{.DriverStatus}}'

docker info | sed -n '/Storage Driver/,$p' | sed -n '1,80p'

Pourquoi cela aide : Le Storage-Driver délimite la classe de problème. DockerRootDir indique où se trouvent les données (par défaut : /var/lib/docker). Le système de fichiers sous-jacent détermine si OverlayFS fonctionne correctement.

Système de fichiers et options de montage sur DockerRootDir

Shell
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"

Interprétation : Pour OverlayFS, XFS ou ext4 sont courants. XFS doit prendre en charge d_type (chez Docker historiquement visible comme ftype=1). Les inodes sont souvent la véritable limitation en présence de nombreux petits fichiers et de layers.

OverlayFS/overlay2 : causes fréquentes, étapes de vérification, corrections

Admin zeigt auf eine skizzierte Schichtenstruktur für OverlayFS-Layering am Arbeitsplatz.
Les problèmes d’OverlayFS surviennent souvent lors de nombreuses opérations de métadonnées et d’effets de copy-up.

OverlayFS est un mécanisme du noyau qui « superpose » deux niveaux de répertoires : une lowerdir-chaîne (image-layer, lecture seule) et un upperdir (couche d’écriture du conteneur). Lorsqu’un conteneur modifie un fichier provenant d’un layer inférieur, se produit un Copy-up : le fichier est copié dans le layer supérieur puis modifié. C’est fonctionnellement robuste, mais cela a des caractéristiques nettes en matière de performances et de métadonnées.

Piège 1 : XFS sans d_type (ftype=0) ou « Invalid argument »

Un classique : Docker démarre, mais certaines opérations provoquent des erreurs de montage ou des échecs au démarrage des conteneurs. Contexte : OverlayFS exige d_type (Directory Entry Type) pour reconnaître de manière fiable les types de fichiers. Sur XFS, c’est une option de formatage ; sur ext4, c’est généralement peu problématique en pratique.

Shell
# 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=' || true

Réalité de la correction : ftype n’est pas « basculable ». Si XFS a été formaté avec ftype=0, la seule option est de migrer vers un système de fichiers correctement formaté (par ex. un nouveau XFS avec ftype=1 ou ext4) puis de réinitialiser le Docker Data Root. Prévoyez impérativement une interruption de service et un repull des images (voir la section « Migration et stratégie de repli »).

Piège 2 : « no space left » dû à une pénurie d’inodes ou de métadonnées

Overlay2 erzeugt viele Verzeichnisse und Metadaten pro Layer. Bei CI-Workloads oder Build-Hosts ist Inode-Erschöpfung häufiger als echter Kapazitätsmangel.

Shell
DOCKER_DIR=$(docker info --format '{{.DockerRootDir}}')

df -h "$DOCKER_DIR"
df -ih "$DOCKER_DIR"

# Recherche des points chauds : où se trouvent beaucoup d'entrées ?
# (Peut prendre du temps ; exécuter si nécessaire en dehors des heures de pointe.)
sudo du -x -d 2 -h "$DOCKER_DIR" 2>/dev/null | sort -h | tail -n 30

Warum das scheitert: Auf manchen Filesystemen/Partitionen sind Inodes fix vorgegeben. Selbst wenn 200 GB frei sind, kann ein volles Inode-Kontingent Schreiboperationen hart blockieren. Außerdem können thin-provisioning- oder quota-Mechanismen auf VM-/SAN-Ebene ähnliche Effekte erzeugen.

Stolperfalle 3: Performance-Einbrüche durch Copy-up und „chown -R“ in Images

Viele Admins sehen das Problem zuerst in der Anwendung. Typisch ist aber ein Image/Entrypoint, der beim Start rekursiv Rechte setzt oder große Verzeichnisse verändert. Auf OverlayFS triggert das Copy-ups und Metadaten-Updates – auf vielen kleinen Dateien ist das teuer.

Prüfen Sie, ob der Hotspot in der Container-Schicht liegt oder in Volumes. Ein schneller Indikator ist die I/O-Last beim Start und ob die Pfade innerhalb von Bind-Mounts liegen. In produktiven Setups gilt: Datenverzeichnisse (z. B. Datenbanken) gehören in Volumes, nicht in die Container-Schreibschicht.

OverlayFS-Checks, die im Incident wirklich helfen

Shell
# Visibilité du kernel et d'OverlayFS
uname -r
lsmod | grep -i overlay || true

# Logs du daemon Docker (systemd)
sudo journalctl -u docker --since "-2h" | tail -n 200

# Mounts actifs : les mounts overlay montrent lowerdir/upperdir/workdir
mount | grep -E ' type overlay ' | head -n 20

Interpretation: Häufig sehen Sie hier direkt „failed to mount overlay“ oder Kernel-Fehler, die auf inkompatible Optionen, zu lange lowerdir-Ketten (selten heute) oder beschädigte Metadaten hindeuten. Wenn Mounts massiv zunehmen, lohnt auch ein Blick auf Container-Leaks (Container werden nicht entfernt, temporäre Builder laufen voll).

device-mapper/devicemapper: Thin-Pool, Metadaten und Betriebsfallen

Graphique sans texte d'un Thin-Pool device-mapper avec zones séparées pour données et métadonnées.
Avec devicemapper, les métadonnées sont aussi critiques que la capacité.

device-mapper ist ein Linux-Kernel-Subsystem, das Blockdevices virtualisiert. Im Docker-Kontext ist devicemapper meist als thin provisioning implementiert: Daten und Metadaten werden in einem Thin-Pool verwaltet. Das kann stabil laufen, ist aber empfindlich gegenüber falscher Provisionierung (Pool/Meta voll), Monitoring-Lücken und – ganz besonders – loopback-Setups.

Wichtig: Loopback bei devicemapper ist fast immer ein Anti-Pattern

Avec loopback, des « périphériques de bloc virtuels » existent sous forme de fichiers sur un système de fichiers. Devicemapper est ensuite appliqué par-dessus. Cela ajoute de la latence, des effets de cache et des modes de défaillance. C’est acceptable en tests, mais en exploitation continue c’est souvent une cause de problèmes de performance, de pics d’I/O et d’erreurs « Device is busy » difficiles à expliquer.

Lire le statut devicemapper depuis Docker

Shell
docker info | sed -n '/Storage Driver: devicemapper/,$p' | sed -n '1,120p'

Surveillez ici des termes tels que Pool Name, Data file/Metadata file (indice de loopback) ainsi que Deferred Removal/Deferred Deletion.

Vérifier le taux de remplissage du Thin Pool et les métadonnées (lvs)

Si devicemapper fonctionne sur LVM (fréquent), les LVM-Thin-Pools en sont le cœur. Important n’est pas seulement la part de données, mais aussi les métadonnées (tables de mapping). Métadonnées pleines signifie : arrêt des écritures, souvent de façon abrupte.

Shell
# Übersicht über LVM Thin Pools und deren Auslastung
sudo lvs -a -o +devices,lv_size,data_percent,metadata_percent,segtype,lv_attr,origin,pool_lv

Interprétation : data_percent proche de 100% est critique. metadata_percent proche de 100% est souvent encore plus critique, car alors même de « petites » modifications échouent. Prévoyez du monitoring/alerting sur les deux valeurs.

Vérifier directement via dmsetup (si les infos LVM ne suffisent pas)

Shell
sudo dmsetup status
sudo dmsetup ls --tree

Pourquoi c’est utile : dmsetup montre aussi des états invisibles depuis Docker (p. ex. l’engorgement de deferred deletion). Avec un fort churn de conteneurs, le « deferred deletion » peut donner l’illusion que l’espace ne se libère jamais.

Scénarios d’erreur typiques avec devicemapper

  • Pool/Meta plein : les conteneurs ne démarrent pas, les pulls échouent, « no space left » alors que la partition hôte est libre.
  • Latence du loopback : timeouts sporadiques, iowait élevé, particulièrement lors de builds parallèles.
  • Inattendu « Device is busy » : les opérations de nettoyage sont bloquées parce que des devices sont encore référencés.

Identifier et évaluer spécifiquement les écueils du loopback

Loopback n’est pas seulement « plus lent » — il change aussi la façon de diagnostiquer les erreurs. Vous vous retrouvez alors avec deux niveaux susceptibles d’être à court d’espace : le système de fichiers qui contient les fichiers loopback, et le Thin-Pool au-dessus. Par ailleurs, la fragmentation et le journal du système de fichiers peuvent augmenter la latence.

Est-ce vraiment du loopback ?

Shell
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'

Interprétation : Si vous voyez de nombreux /dev/loop* et que Docker utilise devicemapper, il est très probable que loopback soit en jeu. Avec overlay2, loopback est généralement non pertinent (sauf si vous exécutez Docker sur une couche sous-jacente basée sur loopback, p. ex. des environnements de laboratoire emboîtés).

Décision : mesure immédiate vs correction durable

En incident, l’objectif est souvent la stabilisation : réduire la pression sur le système avant de migrer. De manière durable, la solution est presque toujours : supprimer loopback, standardiser le Storage-Driver et placer les données Docker sur un blockdevice approprié.

Runbook : séquence d’étapes pour un dépannage reproductible du stockage de conteneurs

La séquence de vérifications suivante est conçue pour vous permettre de décider rapidement si vous avez affaire à du nettoyage, à de la capacité ou à une migration structurelle.

1) Scope klären: Layer-Storage oder Volume-Storage?

Shell
# Quels conteneurs écrivent le plus ? (indicateur grossier, pas directement visible via log/IO)
# Aide à identifier les candidats.
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 .

Warum das hilft: Wenn ein Problem primär in Volumes liegt (z. B. NFS, CIFS/SMB, iSCSI), bringt Storage-Driver-Tuning wenig. Umgekehrt sind « image-pull lent » oder « build bloqué » oft Layer-Storage-Themen.

2) Host-Kapazität, Inodes, Top-Verursacher

Shell
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 -h

3) Docker-Objekte: Wie viel ist wirklich belegbar?

Shell
docker system df
docker system df -v | sed -n '1,200p'

Interpretation: Hohe « Reclaimable »-Anteile deuten auf Cleanup-Potenzial. Achtung: « Reclaimable » ist nicht gleich « gefahrlos ». Löschen kann Build-Caches entfernen und Pull-Last erhöhen.

4) Safe Cleanup (mit klaren Grenzen)

Wenn Sie Speicher kurzfristig freigeben müssen, beginnen Sie konservativ. Planen Sie dabei, dass laufende Container nicht entfernt werden, aber ungenutzte Ressourcen schon.

Shell
# Supprimer les images inutilisées, Container (stopped), Netzwerke, Build-Cache
# Prudence en CI-Umgebungen: la perte du cache de build peut ralentir les builds.
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 prune

Warum das funktioniert: Viele « vollgelaufene » Hosts sind schlicht Ergebnis fehlender Lifecycle-Regeln. Wann es scheitert: Wenn der Engpass nicht Kapazität ist, sondern Inodes, Thin-Pool-Metadaten oder I/O-Latenz. Oder wenn Platz wegen deferred deletion nicht sofort frei wird (devicemapper).

5) I/O-Latenz sichtbar machen (Host-Perspektive)

Für Storage-Probleme ist nicht nur « %util » relevant, sondern vor allem Latenz. Je nach Distribution stehen unterschiedliche Tools bereit; iostat ist oft schnell verfügbar.

Shell
# 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 10

Interpretation: Hohe await oder svctm (je nach Version) und dauerhaft hohe Auslastung deuten auf Blockdevice-Engpässe hin. Dann sind Cleanup-Maßnahmen oft nur Symptombekämpfung.

Migration: Storage-Driver wechseln oder DockerRootDir verlagern (mit Rückfallstrategie)

Wenn die Diagnose klar ist (z. B. devicemapper loopback im Dauerbetrieb, XFS ohne ftype, dauerhaft zu wenig IOPS), ist eine strukturelle Änderung sauberer als « mehr Platz ». Für Betreiber ist wichtig: Ein Storage-Driver-Wechsel bedeutet in der Regel, dass bestehende lokale Images/Layer im DockerRootDir neu aufgebaut werden müssen. Persistente Daten müssen ohnehin in Volumes liegen; alles andere ist ersetzbar.

Vorbereitung: Was muss gesichert werden?

  • Compose-/Stack-Definitionen, systemd-Units, Environment-Dateien: damit Sie Container reproduzierbar starten.
  • Registry-Zugriffe (identifiants, miroirs): damit ein Repull funktioniert.
  • Volumes: selon la mise en œuvre, ils se trouvent sous DockerRootDir ou en tant que montages séparés. Vérifiez l’emplacement réel.
  • Plan d’indisponibilité (générique, sans orchestrateur)

    Shell
    # 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)

    Pourquoi un backup tar comme chemin de repli ? Pas parce que vous comptez le restaurer « à chaque fois », mais parce qu’il vous offre une option si des dépendances inattendues résident dans l’ancien Root (p. ex. des images locales sans registry, des données oubliées dans la couche d’écriture). Dans des environnements plus grands, un snapshot de stockage (LVM, SAN, VM-snapshot avec prudence) est souvent plus pratique.

    Définir DockerRootDir via daemon.json

    Beaucoup d’équipes utilisent une partition dédiée pour Docker afin d’isoler clairement l’espace, les inodes et les IOPS. Cela se configure dans /etc/docker/daemon.json.

    JSON
    {
      "data-root": "/var/lib/docker",
      "storage-driver": "overlay2"
    }

    Important : Ne modifiez pas le storage-driver « à la légère » sur un hôte avec des layers locaux en production sans prévoir une reconstruction. Et : vérifiez après une migration les SELinux/contextes AppArmor et les options de montage, sinon des erreurs secondaires peuvent survenir (p. ex. Permission Denied sur des systèmes basés sur des labels).

    Bonnes pratiques pour une exploitation stable (pour éviter de vous retrouver de nouveau dans un incident)

    1) La capacité ne se limite pas aux Go : inodes, métadonnées, IOPS

    Prévoyez une surveillance sur au moins trois axes : espace occupé, utilisation des inodes et latence I/O. Les hosts de build avec de nombreux layers ont particulièrement besoin de réserves d’inodes.

    2) Placer et séparer les Volumes de manière réfléchie

    Les workloads intensifs en données (bases de données, dépôts d’artefacts, logs) ne devraient pas résider sur la couche d’écriture des conteneurs. Utilisez des Volumes ou des bind-mounts sur des systèmes de fichiers dédiés. Cela réduit le copy-up et rend les performances plus prévisibles.

    3) Définir une stratégie de nettoyage au lieu d’un « prune » manuel

    Une maintenance régulière vaut mieux que des suppressions ad hoc en cas d’incident. Définissez des règles sur la durée de conservation des caches de build, des dangling images et des anciens conteneurs sur l’hôte. Dans les environnements CI, des runners dédiés et une gestion contrôlée du cache font partie de la routine d’exploitation.

    4) Traiter les changements de noyau / système de fichiers comme des déploiements

    Une mise à jour du kernel peut modifier le comportement d’OverlayFS ; une migration de système de fichiers peut affecter d_type/options. Testez ces changements sur un hôte de staging avec des builds représentatifs et des charges I/O avant de les déployer à grande échelle.

    Conclusion : les problèmes de stockage sont rarement « mystiques », mais souvent complexes et à plusieurs niveaux

    OverlayFS, device-mapper et loopback semblent être des détails internes au quotidien – lors d’un incident, ils déterminent cependant la stabilité, les performances et la rapidité de votre récupération. Un dépannage du stockage de conteneurs rigoureux commence par une baseline claire (Driver, Filesystem, DockerRootDir), sépare les problèmes de couche des problèmes de volume et vérifie systématiquement les inodes, les métadonnées du thin pool et la latence I/O. Si loopback ou un système de fichiers inadapté est la cause, une migration planifiée est généralement préférable à un « nettoyage » permanent sous pression.

    Si vous souhaitez standardiser le sujet dans votre environnement, rédigez un court runbook avec une séquence de vérification, des seuils et une procédure de repli testée – ainsi, le prochain incident de stockage deviendra une opération de maintenance maîtrisée.

    Pour ce sujet, Overlayfs Docker et Device-Mapper Docker sont également importants. L’article met ces aspects en perspective de manière claire et montre ce qui compte au quotidien.