Docker pour les devs - 11 - Networking Docker, les bases

Le réseau bridge par défaut, le DNS interne, expose vs ports, et le piège classique de localhost dans un conteneur.

  1. 01 Docker pour les devs - 00 - Pourquoi Docker change tout
  2. 02 Docker pour les devs - 01 - Containers vs VMs
  3. 03 Docker pour les devs - 02 - L'architecture de Docker
  4. 04 Docker pour les devs - 03 - Docker Desktop, Engine et alternatives
  5. 05 Docker pour les devs - 04 - Écrire un Dockerfile
  6. 06 Docker pour les devs - 05 - Layers et cache
  7. 07 Docker pour les devs - 06 - Le .dockerignore
  8. 08 Docker pour les devs - 07 - Multi-stage builds
  9. 09 Docker pour les devs - 08 - Choisir son image de base
  10. 10 Docker pour les devs - 09 - Docker Compose, les bases
  11. 11 Docker pour les devs - 10 - Docker Compose avance
  12. 12 Docker pour les devs - 11 - Networking Docker, les bases
  13. 13 Docker pour les devs - 12 - Networking Docker avance
  14. 14 Docker pour les devs - 13 - Volumes et persistance
  15. 15 Docker pour les devs - 14 - Variables d'environnement et secrets
  16. 16 Docker pour les devs - 15 - Permissions et utilisateurs
  17. 17 Docker pour les devs - 16 - Docker et monorepo
  18. 18 Docker pour les devs - 17 - Dev vs Prod
  19. 19 Docker pour les devs - 18 - ENTRYPOINT, CMD et scripts d'initialisation
  20. 20 Docker pour les devs - 19 - Debugger ses conteneurs
  21. 21 Docker pour les devs - 20 - Bases de donnees dans Docker
  22. 22 Docker pour les devs - 21 - Sauvegardes et restauration
  23. 23 Docker pour les devs - 22 - Conteneuriser un frontend
  24. 24 Docker pour les devs - 23 - Sécurité des conteneurs
  25. 25 Docker pour les devs - 24 - Optimisation des images
  26. 26 Docker pour les devs - 25 - Builds multi-platform
  27. 27 Docker pour les devs - 26 - Limiter les ressources de tes conteneurs
  28. 28 Docker pour les devs - 27 - Gerer les logs comme un adulte
  29. 29 Docker pour les devs - 28 - Healthchecks et restart policies
  30. 30 Docker pour les devs - 29 - Nettoyer Docker avant qu'il mange ton disque
  31. 31 Docker pour les devs - 30 - Registries et stratégie de tags
  32. 32 Docker pour les devs - 31 - Docker en CI/CD
  33. 33 Docker pour les devs - 32 - Au-dela de Compose
  34. 34 Docker pour les devs - 33 - Glossaire Docker de A a Z

11 - Networking Docker, les bases

Ce que tu vas apprendre

  • Comment fonctionne le réseau bridge par défaut
  • Pourquoi le nom du service est le hostname dans Compose
  • La différence entre expose et ports
  • Le piège de localhost dans un conteneur
  • Comment contacter la machine hote depuis un conteneur
  • Le mapping de ports en détail

Prerequisites


Le networking Docker est la source numero un de bugs mysterieux chez les devs qui debutent. "Ca marche sur ma machine mais pas dans le conteneur." Neuf fois sur dix, c'est un problème de réseau. Et la raison est simple : un conteneur a son propre espace réseau. Il ne voit pas le meme localhost que toi.

Le réseau bridge par défaut

Quand tu demarres un conteneur sans rien spécifier, Docker le place sur le réseau bridge par défaut. C'est un réseau interne, isole de ta machine hote.

bashdocker network ls

Tu verras un réseau bridge, un host et un none. Chaque conteneur sur bridge recoit une adresse IP interne (typiquement dans la plage 172.17.0.x).

Quand tu utilises Docker Compose, c'est différent. Compose créé un réseau dédié pour chaque projet, nomme <nom-du-dossier>_default. Les services du meme compose.yaml sont tous sur ce réseau.

Le DNS interne : le nom du service = le hostname

C'est une des fonctionnalités les plus pratiques de Compose, et beaucoup de devs ne la comprennent pas vraiment.

Dans ton compose.yaml :

yamlservices:
  app:
    build: .
    environment:
      DATABASE_URL: postgres://postgres:secret@db:5432/myapp
  db:
    image: postgres:16-alpine

