Setup classique pour mixer dev local et conteneurs Docker. Mon docker-compose.yml lance des services satellites (Postgres, un autre service tiers), mais le backend tourne directement sur l’hôte en dev (npm run dev, hot reload). Pour que les autres conteneurs joignent le backend, je mappe son nom vers le host-gateway :
services:
satellite:
image: vendor/satellite:latest
extra_hosts:
- "backend:host-gateway"
En dev ça marche : depuis le conteneur satellite, wget http://backend:3000/healthz tape l’hôte (où npm run dev écoute sur :3000). En prod, je rajoute un service backend au compose, je le déploie sur Coolify/n’importe quel PaaS docker-compose-friendly. Les conteneurs sont sur le même réseau. Et là silencieusement :
Symptôme
docker exec satellite getent hosts backend
# → 172.17.0.1 backend backend
docker exec satellite wget http://backend:3000/healthz
# → wget: can't connect to remote host (172.17.0.1): Connection refused
backend résout vers 172.17.0.1 (host-gateway), pas vers le conteneur backend qui est pourtant sur le même réseau Docker. Le wget échoue parce que rien n’écoute sur 172.17.0.1:3000 côté hôte en prod.
Le service satellite continue à fonctionner pour le reste. Aucun log d’erreur dans le service ni dans Docker. Le forward / le call HTTP qui devrait atteindre le backend tombe juste dans le vide.
Cause
extra_hosts en docker-compose prend la priorité sur le DNS Docker du réseau. Tant que cette ligne est là, le conteneur résout backend selon extra_hosts (= host-gateway), JAMAIS via le DNS Docker interne qui pointerait vers le conteneur du service backend.
Cette priorité est documentée mais peu mise en avant. Le piège tombe au moment où l’archi passe de « dev local hors Docker » → « tout containerisé en prod », parce que le extra_hosts qui était utile en dev devient une bombe silencieuse en prod.
Solution
Utiliser un alias dédié au dev, ne JAMAIS reprendre le nom d’un service qui existera en prod. Convention propre :
services:
satellite:
image: vendor/satellite:latest
extra_hosts:
- "host.docker.internal:host-gateway" # alias générique standard
environment:
# En dev (depuis l'hôte) : BACKEND_URL=http://host.docker.internal:3000
# En prod (compose Docker) : BACKEND_URL=http://backend:3000
BACKEND_URL: ${BACKEND_URL:-http://host.docker.internal:3000}
Et la config statique du service (par exemple traccar.xml, forward.url…) doit utiliser l’alias host.docker.internal en dev, le nom du service en prod. Si la config est statique sans interpolation possible, choisir la valeur prod (http://backend:3000) et gérer le cas dev autrement (par exemple générer une variante locale du fichier).
Lessons learned
extra_hostsoverride le DNS Docker sans warning ni log — ce qui était utile en dev devient un piège silencieux en prod- Ne jamais réutiliser un nom de service dans
extra_hosts: siservice-xest un service du compose, l’aliaser dansextra_hostsempêche le DNS Docker normal vers son conteneur - L’alias canonique pour « l’hôte depuis le conteneur » est
host.docker.internal— c’est la convention Docker (et le default Windows/Mac). Sur Linux, ajouter explicitementhost.docker.internal:host-gatewaydansextra_hostspermet aux conteneurs Linux d’utiliser le même nom - Symptôme typique de l’override :
wget http://service:portretourne « Connection refused » sur l’IP du host-gateway (172.17.0.1 ou similaire) — sniff DNS révèle l’aliasing - Diagnostic en 5 secondes :
docker exec <conteneur> getent hosts <service>— si la réponse n’est pas l’IP du réseau Docker (172.20.0.Xou similaire), c’estextra_hostsqui pirate
#docker #compose #devops #troubleshooting #networking #dns #host-gateway