Collisions de noms de projet Docker Compose : empêcher les stacks de s’écraser entre elles

Cet article vous a aidé ?

Tout commence par un « petit test rapide ». Quelqu’un lance docker compose up -d dans un nouveau répertoire, sur un hôte qui exécute déjà trois autres stacks Compose. Cinq minutes plus tard, un pager se déclenche. Un conteneur a été « recréé », un nom de réseau a été réutilisé, et un volume a été monté par le mauvais service. La production n’a pas seulement dérivé. Elle s’est fait voler dans une ruelle par une convention de nommage.

Compose est convivial jusqu’au moment où il ne l’est plus. Le mode de défaillance est subtil : rien ne « plante » immédiatement ; au lieu de cela, les stacks se chevauchent silencieusement, des conteneurs sont adoptés, et down supprime les mauvaises ressources avec la confiance d’un enfant tenant des ciseaux.

Ce qu’est réellement un « nom de projet » Compose (et pourquoi ça pique)

Dans Compose, le nom de projet est la limite du namespace. C’est ainsi que Compose décide quels conteneurs, réseaux et volumes appartiennent ensemble en tant que « une stack ». Si vous pensez « le nom du répertoire est le projet », vous avez à moitié raison. Cette moitié est celle qui cause des ennuis.

Compose utilise le nom de projet pour générer les noms des ressources et pour appliquer des labels qu’il utilise ensuite pour retrouver et gérer la stack. Cela signifie :

  • Les noms de conteneurs ressemblent souvent à <project>_<service>_1 (ou avec des tirets, selon la version et les paramètres de Compose).
  • Les noms de réseau par défaut ressemblent souvent à <project>_default.
  • Les volumes nommés deviennent souvent <project>_<volume> sauf si vous les nommez explicitement.
  • Des labels comme com.docker.compose.project et com.docker.compose.service sont appliqués, et Compose utilise ces labels plus tard lors de up, down, ps et du nettoyage.

Une collision de nom de projet se produit lorsque deux exécutions de Compose utilisent le même nom de projet (intentionnellement ou non) sur le même démon Docker. Compose les traite alors comme la même stack. Il « réconciliera » l’état : recréer des conteneurs, rattacher des réseaux, réutiliser des volumes, ou supprimer des ressources nécessaires à l’autre stack.

Voici la partie qui surprend les gens : les collisions n’exigent pas des fichiers Compose identiques. Elles nécessitent seulement le même nom de projet et des noms/labels de ressources qui se chevauchent. Compose n’est pas un ordonnanceur de cluster. C’est un réconciliateur d’état qui suppose que vous vouliez ce que vous avez tapé.

Blague n°1 : Les noms de projet Docker Compose sont comme les étiquettes de la cuisine au bureau : si deux personnes écrivent « Lunch », quelqu’un mange de la tristesse.

D’où vient le nom de projet (la priorité compte)

Compose choisit un nom de projet selon un ordre de priorité. Si vous ne le définissez pas volontairement, vous laissez l’environnement le fixer pour vous — une façon optimiste d’exécuter de la production.

Sources courantes, de la « plus explicite » à la « moins explicite » :

  • docker compose -p <name>
  • Variable d’environnement COMPOSE_PROJECT_NAME
  • name: au niveau supérieur dans le fichier Compose (pris en charge par le Compose moderne v2)
  • Le nom de base du répertoire du projet (généralement le répertoire courant)

Si votre organisation a plusieurs dépôts nommés app, plusieurs répertoires nommés docker, ou l’habitude de cloner des choses dans /srv sans noms de dossiers uniques, vous avez déjà construit une machine à collisions. Ajoutez des runners CI qui utilisent le même chemin de checkout et vous pouvez fabriquer des incidents à la demande.

Comment se produisent les collisions : les trois couches de nommage

Pour arrêter les collisions, vous devez comprendre ce qui se chevauche. Les stacks Compose se recoupent de trois manières principales :

1) Namespace de projet de Compose (labels et recherche)

Compose retrouve « ses » ressources par les labels. Le principal est com.docker.compose.project. Si deux stacks partagent le même nom de projet, Compose sélectionnera des ressources à travers les deux lors d’actions comme down, restart, et parfois up avec le nettoyage des orphelins.

C’est ici que « les stacks s’écrasent les unes les autres » se produit réellement. Compose n’écrase pas des fichiers ; il réconcilie des définitions de conteneurs par rapport à un ensemble d’objets labellisés qu’il croit être un seul projet.

2) Noms d’objets Docker (conteneurs, réseaux, volumes)

