IREX - Docker et la communication inter-processus : ports, noms et adresses IP

Tu t'es déjà demandé comment les conteneurs Dockers communiquent-ils entre eux ?

 · 6 min read

Docker et la communication inter-processus : ports, noms et adresses IP

1. Introduction

Docker a révolutionné la façon dont les développeurs et les DevOps conçoivent, testent et déploient des applications. Mais si l’on se limite à un seul conteneur, on passe à côté de sa véritable puissance : celle de composer des environnements complets où plusieurs services collaborent. Dans ce contexte, la communication inter-processus devient un sujet incontournable.

J’ai personnellement découvert cette problématique lors d’un projet en stage : un backend devait échanger avec une base de données et fournir des données à un frontend. Chaque service fonctionnait parfaitement seul, mais dès qu’il fallait les connecter entre eux, tout se compliquait. C’est alors que j’ai compris l’importance de trois mécanismes fondamentaux : les ports, les noms de conteneurs et les adresses IP.

2. Les ports : exposer et sécuriser les services

Par défaut, un conteneur Docker est isolé. Les applications qu’il exécute écoutent sur des ports internes (80 pour un serveur web, 3306 pour MySQL, etc.). Pour rendre un service accessible depuis l’hôte ou l’extérieur, il faut l’exposer en mappant un port du conteneur à un port de la machine hôte.

docker run -p 8080:80 nginx

Ici, le port 80 interne est relié au port 8080 de l’hôte. Cela rend possible un accès via http://localhost:8080. Mais attention : exposer un port revient à ouvrir une porte. Dans un projet réel, on doit choisir avec soin ce que l’on expose. Une base de données, par exemple, devrait rarement être accessible directement de l’extérieur.

Autres points pratiques :

  • Vérifier le mapping réel : docker ps et docker port <container>.
  • Si l’application écoute uniquement sur 127.0.0.1 à l’intérieur du conteneur, elle ne sera pas accessible depuis l’hôte ; il faut qu’elle écoute sur 0.0.0.0.
  • Sur des environnements restreints, un pare-feu (ufw, iptables) ou SELinux peut bloquer l’accès — vérifie ces couches si le port semble publié mais injoignable.

3. Les noms de conteneurs : un DNS intégré

Une fois plusieurs conteneurs créés, il faut qu’ils puissent communiquer entre eux. C’est là que Docker simplifie la vie : dans un réseau Docker, chaque conteneur peut être joint par son nom.


docker network create monreseau
docker run -d --name web --network monreseau nginx
docker run -d --name app --network monreseau python-app
  

Dans cet exemple, app peut appeler web via http://web:80. Docker fait office de DNS et traduit automatiquement le nom du conteneur en son adresse IP interne. Cela évite le casse-tête des IP qui changent à chaque redémarrage, et permet une configuration beaucoup plus lisible et robuste.

4. Les adresses IP : comprendre la couche réseau

Sous le capot, Docker attribue une adresse IP à chaque conteneur dans le réseau défini. Par défaut, il utilise un réseau de type bridge avec une plage d’adresses privée.

docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' web

On peut donc joindre un conteneur par son IP, mais c’est déconseillé : ces adresses sont éphémères. La bonne pratique est de s’appuyer sur les noms de conteneurs, et de garder l’IP comme un outil de diagnostic en cas de problème réseau.

5. Exemple détaillé : architecture 3 tiers

Imaginons une application composée de trois parties : un frontend en Nginx, une API backend en Python et une base de données PostgreSQL. Avec Docker Compose, leur communication devient explicite :


version: '3'
services:
  frontend:
    image: nginx
    ports:
      - "8080:80"
    networks:
      - appnet

  backend:
    build: ./backend
    networks:
      - appnet

  db:
    image: postgres
    environment:
      POSTGRES_PASSWORD: exemple
    networks:
      - appnet

networks:
  appnet:
  

Dans cette configuration :

  • Le frontend appelle le backend via http://backend:5000.
  • Le backend se connecte à la base via db:5432.
  • Seul le frontend expose un port vers l’extérieur ; les autres services communiquent en interne.
Ce schéma est sécurisé et clair : le trafic interne reste isolé du réseau hôte.

6. Bonnes pratiques et pièges courants

  • Limiter l’exposition des ports : n’ouvrez à l’extérieur que ce qui est nécessaire.
  • Nommer clairement vos services pour éviter toute confusion dans les configurations.
  • Utiliser des réseaux dédiés pour isoler vos environnements (par ex. test, prod).
  • Privilégier Docker Compose pour gérer plusieurs services plutôt que de lancer chaque conteneur à la main.
  • Vérifier régulièrement la configuration réseau avec docker network inspect et docker ps.
  • S’assurer que les applications écoutent sur 0.0.0.0 si elles doivent accepter des connexions externes au conteneur.

