Docker Compose : aide-mémoire pour serveurs
Retrouvez les commandes Compose V2 par tâche : cycle de vie, changements, logs, shells, réseaux, volumes et nettoyage sûr, avec les pièges courants.
Les commandes Compose que vous utilisez réellement
Docker Compose fournit plus de quarante sous-commandes. Au quotidien, l’administration d’un serveur en utilise environ une douzaine. Cette page les regroupe selon la tâche à effectuer, explique simplement l’utilité de chacune et renvoie vers les explications détaillées lorsqu’une commande présente un piège.
Tout ce qui suit utilise Compose V2 : docker compose avec un espace, et non l’ancien script docker-compose. V2 est un plugin Go qui s’installe avec Docker Engine. V1 a disparu des paquets actuels. Un docker-compose: command not found sur une nouvelle machine Ubuntu en juillet 2026 est donc attendu et n’indique pas un problème. Vérifiez avec docker compose version. Si cette commande n’affiche rien, installez le paquet docker-compose-plugin.
Chaque commande ci-dessous s’exécute depuis le répertoire qui contient votre compose.yaml, car Compose déduit le nom du projet de ce répertoire et recherche le fichier relativement à celui-ci. Si vous exécutez la même commande un niveau plus haut, Compose s’arrête avec no configuration file provided: not found. Si le format du fichier ne vous est pas encore familier, commencez par un premier fichier Compose sur un VPS, puis revenez ici pour les commandes.
Cycle de vie : les quatre commandes que vous utilisez, et celle qui supprime les conteneurs
docker compose up -d
docker compose up -d --wait
docker compose stop
docker compose start
docker compose restart web
docker compose downup -d crée le réseau, crée les conteneurs, les démarre, puis rend la main. Elle rend la main dès que les conteneurs sont créés. C’est pourquoi un script de déploiement qui exécute ensuite une sonde curl échoue souvent au premier essai. up -d --wait attend que chaque service qui déclare un healthcheck indique un état sain, puis renvoie un code différent de zéro si l’un d’eux n’y arrive jamais. Cette option n’est efficace que si le contrôle sous-jacent l’est aussi. Écrivez donc un healthcheck que Compose peut utiliser avant de vous y fier dans l’automatisation.
stop arrête les conteneurs et les conserve. start redémarre donc les mêmes conteneurs avec la même couche inscriptible. down les arrête, puis supprime les conteneurs et le réseau du projet. Tout ce qui a été écrit dans le conteneur, en dehors d’un volume, est supprimé avec lui. C’est la confusion la plus coûteuse dans Compose. La différence complète entre down et stop explique dans quels cas elle pose problème.
restart ne recharge pas la configuration. Elle arrête et redémarre le même conteneur avec la configuration qu’il possède déjà. Une variable d’environnement modifiée, un nouveau tag d’image ou une modification du mapping de port n’a donc aucun effet. Pour appliquer une modification du fichier, exécutez de nouveau up -d. Compose compare chaque service à son conteneur en cours d’exécution et recrée uniquement ceux dont la configuration a changé.
Appliquer une modification : recréer, télécharger ou reconstruire
docker compose up -d --force-recreate
docker compose pull && docker compose up -d
docker compose build --no-cache web
docker compose up -d --build webup -d ne fait rien si aucune modification n’est détectée, ce qui permet de l’exécuter plusieurs fois sans risque. --force-recreate force la recréation de chaque conteneur, même lorsque la configuration est identique. C’est le moyen le plus rapide de supprimer un état inhabituel dans les conteneurs.
Mettre à jour une image nécessite deux commandes, car elles ont des rôles différents. pull télécharge l’image actuelle pour chaque tag indiqué dans le fichier. up -d détecte ensuite que l’ID de l’image du service ne correspond plus à celui de son conteneur en cours d’exécution et le recrée. Si vous omettez le pull, up -d laisse tourner le latest du mois dernier sans signaler d’erreur. Le risque inverse apparaît sur une stack composée de plusieurs services : télécharger latest pour tous les services en même temps peut casser une application qui fonctionnait encore dix secondes plus tôt. C’est pourquoi un espace de travail AFFiNE auto-hébergé épingle chacun de ses quatre tags d’image. L’épinglage transforme également une mise à niveau en une modification délibérée du tag, suivie du même pull et de la même recréation. Sur une stack qui migre sa base de données au démarrage, vous devez disposer d’un dump avant d’exécuter l’une ou l’autre commande. C’est la procédure suivie par un centre de support Chatwoot auto-hébergé pour chaque mise à niveau de version.
build s’applique aux services qui déclarent une section build: au lieu d’une section image:. up -d --build construit l’image et démarre le service en une seule étape. C’est la boucle normale lorsque vous modifiez du code. Utilisez --no-cache uniquement lorsqu’une couche mise en cache est manifestement obsolète, car cette commande reconstruit toutes les couches depuis zéro. Lorsqu’une stack est déployée à partir d’un tag git extrait plutôt qu’à partir d’une image de registre, cette même boucle de build constitue également sa procédure de mise à jour. C’est ainsi que un outil de suivi d’entraînement openGym auto-hébergé passe d’une version épinglée à la suivante.
Voir ce qui est en cours d’exécution
docker compose ps
docker compose ps -a
docker compose logs -f --tail=100
docker compose logs --since 15m --timestamps db
docker compose top
docker compose lsps liste uniquement les conteneurs en cours d’exécution. Un service qui a échoué au démarrage n’y apparaît pas tant que vous n’ajoutez pas -a. Un conteneur absent de ps alors que ps -a l’affiche comme Exited (1) correspond donc au cas habituel d’un échec au démarrage. Lisez le code de sortie, puis consultez les journaux.
logs -f suit tous les services simultanément et préfixe chaque ligne avec le nom du service. C’est la vue adaptée lorsque les services communiquent entre eux et que l’ordre des événements compte. Indiquez le nom d’un service pour limiter l’affichage. --tail=100 est important pour un conteneur qui fonctionne depuis un mois, car l’affichage par défaut montre tout l’historique et surcharge le terminal. --since 15m répond généralement à la question que vous vous posez : que s’est-il passé pendant le redémarrage que vous venez d’effectuer ?
top liste les processus présents dans chaque conteneur. Cela permet de distinguer « le conteneur est en cours d’exécution » de « le processus qu’il contient est en cours d’exécution ». ls sort du répertoire courant et liste tous les projets Compose présents sur l’hôte avec leur état. Vous pouvez ainsi retrouver la stack que vous avez démarrée il y a trois mois.
Ouvrir un shell dans un service
docker compose exec web sh
docker compose exec -u root web sh
docker compose run --rm web env
docker compose run --rm --no-deps web shexec exécute une commande dans un conteneur déjà démarré. run démarre un nouveau conteneur à partir de la même définition de service. C’est nécessaire lorsque le service ne reste pas démarré assez longtemps pour y exécuter une commande avec exec. Utilisez toujours run avec --rm. Sans cette option, chaque exécution laisse un conteneur arrêté, qui s’accumule jusqu’à rendre docker compose ps -a illisible.
Essayez sh avant bash. Les images basées sur Alpine ne contiennent pas bash, et l’échec affiche exec: "bash": executable file not found in $PATH. Ajouter --no-deps à run ignore les dépendances du service. Cela évite qu’une vérification rapide de la configuration ne démarre toute votre base de données.
run --rm web env est le moyen le plus rapide de voir l’environnement réellement reçu par un service, une fois chaque fichier .env, bloc environment: et variable shell fusionnés. Lorsqu’une valeur est incorrecte, l’ordre de fusion en est généralement la cause. La résolution des fichiers env et des secrets par Compose précise quelle source est prioritaire.
Réseaux, ports et résolution de noms
docker compose port web 80
docker compose exec web getent hosts db
docker compose config --networksCompose place tous les services sur un même réseau de projet, et le nom de chaque service y fait office de nom DNS. L’exécution de getent hosts db dans web affiche l’adresse IP du conteneur lorsque la résolution fonctionne, et n’affiche rien dans le cas contraire. Cela permet de vérifier en deux secondes si ces conteneurs peuvent communiquer entre eux. Si le nom est résolu mais que la connexion est refusée, le processus dans db est lié à 127.0.0.1 au lieu de 0.0.0.0. Il n’accepte donc aucun paquet provenant d’un autre conteneur. La même séparation explique pourquoi un conteneur démarré en dehors du projet, avec docker run ou dans sa propre stack, ne peut pas résoudre un nom comme jellyfin. C’est le premier point à vérifier lorsqu’une interface Halcyon pour votre bibliothèque Jellyfin ne peut pas joindre le serveur configuré. Le reste de ce modèle est expliqué dans le fonctionnement des réseaux Compose et du DNS des services.
port web 80 affiche l’adresse de l’hôte et le port sur lesquels le port d’un conteneur est publié. Cela évite de devoir deviner lorsque la correspondance provient d’une variable. La publication d’un port ajoute également une règle de pare-feu gérée directement par Docker. Cette règle passe avant les vôtres. Un service que vous pensiez privé peut donc être accessible depuis Internet. Ce cas est traité dans pourquoi les ports Docker publiés contournent ufw. Il est plus sûr de ne pas publier ces ports et de placer à la place un proxy d’authentification sur le réseau du projet, devant les services. C’est ce que permet l’exécution d’Authentik comme couche d’authentification unique.
Volumes et données
docker compose config --volumes
docker compose cp db:/etc/postgresql/pg_hba.conf ./pg_hba.conf
docker compose down -vconfig --volumes affiche les volumes nommés déclarés par le projet, à raison d’un par ligne. Cette liste correspond à ce que vous devez sauvegarder. Lorsque les volumes contiennent des données irremplaçables, la commande de sauvegarde exacte est aussi importante que la liste. C’est pourquoi la comparaison entre PhotoPrism et Immich détaille les commandes de dump et de copie nécessaires pour chaque serveur photo. cp copie un fichier vers ou depuis un conteneur sans ouvrir de shell, en utilisant la forme service:path du côté où se trouve le conteneur.
down -v supprime ces volumes nommés avec les conteneurs. C’est la bonne commande pour démanteler une stack de test, mais la mauvaise pour tout ce qui contient des données importantes, car aucune confirmation n’est demandée et l’opération est irréversible. Les bind mounts y survivent, car ils résident sur le système de fichiers de l’hôte. Cette différence de portée en cas d’incident est l’une des raisons pour lesquelles il faut choisir délibérément entre les bind mounts et les volumes nommés.
Nettoyage pour libérer de l’espace disque sans perdre de données
docker compose down --remove-orphans
docker system df
docker image prune -a
docker builder prune--remove-orphans supprime les conteneurs qui appartiennent au projet mais qui n’apparaissent plus dans le fichier. C’est exactement ce qui se produit après le renommage d’un service. Sans cette option, ces conteneurs continuent de fonctionner, sans apparaître dans docker compose ps.
docker system df indique comment l’espace disque est utilisé avant toute suppression. La commande distingue les images, les conteneurs, les volumes locaux et le cache de build, avec pour chacun la quantité d’espace récupérable. image prune -a supprime toutes les images vers lesquelles aucun tag ne pointe. Sur un serveur qui a téléchargé plusieurs versions d’une image volumineuse, c’est généralement le gain le plus important. builder prune vide le cache de build, qui augmente progressivement sur tout serveur qui construit ses propres images.
Aucune de ces commandes ne modifie un volume nommé. Seules docker volume prune et docker compose down -v le font.
Vérifier le fichier avant qu’il ne provoque un problème
docker compose config --quiet
docker compose config --services
docker compose --dry-run up -dconfig --quiet valide le fichier et n’affiche rien en cas de succès. Il convient donc à une étape de pré-déploiement ou à un hook Git. config affiche le fichier entièrement fusionné et interpolé. Cela permet de vérifier qu’une variable a bien été résolue et qu’un fichier d’override a été appliqué comme prévu. Une variable non définie apparaît alors avec une valeur vide, accompagnée de l’avertissement The "X" variable is not set. Defaulting to a blank string.
--dry-run est une option globale, et non une option de sous-commande. Elle doit donc être placée avant up. Cette commande affiche toutes les actions que Compose effectuerait sans rien modifier. Ces trente secondes sont utiles avant un down sur une stack importante.
Utiliser plusieurs fichiers, profils et projets
docker compose -f compose.yaml -f compose.prod.yaml up -d
docker compose --profile debug up -d
docker compose -p staging up -dPlusieurs options -f sont fusionnées dans l’ordre. Les fichiers suivants remplacent les valeurs des fichiers précédents, clé par clé. C’est la méthode standard pour conserver un fichier de base avec une petite surcharge de configuration pour la production. Les règles diffèrent toutefois pour les listes et les maps. Consultez donc la fusion de plusieurs fichiers Compose avant de chercher la cause d’un résultat inattendu.
--profile démarre les services associés à ce profil en plus des services sans profil. Cela permet de ne pas inclure les outils de débogage dans un up normal. -p définit le nom du projet. Deux copies d’une même stack peuvent ainsi fonctionner côte à côte avec des réseaux et des noms de volumes distincts. Pour restaurer la stack après un redémarrage, vous n’avez pas besoin de saisir une commande. Une unité s’en charge automatiquement. Elle est décrite dans démarrer des stacks Compose au boot.
FAQ
Qu’est-ce qui a remplacé docker-compose avec un trait d’union ?
Compose V2, appelé avec docker compose séparé par un espace. Il s’agit d’un plugin fourni avec Docker Engine, et l’outil Python V1 n’est plus installé par les paquets actuels. Si la forme avec espace n’affiche rien, installez le paquet docker-compose-plugin correspondant à votre distribution. Mettez à jour les anciens scripts pour utiliser la forme avec espace au lieu d’ajouter un alias, car V2 propose des options que V1 ne possédait pas.
Pourquoi docker compose restart ne prend-il pas en compte ma modification de configuration ?
restart arrête puis redémarre le conteneur existant avec la configuration utilisée lors de sa création. Il ne relit jamais compose.yaml. Toute modification des variables d’environnement, des ports, des volumes ou du tag de l’image nécessite docker compose up -d. Cette commande compare chaque service à son conteneur en cours d’exécution et recrée ceux qui diffèrent. Ajoutez --force-recreate lorsque vous voulez forcer le remplacement même si rien n’a changé dans le fichier.
Comment mettre à jour un service vers une image plus récente ?
Exécutez docker compose pull, puis docker compose up -d. La commande pull récupère l’image actuelle pour chaque tag défini dans le fichier, et up -d recrée les services dont l’ID d’image ne correspond plus à celui de leur conteneur. Exécuter up -d seul réutilise l’image déjà présente sur le disque. C’est pourquoi une stack utilisant latest peut rester sur une build datant de plusieurs mois sans afficher d’erreur.
Quelles commandes de nettoyage sont sans risque sur un serveur en production ?
docker system df, docker image prune -a et docker builder prune suppriment uniquement les images et le cache. Les services en cours d’exécution continuent donc de fonctionner et les volumes nommés ne sont pas modifiés. Les commandes dangereuses sont docker compose down -v et docker volume prune : elles suppriment les volumes nommés sans demander de confirmation. Exécutez d’abord docker compose config --volumes afin de connaître les éléments susceptibles d’être supprimés.
Puis-je exécuter une seule commande sans démarrer toute la stack ?
Oui. docker compose run --rm --no-deps web sh démarre un conteneur unique à partir de la définition du service web, ignore ses dépendances et supprime le conteneur lorsque vous quittez. Utilisez plutôt exec lorsque le conteneur est déjà en cours d’exécution, car exec se connecte au processus actif et vous montre l’état réel du service.