Même si les labels sont corrects, les noms d’objets Docker peuvent entrer en collision si vous codifiez des noms :

  • Noms de conteneurs codés en dur via container_name: sont globaux sur un démon. Deux stacks ne peuvent pas avoir container_name: postgres. L’un échouera, ou pire, vous le gérerez manuellement et oublierez qui le possède.
  • Noms de réseaux codés en dur via networks: default: name: foo peuvent faire partager un réseau à des projets séparés. Cela peut être intentionnel. Cela peut aussi être une fête de fuite de données.
  • Noms de volumes codés en dur peuvent faire partager des données entre projets différents. Là encore, peut-être intentionnel. Mais la plupart du temps c’est un « pourquoi l’environnement de staging utilise les données de prod ? » intentionnel.

3) Bindings de ports et ressources hôtes

Même si le nommage est parfait, l’hôte reste un seul hôte :

  • Deux stacks liant 0.0.0.0:80 vont entrer en collision. Compose retournera une erreur (meilleur des cas) ou vous redirigerez le trafic vers un endroit étrange (pire cas : le proxy frontal pointe vers le mauvais backend).
  • Deux stacks montant le même chemin hôte (comme /var/lib/app) peuvent écraser l’état l’un de l’autre.
  • Deux stacks utilisant les mêmes chemins de secrets/config sur l’hôte peuvent provoquer des échecs du type « ça marche sur ma machine » avec une touche productionnelle.

Les collisions les plus sournoises sont celles que Docker autorise à partager (volumes, réseaux) et que Compose encourage à moins que vous lui interdisiez.

Faits intéressants et contexte historique

Un peu de contexte aide car le comportement de Compose n’est pas sorti de nulle part. Voici des faits concrets qui expliquent pourquoi le nom de projet est à la fois puissant et dangereux :

  1. Compose a commencé sous le nom « Fig » (ère 2013–2014). Sa mission initiale était : « lancer une série de conteneurs depuis du YAML », pas « gérer des environnements multi-tenant sur le même démon ». Le namespacing était pragmatique, pas paranoïaque.
  2. Compose v1 était un outil Python pendant des années. Le docker compose moderne (v2) est un plugin du CLI Docker, et certains defaults et sorties de nommage ont changé lors de la transition.
  3. Les noms de projet étaient conçus pour être dérivés des répertoires parce que cela simplifiait le dev local : cloner le repo, lancer Compose, obtenir des ressources isolées « automatiquement ». Sur des hôtes partagés, cet « automatique » devient « aléatoire ».
  4. Les labels sont devenus le mécanisme principal de propriété à mesure que Docker a mûri. Compose s’appuie fortement sur des labels comme com.docker.compose.project parce que les noms de conteneur seuls ne sont pas fiables une fois que les utilisateurs les personnalisent.
  5. container_name: est volontairement déconseillé dans de nombreux patterns de production parce que ça casse le scaling et augmente les collisions de noms globaux. Compose ne peut pas créer plusieurs réplicas d’un service avec un nom de conteneur fixe.
  6. Le réseau par défaut par projet a été un gros gain d’ergonomie : il a réduit le besoin de liaisons manuelles et a offert la découverte de services au sein d’un projet. Il a aussi fait du nom de projet le namespace réseau.
  7. Le nettoyage des « conteneurs orphelins » a évolué dans le temps. Des options comme --remove-orphans sont utiles, mais quand l’identité de projet est erronée, elles deviennent une tronçonneuse.
  8. La sémantique de down de Compose est volontairement destructive : il supprime les ressources qu’il croit avoir créées. C’est un comportement correct — sauf si votre frontière de projet est fausse.
  9. Les stacks Swarm et les projets Compose sont des concepts différents, mais les humains les confondent parce que les deux utilisent du YAML et le mot « stack ». Cette confusion entraîne des raccourcis opérationnels et des erreurs de nommage.

Trois mini-récits d’entreprise issus des tranchées des collisions

Mini-récit 1 : L’incident causé par une mauvaise hypothèse

Dans une entreprise SaaS de taille moyenne, une équipe a lancé des tests de charge « temporaires » sur le même hôte Docker que l’environnement de staging. Ils étaient prudents, disaient-ils : répertoires différents, fichiers Compose différents, noms de services différents. Qu’est-ce qui pourrait entrer en collision ?

L’hypothèse était : « des répertoires différents signifient des stacks différentes. » Ils n’ont pas passé -p, n’ont pas défini COMPOSE_PROJECT_NAME, et leur répertoire de travail pour les deux runs se trouvait par hasard dans /srv/app parce qu’ils utilisaient un script d’automatisation partagé qui faisait un cd là systématiquement.

Le fichier Compose du test de charge définissait un service Redis et un service worker. Staging avait aussi Redis et des workers. Même nom de projet signifiait que Compose croyait que c’était un seul projet. Quand le test de charge a démarré, Compose a « utilement » recréé le conteneur worker avec l’image du test de charge parce qu’il correspondait au nom de service sous le même label de projet.