Le db dans l'URL n'est pas magique. Compose créé un enregistrement DNS interne : le nom du service (db) pointe vers l'IP du conteneur PostgreSQL. Pas besoin de connaître l'IP, pas besoin de config supplementaire.

Sur paltemps.fr, j'ai trois services qui communiquent entre eux uniquement par leurs noms de service. Jamais une IP en dur.

expose vs ports

Ces deux directives sont souvent confondues :

yamlservices:
  app:
    ports:
      - "3000:3000"   # accessible depuis l'hote ET les autres conteneurs
    expose:
      - "9090"         # accessible UNIQUEMENT depuis les autres conteneurs

ports mappe un port du conteneur vers un port de ta machine. Tu peux acceder au service depuis ton navigateur.

expose déclaré un port disponible sur le réseau interne Docker. Les autres conteneurs peuvent y acceder, mais pas ta machine hote. En pratique, expose est surtout documentaire : les conteneurs peuvent toujours communiquer entre eux sur n'importe quel port du réseau interne, meme sans expose.

La regle simple : utilise ports pour ce que tu veux atteindre depuis ton navigateur ou tes outils. Laisse tout le reste en interne.

Le piège de localhost

C'est le piège classique. Tu as une app qui écoûte sur localhost:5432 en local. Tu la mets dans un conteneur, et soudain elle ne trouve plus la base de donnees.

Pourquoi ? Parce que localhost dans un conteneur, c'est le conteneur lui-meme. Pas ta machine. Pas le conteneur d'a cote.

[Ta machine]
  localhost:5432 --> PostgreSQL local

[Conteneur app]
  localhost:5432 --> rien (il n'y a pas de PostgreSQL dans ce conteneur)

La solution : utiliser le nom du service comme hostname :

yaml# Dans le conteneur app, pour joindre PostgreSQL :
DATABASE_URL: postgres://postgres:secret@db:5432/myapp
#                                        ^^ nom du service, pas localhost

Si ton app écoûte sur 127.0.0.1 (localhost only), elle ne sera pas accessible depuis l'extérieur du conteneur meme avec ports. Il faut écoûter sur 0.0.0.0 :

javascript// Mauvais - accessible uniquement dans le conteneur
app.listen(3000, "127.0.0.1");

// Bon - accessible depuis l'hote via le port mapping
app.listen(3000, "0.0.0.0");

host.docker.internal

Parfois tu as besoin de joindre un service qui tourne sur ta machine hote (pas dans Docker). L'hostname special host.docker.internal pointe vers ta machine :

yamlservices:
  app:
    environment:
      API_URL: http://host.docker.internal:8080

Ca fonctionne sur Docker Desktop (Mac, Windows, Linux). Sur Linux sans Docker Desktop, tu dois ajouter la config manuellement :

yamlservices:
  app:
    extra_hosts:
      - "host.docker.internal:host-gateway"

J'utilise ca quand je développé un microservice dans Docker qui doit parler a un autre service que je lance directement sur ma machine avec node index.js.

Le mapping de ports en détail

Le format complet :

yamlports:
  - "3000:3000"              # host:container (toutes les interfaces)
  - "127.0.0.1:3000:3000"   # seulement localhost de l'hote
  - "3000"                   # port aleatoire de l'hote -> 3000 du conteneur

La version 127.0.0.1:3000:3000 est plus sécurisée : le port n'est accessible que depuis ta machine, pas depuis le réseau local. En dev, ca change rarement quelque chose. En production sur un serveur, ca peut éviter une exposition accidentelle.

Pour voir les ports mappes :

bashdocker compose ps

Ou pour un conteneur spécifique :

bashdocker port <container_id>

Résumé

  • Docker Compose créé un réseau interne par projet : les services se trouvent par leur nom
  • localhost dans un conteneur = le conteneur lui-meme, pas ta machine
  • Écoûte toujours sur 0.0.0.0 dans un conteneur, jamais sur 127.0.0.1
  • host.docker.internal permet de joindre la machine hote depuis un conteneur
  • ports expose vers l'hote, expose reste interne au réseau Docker
  • On verra les réseaux custom et l'isolation dans l'article suivant

Navigation : Precedent : 10 - Compose avance | Suivant : 12 - Networking avance


Sources

Réservez un audit gratuit de 30 minutes. Je vous montre concrètement ce qu'on peut automatiser.