Docker est le standard de facto pour la conteneurisation, mais connaître les drapeaux CLI n'est que la moitié du combat. La vraie compétence réside dans l'utilisation de ces commandes pour diagnostiquer les problèmes, vérifier les déploiements et récupérer après des pannes sans causer d'indisponibilité. Ce guide va au-delà d'une simple aide-mémoire. Il structure les commandes Docker essentielles autour d'un cycle de vie opérationnel : inventaire, configuration, vérification, récupération après panne et opérations continues. Chaque commande inclut le contexte d'utilisation, la sortie attendue et l'interprétation des signaux d'échec.
1. Inventaire de la Version et de l'Environnement
Avant de changer quoi que ce soit, vous devez établir une ligne de base. Cette phase est en lecture seule. Son but est de répondre : Qu'est-ce qui tourne, où sont les données et sur quelle version sommes-nous ?
Vérifier les Versions du Moteur et du Client Docker
Commencez par confirmer la compatibilité entre le client et le serveur. Les incompatibilités expliquent souvent des erreurs API cryptiques.
docker version --format '{{.Client.Version}} / {{.Server.Version}}'
Sortie attendue : 24.0.7 / 24.0.7 (les versions doivent correspondre). Signal d'échec : Un client plus récent que le serveur (ou l'inverse) indique une mise à niveau incomplète.
Lister les Conteneurs en Cours avec Contexte
Le docker ps par défaut cache le contexte critique. Utilisez un format personnalisé pour voir immédiatement les noms, statuts et mappings de ports.
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}\t{{.Image}}"
Pourquoi cela importe : Vous identifiez le nom exact du conteneur (requis pour les commandes subséquentes), voyez si un conteneur est Up 2 minutes (boucle de redémarrage récente) vs Up 3 weeks, et vérifiez que les liaisons de ports correspondent à vos règles de reverse proxy ou pare-feu.
Inspecter la Configuration et les Montages du Conteneur
Pour déboguer « ça marche sur ma machine » ou des erreurs de permission, docker inspect est la source de vérité. Filtrez pour les sections spécifiques dont vous avez besoin plutôt que de parser du JSON massif.
# Vérifier les montages (volumes/binds) et chemins sources
docker inspect --format '{{json .Mounts}}' <nom_conteneur> | jq .
# Vérifier les variables d'environnement (masquer les secrets dans la sortie)
docker inspect --format '{{json .Config.Env}}' <nom_conteneur> | jq .
# Vérifier le mode réseau et l'IP
docker inspect --format '{{.NetworkSettings.IPAddress}} / {{.HostConfig.NetworkMode}}' <nom_conteneur>
Exemple pratique : Une application Python échoue à écrire dans /data. inspect révèle que la source du montage est /chemin/hote/data mais que le répertoire hôte appartient à root:root alors que le conteneur tourne en uid=1000. La correction se fait sur l'hôte (chown 1000:1000 /chemin/hote/data), pas dans le conteneur.
Inventorier les Projets Docker Compose
Si vous utilisez Compose (plugin v2), inventoriez l'état du projet séparément. Compose gère les réseaux et volumes implicitement.
# Lister les projets compose et leur statut
docker compose ls --all
# Plongée dans un projet spécifique
docker compose -p mon-projet ps --format "table {{.Name}}\t{{.Status}}\t{{.Ports}}"
docker compose -p mon-projet config # Valide et rend la configuration effective
Vérification de la Persistance des Données (Le Test de Redémarrage)
C'est l'étape d'inventaire la plus importante pour les services avec état. N'assumez pas que les volumes sont configurés correctement.
docker stop <nom_conteneur>docker rm <nom_conteneur>- Redéployez via votre méthode standard (Compose up, commande run, CI/CD).
- Vérifiez que les données de l'application (enregistrements BD, fichiers uploadés, persistance de session) survivent.
Mode d'échec : Les données disparaissent. Le conteneur écrivait dans la couche inscriptible (système de fichiers union) au lieu d'un volume ou bind mount défini. Récupération : Les données sont probablement perdues à moins d'avoir commité le conteneur en image (docker commit) avant suppression. Définissez un volume nommé dans docker-compose.yml ou docker run -v et répétez le test.
2. Chemin de Configuration Sûr
Les changements à l'infrastructure en cours doivent être atomiques, réversibles et auditable. N'éditez jamais directement le système de fichiers d'un conteneur en cours (docker exec -it ... vi /etc/nginx/nginx.conf). Ce changement disparaît au redémarrage.
Gestion des Images : Pull, Tag et Vérification
Toujours puller par digest (immuable) en production, tagger pour la lisibilité humaine.
# Puller un digest spécifique (sûr pour CI/CD)
docker pull nginx@sha256:d85914d547a6c92faa39ce7058bd7529baacab7e0cd4255442b04577c4d1f4e4
# Tagger localement pour les scripts de déploiement
docker tag nginx@sha256:d859... mon-registry.com/prod/nginx:1.25.3
# Vérifier les couches et l'historique de l'image (chercher des secrets dans les couches)
docker history mon-registry.com/prod/nginx:1.25.3 --no-trunc
Mise à Jour d'un Service : Le Permutation de Conteneurs « Bleu/Vert »
Pour des mises à jour sans temps d'arrêt sur un seul hôte sans orchestrateur (Swarm/K8s), lancez la nouvelle version à côté de l'ancienne, vérifiez la santé, puis basculez le proxy.
- Démarrer le nouveau conteneur sur un port différent (ex: 8081) avec le nouveau tag d'image.
docker run -d --name app_v2 --network app_net -p 8081:80 mon-registry.com/prod/app:v2.1.0
- Vérifier la santé (voir Section 3).
- Mettre à jour le reverse proxy (config Nginx/Traefik/Caddy) pour pointer l'upstream vers
app_v2:80(DNS Docker interne) oulocalhost:8081. - Recharger le proxy (
docker exec proxy nginx -s reload). - Surveiller les taux d'erreur pendant 5 minutes.
- Arrêter l'ancien conteneur (
docker stop app_v1 && docker rm app_v1).
Rollback : Revenir à la config proxy -> recharger -> docker start app_v1. Rayon d'impact : secondes.
Gestion des Secrets et Configurations
Ne passez jamais de secrets via -e VAR_ENV=valeur (visible dans docker inspect et ps -ef sur l'hôte).
- Docker Secrets (mode Swarm uniquement) :
echo "motdepasse" | docker secret create db_pass - - Fichiers bind-montés (Standalone/Compose) :
# docker-compose.yml
services:
app:
secrets:
- db_password
secrets:
db_password:
file: ./secrets/db_password.txt # Fichier .gitignored sur l'hôte
Le fichier apparaît à /run/secrets/db_password dans le conteneur. L'application lit le chemin du fichier, pas la variable d'env.
Contraintes de Ressources (Prévenir les Voisins Bruyants)
Définissez des limites pour empêcher un conteneur de tuer l'hôte par OOM ou d'affamer les autres.
docker run -d \
--name api \
--memory="512m" --memory-swap="1g" \
--cpus="1.5" \
--pids-limit=100 \
mon-image:latest
--memory-swap: Permet d'éclater en swap (total 1,5 Go) mais empêche le kill OOM si la RAM grimpe brièvement.--pids-limit: Empêche les fork bombs.
3. Vérification et Diagnostics
Vous avez déployé un changement. Maintenant, vous prouvez qu'il fonctionne. La vérification est active ; les diagnostics sont réactifs.
Health Checks : Le Contrat Entre Conteneur et Orchestrateur
Définissez un HEALTHCHECK dans le Dockerfile ou docker-compose.yml. Docker met à jour le statut du conteneur à healthy/unhealthy.
# Exemple Dockerfile
HEALTHCHECK --interval=30s --timeout=10s --start-period=15s --retries=3 \
CMD curl -f http://localhost:8080/healthz || exit 1
Observer le statut de santé :
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Health}}"
Progression du statut : starting -> healthy (bon) OU starting -> unhealthy (investiguer les logs immédiatement).
Agrégation et Filtrage des Logs
docker logs est votre première ligne de défense. Utilisez des drapeaux pour éviter d'inonder le terminal.
# Suivre les 200 dernières lignes avec timestamps (essentiel pour la corrélation)
docker logs -f --tail 200 -t <nom_conteneur>
# Filtrer les erreurs (insensible à la casse) depuis un moment précis
docker logs --since "2024-01-15T10:00:00" <nom_conteneur> 2>&1 | grep -i -e error -e exception -e fatal
# Exporter vers fichier pour analyse hors ligne / support vendeur
docker logs <nom_conteneur> > /tmp/container_logs_$(date +%F).txt 2>&1
Note sur les drivers de logging : Si vous utilisez json-file (défaut), les logs vivent sur le disque hôte (/var/lib/docker/containers/<id>/<id>-json.log). Faites-les tourner via /etc/docker/daemon.json ("log-opts": {"max-size": "10m", "max-file": "3"}) pour prévenir la pression disque.
Diagnostics Réseau à l'Intérieur du Conteneur
« Connection refused » dans un conteneur signifie généralement : mauvais port, service n'écoute pas sur 0.0.0.0, ou politique réseau.
# Entrer dans l'espace de noms réseau du conteneur (meilleure boîte à outils)
docker exec -it <nom_conteneur> sh -c "apk add --no-cache curl bind-tools netcat-openbsd iproute2 2>/dev/null || apt-get update && apt-get install -y curl dnsutils netcat iproute2 2>/dev/null"
# Tester la connectivité interne (DNS résout les noms de services dans les réseaux user-defined)
docker exec <nom_conteneur> curl -v http://database:5432 # Vérification TCP
docker exec <nom_conteneur> nslookup database # Vérification DNS
docker exec <nom_conteneur> ss -tulpn # Lister les ports en écoute DANS le conteneur
Constatation fréquente : L'app écoute sur 127.0.0.1:8080 dans le conteneur. Les requêtes externes (même depuis le même hôte via mapping de port) échouent. Correction : Binder sur 0.0.0.0:8080.
Surveillance de l'Utilisation des Ressources (cgroups v1/v2)
Repérez les fuites mémoire ou le throttling CPU avant que le killer OOM ne frappe.
# Flux temps réel (comme top)
docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.MemPerc}}\t{{.NetIO}}\t{{.BlockIO}}"
# Vérifier les kills OOM dans le log noyau (niveau hôte)
dmesg -T | grep -i -e oom -e kill
4. Modes d'Échec et Récupération
Quand la vérification échoue, vous avez besoin d'un runbook, pas de panique. Voici les patterns d'échec Docker les plus courants et leurs récupérations.
1. Le Conteneur Quitte Immédiatement (Équivalent CrashLoopBackOff)
Symptôme : docker ps -a montre Exited (137) 2 minutes ago ou Restarting (1) 5s ago. Diagnostic :
docker logs --tail 50 <nom_conteneur>
docker inspect --format '{{.State.ExitCode}} {{.State.Error}} {{.State.OOMKilled}}' <nom_conteneur>
- Code de sortie 137 (SIGKILL) : Presque toujours OOM (Out Of Memory). Vérifiez l'historique
docker stats; augmentez la limite--memoryou corrigez la fuite applicative. - Code de sortie 1/127 : Erreur application (binaire manquant, erreur syntaxe config, échec migration). Lisez les logs.
- Code de sortie 0 : Processus fini avec succès (job batch) ou script entrypoint fini sans
exec-uter le processus principal. Correction : Assurez-vous que l'entrypoint se termine parexec "$@".
2. Conflits de Port / « Address Already in Use »
Symptôme : docker run échoue : Error starting userland proxy: listen tcp4 0.0.0.0:80: bind: address already in use. Diagnostic :
# Vérifier ce qui tient le port 80 sur L'HÔTE
sudo ss -tulpn | grep :80
# Ou vérifier si un autre conteneur le possède
docker ps --format "table {{.Names}}\t{{.Ports}}" | grep :80
Récupération :
- Arrêter le processus hôte conflictuel (service systemd ?).
- Changer le mapping de port conteneur :
-p 8080:80. - Binder sur IP spécifique :
-p 127.0.0.1:80:80(localhost seulement).
3. Permission Refusée sur les Volumes
Symptôme : Logs app PermissionError: [Errno 13] Permission denied: '/data'. Diagnostic :
# Côté hôte
ls -ld /chemin/hote/data
# Côté conteneur
docker exec <nom_conteneur> ls -ld /data
docker exec <nom_conteneur> id # Vérifier UID/GID exécutant l'app
Récupération :
- Volume Nommé (Préféré) :
docker volume create app_data. Docker gère les permissions (généralement root dans le conteneur, mais l'app tourne en non-root ? Utilisezuser: "1000:1000"dans compose ouDockerfile USER). - Bind Mount :
chown -R 1000:1000 /chemin/hote/datasur l'hôte (correspondre à l'UID conteneur). Ou utilisez--userns-remap(avancé).
4. Échecs de Pull d'Image (Auth Registry / Rate Limits)
Symptôme : Error response from daemon: pull access denied ou toomanyrequests. Récupération :
- Auth :
docker login mon-registry.com(stocke les creds dans~/.docker/config.json). Pour CI :echo $TOKEN | docker login -u $USER --password-stdin. - Rate Limits (Docker Hub) : Utilisez un miroir/proxy (ex: miroir
registry.docker.iodans/etc/docker/daemon.json), authentifiez-vous (limites plus hautes), ou vendezorez les images vers un registry privé.
5. Pression Disque : « No Space Left on Device »
Symptôme : docker run échoue, builds échouent, hôte lent. Diagnostic :
df -h /var/lib/docker
docker system df -v # Détail : images, conteneurs, volumes, cache build
Récupération (Nettoyage Sûr) :
# 1. Supprimer conteneurs arrêtés (sûr)
docker container prune -f
# 2. Supprimer images dangling (sans tag, sans ref conteneur) - SÛR
docker image prune -f
# 3. Supprimer volumes inutilisés (DANGEREUX - PERTE DONNÉES) - SEULEMENT si vous savez qu'ils sont orphelins
# docker volume prune -f # NE PAS LANCER AVEUGLEMENT
# 4. Supprimer cache build (sûr, ralentit prochain build)
docker builder prune -f
Prévention : Configurez la rotation des logs (daemon.json), surveillez docker system df via Prometheus/node_exporter, planifiez un cron hebdomadaire de prune pour les éléments sûrs seulement.
5. Checklist Opérationnelle
Intégrez ces éléments dans vos routines quotidiennes/hebdomadaires et pipelines CI/CD.
Quotidien / Par Déploiement
- [ ]
docker compose configvalide la syntaxe et rend la config finale avantup. - [ ]
docker pull <image@digest>réussit dans la CI avant l'étape de déploiement. - [ ] Health check passe (statut
healthy) pour 2 intervalles consécutifs post-déploiement. - [ ]
docker logs --since <heure_deploiement> <conteneur> | grep -i errorretourne zéro ligne critique. - [ ] Reverse proxy / Load Balancer affiche le backend comme
UP.
Hebdomadaire
- [ ] Lancer
docker system df -v; alerter si espace récupérable > 20 Go ou > 50 % total. - [ ] Vérifier la restauration de backup pour un volume nommé (tester la restauration vers la staging).
- [ ] Scanner les images pour CVEs :
docker scout cves <image>outrivy image <image>. Bloquer le déploiement sur Critique/Élevé si la politique le dicte. - [ ] Revoir
docker ps -apour les conteneurs « zombies » (Exited > 7 jours). Supprimer après confirmation qu'ils ne sont pas nécessaires pour la forensique.
Mensuel / Trimestriel
- [ ] Exercice Complet de Reprise d'Activité : Remonter la stack from scratch sur hôte propre en utilisant seulement le repo Git (fichiers Compose, scripts,
.env.example) et volumes sauvegardés. Chronométrez. Documentez les lacunes. - [ ] Auditer
docker imagespour la fraîcheur des images de base. Rebuilder les images dépendantes sur base mise à jour (ex:python:3.11-slim->python:3.12-slim). - [ ] Revoir la config daemon Docker (
/etc/docker/daemon.json) : rotation logs, live-restore, userns-remap, insecure-registries (supprimer si inutilisés). - [ ] Rotater les identifiants registry et mettre à jour les secrets CI/CD.
Conclusion
Les commandes Docker ne sont fiables que par la discipline opérationnelle qui les entoure. Mémoriser les drapeaux de docker run ou docker compose up est le droit d'entrée ; la pratique consiste à construire un flux où chaque changement est observé, vérifié et réversible. Commencez par instrumenter votre stack actuelle : ajoutez des health checks à chaque service, imposez des volumes nommés pour l'état, et scriptez le test de redémarrage dans votre pipeline CI. Quand la prochaine alerte 3 heures du matin sonnera, vous ne lirez pas docker --help ; vous lancerez docker logs --tail 200 -t <conteneur>, verrez l'erreur, exécuterez le rollback documenté, et retournerez dormir. C'est le standard que ce guide vous prépare à atteindre.