Rien n’a échoué immédiatement. Le worker est monté correctement. C’était juste le mauvais worker, connecté au même Redis et à la même queue de staging. Les utilisateurs de staging ont vu des jobs traités hors d’ordre et certains jobs « disparaître » à cause de formats de messages incompatibles. L’incident n’était pas un crash ; c’était un comportement corrompu. Ceux-là vous volent le week-end.

La correction a été banale : des noms de projet explicites pour chaque environnement, et une automatisation qui refuse d’exécuter Compose sans nom de projet. La ligne pertinente du postmortem : « Les noms de répertoires ne sont pas une isolation. »

Mini-récit 2 : L’optimisation qui s’est retournée contre eux

Une équipe plateforme voulait des déploiements plus rapides. Ils ont remarqué que les recréations Compose prenaient du temps sur un hôte chargé, alors ils ont optimisé en fixant des noms d’objets : container_name explicite, noms de réseaux explicites, noms de volumes explicites. L’idée était de faciliter le troubleshooting et réduire le « churn ».

Ça a marché pendant un mois. Puis deux équipes internes ont déployé différents services qui utilisaient tous deux un snippet Compose « de base » partagé. Le snippet définissait container_name: api parce que quelqu’un trouvait cela « propre ». Maintenant deux stacks essayaient de créer un conteneur nommé api sur le même démon.

Compose a refusé de démarrer la deuxième stack, et l’équipe l’a « réparé » en supprimant manuellement le conteneur existant puis en redémarrant. Ça a démarré la deuxième stack… et a tué silencieusement le premier service. L’incident n’était pas causé par Docker ; il résultait d’humains qui se débattaient avec une décision de nommage qui supprimait la capacité de Compose à gérer plusieurs instances en sécurité.

Le dernier retournement : le nom de réseau explicite a causé des interférences. Des conteneurs de debug d’une stack pouvaient résoudre et atteindre des services d’une autre stack parce qu’ils étaient sur le même réseau utilisateur défini. Personne ne l’avait prévu. C’est juste arrivé parce que « l’optimisation » avait remplacé l’isolation par la commodité.

Ils ont annulé l’« optimisation » de nommage, conservé des noms de projet explicites, et n’ont codé des noms en dur que lorsque l’exigence était réelle (par exemple pour intégrer des systèmes externes qui attendent un nom de réseau stable). Le gain de performance n’en valait pas la taxe d’ambiguïté.

Mini-récit 3 : La pratique austère mais correcte qui a sauvé la journée

Une entreprise régulée exécutait Compose sur une flotte de VM uniques (n’essayez pas de rire, vous avez déjà vu ça). Ils avaient une habitude qui paraissait excessive : chaque stack avait un nom de projet unique, ce nom incluait l’environnement et le propriétaire, et il était défini à deux endroits : le CI passait -p, et le repo incluait un .env avec COMPOSE_PROJECT_NAME pour les runs locaux.

Un jour un ingénieur a dû corriger rapidement un problème en staging et a accidentellement lancé Compose depuis le mauvais répertoire sur l’hôte. Le fichier Compose était correct, mais le répertoire de travail se trouvait dans un autre repo. Sans les garde-fous, cela aurait réutilisé le nom de projet de l’autre repo et lancé la danse du chevauchement.

Au lieu de cela, leur wrapper de déploiement affichait le nom de projet résolu et refusait de continuer à moins qu’il figure dans une allowlist pour cet hôte. C’était simple : analyser docker compose config, vérifier le nom, vérifier les labels attendus, puis exécuter up. L’ingénieur a grogné, a corrigé la commande et a continué.

Des semaines plus tard, lors d’un postmortem non lié, ils ont réalisé que le wrapper avait empêché une collision qui aurait amplifié l’incident. Personne n’a écrit un fil Slack héroïque à ce sujet. C’est le but. Des contrôles ennuyeux vous empêchent de jouer le rôle principal dans votre propre postmortem.

Tâches pratiques : 12+ commandes qui exposent les collisions (et que faire ensuite)

Ceci n’est pas du « bon à savoir ». Ce sont les commandes à exécuter quand quelqu’un dit « Compose a écrasé ma stack » et que vous voulez des preuves, pas des impressions. Chaque tâche inclut : la commande, ce que signifie la sortie, et la décision à prendre.

Tâche 1 : Voir quel nom de projet Compose utilisera avant qu’il ne touche quoi que ce soit

