Docker mis en réseau : Différences et avantages des modes Bridge et Host
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. 💪