Échec de « docker-compose up » : dépannage systématique des erreurs courantes
Ce tutoriel propose une méthode systématique pour diagnostiquer et corriger les pannes les plus fréquentes lors d’un docker-compose up (ou docker compose up selon la version). L’objectif n’est pas de lister des “trucs”, mais de vous donner une procédure reproductible : identifier la classe d’erreur, collecter les preuves (logs, état, réseau, images), corriger, puis valider.
1) Pré-requis et vocabulaire (important pour éviter les fausses pistes)
1.1 docker-compose vs docker compose
- Docker Compose v1 : commande
docker-compose(binaire Python historique). - Docker Compose v2 : commande
docker compose(plugin officiel Docker).
Vérifiez ce que vous utilisez :
docker compose version
docker-compose version
docker version
En cas de doute, privilégiez Compose v2 si disponible.
1.2 “Up” fait plusieurs choses
Un docker compose up peut échouer à différentes étapes :
- Lecture/validation du fichier Compose
- Interpolation des variables d’environnement
- Construction d’images (si
build:) - Pull d’images (si
image:ou build manquant) - Création des réseaux/volumes
- Création des conteneurs
- Démarrage des conteneurs
- Exécution du processus applicatif (qui peut crasher immédiatement)
Le message d’erreur indique souvent à quelle étape ça casse. Votre diagnostic doit suivre cette chronologie.
2) Méthode de dépannage : la checklist “preuve → hypothèse → correction”
2.1 Relancer avec plus de signal
Commencez par obtenir un maximum d’informations sans noyer l’essentiel :
docker compose up
Si ça échoue vite, relancez en mode “sans attacher” + logs :
docker compose up -d
docker compose ps
docker compose logs --no-color --tail=200
Si un service ne démarre pas, isolez-le :
docker compose up <service>
docker compose logs -f <service>
2.2 Inspecter l’état réel côté Docker
Compose peut échouer mais laisser des artefacts. Vérifiez :
docker ps -a
docker images
docker network ls
docker volume ls
Puis inspectez un conteneur précis :
docker inspect <container_id_or_name> --format '{{json .State}}' | jq
Si jq n’est pas disponible :
docker inspect <container_id_or_name> | less
2.3 Valider la configuration Compose (avant d’accuser Docker)
Générez la configuration finale (après interpolation des variables) :
docker compose config
C’est une étape clé : elle révèle souvent une variable vide, un chemin erroné, un port mal formé, etc.
3) Erreurs de lecture/validation du fichier Compose
3.1 “Additional property … is not allowed” / “Unsupported config option”
Symptômes :
- Erreur dès le lancement, avant toute création de conteneur.
- Souvent liée à une version Compose incompatible ou à des clés mal placées.
Actions :
- Affichez la config normalisée :
docker compose config
- Vérifiez la version Compose et la compatibilité des champs utilisés.
- Si vous migrez d’exemples trouvés en ligne, certains utilisent des options obsolètes.
Cas fréquent : confusion entre options de deploy: (orientées Swarm) et Compose “local”. Par exemple, deploy.resources n’est pas appliqué en mode non-Swarm (même si accepté).
3.2 “services..ports contains an invalid type”
Souvent causé par une mauvaise forme de port, ex. ports: - 8080 au lieu de "8080:80".
Même sans voir votre YAML, la règle est :
portsattend des chaînes"HOST:CONTAINER"ou des objets (selon syntaxe), mais pas un entier brut (selon version).
Vérifiez avec :
docker compose config | sed -n '/ports:/,/^[^ ]/p'
3.3 Mauvaise indentation / erreur YAML
Message typique : yaml: line X: did not find expected key
Approche :
- Vérifiez l’indentation (espaces, pas de tabulations).
- Minimisez : commentez des blocs jusqu’à ce que
docker compose configpasse.
4) Problèmes de variables d’environnement et interpolation
4.1 Variables vides ou non définies
Compose substitue ${VAR} à partir :
- de l’environnement courant
- du fichier
.env(dans le répertoire du projet, par défaut)
Validez ce que Compose voit :
docker compose config
Pour voir les variables réellement définies dans votre shell :
env | sort | less
Cas typique :
DATABASE_URL=${DATABASE_URL}mais la variable n’existe pas → valeur vide → l’app crashe.ports: - "${PORT}:80"avecPORTvide → erreur de parsing.
Solution :
- Créez/complétez
.env:
cat > .env <<'EOF'
PORT=8080
DB_USER=app
DB_PASSWORD=secret
EOF
Puis :
docker compose up -d
4.2 Confusion entre env_file: et .env
.envsert à interpoler le fichier compose.env_file:sert à injecter des variables dans le conteneur.
Exemple de diagnostic :
docker compose configmontre que${PORT}n’est pas remplacé →.envabsent.- Mais vous avez
env_file: .envdans un service → cela n’aide pas l’interpolation du champports.
5) Échecs de build (services avec build:)
5.1 “failed to solve: …” (BuildKit) / “COPY failed”
Si le build échoue, Compose ne pourra pas démarrer.
Procédure :
- Reproduisez le build seul :
docker compose build --no-cache --progress=plain
- Si un service spécifique :
docker compose build --no-cache --progress=plain <service>
- Vérifiez le contexte de build (répertoire envoyé au daemon) :
build: .envoie tout le dossier ; un.dockerignoremal configuré peut exclure des fichiers indispensables.
Inspectez .dockerignore :
sed -n '1,200p' .dockerignore
5.2 Problèmes de droits/chemins lors d’un COPY
Erreurs fréquentes :
COPY package.jsonmais le fichier n’est pas dans le contexte.COPYd’un chemin relatif incorrect.
Astuce : affichez l’arborescence du contexte :
ls -la
git status --porcelain
5.3 Architecture CPU (ARM vs AMD64)
Sur Mac Apple Silicon ou Raspberry Pi :
- Une image ou une dépendance native peut ne pas exister pour
arm64.
Vérifiez l’architecture :
uname -m
docker info --format '{{.Architecture}}'
Forcer une plateforme (si nécessaire) :
docker compose up --build --pull=always --quiet-pull
Ou dans certains cas :
docker run --platform linux/amd64 -it --rm alpine uname -m
Si votre service dépend d’une image non multi-arch, vous devrez soit :
- choisir une image compatible,
- soit builder vous-même une image multi-arch,
- soit exécuter via émulation (plus lent).
6) Échecs de pull d’images (registre, authentification, tags)
6.1 “pull access denied” / “requested access to the resource is denied”
Causes :
- image privée sans login
- mauvais nom d’image
- tag inexistant
Vérifications :
docker compose pull
Puis login si registre privé :
docker login
# ou
docker login registry.example.com
Testez le pull direct :
docker pull registry.example.com/monapp:1.2.3
6.2 “manifest unknown” / tag introuvable
Le tag mentionné n’existe pas. Corrigez image: (tag) ou publiez l’image.
7) Problèmes de ports : “bind: address already in use” et variantes
7.1 Port déjà utilisé sur l’hôte
Message : Bind for 0.0.0.0:8080 failed: port is already allocated
Identifiez le processus :
- Linux :
sudo ss -ltnp | grep ':8080'
# ou
sudo lsof -iTCP:8080 -sTCP:LISTEN -n -P
- macOS :
lsof -iTCP:8080 -sTCP:LISTEN -n -P
Solutions :
- changer le port hôte dans Compose
- arrêter le service qui occupe le port
- éviter l’exposition si inutile (utiliser réseau interne)
7.2 Conflits avec des conteneurs existants
Même si votre app est arrêtée, un ancien conteneur peut réserver le port.
Listez :
docker ps -a --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'
Nettoyez :
docker compose down
docker rm -f <container>
8) Problèmes de volumes et permissions (la source n°1 de “ça marche sur ma machine”)
8.1 “permission denied” sur un volume bind-mount
Symptômes :
- l’app ne peut pas écrire dans
/var/lib/...ou/app/storage - erreurs
EACCES,Permission denied,Operation not permitted
Démarche :
- Voyez quel chemin est monté :
docker compose config | sed -n '/volumes:/,/^[^ ]/p'
- Inspectez le montage réel :
docker inspect <container> --format '{{json .Mounts}}' | jq
- Vérifiez UID/GID dans le conteneur :
docker exec -it <container> id
docker exec -it <container> ls -la /chemin
Cause classique : l’utilisateur dans le conteneur (ex. UID 1000) ne correspond pas au propriétaire du dossier sur l’hôte.
Correctifs possibles :
- Ajuster propriétaire sur l’hôte (Linux) :
sudo chown -R 1000:1000 ./data
- Lancer le service avec un utilisateur adapté (selon image) :
docker exec -it <container> sh
- Éviter les bind-mounts pour des données applicatives sensibles, préférer un volume nommé :
docker volume create mon_volume
Puis dans Compose (conceptuellement) : monter mon_volume:/var/lib/....
8.2 SELinux (Fedora/RHEL/CentOS) : accès refusé malgré des droits corrects
Sur systèmes avec SELinux, un bind-mount peut être bloqué.
Indicateur : vous avez Permission denied alors que chmod/chown semblent corrects.
Vérifiez SELinux :
getenforce
Solutions :
- utiliser les options de label
:zou:Zsur les montages (selon besoin) - ou ajuster les contextes SELinux.
9) Réseaux Docker : DNS interne, noms de services, collisions
9.1 “Temporary failure in name resolution” / service introuvable
Dans Compose, les conteneurs se résolvent par nom de service sur le réseau Compose.
Erreurs typiques :
- l’app tente
localhostau lieu dedb(service Postgres) - le service n’est pas sur le même réseau
Vérifiez les réseaux :
docker compose ps
docker network ls
docker network inspect <projet>_default | less
Test DNS depuis un conteneur :
docker exec -it <container_app> getent hosts db
docker exec -it <container_app> ping -c 1 db
Si getent n’existe pas, utilisez nslookup (selon image) ou lancez un conteneur utilitaire sur le réseau :
docker run --rm -it --network <projet>_default alpine sh
# puis
apk add --no-cache bind-tools
nslookup db
9.2 Collision de réseaux / projets multiples
Compose nomme les ressources avec un “project name” (souvent le nom du dossier). Si vous avez plusieurs clones du même projet, vous pouvez avoir des collisions.
Fix :
- définir un nom de projet explicite :
docker compose -p monprojet up -d
Ou via variable :
export COMPOSE_PROJECT_NAME=monprojet
docker compose up -d
10) Dépendances entre services : depends_on ne garantit pas la “prêtitude”
10.1 Symptôme : l’app démarre avant la base, puis crashe
depends_on gère l’ordre de démarrage des conteneurs, pas la disponibilité applicative.
Diagnostic :
- logs de l’app : “connection refused” vers DB
- DB met quelques secondes à initialiser
Commandes :
docker compose logs -f db
docker compose logs -f app
Solutions robustes :
- Ajouter un healthcheck à la DB et conditionner le démarrage (selon capacités Compose)
- Ajouter une logique de retry côté application
- Utiliser un script d’attente (ex.
wait-for-it,dockerize,bashloop)
Test manuel de connectivité depuis le conteneur app :
- Pour Postgres :
docker exec -it <container_app> sh -lc 'nc -vz db 5432'
- Pour MySQL :
docker exec -it <container_app> sh -lc 'nc -vz db 3306'
11) Crash immédiat du conteneur : comprendre ExitCode, CMD, ENTRYPOINT
11.1 Lire le code de sortie et la raison
docker compose ps
docker inspect <container> --format 'ExitCode={{.State.ExitCode}} Error={{.State.Error}} OOMKilled={{.State.OOMKilled}}'
docker compose logs --tail=200 <service>
11.2 “exec: …: not found” / script non exécutable
Causes :
- fichier absent (mauvais chemin)
- script sans bit exécutable
- shebang incorrect
- fin de ligne Windows CRLF
Vérifiez dans l’image :
docker exec -it <container> ls -la /chemin/du/script
docker exec -it <container> head -n 1 /chemin/du/script
Détecter CRLF (depuis l’hôte) :
file ./entrypoint.sh
Convertir :
sed -i 's/\r$//' entrypoint.sh
chmod +x entrypoint.sh
11.3 Mauvaise commande par défaut
Testez en lançant un shell dans l’image (si possible) :
docker compose run --rm <service> sh
Ou, si l’image n’a pas sh, essayez bash :
docker compose run --rm <service> bash
Puis exécutez la commande attendue manuellement pour voir l’erreur.
12) Problèmes de ressources : mémoire, disque, inodes
12.1 OOMKilled (manque de mémoire)
Symptôme : conteneur s’arrête, OOMKilled=true.
Vérifiez :
docker inspect <container> --format '{{.State.OOMKilled}}'
docker stats --no-stream
Sur Docker Desktop, augmentez la mémoire allouée. Sinon :
- réduire la consommation (paramètres JVM/Node)
- limiter des services
- éviter de lancer trop de stacks en parallèle
12.2 Disque plein
Symptômes :
- erreurs d’écriture, build qui échoue, DB corrompue
no space left on device
Vérifiez :
df -h
docker system df
Nettoyage (attention : cela supprime des ressources non utilisées) :
docker system prune
docker system prune -a
docker volume prune
13) Conflits de conteneurs, noms déjà pris, état incohérent
13.1 “Conflict. The container name … is already in use”
Un conteneur existant a le même nom.
Listez et supprimez :
docker ps -a | grep mon_service
docker rm -f <container_id>
Puis relancez :
docker compose up -d
13.2 État Compose vs état Docker
Parfois Compose “pense” qu’un conteneur existe mais il est cassé.
Remise à plat :
docker compose down --remove-orphans
docker compose up -d --build
Si vous suspectez des volumes problématiques (DB de test), vous pouvez supprimer aussi les volumes du projet (perte de données) :
docker compose down -v
14) TLS, proxies, certificats : pulls/builds qui cassent derrière un proxy
Symptômes :
x509: certificate signed by unknown authority- timeouts vers Docker Hub
- build qui ne peut pas
apt-get/npm install
Vérifications :
- test réseau simple :
curl -I https://registry-1.docker.io/v2/
- variables proxy :
env | grep -i proxy
Si vous êtes en entreprise, il faut souvent :
- configurer le proxy pour Docker daemon / Docker Desktop
- ajouter le CA de l’entreprise dans le trust store (hôte et/ou image)
- passer
HTTP_PROXY/HTTPS_PROXY/NO_PROXYau build
Testez un build avec logs :
docker compose build --progress=plain --no-cache
15) Techniques avancées : isoler, reproduire, instrumenter
15.1 Lancer un service “en debug”
Exécuter un shell au lieu de la commande normale (utile si le conteneur crash trop vite) :
docker compose run --rm --entrypoint sh <service>
Puis inspecter variables, fichiers, connectivité :
env | sort
ls -la
nc -vz db 5432
15.2 Comparer image attendue vs image réellement utilisée
Listez les images et tags :
docker compose images
docker images | head
Forcer un rebuild complet :
docker compose build --no-cache
docker compose up -d --force-recreate
15.3 Observer les événements Docker en temps réel
Très utile pour voir les redémarrages, créations, erreurs réseau :
docker events
Dans un autre terminal :
docker compose up
15.4 Vérifier les logs “daemon” (Linux)
Si Docker lui-même échoue (montage, réseau), regardez le service Docker :
sudo journalctl -u docker --since "1 hour ago" -f
16) Scénarios d’erreurs courantes (diagnostic → correction)
16.1 “Cannot connect to the Docker daemon”
Message : Cannot connect to the Docker daemon at unix:///var/run/docker.sock
Causes :
- daemon Docker arrêté
- permissions sur le socket
- Docker Desktop non lancé
Fix (Linux) :
sudo systemctl status docker
sudo systemctl start docker
Permissions (ajouter votre user au groupe docker) :
sudo usermod -aG docker $USER
newgrp docker
docker ps
16.2 “network … not found” après nettoyage
Si vous avez supprimé des réseaux manuellement, Compose peut être confus.
Remise à plat :
docker compose down
docker network prune
docker compose up -d
16.3 “Mounts denied” (Docker Desktop macOS/Windows)
Symptôme : montage d’un chemin hôte refusé.
Sur Docker Desktop, vous devez autoriser le partage du dossier. Vérifiez les réglages “File sharing”/“Resources”.
En attendant, testez un chemin sous votre home, typiquement autorisé :
pwd
# évitez /Volumes non partagés ou des chemins système
17) Procédure “standard” de dépannage (résumé opératoire)
Quand docker compose up échoue, appliquez cette séquence dans l’ordre :
- Valider la config
docker compose config
- Pull / build séparément
docker compose pull
docker compose build --progress=plain
- Démarrer en arrière-plan
docker compose up -d
docker compose ps
- Lire les logs
docker compose logs --tail=200
docker compose logs -f <service_en_erreur>
- Inspecter le conteneur
docker inspect <container> --format 'ExitCode={{.State.ExitCode}} OOMKilled={{.State.OOMKilled}}'
docker inspect <container> --format '{{json .Mounts}}' | jq
- Tester réseau/DNS depuis un conteneur
docker exec -it <container_app> sh -lc 'getent hosts db || true'
docker exec -it <container_app> sh -lc 'nc -vz db 5432 || true'
- Nettoyage contrôlé
docker compose down --remove-orphans
docker compose up -d --build
- Nettoyage “fort” si nécessaire (attention données)
docker compose down -v
18) Conseils de prévention (pour éviter les pannes récurrentes)
- Ajoutez des healthchecks aux services critiques (DB, cache) et faites dépendre l’app de la disponibilité réelle (ou implémentez un retry).
- Utilisez des volumes nommés pour les données (DB) et des bind-mounts uniquement pour le code.
- Documentez les variables nécessaires dans un
.env.example, et validez leur présence au démarrage. - Évitez d’exposer des ports inutiles sur l’hôte ; préférez la communication via réseau Docker.
- Épinglez les versions d’images (
postgres:16,redis:7) plutôt quelatest. - Sur équipe, standardisez la commande :
docker compose(v2) et la version Docker.
19) Si vous êtes bloqué : quelles informations fournir pour un diagnostic rapide
Si malgré tout docker compose up échoue, collectez ces éléments (sans secrets) :
docker compose version
docker version
docker compose config
docker compose ps
docker compose logs --tail=300
docker ps -a
docker network ls
docker system df
Et pour le service fautif :
docker inspect <container> | sed -n '1,200p'
En pratique, docker compose config + docker compose logs + docker inspect résolvent la majorité des cas.
Conclusion
Un échec de docker-compose up n’est pas une “boîte noire” : il se décompose en étapes observables (config → build/pull → création → démarrage → exécution). En appliquant la méthode ci-dessus — validation de config, isolation du service, inspection des montages/réseaux, lecture structurée des logs et remise à plat contrôlée — vous transformez un incident frustrant en diagnostic rapide et documentable.