cr0x@server:~$ cd /srv/staging/app
cr0x@server:~$ docker compose config --format json | head
{
  "name": "app",
  "services": {
...

Ce que ça signifie : Le nom de projet résolu est app. Si vous attendiez staging-app, vous êtes déjà en territoire de collision.

Décision : Si le nom est trop générique, arrêtez et relancez avec -p ou définissez name:/COMPOSE_PROJECT_NAME. Ne lancez pas up.

Tâche 2 : Confirmer le nom de projet que Compose utilise pour une stack en cours

cr0x@server:~$ docker ps --format 'table {{.Names}}\t{{.Label "com.docker.compose.project"}}\t{{.Label "com.docker.compose.service"}}' | head
NAMES              COM.DOCKER.COMPOSE.PROJECT   COM.DOCKER.COMPOSE.SERVICE
app-web-1          app                          web
app-db-1           app                          db
payments-web-1     payments                     web

Ce que ça signifie : Les deux premiers conteneurs appartiennent au projet app. Le troisième appartient à payments. Si vous voyez des conteneurs inattendus sous le même label de projet, vous avez une collision.

Décision : Identifiez quel repo/quelle automatisation utilise aussi ce nom de projet. Quarantainez en choisissant un nouveau nom de projet pour l’un d’eux.

Tâche 3 : Lister les « projets » Compose sur le démon (inventaire rapide)

cr0x@server:~$ docker compose ls
NAME       STATUS              CONFIG FILES
app        running(2)          /srv/staging/app/docker-compose.yml
payments   running(1)          /srv/payments/docker-compose.yml

Ce que ça signifie : Compose pense qu’il existe un projet appelé app et l’associe à un chemin de fichier de config. Si plusieurs déploiements utilisent le même nom de projet, cette liste devient trompeuse ou bascule entre des chemins.

Décision : Si le projet montre un chemin de config inattendu, supposez une collision et auditez les déploiements récents.

Tâche 4 : Inspecter les labels d’un conteneur suspect pour trouver la propriété

cr0x@server:~$ docker inspect app-web-1 --format '{{json .Config.Labels}}' | head
{"com.docker.compose.config-hash":"b1b4...","com.docker.compose.container-number":"1","com.docker.compose.oneoff":"False","com.docker.compose.project":"app","com.docker.compose.project.config_files":"docker-compose.yml","com.docker.compose.project.working_dir":"/srv/staging/app","com.docker.compose.service":"web"}

Ce que ça signifie : Le conteneur indique qu’il a été créé depuis /srv/staging/app. Si vous trouvez des conteneurs avec le même label de projet mais un working_dir différent, vous avez deux sources qui alimentent un même projet.

Décision : Choisissez une source de vérité. Renommez un projet et redéployez proprement. Ne continuez pas à « partager » le label de projet entre des repos.

Tâche 5 : Identifier les réseaux partagés (parfois involontairement)

cr0x@server:~$ docker network ls --format 'table {{.Name}}\t{{.Driver}}' | grep -E 'app|payments'
NAME              DRIVER
app_default       bridge
payments_default  bridge
shared_frontend   bridge

Ce que ça signifie : app_default est le réseau par défaut pour le projet app. Si vous voyez deux projets attachés à un même réseau, cela peut être délibéré — ou une fuite.

Décision : Si vous n’avez pas intentionnellement créé un réseau partagé, n’attachez pas plusieurs projets à celui-ci. Utilisez des réseaux distincts par projet par défaut.

Tâche 6 : Vérifier quels conteneurs sont attachés à un réseau

cr0x@server:~$ docker network inspect app_default --format '{{json .Containers}}' | head
{"3c1f...":{"Name":"app-web-1","IPv4Address":"172.20.0.2/16"},"a77b...":{"Name":"app-db-1","IPv4Address":"172.20.0.3/16"}}

Ce que ça signifie : Seuls app-web-1 et app-db-1 sont sur app_default. Si vous voyiez payments-web-1 ici, ce serait une attache inter-projets.

Décision : Les attachements inter-projets exigent une discussion sur la sécurité et le debugging. Si c’est accidentel, détachez et redéployez avec des définitions de réseau corrigées.

Tâche 7 : Trouver les volumes qui semblent être scoped au projet mais ne le sont pas

cr0x@server:~$ docker volume ls --format 'table {{.Name}}\t{{.Driver}}' | grep -E '^app_|^payments_'
NAME          DRIVER
app_dbdata    local
payments_pg   local

Ce que ça signifie : Ce sont des volumes nommés, probablement créés par Compose. Si deux stacks utilisent le même nom de volume via name: explicite, elles partageront les données.

Décision : Si le partage de volumes n’est pas explicitement voulu et documenté, renommez les volumes et migrez les données. Traitez le partage accidentel de volumes comme un incident de données jusqu’à preuve du contraire.

Tâche 8 : Confirmer quels conteneurs montent un volume donné

cr0x@server:~$ docker ps -a --filter volume=app_dbdata --format 'table {{.Names}}\t{{.Status}}'
NAMES      STATUS
app-db-1   Up 3 hours

Ce que ça signifie : Seul app-db-1 utilise app_dbdata. Si vous voyez des DB de plusieurs stacks utilisant le même volume, vous avez un état partagé.

Décision : Arrêtez-vous et évaluez l’intégrité des données. Séparez les volumes avant d’effectuer tout « nettoyage ».

Tâche 9 : Détecter les conteneurs orphelins que Compose pourrait supprimer

cr0x@server:~$ docker compose -p app ps
NAME       IMAGE          COMMAND                  SERVICE   CREATED        STATUS        PORTS
app-web-1  nginx:1.25     "/docker-entrypoint.…"   web       3 hours ago    Up 3 hours    0.0.0.0:8080->80/tcp
app-db-1   postgres:16    "docker-entrypoint.s…"   db        3 hours ago    Up 3 hours

Ce que ça signifie : Compose liste ce qu’il croit appartenir à -p app. Si vous avez récemment modifié des services dans le YAML et que vous voyez maintenant des conteneurs inattendus avec le même label de projet, --remove-orphans pourrait supprimer quelque chose dont vous avez encore besoin.

Décision : N’exécutez pas --remove-orphans tant que vous n’avez pas confirmé que la frontière de projet est correcte.

Tâche 10 : Prévisualiser ce qui sera créé/recréé par un changement Compose

cr0x@server:~$ docker compose -p app up -d --no-start
[+] Running 2/2
 ✔ Network app_default  Created
 ✔ Container app-web-1  Created

Ce que ça signifie : --no-start crée toujours des ressources mais ne les démarre pas. C’est une façon plus sûre de voir si Compose est sur le point de créer des objets sous un nom de projet que vous ne vouliez pas utiliser.

Décision : Si vous voyez des ressources créées qui existent déjà sous les attentes d’une autre stack, abandonnez et corrigez d’abord le nom de projet.

Tâche 11 : Prouver une collision en comparant les hashes de config entre conteneurs

cr0x@server:~$ docker inspect app-web-1 --format '{{.Config.Labels.com.docker.compose.config-hash}}'
b1b4c7f2d4a0...
cr0x@server:~$ docker inspect app-db-1 --format '{{.Config.Labels.com.docker.compose.config-hash}}'
b1b4c7f2d4a0...

Ce que ça signifie : Des hashes qui correspondent suggèrent que les conteneurs ont été créés à partir de la même config Compose résolue. Si dans un même « projet » vous voyez des hashes différents pour ce qui devrait être la même génération de stack, vous pouvez avoir deux configs différentes gérant le même nom de projet au fil du temps.

Décision : Geler les changements. Décidez quelle config est authoritative et redéployez avec un nouveau nom de projet si nécessaire pour séparer l’état en sécurité.

Tâche 12 : Vérifier les noms globaux codés en dur qui vont entrer en collision

cr0x@server:~$ grep -R --line-number -E 'container_name:|name:' /srv/staging/app/docker-compose.yml
14:    container_name: postgres
33:  default:
34:    name: shared_frontend

Ce que ça signifie : container_name: postgres est un nom de conteneur global. Le réseau shared_frontend est explicitement partagé entre projets (ou le sera si une autre stack utilise le même nom).

Décision : Supprimez container_name à moins d’avoir une exigence opérationnelle très spécifique. Traitez les noms de réseau explicites comme une décision de frontière de sécurité, pas une commodité.

Tâche 13 : Vérifier ce que Compose pense du nom de projet quand un fichier .env est présent

cr0x@server:~$ cat /srv/staging/app/.env
COMPOSE_PROJECT_NAME=app
cr0x@server:~$ docker compose config --format json | head
{
  "name": "app",
  "services": {
...

Ce que ça signifie : Le nom de projet est forcé par le .env. Les gens oublient l’existence de ces fichiers, surtout en réponse à incident.

Décision : Si la valeur est trop générique, changez-la et redéployez. Vérifiez aussi si d’autres repos ont copié le même template .env.

Tâche 14 : Montrer les événements lors d’un « écrasement » pour attraper les recréations et suppressions

cr0x@server:~$ docker events --since 10m --filter type=container --filter event=destroy
2026-01-03T10:11:22.123456789Z container destroy 3c1f... (name=app-web-1, image=nginx:1.25)

Ce que ça signifie : Vous avez la preuve qu’un conteneur a été détruit, quand, et sous quel nom. Combinez avec les logs de déploiement pour corréler l’exécution Compose responsable.

Décision : Si la destruction s’est produite pendant un déploiement dans un repo/chemin hôte différent de celui attendu, vous avez une collision de nom de projet ou un opérateur a exécuté down au mauvais endroit.

Tâche 15 : Confirmer que down ciblera le bon projet avant de l’exécuter

cr0x@server:~$ docker compose -p app ps --all
NAME       IMAGE          SERVICE   STATUS
app-web-1  nginx:1.25     web       Up 3 hours
app-db-1   postgres:16    db        Up 3 hours

Ce que ça signifie : C’est votre pré-vol. Si la liste inclut des conteneurs que vous ne vouliez pas gérer, down les supprimera.

Décision : Si quelque chose vous semble étranger, ne lancez pas down. Corrigez d’abord le nommage du projet, ou utilisez des opérations ciblées sur les conteneurs à la place.

Blague n°2 : Lancer docker compose down avec le mauvais nom de projet, c’est comme renvoyer le stagiaire parce que le lecteur de badges est cassé.

Feuille de diagnostic rapide

Quand une stack « écrase » une autre, vous n’avez pas le temps de philosopher sur le YAML. Vous voulez le chemin le plus court vers : ce qui a changé, qui en est propriétaire, et comment arrêter l’hémorragie.

Première étape : établir le namespace de projet en collision

  1. Exécutez docker compose ls et cherchez des noms suspectement génériques (comme app, backend, prod).
  2. Exécutez docker ps avec la sortie des labels et confirmez quels conteneurs partagent com.docker.compose.project.
  3. Inspectez au moins un conteneur pour le label com.docker.compose.project.working_dir. Ça vous indique d’où il a été créé.

Deuxième étape : identifier ce qui est réellement partagé (réseaux, volumes, ports)

  1. Lister les réseaux et inspecter les réseaux pour des conteneurs inattendus.
  2. Lister les volumes et trouver quels conteneurs les montent.
  3. Vérifier les bindings de ports sur le service « écrasé » : si un port a bougé, le trafic a bougé.

Troisième étape : arrêter l’automatisation et empêcher une réconciliation supplémentaire

  1. Mettre en pause les jobs CI/CD ou scripts de déploiement planifiés qui pourraient relancer Compose.
  2. Ne pas exécuter down tant que vous n’avez pas prouvé que la frontière de projet est correcte.
  3. Si vous devez stabiliser rapidement le service, privilégiez docker stop/docker start sur des conteneurs spécifiques pendant que vous démêlez la propriété.

Quatrième étape : récupérer avec un nom de projet propre et explicite

  1. Choisir un nouveau nom de projet unique pour la stack que vous restaurez (style team-env-app).
  2. Déployer côte à côte avec des ports différents (ou derrière un switch proxy) et avec des volumes isolés à moins que la continuité des données n’exige une réutilisation.
  3. Ce n’est qu’après la récupération que vous nettoyez soigneusement les ressources en collision.

Une citation à afficher sur tous les murs des équipes d’exploitation, parce qu’elle explique pourquoi vous standardisez des choses ennuyeuses comme le nommage : idée paraphrasée de John Allspaw : les incidents naissent des travaux ordinaires qui interagissent de façon inattendue.

Comment prévenir les collisions de noms de projet (règles strictes, pas des impressions)

Si vous exécutez plusieurs stacks Compose sur le même démon, vous avez besoin de noms explicites et appliqués. Pas « souvenez-vous de passer -p ». Appliqués. Les humains oublient. L’automatisation répète.

Règle 1 : Toujours définir explicitement un nom de projet unique

Choisissez une méthode et standardisez-la :

  • Préféré pour l’automatisation : toujours utiliser docker compose -p avec un nom calculé (par exemple payments-staging).
  • Préféré pour les laptops développeur : name: au niveau supérieur dans le fichier Compose, ou un .env par développeur qui inclut le nom d’utilisateur dans le nom de projet.

Ce qu’il faut éviter : compter sur le nom du répertoire, surtout sur des hôtes partagés et des runners CI.

Règle 2 : Interdire container_name: sauf justification écrite

Cela casse le scaling, empêche la réutilisation multi-stack, et encourage les commandes docker manuelles qui font dériver l’état par rapport à Compose.

Si vous avez besoin d’un nom DNS stable pour d’autres conteneurs, vous l’avez déjà : les noms de service sur le réseau du projet. Si vous avez besoin d’une intégration externe stable, utilisez un reverse proxy, un nom d’hôte stable, ou un alias réseau stable — pas un nom de conteneur global.

Règle 3 : Traiter les noms explicites de réseaux et volumes comme de l’infrastructure partagée

Si vous définissez name: pour un réseau ou un volume, vous sortez du namespace par projet de Compose. Cela peut être correct. Cela peut aussi être un pont multi-tenant accidentel.

Faites-en une politique : les noms explicites doivent inclure environnement et propriétaire, comme shared_frontend_prod ou payments_pg_prod. « shared » doit signifier « revu », pas « quelqu’un l’a tapé une fois ».

Règle 4 : Rendre le « pre-flight » obligatoire dans les scripts de déploiement

Votre wrapper doit afficher le nom de projet résolu et échouer vite s’il n’est pas ce à quoi vous vous attendez. Vous pouvez le faire sans construire une plateforme :

  • Résoudre la config (docker compose config)
  • Vérifier le nom résultant
  • Vérifier que docker compose -p NAME ps correspond aux services attendus (ou est vide au premier déploiement)
  • Puis lancer up -d

Règle 5 : Séparer les environnements par démon quand c’est possible

Oui, vous pouvez exécuter prod et staging sur le même hôte. Vous pouvez aussi passer à vélo dans un lavage auto. Si vous devez co-localiser, la discipline de nommage devient non négociable, et vous devez isoler ports, volumes et réseaux avec intention.

Erreurs courantes : symptôme → cause racine → fix

Voici la section que vous regretterez de ne pas avoir lue avant l’incident. Chaque point est spécifique et pointe vers le véritable levier à actionner.

1) Symptom : docker compose up a « recréé » un conteneur d’une autre stack

Cause racine : Même nom de projet, même nom de service. Compose a réconcilié et remplacé la définition du conteneur.

Fix : Utiliser des noms de projet uniques via -p, COMPOSE_PROJECT_NAME, ou name:. Redéployer la stack écrasée sous un nouveau nom.

2) Symptom : Exécuter docker compose down a supprimé des conteneurs que vous ne vouliez pas

Cause racine : Vous avez exécuté down avec un nom de projet qui correspondait à plusieurs déploiements ; Compose a supprimé tout ce qui était labellisé avec ce projet.

Fix : Avant down, exécutez toujours docker compose -p NAME ps --all. Si la liste est incorrecte, arrêtez-vous et corrigez le nom de projet.

3) Symptom : Un service est accessible depuis une autre stack « non liée »

Cause racine : Réseau utilisateur partagé dû à un nom de réseau explicite ou des connexions réseau manuelles.

Fix : Supprimez les noms de réseau partagés explicites sauf si le partage est voulu ; auditez docker network inspect pour les attachements ; redéployez avec des réseaux isolés.

4) Symptom : La base de données de staging contient des données ressemblant à la production

