← Retour aux tutoriels

Récupérer après une mise à jour Docker cassée : socket, service et incompatibilités de version

dockerdevopslinuxsystemddockerddocker.sockupgradetroubleshootingversion-mismatchrollback

Récupérer après une mise à jour Docker cassée : socket, service et incompatibilités de version

Une mise à jour de Docker peut parfois “casser” un environnement qui fonctionnait la veille : docker ps répond soudain Cannot connect to the Docker daemon, le service ne démarre plus, le socket /var/run/docker.sock est absent, ou bien le client et le démon ne sont plus compatibles. Ce tutoriel propose une méthode systématique pour diagnostiquer et réparer, avec des commandes réelles, et en expliquant pourquoi chaque étape est utile.

Public visé : Linux (Debian/Ubuntu, RHEL/CentOS/Fedora, et dérivés).
Les exemples utilisent systemd (cas le plus courant). Si vous êtes sur une distribution sans systemd, adaptez les commandes de service.


1) Comprendre ce qui casse après une mise à jour

Après une mise à jour, les problèmes se regroupent en quelques familles :

  1. Le démon Docker (dockerd) ne tourne pas

    • systemctl status docker montre un échec.
    • journalctl -u docker contient une erreur (storage driver, cgroups, iptables/nftables, config JSON invalide…).
  2. Le socket Docker n’est pas accessible

    • Le fichier /var/run/docker.sock n’existe plus, ou a de mauvais droits.
    • Le socket est géré par docker.socket (activation par socket) et ce dernier est désactivé ou cassé.
  3. Incompatibilité client/serveur

    • Le binaire docker (client) a été mis à jour mais pas dockerd, ou l’inverse.
    • Les API versions ne concordent pas, ou un plugin/compose n’est plus compatible.
  4. Conflit de paquets / dépôts

    • Mélange entre Docker Engine “officiel” (Docker Inc.) et paquets distribution (docker.io, podman-docker, etc.).
    • Sur Debian/Ubuntu : passage de docker.io à docker-ce (ou inversement) sans purge propre.
  5. Changements système induits par la mise à jour

    • Mise à jour du kernel : cgroups v2, modules overlay, AppArmor/SELinux, nftables.
    • Changement de configuration réseau (iptables vs nft).

L’objectif est de localiser la panne (socket ? service ? version ? config ?) avant de “réinstaller au hasard”.


2) Vérifications rapides (triage)

2.1 Vérifier le client Docker et l’erreur exacte

docker version
docker info
docker ps

2.2 Vérifier si dockerd tourne

ps aux | grep -E 'dockerd|containerd' | grep -v grep

2.3 Vérifier service et socket systemd

systemctl status docker --no-pager
systemctl status docker.socket --no-pager
systemctl is-enabled docker
systemctl is-enabled docker.socket

2.4 Vérifier l’existence et les droits du socket

ls -l /var/run/docker.sock
stat /var/run/docker.sock
getent group docker
id

3) Cas n°1 : le démon Docker ne démarre pas

3.1 Lire les logs du service

Les logs sont la source n°1 de vérité :

journalctl -u docker -b --no-pager
journalctl -u docker -b -n 200 --no-pager

Pour suivre en direct :

journalctl -u docker -f

3.2 Lancer dockerd en debug (diagnostic)

Arrêtez d’abord le service, puis lancez dockerd au premier plan :

sudo systemctl stop docker
sudo dockerd --debug

Astuce : si dockerd se lance en debug mais pas via systemd, le problème peut venir d’un override systemd, d’une variable d’environnement, ou d’un fichier de config.

3.3 Vérifier la configuration /etc/docker/daemon.json

Une mise à jour peut rendre une option obsolète ou invalide. Vérifiez la syntaxe JSON :

sudo cat /etc/docker/daemon.json
python3 -m json.tool /etc/docker/daemon.json

Si python3 -m json.tool échoue, corrigez le JSON.

Exemples d’options qui causent fréquemment des soucis après upgrade :

Pour tester rapidement, vous pouvez temporairement renommer le fichier :

sudo mv /etc/docker/daemon.json /etc/docker/daemon.json.bak
sudo systemctl start docker

Si Docker redémarre, vous savez que la panne vient de la config. Réintroduisez les options une par une.

3.4 Problèmes de driver de stockage (overlay2, aufs…)

Vérifiez le driver attendu et l’état :

docker info 2>/dev/null | sed -n '1,120p'

Si Docker ne démarre pas, regardez les logs : vous verrez souvent des mentions overlay2, failed to mount overlay, etc.

Vérifications utiles :