L’un des pièges les plus fréquents est de penser que tout doit passer par des ports exposés. En réalité, la majorité des communications entre conteneurs se font en interne, sans jamais avoir besoin d’ouvrir un accès vers l’hôte.

7. Erreurs fréquentes et comment les éviter

Deux erreurs reviennent souvent dans les tickets et dans les conversations de salle : elles sont simples, mais elles coûtent du temps quand on les ignore. Je les ai moi-même rencontrées en stage — et je les ai résolues, parfois à la sueur du front.

Erreur fréquente A — Pas de réseau commun entre conteneurs

Symptôme : deux conteneurs semblent lancés, mais l’un ne peut pas joindre l’autre (ex. : l’API ne joint pas la base). Cause : les conteneurs ne sont pas rattachés au même réseau Docker. Par défaut, si on lance des conteneurs individuellement sans préciser de réseau, ils peuvent être isolés les uns des autres.

Diagnostic :

  • docker ps pour lister les conteneurs en cours.
  • docker network ls pour voir les réseaux existants.
  • docker inspect <container> pour vérifier les réseaux auxquels le conteneur est connecté.
  • docker network inspect <network> pour lister les conteneurs attachés à un réseau.

Correction :

docker network create mon_reseau
docker run -d --network=mon_reseau --name db mysql:5.7
docker run -d --network=mon_reseau --name api mon_api

Avec Docker Compose, on définit le réseau dans le fichier et on laisse Compose attacher automatiquement les services au bon réseau. Après cela, la résolution par nom fonctionne (ex. api vers db).

Astuce pratique : si tout semble bien configuré mais que ça ne marche pas, exécutez un shell dans un conteneur et testez la résolution DNS / connectivité :

docker exec -it api sh
# from inside the container
ping db || curl -v http://db:5432

Erreur fréquente B — Port mappé manquant ou application liée à 127.0.0.1

Symptôme : le service tourne dans le conteneur mais n’est pas accessible depuis l’hôte (ou depuis d’autres conteneurs). Causes possibles :

  • Le port n’a pas été publié (oubli du -p ou du mapping dans docker-compose).
  • L’application écoute uniquement sur 127.0.0.1 à l’intérieur du conteneur (par défaut certains serveurs de développement le font).
  • Un pare-feu ou une politique réseau bloque le port exposé.

Diagnostic :

  • docker ps pour vérifier la colonne PORTS (mapping hôte→conteneur).
  • docker port <container> pour voir les ports exposés par le conteneur.
  • docker logs <container> pour vérifier sur quelle interface l’application indique qu’elle écoute.
  • Se connecter dans le conteneur et lister les sockets : docker exec -it <container> ss -tulnp ou netstat -tuln.

Correction :

  • Publier le port lors du lancement : docker run -p 8080:5000 mon_api ou configurer ports dans docker-compose.yml.
  • Faire en sorte que l’application écoute sur 0.0.0.0 (ex. Flask : app.run(host='0.0.0.0') ; ou préférer Gunicorn en production).
  • Vérifier le pare-feu de l’hôte (ufw/iptables) et les règles SELinux si présentes.

Cas pratique rencontré : j’ai une fois monté une API Flask dans un conteneur ; l’API était accessible en local sur la machine de développement, mais pas depuis le navigateur via localhost:5000 après le docker run. La cause : Flask écoutait par défaut sur 127.0.0.1 ; la correction a été d’ajouter app.run(host='0.0.0.0') et de relancer le conteneur avec -p 5000:5000.

8. Conclusion et ouverture

Maîtriser la communication inter-processus avec Docker, c’est comprendre trois leviers : les ports, les noms et les adresses IP. En pratique, cela signifie organiser ses réseaux, limiter l’exposition, vérifier les bindings applicatifs et diagnostiquer efficacement quand ça casse.

Savoir repérer et corriger les erreurs décrites ici vous fera gagner du temps et démontrera une vraie compétence DevOps : connecter correctement des services conteneurisés n’est pas magique, c’est méthodique. Quand vos besoins dépassent quelques conteneurs, des solutions d’orchestration (Kubernetes, Docker Swarm) et des outils de service discovery deviennent nécessaires — mais les principes restent les mêmes.

9. Voir aussi


No comments yet

No comments yet. Start a new discussion.

Add Comment