Cause racine : Volume nommé partagé causé par un name: de volume explicite ou par le même nom de projet, conduisant au même nom de volume généré.

Fix : Séparez les volumes par environnement. Si vous devez cloner des données, faites-le via sauvegarde/restauration explicite, pas par partage accidentel de volume.

5) Symptom : Compose refuse de démarrer avec « Conflict. The container name is already in use »

Cause racine : container_name: force un nom global. Un autre conteneur l’utilise déjà.

Fix : Supprimez container_name:. Si vous avez besoin d’une adresse stable, utilisez les noms DNS de service ou un proxy.

6) Symptom : Un déploiement a marché hier, échoue aujourd’hui sur le même hôte

Cause racine : Une autre équipe a introduit une collision de nom de projet ou de réseau ; votre stack partage maintenant le namespace ou des ports.

Fix : Inventoriez avec docker compose ls, vérifiez les labels, et imposez une convention de nommage. Ajoutez des garde-fous dans le CI.

7) Symptom : --remove-orphans a supprimé quelque chose d’« important »

Cause racine : La frontière de projet était incorrecte ; Compose a considéré le conteneur « important » comme un orphelin dans ce projet.

Fix : N’utilisez pas --remove-orphans sur des hôtes partagés sauf si le nommage de projet est appliqué et audité. Privilégiez un nettoyage explicite après validation.