uname -r
lsmod | grep overlay || true
sudo modprobe overlay
df -T /var/lib/docker

Attention : ne supprimez pas /var/lib/docker à la légère, vous perdriez images/containers/volumes (selon configuration). Faites d’abord une sauvegarde si vous devez intervenir.

Sauvegarde simple (peut être longue) :

sudo systemctl stop docker
sudo tar -C /var/lib -cpf /root/backup-var-lib-docker.tar docker

3.5 Problèmes cgroups (souvent après upgrade kernel / systemd)

Vérifiez si vous êtes en cgroups v2 :

stat -fc %T /sys/fs/cgroup
# "cgroup2fs" => cgroups v2

Vérifiez les paramètres du kernel :

cat /proc/cmdline

Sur certains environnements, une bascule cgroups v1/v2 peut casser un runtime ou une config. Docker moderne supporte cgroups v2, mais des combinaisons (kernel ancien + Docker récent ou inversement) peuvent poser problème.

Vérifiez aussi containerd :

systemctl status containerd --no-pager
journalctl -u containerd -b --no-pager

Docker dépend de containerd ; si containerd est KO, Docker peut échouer.


4) Cas n°2 : problème de socket (docker.sock) ou d’activation par socket

4.1 Comprendre le rôle de docker.socket

Sur beaucoup de distributions, Docker peut être démarré “à la demande” via docker.socket :

Si docker.socket est désactivé ou cassé, le socket peut manquer.

4.2 Vérifier et réactiver le socket

sudo systemctl status docker.socket --no-pager
sudo systemctl enable --now docker.socket
sudo systemctl restart docker.socket

Puis :

ls -l /var/run/docker.sock

4.3 Forcer le démarrage du service (sans socket activation)

Si vous préférez un service toujours actif :

sudo systemctl disable --now docker.socket
sudo systemctl enable --now docker
sudo systemctl restart docker

4.4 Droits du socket : “permission denied”

Si l’erreur est :

Alors vous avez un problème de permissions. Vérifiez :

ls -l /var/run/docker.sock
id
getent group docker

Solution classique : ajouter l’utilisateur au groupe docker :

sudo usermod -aG docker "$USER"
newgrp docker

Ensuite test :

docker ps

Note sécurité : appartenir au groupe docker équivaut pratiquement à un accès root (possibilité de monter le FS hôte, etc.). N’ajoutez pas des comptes non fiables.

4.5 Socket “fantôme” ou mauvais chemin

Le client Docker utilise par défaut unix:///var/run/docker.sock. Vérifiez la variable DOCKER_HOST :

echo "$DOCKER_HOST"
env | grep -E '^DOCKER_'

Si DOCKER_HOST pointe ailleurs, corrigez-le :

unset DOCKER_HOST
docker ps

5) Cas n°3 : incompatibilités de version (client/serveur/API/plugins)

5.1 Vérifier versions client/serveur

docker version

Vous verrez quelque chose comme :

Un écart majeur peut provoquer des comportements étranges. En général, un client plus récent reste compatible, mais pas toujours (API, plugins, packaging).

5.2 Vérifier la version d’API et forcer une version (dépannage)

Docker permet de forcer une version d’API via DOCKER_API_VERSION. Cela peut dépanner temporairement si le client est trop récent :

export DOCKER_API_VERSION=1.41
docker version
docker ps

Pour connaître l’API côté serveur (si accessible) :

docker version --format '{{.Server.APIVersion}}'

Ce contournement n’est pas une solution durable : il faut aligner les versions de paquets.

5.3 Docker Compose : plugin vs binaire séparé

Après mise à jour, docker compose (plugin v2) peut remplacer docker-compose (v1). Vérifiez :

docker compose version
docker-compose version || true

Si vos scripts appellent docker-compose et qu’il a disparu :

Exemple Debian/Ubuntu :

sudo apt-get update
sudo apt-get install -y docker-compose-plugin

Puis utilisez :

docker compose up -d

5.4 Conflits avec podman-docker

Sur certaines distributions, docker peut être un wrapper vers Podman. Vérifiez :

which docker
docker --version
rpm -qa | grep -E 'podman-docker|docker' || true
dpkg -l | grep -E 'podman-docker|docker' || true

Si which docker pointe vers un wrapper inattendu, vous pouvez avoir l’impression que “Docker est cassé” alors que vous n’utilisez pas le bon binaire.


6) Cas n°4 : conflit de paquets (Debian/Ubuntu vs Docker Inc.)

6.1 Identifier ce qui est installé

Debian/Ubuntu :

dpkg -l | grep -E 'docker|containerd|runc' | sed -n '1,200p'
apt-cache policy docker.io docker-ce docker-ce-cli containerd.io

