Hostinger

Docker mis en réseau : Différences et avantages des modes Bridge et Host

Vidéo sur Youtube Le play Youtube

Docker propose plusieurs modes de mise en réseau pour connecter vos conteneurs, dont Bridge et Host. Chacun de ces modes présente des avantages et des inconvénients.

Dans cette leçon, nous découvrirons les avantages de chaque mode et apprendrons à les utiliser 🙂.

🚨 Cela ne fonctionne qu'avec Linux et pas avec macOS et Windows. En effet, sur ces systèmes, Docker Desktop s'exécute dans une machine virtuelle, ce qui empêche l'accès direct au réseau de l’hôte. De ce fait, le mode Host ne se comporte pas de la même manière que sur Linux.

Réseau Bridge : fonctionnement

Définition du réseau de type Bridge

C’est le mode par défaut de Docker lorsqu’aucun réseau n’est explicitement spécifié. Dans ce mode, les conteneurs sont connectés à un réseau virtuel interne, totalement isolé du réseau de l’hôte.

Par « hôte », on désigne l’ordinateur local, qu’il fonctionne sous Windows, macOS ou Linux.

Lorsque les conteneurs appartiennent au même réseau, ils peuvent communiquer entre eux aisément en utilisant une adresse IP privée.

Cependant, rappelez-vous qu’ils ne pourront pas, dans l’état actuel, communiquer directement avec notre machine locale.

Bridge : avantage

Approche sécurisée 👮‍♂️ : Par défaut, les conteneurs sont isolés les uns des autres, et ils ne peuvent pas communiquer avec l’hôte sans configuration particulière.

Il est donc nécessaire de mapper des ports pour autoriser la communication.

Bridge : inconvénient

Les performances sont moins bonnes qu’en mode Host à cause de l’ajout d’une couche de virtualisation réseau.

Réseau Host : fonctionnement

Le réseau Host et le réseau Bridge fonctionnent différemment.

Contrairement au réseau Bridge, le réseau Host permet aux conteneurs de partager directement le réseau de l’hôte. Cela signifie que les conteneurs utilisent la même adresse IP et les mêmes ports que l’hôte, sans passer par une couche intermédiaire.

On rappelle que l'« hôte » est l’ordinateur local (Windows, macOS ou Linux).

Dans le mode réseau Host, les ports exposés par le conteneur sont directement accessibles depuis l’extérieur, car ils sont liés directement à l’interface réseau de l’hôte.

Host : avantage

Performances accrues par rapport au mode Bridge 💪, puisqu’il n’y a pas de couche supplémentaire.

Host : inconvénient

Ce mode est plus vulnérable, car il n’y a pas d’isolation réseau. De plus, il peut y avoir des conflits de ports, puisque les ports utilisés par le conteneur doivent être uniques et ne pas entrer en conflit avec ceux de l’hôte. Cela rend la gestion des ports un peu plus complexe par rapport au mode Bridge.

Exercice pratique

Dans cet exercice, nous allons comparer la configuration d’un fichier compose.yml en mode Bridge et en mode Host, pour bien comprendre les différences entre ces deux modes. 😊

compose.yml avec un réseau Bridge

Créer trois conteneurs Ubuntu

Nous allons créer trois conteneurs reliés par un réseau de type Bridge.

services:
  ubuntu1: 
    image: ubuntu:24.10
    container_name: ubuntu1
    command: tail -f /dev/null # Commande exécutée dans le conteneur pour le garder actif en lisant en continu un fichier vide
    networks:
      - ubuntu_bridge # Connexion au réseau nommé "ubuntu_bridge"
  
  ubuntu2:
    image: ubuntu:24.10
    container_name: ubuntu2
    command: tail -f /dev/null # Commande pour garder ce conteneur actif également
    networks:
      - ubuntu_bridge # Connexion au réseau nommé "ubuntu_bridge"

  ubuntu3:
    image: ubuntu:24.10
    container_name: ubuntu3
    command: tail -f /dev/null # Commande pour garder ce conteneur actif également
    networks:
      - ubuntu_bridge # Connexion au réseau nommé "ubuntu_bridge"

# --

networks: 
  ubuntu_bridge:
    driver: bridge # Utilisation du driver "bridge" pour permettre aux conteneurs de communiquer entre eux

J’ai inséré des commentaires à certains endroits.