Listes de contrôle / plan pas-à-pas

Checklist A : Standard sûr pour chaque déploiement Compose

  1. Choisir un schéma de nommage de projet : <team>-<env>-<app>. Restez concis, unique et lisible par des humains.
  2. Appliquer-le dans l’automatisation : les scripts de déploiement appellent toujours docker compose -p "$NAME".
  3. Appliquer-le dans les repos : ajoutez un .env.example qui définit COMPOSE_PROJECT_NAME avec un pattern sûr pour le dev local (inclure le nom d’utilisateur).
  4. Interdire container_name: par politique sauf revue.
  5. Auditer les noms explicites de réseau/volume : tout name: doit être revu comme de l’infrastructure.
  6. Pre-flight avant les changements : docker compose -p NAME config et docker compose -p NAME ps doivent paraître sensés.

Checklist B : Plan de récupération pas-à-pas après une collision

  1. Arrêter le churn : mettre en pause les pipelines de déploiement et jobs planifiés qui pourraient relancer Compose.
  2. Identifier le nom de projet en collision : utilisez les labels pour confirmer quels conteneurs partagent com.docker.compose.project.
  3. Snapshotter l’état si des données sont impliquées : si des volumes sont partagés, faites une sauvegarde avant de modifier quoi que ce soit.
  4. Monter une stack propre sous un nouveau nom de projet : utilisez des réseaux et volumes isolés sauf si vous réutilisez volontairement des données.
  5. Basculer le trafic : mettez à jour la config du reverse proxy ou les bindings de ports pour diriger vers la stack restaurée.
  6. Nettoyer la stack en collision soigneusement : supprimer uniquement ce que vous pouvez prouver comme erroné ; évitez un down aveugle si la propriété est mixte.
  7. Ajouter un garde-fou : wrapper de déploiement qui affiche le nom de projet résolu et échoue si celui-ci ne correspond pas aux attentes de l’hôte.