RHEL/Fedora :

rpm -qa | grep -E 'docker|containerd|runc' | sed -n '1,200p'
dnf list installed | grep -E 'docker|containerd|runc'

Problème typique : avoir à la fois docker.io et docker-ce (ou des restes), ou containerd provenant d’une source différente.

6.2 Stratégie de remise à plat (sans perdre les données)

Objectif : nettoyer les paquets, sans supprimer /var/lib/docker si vous voulez conserver images/containers.

Debian/Ubuntu (exemple de nettoyage prudent)

  1. Stopper Docker :
sudo systemctl stop docker docker.socket containerd || true
  1. Purger les paquets conflictuels (adaptez selon votre cas) :
sudo apt-get remove -y docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc || true
sudo apt-get purge -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin || true
  1. Vérifier ce qui reste :
dpkg -l | grep -E 'docker|containerd|runc' || true
  1. Réinstaller depuis une seule source (exemple : Docker Inc. sur Ubuntu/Debian).
    Si vous avez déjà le dépôt Docker configuré, vous pouvez faire :
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
  1. Redémarrer et vérifier :
sudo systemctl enable --now docker
docker version
docker ps

Important : la purge de paquets ne supprime pas forcément /var/lib/docker. Mais selon options et distribution, certains scripts peuvent toucher des répertoires. Sauvegardez si c’est critique.

Fedora/RHEL (exemple générique)

Selon votre distribution, Docker peut ne plus être le runtime privilégié (Podman est courant). Si vous utilisez Docker Engine officiel, vous passerez souvent par le dépôt Docker.

Stop :

sudo systemctl stop docker docker.socket containerd || true

Nettoyage (à adapter) :

sudo dnf remove -y docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine || true

Puis installation via dépôt Docker (si configuré) :

sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo systemctl enable --now docker
docker ps

7) Cas n°5 : réseau cassé (iptables/nftables) après mise à jour

Après certaines mises à jour, Docker échoue à programmer les règles NAT/forwarding. Symptômes :

7.1 Vérifier les logs réseau

journalctl -u docker -b --no-pager | grep -iE 'iptables|nft|nat|bridge|forward' || true

7.2 Vérifier la politique FORWARD et l’IP forwarding

sysctl net.ipv4.ip_forward
sudo iptables -S FORWARD 2>/dev/null || true
sudo nft list ruleset 2>/dev/null | sed -n '1,200p' || true

Docker a besoin de net.ipv4.ip_forward=1 (souvent activé automatiquement, mais pas toujours).

Activer temporairement :

sudo sysctl -w net.ipv4.ip_forward=1

Pour rendre permanent (exemple) :

echo 'net.ipv4.ip_forward=1' | sudo tee /etc/sysctl.d/99-docker-ipforward.conf
sudo sysctl --system

7.3 Choix iptables-legacy vs nft (Debian/Ubuntu)

Sur Debian/Ubuntu, iptables peut être un frontend nft. Certaines configurations anciennes nécessitent iptables-legacy.

Vérifiez l’alternative :

sudo update-alternatives --display iptables
sudo iptables --version

Basculer (exemple) :

sudo update-alternatives --set iptables /usr/sbin/iptables-legacy
sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
sudo systemctl restart docker

À n’utiliser que si vous savez que votre environnement/pare-feu le requiert. Sur des systèmes modernes, nft est généralement OK, mais des interactions avec des firewalls tiers existent.


8) Procédure “de secours” : repartir d’un état sain sans perdre les données

Si vous êtes dans un état confus (paquets mélangés, service cassé, socket absent), voici une procédure structurée.

8.1 Sauvegarder l’état (au minimum la config)

sudo cp -a /etc/docker /root/backup-etc-docker-$(date +%F) 2>/dev/null || true
sudo systemctl stop docker docker.socket containerd || true

Si vos données sont critiques, sauvegardez /var/lib/docker (peut être volumineux) :

sudo tar -C /var/lib -cpf /root/backup-var-lib-docker-$(date +%F).tar docker

8.2 Nettoyer les overrides systemd (si vous en avez)

Vérifiez s’il existe des overrides :

systemctl cat docker
systemctl cat containerd

S’il y a des fichiers dans /etc/systemd/system/docker.service.d/, ils peuvent casser le démarrage après update (options obsolètes). Pour tester, vous pouvez les déplacer :

sudo ls -R /etc/systemd/system/docker.service.d/ || true
sudo mv /etc/systemd/system/docker.service.d /etc/systemd/system/docker.service.d.bak.$(date +%s) 2>/dev/null || true
sudo systemctl daemon-reload