Ensuite, pour déployer cette configuration, exécutez la commande suivante.

docker-compose up

Nous avons trois conteneurs connectés entre eux via un réseau de type Bridge.

Se connecter aux trois conteneurs Ubuntu

Ouvrez trois autres terminaux (ou onglets) pour vous connecter directement à chacun des conteneurs.

1er terminal (ou onglet)

docker exec -it ubuntu1 bash

2e terminal (ou onglet)

docker exec -it ubuntu2 bash

3e terminal (ou onglet)

docker exec -it ubuntu3 bash

Intaller Ping

Pour permettre aux conteneurs de tester leur connectivité, nous installons Ping.

apt-get update && apt-get install -y iputils-ping

Communiquer avec les conteneurs !

Accédez au conteneur grâce au terminal (ou à l'onglet) correspondant à Ubuntu1, et exécutez la commande suivante.

ping Ubuntu2

Le résultat montre qu’Ubuntu1 communique correctement avec Ubuntu2, ce qui nous confirme que le réseau est opérationnel.

Nous ne le réaliserons pas dans cet exercice, mais cela fonctionne également avec les autres conteneurs, quel que soit le sens de communication. 😊

Communiquer depuis l'hôte grâce au réseau "ubuntu_bridge" !

Si nous ouvrons un nouveau terminal et exécutons la commande suivante, cela ne fonctionnera pas, car ce terminal correspond à notre machine hôte (machine locale), qui n’est pas connectée au réseau des conteneurs.

ping Ubuntu1

Mapper les ports

Une façon d’établir la communication consiste à mapper un port de notre machine locale avec un port de notre ou de nos conteneurs.

Émettre une information dans le port 9000 de Ubuntu1

Avant de mapper les ports, nous allons configurer le conteneur pour émettre une information sur le port 9000.

Pour ce faire, ouvrez le terminal de Ubuntu1 et installez le programme Netcat en exécutant la commande suivante.

apt-get update && apt-get install -y netcat-traditional

Une fois Netcat installé, nous allons émettre une information sur le port 9000. Il enverra le phrase "Hello from ubuntu1".

echo 'Hello from ubuntu1' | nc -l -p 9000

Récupérer l'information depuis Ubuntu2

Pour vérifier que tout fonctionne correctement, nous allons tester la communication en récupérant les informations depuis le conteneur ubuntu2. Suivez ces étapes.

1 - Installer Curl dans le conteneur Ubuntu2 !

Ouvrez un terminal dans ubuntu2 et installez curl à l’aide de la commande suivante.

apt update && apt install curl -y

2 - Tester la connexion avec Ubuntu1 depuis Ubuntu2 !

Une fois curl installé, exécutez la commande suivante pour vous connecter à ubuntu1 via le port 9000.

curl --http0.9 http://ubuntu1:9000

3 - Résultat attendu 😃 !

Si tout est correctement configuré, vous devriez voir une réponse similaire à ceci.

Hello from ubuntu1

Félicitations, la communication entre les conteneurs fonctionne ! 🎉

Mais l'objectif n'est pas celui-ci mais de récupérer l'information grâce la machine hôte.

💡 En effet, je vous rappelle que l’objectif est de récupérer les informations transmises par un conteneur depuis la machine hôte en utilisant le mappage de ports, car dans le mode Bridge, la machine hôte n’appartient pas au même réseau que les conteneurs.

Modifier le fichier compose.yml afin de mapper le port 9000 de Ubuntu1

Nous devons maintenant modifier le fichier compose.yml pour mapper le port 9000 de notre conteneur, permettant ainsi à la machine hôte d’accéder aux informations.

services:
  ubuntu1: 
    image: ubuntu:24.10
    container_name: ubuntu1
    command: tail -f /dev/null # Commande exécutée dans le conteneur pour le garder actif en lisant en continu un fichier vide
    networks:
      - ubuntu_bridge # Connexion au réseau nommé "ubuntu_bridge"
    ports:
      - "9000:9000" # Mapper le port 9000
  
  ubuntu2:
    image: ubuntu:24.10
    container_name: ubuntu2
    command: tail -f /dev/null # Commande pour garder ce conteneur actif également
    networks:
      - ubuntu_bridge # Connexion au réseau nommé "ubuntu_bridge"

  ubuntu3:
    image: ubuntu:24.10
    container_name: ubuntu3
    command: tail -f /dev/null # Commande pour garder ce conteneur actif également
    networks:
      - ubuntu_bridge # Connexion au réseau nommé "ubuntu_bridge"

# --

networks: 
  ubuntu_bridge:
    driver: bridge # Utilisation du driver "bridge" pour permettre aux conteneurs de communiquer entre eux

Dans cette configuration, nous associons le port 9000 de notre machine locale au port 9000 du conteneur Ubuntu1.

Il est maintenant nécessaire de redémarrer la configuration du fichier compose.yml.

Pour arrêter tous les services, utilisez les touches suivantes : CTRL + c

Et redémarrez la configuration définie dans le fichier compose.yml depuis le terminal approprié.

docker compose up
[+] Running 3/3
 ✔ Container ubuntu3  Created                                                                            0.0s 
 ✔ Container ubuntu2  Created                                                                            0.0s 
 ✔ Container ubuntu1  Recreated   

Le conteneur Ubuntu1 a été reconstruit car nous avons modifié la ligne 9 du fichier compose.yml (voir ligne 4).

Récupérer les données d'Ubuntu1 depuis notre machine locale

Assurez-vous que le conteneur Ubuntu1 émet bien sur le port 9000. Si ce n’est pas le cas, utilisez à nouveau la commande suivante.

echo 'Hello from ubuntu1' | nc -l -p 9000

Ensuite dans un autre terminal utilisez la commande suivante.

curl --http0.9 http://localhost:9000

Cela fonctionne 😮.

Hello from ubuntu1

C'est génial ! Nous avons réussi.

Résumé pour Bridge

Avec le réseau Bridge, les conteneurs sont isolés de l’hôte. Pour leur permettre de communiquer avec la machine locale, nous devons mapper les ports, ce qui renforce la sécurité et le contrôle, mais entraîne une couche supplémentaire de configuration.

Qu’en est-il avec un réseau de type host ?

Voyons cela ! 🧐

compose.yml avec un réseau Host

Adapter avec le mode Host

Reprenons l’exemple avec trois conteneurs, cette fois-ci en mode Host.

Observer la différence ! 🕵🏽‍♂️

services:
  ubuntu1: 
    image: ubuntu:24.10
    container_name: ubuntu1
    command: tail -f /dev/null # Commande exécutée dans le conteneur pour le garder actif en lisant en continu un fichier vide
    network_mode: host # Utilisation du mode réseau host

  ubuntu2:
    image: ubuntu:24.10
    container_name: ubuntu2
    command: tail -f /dev/null # Commande pour garder ce conteneur actif également
    network_mode: host # Utilisation du mode réseau host

  ubuntu3:
    image: ubuntu:24.10
    container_name: ubuntu3
    command: tail -f /dev/null # Commande pour garder ce conteneur actif également
    network_mode: host # Utilisation du mode réseau host

Les différences

Il n’est plus nécessaire de mapper les ports en mode réseau “host”, car dans cette configuration, les conteneurs partagent directement l’adresse IP et les ports de l’hôte, sans utiliser de couche réseau intermédiaire.

Nous avons défini le "network_mode" sur "host".

Se connecter à Ubuntu1

Nous allons procéder de la même manière qu’avec le réseau de type bridge.

Je vais accélérer un peu les choses et me concentrer uniquement sur Ubuntu1. 😁

docker compose up

Dans un autre terminal (Ubuntu1) :

docker exec -it ubuntu1 bash
apt update && apt install -y netcat-traditional
echo 'Hello from ubuntu1' | nc -l -p 9000

Résultat

Et cela fonctionne correctement, même sans avoir mappé les ports.

Hello from ubuntu1

C’est la preuve qu’en mode Host de Docker, la machine locale et les conteneurs se partagent les mêmes ports et utilisent le même réseau.

Conclusion des modes Bridge et Host

Le mode Bridge offre une isolation réseau entre l’hôte et les conteneurs, vous obligeant à mapper explicitement les ports pour y accéder depuis la machine locale. Ce mécanisme renforce la sécurité, mais peut diminuer les performances. 👮🏻

À l’inverse, le mode Host partage directement le réseau de l’hôte : il est plus performant puisqu’aucune couche intermédiaire n’intervient, mais il expose les mêmes ports que l’hôte, créant un risque de conflit et réduisant l’isolation. 💪