Checklist C : Hygiène de l’hôte pour des daemons Docker partagés

  1. Inventorier les projets chaque semaine : docker compose ls et rechercher des noms génériques.
  2. Inventorier les réseaux/volumes orphelins : confirmer que les noms explicites ont des propriétaires.
  3. Documenter les réseaux partagés : si vous avez besoin d’une communication cross-stack, traitez le réseau partagé comme une interface contrôlée.
  4. Garder les environnements séparés : si possible, séparez les daemons/hôtes pour prod vs staging.

FAQ

1) Qu’est-ce qui est exactement « écrasé » lors d’une collision de nom de projet ?

Compose n’écrase pas le YAML. Il réconcilie les objets Docker sous le même label de projet. Cela peut signifier que des conteneurs sont recréés avec d’autres images/variables d’environnement, que des réseaux sont partagés, et que des volumes sont réutilisés.

2) Si j’utilise des fichiers Compose différents, puis-je encore entrer en collision ?

Oui. Le même nom de projet suffit. Des fichiers différents peuvent toujours générer des ressources sous le même namespace de projet, surtout si les noms de services se chevauchent.

3) Le nom de répertoire est-il toujours le nom de projet par défaut ?

Souvent oui, mais pas toujours. Un fichier .env, COMPOSE_PROJECT_NAME, ou un name: au niveau supérieur peut le remplacer. C’est pourquoi vous devez toujours vérifier docker compose config avant de déployer.