8.3 Réinstaller proprement et redémarrer

Après avoir choisi une source de paquets (distro ou Docker Inc.), réinstallez puis :

sudo systemctl enable --now containerd || true
sudo systemctl enable --now docker
sudo systemctl restart docker

Vérifiez :

docker version
docker info
docker ps

9) Diagnostiquer des erreurs fréquentes (avec remèdes)

9.1 Cannot connect to the Docker daemon at unix:///var/run/docker.sock

Causes probables :

Checklist :

systemctl status docker --no-pager
systemctl status docker.socket --no-pager
echo "$DOCKER_HOST"
ls -l /var/run/docker.sock
journalctl -u docker -b --no-pager | tail -n 200

9.2 Job for docker.service failed because the control process exited with error code

Toujours lire les logs :

journalctl -u docker -b --no-pager

Puis test en debug :

sudo systemctl stop docker
sudo dockerd --debug

9.3 Error starting daemon: ... à cause de daemon.json

Validez le JSON :

python3 -m json.tool /etc/docker/daemon.json

Désactivez temporairement :

sudo mv /etc/docker/daemon.json /etc/docker/daemon.json.off
sudo systemctl start docker

9.4 permission denied sur le socket

Ajout au groupe :

sudo usermod -aG docker "$USER"
newgrp docker
docker ps

9.5 client is newer than server / API mismatch

Vérifiez versions :

docker version

Solution durable : aligner les paquets (client + serveur).
Solution temporaire : forcer l’API :

export DOCKER_API_VERSION=1.41
docker ps

10) Bonnes pratiques pour éviter la casse lors des prochaines mises à jour

  1. Éviter de mélanger les sources
    Choisissez soit les paquets de la distribution (docker.io), soit ceux de Docker Inc. (docker-ce), mais pas un mélange.

  2. Garder une trace de /etc/docker/daemon.json et des overrides systemd
    Une option valide aujourd’hui peut devenir obsolète demain. Versionnez votre config (Git privé, Ansible, etc.).

  3. Surveiller les changements kernel/cgroups
    Après une mise à jour kernel majeure, vérifiez rapidement :

    docker info | grep -E 'Cgroup|Kernel'
  4. Tester la mise à jour sur un environnement de staging
    Surtout si vous dépendez de règles réseau complexes, de drivers de stockage spécifiques, ou de plugins.

  5. Sauvegarder les données et savoir restaurer

    • Volumes : souvent plus importants que les images.
    • Pensez à exporter ce qui est critique (bases de données via dump), pas uniquement /var/lib/docker.

11) Exemple de session complète de dépannage (scénario réaliste)

Symptôme

Après apt upgrade, docker ps renvoie : Cannot connect to the Docker daemon at unix:///var/run/docker.sock

Étapes

  1. Vérifier service/socket :
systemctl status docker --no-pager
systemctl status docker.socket --no-pager
  1. Lire les logs :
journalctl -u docker -b --no-pager | tail -n 200

Supposons que vous voyez une erreur du type : failed to start daemon: error while opening volume store metadata database

  1. Stopper et sauvegarder :
sudo systemctl stop docker
sudo tar -C /var/lib -cpf /root/backup-var-lib-docker-$(date +%F).tar docker
  1. Tester sans config custom :
sudo mv /etc/docker/daemon.json /etc/docker/daemon.json.bak
sudo systemctl start docker
  1. Vérifier :
docker ps
docker info

Si ça repart, vous réintroduisez progressivement les paramètres de daemon.json jusqu’à identifier celui qui casse.


12) Commandes “mémo” (à copier-coller)

État général

docker version
docker info
systemctl status docker --no-pager
systemctl status docker.socket --no-pager
journalctl -u docker -b --no-pager | tail -n 200
ls -l /var/run/docker.sock

Redémarrage propre

sudo systemctl daemon-reload
sudo systemctl restart containerd || true
sudo systemctl restart docker

Debug

sudo systemctl stop docker
sudo dockerd --debug

Vérifier daemon.json

python3 -m json.tool /etc/docker/daemon.json

Droits utilisateur

sudo usermod -aG docker "$USER"
newgrp docker

Conclusion

Quand Docker “casse” après une mise à jour, la clé est de séparer les problèmes : service, socket, permissions, configuration, versions, réseau. En procédant dans cet ordre — logs systemd, test dockerd --debug, validation de daemon.json, vérification du socket et des droits, puis alignement des paquets — vous évitez les réinstallations hasardeuses et vous maximisez vos chances de récupérer rapidement, sans perdre de données.

Si vous me donnez :