Quand le démon Docker ne démarre pas, votre hôte devient une pièce de musée : des conteneurs figés dans le temps, des tâches CI bloquées, des déploiements qui font marche arrière, et quelqu’un qui demande « on peut juste reboot ? ». Vous pouvez redémarrer, bien sûr. Vous pouvez aussi mettre un ordinateur portable mouillé au micro-ondes. Aucun des deux n’est une stratégie.
Le chemin le plus rapide pour s’en sortir n’est pas une suite aléatoire de redémarrages. C’est une lecture propre du bon journal, suivie d’un petit nombre de commandes délibérées qui vous disent ce qui a cassé : config, stockage, fonctionnalités du noyau, règles réseau, permissions, ou containerd.
Jouer le diagnostic rapide (quoi vérifier en premier)
Si vous n’avez que cinq minutes et un pager qui vibre contre vos molaires, faites ceci dans l’ordre. L’objectif est d’identifier rapidement la classe du goulot : échec d’analyse de la config, dépendance runtime en panne, corruption/capacité du stockage, incompatibilité des fonctionnalités noyau, ou échec des règles réseau.
Premier point : systemd dit pourquoi il a refusé de garder Docker vivant
Docker est généralement géré par systemd. systemd a le premier avis qui compte : le code de sortie et stderr immédiat.
cr0x@server:~$ systemctl status docker --no-pager -l
● docker.service - Docker Application Container Engine
Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
Active: failed (Result: exit-code) since Tue 2026-01-02 10:12:54 UTC; 17s ago
Process: 1842 ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock (code=exited, status=1/FAILURE)
Main PID: 1842 (code=exited, status=1/FAILURE)
CPU: 230ms
Jan 02 10:12:54 server dockerd[1842]: failed to start daemon: error initializing graphdriver: overlay2: failed to mount /var/lib/docker/overlay2: invalid argument
Jan 02 10:12:54 server systemd[1]: docker.service: Main process exited, code=exited, status=1/FAILURE
Jan 02 10:12:54 server systemd[1]: docker.service: Failed with result 'exit-code'.
Jan 02 10:12:54 server systemd[1]: Failed to start Docker Application Container Engine.
Décision : Prenez au sérieux la première ligne failed to start daemon:. C’est généralement la classe de cause racine. Ici elle crie « overlay2 mount invalid argument » → incompatibilité noyau/système de fichiers/overlayfs, pas un « bug Docker ».
Second point : journalctl pour Docker donne la pile complète, pas seulement le titre
cr0x@server:~$ journalctl -u docker -b --no-pager -n 200
Jan 02 10:12:54 server dockerd[1842]: time="2026-01-02T10:12:54.118922635Z" level=info msg="Starting up"
Jan 02 10:12:54 server dockerd[1842]: time="2026-01-02T10:12:54.152001115Z" level=error msg="failed to mount overlay: invalid argument" storage-driver=overlay2
Jan 02 10:12:54 server dockerd[1842]: time="2026-01-02T10:12:54.152114935Z" level=fatal msg="Error starting daemon: error initializing graphdriver: overlay2: failed to mount /var/lib/docker/overlay2: invalid argument"
Décision : Si vous voyez level=fatal suivi d’un sous-système concret (graphdriver, iptables, daemon.json), arrêtez de deviner. Orientez-vous vers les vérifications de ce sous-système.
Troisième point : vérifier la capacité et le système de fichiers sous /var/lib/docker
Un disque plein et une pénurie d’inodes ne s’annoncent pas toujours poliment. Ils font simplement que les daemons se comportent comme s’ils avaient oublié comment écrire.
cr0x@server:~$ df -h /var/lib/docker
Filesystem Size Used Avail Use% Mounted on
/dev/nvme0n1p4 80G 79G 300M 100% /
cr0x@server:~$ df -i /var/lib/docker
Filesystem Inodes IUsed IFree IUse% Mounted on
/dev/nvme0n1p4 5.0M 5.0M 0 100% /
Décision : Si soit les blocs soit les inodes sont à 100%, votre « Docker ne démarre pas » est un incident de stockage. Libérez de l’espace d’abord ; ne changez pas de driver, ne réinstallez pas de paquets ni ne « réinitialisez Docker » tant que l’hôte ne peut pas écrire.
Quatrième point : valider la config du démon avant de courir après des fantômes
Une virgule finale en JSON peut faire tomber toute votre plateforme de conteneurs. J’aimerais que ce soit une blague. Ce n’est pas le cas.
cr0x@server:~$ sudo cat /etc/docker/daemon.json
{
"log-driver": "json-file",
"log-opts": { "max-size": "10m", },
"iptables": true
}
Décision : Cette virgule après "10m" empêchera dockerd de démarrer. Corrigez le JSON, puis redémarrez. Ne touchez rien d’autre.
Cinquième point : vérifier que containerd est vivant (ou confirmer qu’il ne l’est pas)
cr0x@server:~$ systemctl status containerd --no-pager -l
● containerd.service - containerd container runtime
Loaded: loaded (/lib/systemd/system/containerd.service; enabled; vendor preset: enabled)
Active: active (running) since Tue 2026-01-02 10:08:11 UTC; 6min ago
Docs: man:containerd(8)
Main PID: 1210 (containerd)
Décision : Si containerd est arrêté, Docker peut échouer avec une erreur de socket ou runtime. Réparez containerd d’abord. Si containerd est sain, poursuivez.
Le journal unique à lire d’abord (et pourquoi)
Lisez le journal systemd pour l’unité docker avant de lire quoi que ce soit d’autre. Pas parce que c’est joli, mais parce que c’est la source d’autorité. Il capture :
- Pourquoi systemd a arrêté de redémarrer le service (limites de démarrage atteintes, crash loops).
- Exactement ce que
dockerda imprimé sur stderr/stdout. - Le timing par rapport aux autres services (containerd, réseau, montages).
Sur la plupart des distributions modernes, voici la commande clé :
cr0x@server:~$ journalctl -u docker -b --no-pager -o cat
time="2026-01-02T10:12:54.118922635Z" level=info msg="Starting up"
time="2026-01-02T10:12:54.152114935Z" level=fatal msg="Error starting daemon: failed to load listeners: can't create unix socket /var/run/docker.sock: permission denied"
Décision : Cette erreur n’est pas un problème « Docker ne peut pas parler à Docker ». C’est une question de permissions/possession/SELinux/AppArmor sur le chemin du socket (ou son parent). Vous savez maintenant dans quelle classe d’échec vous êtes.
Ne commencez pas par /var/log/docker.log à moins que vous ne soyez sur un système qui y journalise explicitement. Beaucoup d’installations n’y journalisent pas. Ne commencez pas par des correctifs aléatoires trouvés sur Stack Overflow. Votre système vous a déjà dit ce qui ne va pas ; vous ne l’avez simplement pas encore écouté.
Faits et histoire intéressants (pour comprendre les erreurs)
- Docker utilisait originellement LXC (Linux Containers) pour l’isolation avant de passer à libcontainer, ce qui a changé la façon dont les fonctionnalités bas-niveau du noyau étaient consommées.
- containerd a été extrait de Docker pour que le runtime de base puisse évoluer indépendamment ; c’est pour cela qu’« Docker est down » peut en réalité signifier « containerd est down ».
- overlay2 est devenu le driver par défaut sur de nombreuses distributions parce qu’il est rapide et économe en espace, mais il est exigeant sur les fonctionnalités du système de fichiers (surtout sur les noyaux anciens).
- L’intégration d’iptables n’est pas optionnelle pour le réseau Docker classique ; quand firewalld/nftables/iptables sont en désaccord, Docker peut échouer au démarrage, pas seulement à l’exécution des conteneurs.
- L’adoption de cgroups v2 a modifié la plomberie du contrôle de ressources ; les anciennes versions de Docker sur de nouvelles distributions peuvent échouer tôt à cause de mismatches de driver cgroup.
- Les paramètres de journalisation par défaut de Docker (json-file) peuvent remplir les disques en silence ; le démon qui ne démarre plus après un événement disque plein est souvent auto-infligé par la croissance des logs.
- Le comportement de start-limit est une fonctionnalité de systemd : après des échecs répétés, il arrête d’essayer. Les opérateurs interprètent souvent cela comme « Docker est gelé ».
- /var/lib/docker n’est pas sacré ; c’est juste l’état. Il contient images, couches, métadonnées et volumes (selon la config). Il peut être migré, mais le faire à la légère est la meilleure façon de gagner du travail le week-end.
- Rootless Docker existe pour réduire les privilèges du démon, mais il ajoute une classe distincte d’échecs autour des services utilisateur, XDG_RUNTIME_DIR, et la délégation des cgroups.
Tâches pratiques : commandes, sorties et décisions à prendre
Vous ne réparez pas Docker en répétant « restart ». Vous réparez Docker en collectant un petit ensemble de faits et en prenant une décision après chacun d’eux. Ci‑dessous les tâches que j’ai utilisées dans de vrais incidents, avec des sorties réalistes et leur signification.
Tâche 1 : Confirmer l’état de l’unité et la dernière raison d’échec
cr0x@server:~$ systemctl is-enabled docker; systemctl is-active docker; systemctl status docker --no-pager -l
enabled
failed
● docker.service - Docker Application Container Engine
Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
Active: failed (Result: exit-code) since Tue 2026-01-02 10:12:54 UTC; 2min 11s ago
Process: 1842 ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock (code=exited, status=1/FAILURE)
Jan 02 10:12:54 server dockerd[1842]: failed to start daemon: Error initializing network controller: failed to create NAT chain DOCKER: iptables failed
Décision : Si l’échec pointe vers le contrôleur réseau / iptables, ne perdez pas de temps sur des vérifications de stockage d’abord. Passez directement à la section iptables/nftables.
Tâche 2 : Récupérer les journaux complets pour le boot concernant docker
cr0x@server:~$ journalctl -u docker -b --no-pager -n 300
Jan 02 10:12:54 server dockerd[1842]: time="2026-01-02T10:12:54Z" level=info msg="Starting up"
Jan 02 10:12:54 server dockerd[1842]: time="2026-01-02T10:12:54Z" level=info msg="libcontainerd: started new containerd process" pid=1901
Jan 02 10:12:54 server dockerd[1842]: time="2026-01-02T10:12:54Z" level=error msg="iptables failed: iptables -t nat -N DOCKER: iptables v1.8.7 (nf_tables): Chain already exists."
Jan 02 10:12:54 server dockerd[1842]: time="2026-01-02T10:12:54Z" level=fatal msg="Error starting daemon: Error initializing network controller: iptables failed"
Décision : « Chain already exists » suggère des règles obsolètes d’un run précédent ou un conflit avec le backend nftables. Vous êtes dans le mode d’échec des règles réseau.
Tâche 3 : Vérifier si systemd vous limite les démarrages
cr0x@server:~$ systemctl status docker --no-pager -l | sed -n '1,25p'
● docker.service - Docker Application Container Engine
Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
Active: failed (Result: start-limit-hit) since Tue 2026-01-02 10:13:09 UTC; 18s ago
Jan 02 10:13:09 server systemd[1]: docker.service: Start request repeated too quickly.
Jan 02 10:13:09 server systemd[1]: docker.service: Failed with result 'start-limit-hit'.
Décision : Réinitialisez la limite de démarrage après avoir corrigé le problème sous-jacent ; sinon vous « réparerez » et il sera toujours refusé.
cr0x@server:~$ sudo systemctl reset-failed docker
Tâche 4 : Valider /etc/docker/daemon.json sans faire confiance à vos yeux
cr0x@server:~$ sudo python3 -m json.tool /etc/docker/daemon.json
Expecting property name enclosed in double quotes: line 3 column 36 (char 61)
Décision : Corrigez la syntaxe JSON d’abord. Si cela échoue, Docker ne démarrera pas. Point final. Après correction, relancez le validateur jusqu’à ce qu’il affiche le JSON formaté et sorte avec le code 0.
Tâche 5 : Extraire la ligne de commande effective de Docker (les drop-ins importent)
cr0x@server:~$ systemctl cat docker --no-pager
# /lib/systemd/system/docker.service
[Service]
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
# /etc/systemd/system/docker.service.d/override.conf
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd -H fd:// --data-root /mnt/docker-data --storage-driver=overlay2
Décision : Si vous voyez des overrides, considérez-les suspects jusqu’à preuve du contraire. Beaucoup d’incidents « Docker cassé après mise à jour » sont en réalité « ancien override rencontre nouveaux paramètres par défaut ».
Tâche 6 : Vérifier le montage data-root de Docker et le type de système de fichiers
cr0x@server:~$ findmnt -no SOURCE,FSTYPE,OPTIONS /var/lib/docker
/dev/nvme0n1p4 ext4 rw,relatime
cr0x@server:~$ findmnt -no SOURCE,FSTYPE,OPTIONS /mnt/docker-data
/dev/sdb1 xfs rw,relatime,attr2,inode64,logbufs=8,logbsize=32k
Décision : Overlay2 sur XFS exige généralement ftype=1. Si vous avez migré les données Docker vers un XFS formaté anciennement avec ftype=0, overlay2 échouera.
Tâche 7 : Vérifier ftype d’XFS (critique pour overlay2 sur XFS)
cr0x@server:~$ sudo xfs_info /dev/sdb1 | grep ftype
naming =version 2 bsize=4096 ascii-ci=0, ftype=0
Décision : ftype=0 est un arrêt net pour overlay2. La solution consiste à reformater avec ftype=1 (migration des données requise) ou à changer de driver de stockage (généralement une mauvaise journée). Ne continuez pas à réessayer sans l’avoir résolu.
Tâche 8 : Vérifier la prise en charge du noyau pour overlayfs (et repérer les causes de « invalid argument »)
cr0x@server:~$ uname -r
4.15.0-213-generic
cr0x@server:~$ lsmod | grep overlay
overlay 102400 0
cr0x@server:~$ sudo dmesg -T | tail -n 20
[Mon Jan 2 10:12:54 2026] overlayfs: filesystem on '/var/lib/docker/overlay2' not supported as upperdir
Décision : Cette ligne dans dmesg vous indique que le noyau a rejeté le système de fichiers sous-jacent comme upperdir pour overlay (commun avec certains systèmes de fichiers réseau, des chemins mal montés, ou des options non supportées). Corrigez le montage/le système de fichiers ; Docker ne peut pas le masquer.
Tâche 9 : Confirmer le socket containerd et sa santé
cr0x@server:~$ ls -l /run/containerd/containerd.sock
srw-rw---- 1 root root 0 Jan 2 10:08 /run/containerd/containerd.sock
cr0x@server:~$ systemctl status containerd --no-pager -l | sed -n '1,15p'
● containerd.service - containerd container runtime
Active: active (running) since Tue 2026-01-02 10:08:11 UTC; 6min ago
Décision : Si le socket manque ou si containerd échoue, réparez containerd avant Docker. Si containerd est OK, l’erreur de Docker se trouve ailleurs.
Tâche 10 : Chercher des refus de permission évidents (SELinux/AppArmor apparaissent ici)
cr0x@server:~$ sudo journalctl -b --no-pager | grep -E 'DENIED|apparmor="DENIED"|avc:'
Jan 02 10:12:54 server kernel: audit: type=1400 apparmor="DENIED" operation="create" profile="docker-default" name="/var/run/docker.sock" pid=1842 comm="dockerd"
Décision : Si vous voyez des refus explicites, arrêtez de traiter ça comme un problème de config Docker. Corrigez la politique/le profil ou le contexte de fichier. Lancer Docker en « désactivant simplement la sécurité » est la façon dont un incident devient une brèche.
Tâche 11 : Inspecter le mismatch du backend iptables (iptables vs nft)
cr0x@server:~$ sudo iptables --version
iptables v1.8.7 (nf_tables)
cr0x@server:~$ sudo iptables -t nat -S | sed -n '1,25p'
-P PREROUTING ACCEPT
-P INPUT ACCEPT
-P OUTPUT ACCEPT
-P POSTROUTING ACCEPT
-N DOCKER
-N DOCKER-ISOLATION-STAGE-1
-N DOCKER-ISOLATION-STAGE-2
Décision : Si Docker se plaint de chaînes existantes, vous pouvez avoir des gestionnaires de règles en conflit (firewalld, kube-proxy, scripts custom). Décidez qui possède les règles. En cas d’urgence, videz uniquement les chaînes gérées par Docker avec précaution—après avoir compris le rayon d’impact.
Tâche 12 : Confirmer le mode cgroup et un éventuel mismatch de driver
cr0x@server:~$ mount | grep cgroup2
cgroup2 on /sys/fs/cgroup type cgroup2 (rw,nosuid,nodev,noexec,relatime)
cr0x@server:~$ journalctl -u docker -b --no-pager | grep -i cgroup | tail -n 5
Jan 02 10:12:54 server dockerd[1842]: time="2026-01-02T10:12:54Z" level=fatal msg="Error starting daemon: Devices cgroup isn't mounted"
Décision : Cela indique souvent une ancienne build de Docker ou une mauvaise configuration pour cgroups v2. La solution est d’aligner les versions (mettre à jour Docker) ou de configurer le driver/mode cgroup correct pour votre distro. Ne contournez pas en désactivant le contrôle des ressources sauf si vous aimez la roulette des performances.
Tâche 13 : Chercher corruption ou écritures partielles après des coupures
cr0x@server:~$ journalctl -u docker -b --no-pager | tail -n 20
Jan 02 10:12:54 server dockerd[1842]: time="2026-01-02T10:12:54Z" level=error msg="failed to load container metadata" error="unexpected end of JSON input"
Jan 02 10:12:54 server dockerd[1842]: time="2026-01-02T10:12:54Z" level=fatal msg="Error starting daemon: error while opening volume store metadata database"
Décision : La corruption de métadonnées est réelle. Vous décidez maintenant : restaurer depuis une sauvegarde, supprimer chirurgicalement l’objet corrompu, ou reconstruire l’état Docker. Votre choix dépend de la tolérance à perdre images/volumes locaux.
Tâche 14 : Lancer dockerd en « dry-run » directement (utile quand systemd cache stderr)
cr0x@server:~$ sudo dockerd --debug --validate --config-file=/etc/docker/daemon.json
unable to configure the Docker daemon with file /etc/docker/daemon.json: the following directives are specified both as a flag and in the configuration file: hosts
Décision : Vous avez des sources de config en conflit (flags systemd ExecStart vs daemon.json). Enlevez une source de vérité. En production, je préfère laisser hosts à systemd et garder daemon.json pour les paramètres du démon, pas pour les listeners.
Tâche 15 : Vérifier les conflits de ports (commun avec d’anciens flags dockerd)
cr0x@server:~$ sudo ss -ltnp | grep -E ':2375|:2376' || true
LISTEN 0 4096 0.0.0.0:2375 0.0.0.0:* users:(("dockerd",pid=902,fd=7))
Décision : Si un ancien processus dockerd est toujours lié (ou un autre service), votre nouveau démon ne peut pas binder. Tuez le processus errant proprement, puis corrigez l’unité pour ne pas lancer plusieurs daemons.
Tâche 16 : Libérer de l’espace en sécurité sans tout détruire
cr0x@server:~$ sudo du -sh /var/lib/docker/* 2>/dev/null | sort -h | tail -n 10
2.1G /var/lib/docker/containers
12G /var/lib/docker/overlay2
18G /var/lib/docker/volumes
cr0x@server:~$ sudo find /var/lib/docker/containers -name '*-json.log' -size +200M -printf '%p %s\n' | head
/var/lib/docker/containers/2f3.../2f3...-json.log 987654321
Décision : Si les logs des conteneurs sont en cause, tronquez-les plutôt que de supprimer les répertoires des conteneurs.
cr0x@server:~$ sudo truncate -s 0 /var/lib/docker/containers/2f3.../2f3...-json.log
Décision : Faites démarrer le démon d’abord, puis implémentez correctement la rotation des logs. Disque plein = outage ; l’hygiène parfaite peut attendre une heure.
Les grands modes de défaillance (à quoi ils ressemblent dans les journaux)
Les échecs de démarrage du démon Docker se regroupent en quelques catégories. Reconnaître la catégorie réduit déjà de moitié l’incident.
1) Analyse de config et conflits de configuration
Lignes typiques de journal :
unable to configure the Docker daemon with file ...: invalid characterdirectives are specified both as a flag and in the configuration fileunknown log optaprès un changement de version
Ce qui se passe réellement : Docker est strict sur la syntaxe JSON et sur les paramètres dupliqués. Les flags systemd sont aussi des « paramètres ».
Philosophie de correction : Une seule source de vérité. Gardez daemon.json minimal ; mettez les listeners (-H) dans systemd ou l’inverse, mais ne les répartissez pas entre les deux.
2) Échecs du driver de stockage (overlay2, devicemapper, btrfs, zfs)
Lignes typiques de journal :
error initializing graphdriveroverlay2: failed to mountfailed to register layer
Ce qui se passe réellement : Le noyau et le système de fichiers négocient des fonctionnalités. S’ils ne sont pas d’accord, overlayfs retourne « invalid argument » et Docker traduit ça en désespoir.
Philosophie de correction : Confirmez le type/options du système de fichiers et la prise en charge par le noyau. Ne changez pas de driver de stockage en plein incident à moins d’être prêt à perdre des images locales et potentiellement des volumes.
3) Capacité et santé du système de fichiers
Lignes typiques de journal :
no space left on deviceread-only file systemaprès une erreur I/Odatabase is lockedou lectures partielles de métadonnées après un arrêt brutal
Ce qui se passe réellement : Docker est très dépendant de l’état. Si le stockage hôte ne peut pas écrire de manière fiable, le démarrage devient la première victime.
Philosophie de correction : Restaurez la capacité d’écriture (espace, fsck, remount, réparer le disque sous-jacent). Ce n’est qu’ensuite que vous envisagez des remèdes spécifiques à Docker.
4) Rupture de dépendance containerd/runtime
Lignes typiques de journal :
failed to dial "/run/containerd/containerd.sock"containerd: connect: no such file or directory
Ce qui se passe réellement : Docker délègue les responsabilités runtime. Si containerd manque, est incompatible ou n’est pas en cours, Docker ne peut pas continuer.
Philosophie de correction : Traitez containerd comme un service préalable. Alignez les versions via votre gestionnaire de paquets et maintenez l’unité saine.
5) Échecs d’initialisation réseau (iptables/nftables/firewalld)
Lignes typiques de journal :
failed to create NAT chain DOCKERiptables: No chain/target/match by that nameChain already existsavec le backend nf_tables
Ce qui se passe réellement : Docker tente de programmer des règles NAT et filter. Si un autre acteur gère ces tables différemment (ou si le backend iptables a changé), Docker ne peut pas créer ce qu’il attend.
Philosophie de correction : Décidez de la propriété des règles. Si vous devez intervenir, faites-le chirurgicalement et documentez-le. Les vidanges aléatoires sont la manière la plus sûre de couper le SSH sur votre propre hôte.
6) Permissions, LSM et création de socket
Lignes typiques de journal :
can't create unix socket /var/run/docker.sock: permission deniedapparmor="DENIED"ou refus SELinux AVC
Ce qui se passe réellement : Docker a besoin de créer un socket privilégié et des namespaces de montage. Les modules de sécurité et les permissions du système de fichiers peuvent le stopper net.
Philosophie de correction : Lisez le refus. Corrigez la politique/le contexte/la propriété. Désactiver SELinux « à cause de Docker » revient à enlever les détecteurs de fumée parce que vous avez brûlé du pain.
Une citation, parce que ça reste le travail : « L’espoir n’est pas une stratégie. »
— Gene Kranz
Erreurs fréquentes : symptôme → cause racine → correction
Ces cas reviennent constamment parce qu’ils sont faciles à créer et pénibles à diagnostiquer sous pression.
1) Docker bloqué en start-limit-hit
Symptôme : systemctl affiche start-limit-hit et refuse les nouveaux démarrages.
Cause racine : Docker a planté à plusieurs reprises ; systemd a arrêté de réessayer.
Correction : Corrigez d’abord l’erreur sous-jacente, puis :
cr0x@server:~$ sudo systemctl reset-failed docker
cr0x@server:~$ sudo systemctl start docker
2) « invalid character » ou erreurs JSON au démarrage
Symptôme : Docker échoue instantanément après un tweak de config.
Cause racine : JSON invalide, commentaires dans JSON, virgules finales, ou mauvais types.
Correction : Validez le fichier, puis corrigez :
cr0x@server:~$ sudo python3 -m json.tool /etc/docker/daemon.json
3) overlay2 « failed to mount » / « invalid argument »
Symptôme : initialisation graphdriver échoue, erreurs de montage overlay2.
Cause racine : Système de fichiers non supporté pour upperdir (fréquent avec NFS), XFS ftype=0, ou mismatch noyau/système de fichiers.
Correction : Placez data-root de Docker sur un système de fichiers local supporté (ext4, XFS avec ftype=1). Vérifiez avec xfs_info et dmesg. Migrez l’état si nécessaire.
4) erreurs de chaîne iptables après changements du pare-feu
Symptôme : Docker échoue avec des erreurs de création de chaîne NAT.
Cause racine : Gestionnaires de pare-feu en conflit ou changement du backend iptables (legacy vs nf_tables).
Correction : Alignez les outils iptables et la propriété des règles. Dans des environnements contrôlés, définissez un backend cohérent et faites coexister firewalld/kube/Docker de façon intentionnelle.
5) « permission denied » sur /var/run/docker.sock
Symptôme : Docker ne peut pas créer son socket.
Cause racine : Mauvaises permissions sur les sous-chemins de /var/run, socket obsolète appartenant au mauvais utilisateur, ou refus LSM.
Correction : Supprimez le socket obsolète (si Docker est arrêté), corrigez la propriété, traitez les refus AppArmor/SELinux. Ne mettez pas chmod 777 pour résoudre ça.
6) Docker échoue après avoir déplacé data-root vers un « stockage rapide »
Symptôme : Docker fonctionnait ; après le déplacement de --data-root, il meurt au démarrage.
Cause racine : Le nouveau montage est un système de fichiers réseau ou formaté sans les fonctionnalités requises.
Correction : Réévaluez le stockage. Le hot path de Docker veut un disque local à faible latence. Si vous devez utiliser un stockage réseau, gardez-le pour les volumes, pas pour les couches overlay.
7) Disque plein et Docker ne démarre plus après des tentatives de nettoyage
Symptôme : Vous avez supprimé « des trucs », Docker ne démarre toujours pas, et maintenant les métadonnées semblent corrompues.
Cause racine : Supprimer des fichiers aléatoires sous /var/lib/docker casse la cohérence des métadonnées.
Correction : Arrêtez le démon. Restaurez depuis une sauvegarde si disponible. Sinon, acceptez qu’une reconstruction (vider data-root) puisse être plus sûre qu’une réparation artisanale continue.
8) erreurs cgroup sur les nouvelles distributions
Symptôme : Erreurs sur « devices cgroup isn’t mounted », ou mismatch de driver cgroup.
Cause racine : Version de Docker incompatible avec les valeurs par défaut cgroups v2, ou driver cgroup mal configuré.
Correction : Mettez à jour Docker vers une version prenant en charge le mode cgroup de votre distro, et gardez la configuration cohérente sur la flotte.
Blague #1 : Si votre « correctif » consiste à redémarrer Docker jusqu’à ce que ça marche, vous jouez à la machine à sous avec des privilèges root.
Trois mini-récits du monde de l’entreprise tirés de la réalité
Mini-récit 1 : La panne causée par une mauvaise hypothèse
L’équipe avait un plan propre : déplacer le data-root de Docker du disque système vers un montage partagé plus grand. L’équipe stockage a promis que c’était « juste comme un disque ». C’était monté via NFS, mais personne n’a dit NFS à haute voix dans la demande de changement. Tout le monde a supposé « stockage = stockage ».
La migration a eu lieu pendant une fenêtre calme. Ils ont rsynced /var/lib/docker vers /mnt/docker-data, ajouté un override systemd avec --data-root, et redémarré. Docker n’est pas revenu. systemd a affiché « failed to mount overlay ». L’astreignant a passé 40 minutes à courir après les docs overlay2 et les modules du noyau.
La percée est venue de dmesg, pas des journaux Docker : overlayfs a rejeté upperdir parce que le système de fichiers n’était pas supporté. NFS était acceptable pour du stockage en masse. Ce n’était pas acceptable pour les systèmes de fichiers en couches de Docker. L’erreur n’était pas « overlay2 est bancal ». L’erreur était de supposer que « NFS se comporte comme ext4 ».
Ils sont revenus au XFS local avec les bonnes fonctionnalités et ont gardé NFS pour les volumes applicatifs seulement, avec des limites claires. La panne s’est terminée. Le postmortem a abouti à une nouvelle règle : les types de stockage doivent être nommés explicitement dans les demandes de changement. « Montage partagé » n’est pas un type.
Mini-récit 2 : L’optimisation qui s’est retournée contre eux
Un ingénieur soucieux de performance voulait un démarrage de conteneur plus rapide. Il a remarqué la rotation dans overlay2 et a décidé d’ajuster les montages pour réduire l’amplification d’écriture. L’« optimisation » incluait déplacer Docker sur un système de fichiers avec des options agressives et désactiver certaines fonctionnalités de métadonnées qu’il jugeait superflues.
En dev avec quelques conteneurs, ça a bien benchmarké. Puis en production : des centaines de conteneurs, downloads fréquents d’images, beaucoup de petites opérations de fichiers. En quelques jours, le nœud a commencé à lancer des erreurs I/O intermittentes. Après un redémarrage brutal, Docker ne démarrait plus. Les journaux montraient des échecs d’enregistrement de couche et des erreurs de base de données de métadonnées.
Ce qui s’est passé n’était pas mystérieux. L’optimisation avait réduit les marges de sécurité : le système était maintenant plus sensible aux pertes d’alimentation et aux cas limites du système de fichiers. Le gain de quelques pourcents de performance a coûté une probabilité bien plus grande de corruption et une récupération plus difficile.
Ils ont annulé les tweaks de montage, reconstruit le nœud, et adopté une règle ennuyeuse mais correcte : si vous changez le substrat de stockage sous Docker, vous le faites avec une matrice de compatibilité documentée et un plan de rollback. Les gains de performance sont réels, mais « rapide et fragile » est un mauvais compromis en production.
Mini-récit 3 : La pratique ennuyeuse mais correcte qui a sauvé la mise
Une autre organisation avait une habitude dont personne ne se vantait : ils collectaient les logs boot-scoped pour les services critiques et les centralisaient. Pas seulement les logs applicatifs—les journaux des unités systemd et les messages noyau aussi. C’était terne. Ça a aussi marché.
Un matin, un sous-ensemble de nœuds a cessé de démarrer Docker après une mise à jour OS de routine. L’instinct humain initial était « régression Docker ». Mais la chronologie des logs montrait quelque chose de plus net : Docker échouait juste après un reload du pare-feu au démarrage. Le backend iptables avait changé, et le gestionnaire de pare-feu avait commencé à pré-créer des chaînes d’une manière que Docker n’aimait pas.
Parce qu’ils avaient les logs, ils n’ont pas passé des heures à argumenter. Ils ont identifié le point de changement, reproduit sur un canari, et déployé une configuration backend iptables cohérente. Docker est revenu sans toucher au stockage, aux images, ni aux workloads conteneurisés.
Cette pratique n’a pas empêché la panne. Elle a empêché une longue indisponibilité. En production, le temps pour comprendre est la moitié de l’incident.
Listes de contrôle / plan étape par étape
Checklist A : Remettre Docker en route (étapes minimales sûres)
- Arrêtez le thrash. Si le service est en crash-loop, arrêtez-le pendant votre enquête.
cr0x@server:~$ sudo systemctl stop docker - Lisez le journal une fois, correctement.
cr0x@server:~$ journalctl -u docker -b --no-pager -n 200Décision : Identifiez le bucket : config, stockage, capacité, réseau, permissions, dépendance.
- Vérifiez disque et inodes sur le filesystem data-root.
cr0x@server:~$ df -h /var/lib/docker; df -i /var/lib/dockerDécision : Si plein, libérez de l’espace sans supprimer l’état au hasard. Tronquez les logs ; supprimez soigneusement les gros artefacts connus.
- Validez daemon.json s’il existe.
cr0x@server:~$ test -f /etc/docker/daemon.json && sudo python3 -m json.tool /etc/docker/daemon.jsonDécision : Corrigez les erreurs de parsing ; retirez les duplications avec les flags systemd.
- Confirmez que containerd est sain.
cr0x@server:~$ systemctl status containerd --no-pager -lDécision : Réparez containerd d’abord si nécessaire.
- Réinitialisez les limites de démarrage systemd après la correction.
cr0x@server:~$ sudo systemctl reset-failed docker - Démarrez Docker et surveillez les logs en direct pendant 30 secondes.
cr0x@server:~$ sudo systemctl start docker cr0x@server:~$ journalctl -u docker -f --no-pagerDécision : Si ça échoue encore, vous capturez maintenant le point de transition exact sans archéologie de scrolling.
Checklist B : Si une corruption de stockage est suspectée (prudence)
- Snapshot ou copier les preuves d’abord (si possible). Au minimum, capturez les journaux et l’état actuel de la répartition des tailles sous
/var/lib/docker. - Ne supprimez pas de répertoires au hasard sous
/var/lib/dockerpendant que dockerd tourne. Arrêtez-le. - Identifiez si les volumes sont importants sur cet hôte. Certains environnements stockent des données persistantes dans des volumes Docker ; d’autres non. Le plan de récupération dépendra de cela.
- Privilégiez la reconstruction du nœud plutôt que la réparation artisanale quand l’hôte est du type cattle. Privilégiez une récupération soignée quand l’hôte est malheureusement un pet.
Checklist C : Si iptables/réseau est suspecté
- Confirmez que l’erreur de Docker mentionne iptables/nftables.
- Vérifiez le backend iptables et les chaînes courantes.
- Identifiez l’autre gestionnaire de règles (firewalld, kube-proxy, scripts custom).
- Rendez la propriété des règles explicite, puis redémarrez Docker.
Blague #2 : Le réseau Docker est simple jusqu’à ce qu’il ne le soit plus, moment auquel il devient une danse interprétative exécutée par iptables.
FAQ
1) Dois‑je exécuter dockerd manuellement pour déboguer ?
Oui, brièvement, si systemd obscurcit stderr ou si vous suspectez des conflits de config. Utilisez --debug et arrêtez l’unité systemd d’abord pour éviter que deux daemons se battent pour le même socket.
2) Est‑il sûr de supprimer /var/lib/docker pour « réparer » ?
C’est sûr seulement si vous effacez volontairement les images locales, conteneurs, et possiblement les volumes (selon votre configuration). C’est un dernier recours pour récupération rapide sur des nœuds sans état, pas une correction par défaut.
3) Docker dit overlay2 failed to mount. Docker est‑il cassé ?
Généralement non. C’est souvent un problème de compatibilité noyau/système de fichiers (XFS ftype, upperdir non supporté, options de montage non supportées). Consultez dmesg pour la plainte réelle du noyau.
4) Pourquoi Docker échoue au démarrage à cause d’iptables ? Ne peut‑il pas fonctionner sans NAT ?
Le réseau pont Docker classique dépend de règles iptables. Si Docker ne peut pas programmer les règles NAT/filter, il refuse de démarrer correctement le réseau et peut échouer au démarrage pour éviter un comportement partiellement fonctionnel.
5) J’ai modifié daemon.json et Docker ne démarre plus. Quel est le contrôle de sanity le plus rapide ?
Validez le JSON avec un vrai parseur :
cr0x@server:~$ sudo python3 -m json.tool /etc/docker/daemon.json
Si ça renvoie une erreur, corrigez la syntaxe. Si ça réussit, cherchez des directives en conflit avec les flags systemd.
6) Docker ne démarre plus après une mise à jour OS. Quelle est la cause probable ?
Coupables fréquents : changements par défaut de cgroups v2, switches du backend iptables, et anciens overrides dans les drop-ins systemd. Commencez par systemctl cat docker et le journal.
7) containerd peut‑il tourner alors que Docker échoue quand même à démarrer ?
Absolument. La santé de containerd élimine une classe d’échec. Docker peut encore échouer sur l’initialisation du driver de stockage, les règles réseau, les permissions du socket, ou le parsing de daemon.json.
8) Comment savoir si le disque est « assez plein » pour casser Docker ?
Si l’espace libre descend à quelques centaines de Mo, ou si les inodes sont épuisés, Docker peut ne pas démarrer ou se comporter de façon erratique. Vérifiez à la fois df -h et df -i. Surveillez aussi les remontages en lecture seule après des erreurs I/O.
9) Que faire si docker info se fige au lieu d’échouer ?
Si le CLI se fige, il attend généralement le socket. Confirmez si le démon tourne (systemctl is-active docker) et si le socket existe (ls -l /var/run/docker.sock). Un blocage est souvent « démon non répondant », pas « CLI cassé ».
10) Le rootless Docker est‑il moins susceptible d’échouer ?
Il échoue différemment. Vous réduisez la portée des dégâts liés aux privilèges, mais vous ajoutez des dépendances sur les services utilisateur, la délégation des cgroups, et des répertoires runtime par utilisateur. Excellent quand c’est conçu pour, déroutant quand c’est greffé après coup.
Prochaines étapes qui réduisent vraiment les incidents futurs
Faire démarrer Docker est la victoire immédiate. Prévenir le prochain « démon down » est le vrai travail. Voici ce que je ferais après que la poussière de l’incident se soit déposée :
- Codifiez le playbook de diagnostic rapide dans votre runbook, avec vos chemins et décisions spécifiques à la distro. Les commandes ci‑dessus sont une base ; adaptez‑les.
- Standardisez la source de config de Docker : choisissez daemon.json pour les paramètres du démon et les drop-ins systemd pour les flags ExecStart, ou l’inverse—mais ne mixez pas sans précaution.
- Placez l’état Docker sur le bon stockage : ext4 local ou XFS avec les bonnes options, surveillé pour capacité et inodes. Tenez les couches overlay hors des montages réseau.
- Contrôlez la croissance des logs : configurez la rotation des logs des conteneurs et surveillez les tailles de
/var/lib/docker/containers/*-json.log. Les pannes disque dues aux logs sont évitables. - Rendez la propriété du pare-feu explicite dans votre design de plateforme : Docker, firewalld, Kubernetes et agents de sécurité peuvent coexister, mais seulement si vous décidez qui écrit quelles règles.
- Entraînez‑vous à la récupération sur un nœud non‑production : simulez un daemon.json corrompu, un disque plein, et un conflit iptables. Votre moi futur vous remerciera et sera un peu moins caféiné.