4) Dois-je définir le nom de projet dans .env ou toujours passer -p ?

Pour le CI/CD et la production : préférez -p pour que le système de déploiement le contrôle. Pour les développeurs : .env va bien, mais incluez un nom d’utilisateur pour éviter les collisions sur des hôtes de dev partagés.

5) Pourquoi container_name est-il considéré comme nuisible ?

Il force un nom global sur le démon, casse le scaling, et rend les stacks moins portables. Il encourage aussi l’intervention manuelle, là où les « correctifs temporaires » deviennent des pannes permanentes.

6) Puis-je partager intentionnellement un réseau ou un volume entre projets ?

Vous pouvez, et parfois vous devriez (pour un réseau reverse-proxy partagé, par exemple). Mais traitez-le comme un contrat d’interface. Nommez-le explicitement, documentez-le, et révisez les attachements. Ne le faites pas « parce que ça marche ».

7) Comment savoir quel repo a créé un conteneur ?

Inspectez les labels. Cherchez com.docker.compose.project.working_dir et com.docker.compose.project.config_files. Cela montre généralement le chemin utilisé lors de la création.

8) docker compose down est-il sûr ?

C’est sûr quand la frontière de nom de projet est correcte. Sur des hôtes partagés avec un nommage laxiste, c’est un outil de démolition. Exécutez toujours docker compose -p NAME ps --all d’abord.

9) Ce problème disparaît-il si j’utilise Kubernetes/Swarm ?

Vous échangez ce mode de défaillance spécifique contre d’autres. Les namespaces dans Kubernetes aident, mais vous pouvez toujours entrer en collision avec des volumes partagés, des ressources au niveau du cluster, et des selectors mal configurés. La discipline ne se démode pas.

Conclusion : prochaines étapes que vous pouvez déployer aujourd’hui

Les collisions de noms de projet Compose ne sont pas un cas limite étrange. Elles sont le résultat prévisible de laisser des valeurs par défaut décider de vos frontières d’isolation. La correction est simple, mais elle doit être appliquée, pas suggérée.

Faites ceci ensuite :

  1. Choisissez une convention de nommage de projet qui encode équipe + environnement + application.
  2. Mettez à jour chaque commande de déploiement pour passer explicitement -p.
  3. Auditez les fichiers Compose pour container_name: et les name: explicites pour réseaux/volumes ; supprimez-les ou formalisez-les.
  4. Ajoutez une vérification pre-flight dans l’automatisation qui affiche le nom de projet résolu et refuse de s’exécuter s’il est générique ou inattendu.
  5. Exécutez les commandes d’inventaire de cet article sur votre hôte le plus chargé et recherchez des collisions avant qu’elles ne viennent vous chercher.
← Précédent
Incrustations réactives qui ne cassent pas la mise en page : YouTube, iframes et cartes en production
Suivant →
Pagination vs défilement infini : modèles d’interface qui n’énervent pas les utilisateurs

Laisser un commentaire