Réseau Docker avancé : Bridge, Host, Macvlan et Overlay expliqués en profondeur
Ce tutoriel propose une exploration approfondie des principaux modes réseau Docker (Bridge, Host, Macvlan, Overlay), avec des commandes réelles, des scénarios concrets, des méthodes de diagnostic, et des bonnes pratiques de conception. L’objectif est de comprendre comment Docker connecte les conteneurs, comment le trafic circule, et quels compromis (performance, isolation, simplicité, compatibilité) chaque mode implique.
Table des matières
- Pré-requis et environnement
- Rappels : namespaces, veth, iptables/nftables
- Outils de diagnostic indispensables
- Réseau Bridge (par défaut) — en profondeur
- Réseau Host — performances et pièges
- Réseau Macvlan — IP “physiques” sur le LAN
- Réseau Overlay — multi-hôtes et Swarm
- Choisir le bon mode : matrice de décision
- Dépannage : symptômes → causes → commandes
- Bonnes pratiques et sécurité
Pré-requis et environnement
- Linux (idéalement Debian/Ubuntu/RHEL). Les détails varient selon la distribution (iptables vs nftables).
- Docker Engine installé.
- Accès root ou sudo.
- Paquets utiles :
iproute2(commandeip)iptablesounfttcpdumpconntrack(optionnel)dig(dnsutils) ounslookup
Vérifier la version Docker :
docker version
docker info
Rappels : namespaces, veth, iptables/nftables
Docker s’appuie sur des primitives Linux :
- Network namespace : chaque conteneur a (souvent) sa pile réseau isolée (interfaces, routes, tables ARP).
- veth pair : paire d’interfaces virtuelles “câble virtuel”. Une extrémité dans le namespace du conteneur (
eth0), l’autre sur l’hôte (souvent nomméevethXXXX). - Bridge Linux : commutateur L2 logiciel. Le bridge par défaut est
docker0. - NAT/masquerade : pour permettre aux conteneurs en bridge de sortir vers Internet via l’IP de l’hôte.
- Filtrage : règles
iptables/nftables(chaînes DOCKER, DOCKER-USER, etc.) pour la publication de ports et l’isolation.
Pour visualiser rapidement :
ip link show
ip addr show
ip route show
Outils de diagnostic indispensables
1) Inspecter un réseau Docker
docker network ls
docker network inspect bridge
2) Inspecter un conteneur (réseau, IP, endpoints)
docker inspect <container> --format '{{json .NetworkSettings.Networks}}' | jq
3) Entrer dans un conteneur et vérifier sa pile réseau
docker exec -it <container> sh
ip addr
ip route
cat /etc/resolv.conf
4) Sniffer le trafic
Sur l’hôte :
tcpdump -ni any port 80
tcpdump -ni docker0
Dans un conteneur (si tcpdump est présent) :
tcpdump -ni eth0
5) Voir les règles de NAT/filtrage
Selon votre système :
iptables -S
iptables -t nat -S
iptables -L -n -v
iptables -t nat -L -n -v
Ou en nftables :
nft list ruleset
Réseau Bridge (par défaut) — en profondeur
Le mode bridge est le plus courant : chaque conteneur a une IP privée sur un sous-réseau géré par Docker, et l’hôte fait la passerelle.
Comprendre docker0 et le NAT
Par défaut, Docker crée un bridge Linux docker0 (sauf configuration différente). Vérifiez :
ip addr show docker0
ip link show docker0
Vous verrez typiquement une IP comme 172.17.0.1/16.
Quand un conteneur démarre sur le réseau bridge par défaut :
- Docker crée un veth pair
- Attache l’extrémité hôte au bridge
docker0 - Configure l’IP du conteneur sur l’extrémité conteneur (
eth0) - Ajoute des règles NAT pour la sortie
Exemple : lancer un conteneur et inspecter son IP :
docker run -d --name web nginx:alpine
docker inspect web --format '{{.NetworkSettings.IPAddress}}'
Tester la connectivité :
docker exec -it web sh -c "ip addr; ip route; wget -qO- http://example.com | head"
NAT sortant (MASQUERADE)
Le conteneur sort vers Internet via l’IP de l’hôte. Les règles iptables typiques :
iptables -t nat -L -n -v | sed -n '1,200p'
Cherchez des règles MASQUERADE associées aux sous-réseaux Docker.
Conséquence : depuis l’extérieur, un conteneur n’est pas joignable sans publication de port (DNAT), car son IP est privée.
Bridge utilisateur et DNS embarqué
Le bridge par défaut a des limitations (notamment sur la résolution DNS par nom de conteneur selon versions/paramètres). En pratique, on préfère créer un bridge utilisateur : il apporte un DNS interne plus fiable et une meilleure isolation.
Créer un réseau bridge utilisateur :
docker network create --driver bridge app-net
docker network inspect app-net
Lancer deux conteneurs sur ce réseau et tester la résolution par nom :
docker run -d --name api --network app-net hashicorp/http-echo:1.0 -text="hello"
docker run -d --name client --network app-net alpine:3.20 sleep 1d
docker exec -it client sh -c "apk add --no-cache curl >/dev/null; curl -s http://api:5678"
Ici, api est résolu via le DNS Docker (souvent 127.0.0.11 dans /etc/resolv.conf du conteneur).
Vérifier :
docker exec -it client cat /etc/resolv.conf
Publication de ports : -p vs —network host
En bridge, vous exposez un service via -p :
docker run -d --name web2 --network bridge -p 8080:80 nginx:alpine
curl -I http://127.0.0.1:8080
Ce que fait Docker :
- Ajoute une règle DNAT (port mapping) vers l’IP du conteneur
- Ouvre le port sur l’hôte (selon le backend iptables/nft)
Voir les règles :
iptables -t nat -L DOCKER -n -v
Remarque importante : -p 8080:80 publie sur toutes les interfaces. Pour restreindre à localhost :
docker run -d --name web3 -p 127.0.0.1:8081:80 nginx:alpine
curl -I http://127.0.0.1:8081
Isolation inter-conteneurs et ICC
Docker peut contrôler si les conteneurs d’un même bridge peuvent communiquer. Historiquement, le paramètre ICC (Inter-Container Communication) pouvait être ajusté, mais aujourd’hui l’approche recommandée est :
- Utiliser des réseaux distincts pour segmenter (ex:
frontend-net,backend-net) - Connecter un conteneur à plusieurs réseaux si nécessaire
Exemple : un reverse proxy sur deux réseaux (front et back) :
docker network create frontend-net
docker network create backend-net
docker run -d --name app --network backend-net hashicorp/http-echo:1.0 -text="app"
docker run -d --name rp --network frontend-net -p 8082:80 nginx:alpine
docker network connect backend-net rp
docker inspect rp --format '{{json .NetworkSettings.Networks}}' | jq
Le conteneur rp a maintenant deux interfaces (une par réseau Docker).
Exemples complets
Exemple A : micro-stack simple (client → api)
docker network create demo-net
docker run -d --name api --network demo-net hashicorp/http-echo:1.0 -listen=:8080 -text="API OK"
docker run -d --name client --network demo-net alpine:3.20 sleep 1d
docker exec -it client sh -c "apk add --no-cache curl >/dev/null; curl -s http://api:8080"
Exemple B : observer le veth côté hôte
Lister les interfaces avant/après :
ip link show | grep -E 'docker0|veth' || true
docker run -d --name t1 --network bridge alpine:3.20 sleep 1d
ip link show | grep -E 'docker0|veth' || true
Réseau Host — performances et pièges
En mode host, le conteneur partage la pile réseau de l’hôte (pas de namespace réseau isolé). Concrètement :
- Pas d’IP dédiée au conteneur
- Les ports écoutés dans le conteneur sont écoutés directement sur l’hôte
- Pas de
-p(publication) nécessaire (et généralement ignorée) - Moins de surcoût (pas de NAT, moins de règles), mais moins d’isolation
Lancer un service en host :
docker run -d --name web-host --network host nginx:alpine
ss -lntp | grep ':80' || true
curl -I http://127.0.0.1:80
Quand l’utiliser ?
- Agents de monitoring (node exporter), collecteurs, outils réseau
- Workloads très sensibles à la latence (cas spécifiques)
- Besoin d’écouter sur de multiples ports dynamiques sans mapping
Pièges
- Conflits de ports : si l’hôte utilise déjà
:80, le conteneur échoue. - Sécurité : exposition involontaire sur toutes les interfaces.
- Observabilité : distinguer processus hôte vs conteneur peut être moins évident (même si cgroups aident).
Réseau Macvlan — IP “physiques” sur le LAN
Le driver macvlan permet à un conteneur d’apparaître sur le réseau L2 comme une machine distincte, avec :
- sa propre adresse MAC
- une IP du LAN (ex: 192.168.1.50)
- pas de NAT nécessaire pour être joignable depuis le LAN
C’est utile pour :
- Intégration à un réseau existant (appliances, legacy)
- Besoin d’adresses IP “réelles” (DHCP statique, ACL réseau, etc.)
- Éviter la publication de ports (le conteneur est directement adressable)
Bridge vs 802.1Q trunk
Deux grands modes :
- macvlan bridge : attaché à une interface physique (ex:
eth0) sur un VLAN non taggé (ou déjà configuré sur l’interface). - macvlan 802.1Q trunk : attaché à une sous-interface VLAN (ex:
eth0.20) pour tagger le trafic.
Exemple macvlan “bridge” (LAN 192.168.1.0/24)
Supposons :
- Interface hôte :
eth0 - Réseau :
192.168.1.0/24 - Passerelle :
192.168.1.1 - Plage réservée pour Docker :
192.168.1.200-192.168.1.250
Créer le réseau :
docker network create -d macvlan \
--subnet=192.168.1.0/24 \
--gateway=192.168.1.1 \
-o parent=eth0 \
macvlan-net
Démarrer un conteneur avec IP fixe :
docker run -d --name mv1 --network macvlan-net --ip 192.168.1.210 nginx:alpine
docker exec -it mv1 ip addr
Tester depuis une autre machine du LAN :
curl -I http://192.168.1.210
Problème classique : le host ne voit pas le macvlan
Par design, l’interface macvlan isole souvent le trafic entre l’hôte et ses conteneurs macvlan : l’hôte ne peut pas joindre directement 192.168.1.210 (même si le LAN le peut).
Symptôme : depuis l’hôte, ping 192.168.1.210 échoue, mais depuis un autre PC du LAN ça marche.
Solution courante : créer une interface macvlan “shim” côté hôte sur le même parent, avec une IP dédiée dans le sous-réseau, puis router via elle.
Exemple :
ip link add macvlan-shim link eth0 type macvlan mode bridge
ip addr add 192.168.1.199/24 dev macvlan-shim
ip link set macvlan-shim up
ip route add 192.168.1.200/29 dev macvlan-shim || true
Ensuite, l’hôte peut joindre les IP macvlan (selon votre plan d’adressage). Adaptez la route à la plage réellement utilisée.
Exemples complets
Exemple C : service DNS/HTTP sur IP LAN
docker run -d --name mv-http --network macvlan-net --ip 192.168.1.211 nginx:alpine
curl -I http://192.168.1.211
Exemple D : macvlan en VLAN taggé (802.1Q)
Créer une sous-interface VLAN (ex: VLAN 20) :
ip link add link eth0 name eth0.20 type vlan id 20
ip link set eth0.20 up
ip addr show eth0.20
Créer le réseau macvlan sur eth0.20 :
docker network create -d macvlan \
--subnet=10.20.0.0/24 \
--gateway=10.20.0.1 \
-o parent=eth0.20 \
macvlan-v20
Lancer un conteneur :
docker run -d --name mv-v20 --network macvlan-v20 --ip 10.20.0.50 nginx:alpine
Réseau Overlay — multi-hôtes et Swarm
Le driver overlay est conçu pour relier des conteneurs sur plusieurs hôtes comme s’ils étaient sur le même réseau virtuel. Il est historiquement associé à Docker Swarm.
VXLAN, chiffrement, gossip/contrôle
En overlay, Docker encapsule souvent le trafic dans VXLAN (UDP, typiquement port 4789). Il existe aussi un plan de contrôle (ports 2377/tcp pour Swarm, 7946/tcp+udp pour la découverte/état).
Ports à connaître (Swarm) :
2377/tcp: management (join, orchestration)7946/tcpet7946/udp: communication entre nœuds4789/udp: data plane VXLAN
Créer un cluster Swarm (sur le manager) :
docker swarm init --advertise-addr <IP_MANAGER>
Sur un worker, joindre :
docker swarm join --token <TOKEN> <IP_MANAGER>:2377
Vérifier :
docker node ls
Créer un réseau overlay :
docker network create -d overlay --attachable ovl-net
docker network ls
docker network inspect ovl-net
--attachablepermet d’y connecter aussi des conteneurs “standalone” (pas seulement des services Swarm).
Services Swarm, VIP vs DNSRR
En Swarm, un service peut être exposé via :
- VIP (Virtual IP) : un IP virtuel stable, load-balancé via IPVS/iptables selon implémentation.
- DNSRR (DNS Round Robin) : le DNS renvoie plusieurs IP de tâches, le client choisit.
Créer un service sur overlay :
docker service create --name whoami --network ovl-net --replicas 3 traefik/whoami
docker service ls
docker service ps whoami
Résolution DNS depuis un conteneur attaché :
docker run -it --rm --network ovl-net alpine:3.20 sh -c \
"apk add --no-cache bind-tools curl >/dev/null; \
dig +short whoami; \
for i in 1 2 3 4; do curl -s whoami | head -n 1; done"
Selon le mode par défaut, dig peut renvoyer un VIP (une seule IP) ou plusieurs IP si DNSRR est configuré.
Configurer DNSRR :
docker service update --endpoint-mode dnsrr whoami
Exemples complets multi-nœuds
Exemple E : réseau overlay + service + test inter-nœuds
- Sur le manager :
docker network create -d overlay --attachable prod-net
docker service create --name echo --network prod-net --replicas 2 hashicorp/http-echo:1.0 -listen=:5678 -text="OVERLAY OK"
- Sur n’importe quel nœud (manager ou worker), lancer un conteneur client attaché :
docker run -it --rm --network prod-net alpine:3.20 sh -c \
"apk add --no-cache curl >/dev/null; curl -s http://echo:5678"
- Diagnostiquer la distribution :
docker service ps echo
docker service logs echo
Exemple F : overlay chiffré
Docker permet de chiffrer le trafic overlay (surcoût CPU possible) :
docker network create -d overlay --opt encrypted --attachable secure-net
docker service create --name sec-echo --network secure-net --replicas 2 hashicorp/http-echo:1.0 -listen=:5678 -text="SECURE"
Choisir le bon mode : matrice de décision
| Besoin | Mode recommandé | Pourquoi |
|---|---|---|
| Simplicité, dev local, microservices sur un seul hôte | Bridge (user-defined) | DNS interne, isolation, facile à segmenter |
| Performance maximale, accès direct à la pile réseau hôte | Host | Pas de NAT/bridge, latence minimale |
| Conteneur joignable directement sur le LAN avec IP dédiée | Macvlan | IP/MAC “physiques”, intégration réseau |
| Multi-hôtes, orchestration, services distribués | Overlay (Swarm) | Réseau virtuel inter-nœuds, découverte, LB |
Dépannage : symptômes → causes → commandes
1) “Le conteneur a Internet, mais on ne peut pas y accéder depuis l’extérieur”
- Cause : en bridge, pas de port publié.
- Vérifier :
docker port <container> ss -lntp | grep <port> iptables -t nat -L DOCKER -n -v - Fix :
docker run -p 8080:80 ...
2) “Les conteneurs ne se résolvent pas par nom”
- Cause : utilisation du bridge par défaut, ou réseau mal choisi, ou DNS interne cassé.
- Vérifier :
docker exec -it <c> cat /etc/resolv.conf docker network inspect <net> - Fix : créer un réseau bridge utilisateur et y connecter les conteneurs :
docker network create app-net docker network connect app-net <container>
3) “En macvlan, le LAN voit le conteneur mais pas l’hôte”
- Cause : limitation macvlan host↔container.
- Fix : interface macvlan “shim” côté host (voir section dédiée).
4) “Overlay ne marche pas entre nœuds”
- Causes fréquentes :
- Ports Swarm bloqués (2377/7946/4789)
- MTU / fragmentation (VXLAN)
- Nœuds non joignables sur l’IP annoncée
- Vérifier :
Et côté firewall, ouvrir les ports nécessaires.docker node ls docker network inspect <overlay> ss -lunp | grep 4789 || true
Bonnes pratiques et sécurité
1) Préférer les bridges user-defined
Ils offrent :
- DNS interne stable
- Isolation par réseau
- Moins de surprises que le bridge par défaut
docker network create --driver bridge frontend
docker network create --driver bridge backend
2) Segmenter par “zones”
frontend: reverse proxy, exposition de portsbackend: bases de données, APIs internes- connecter uniquement les conteneurs qui doivent communiquer
3) Restreindre l’exposition des ports
Publier sur 127.0.0.1 si l’accès externe n’est pas requis :
docker run -p 127.0.0.1:5432:5432 postgres:16
4) Utiliser DOCKER-USER pour les politiques firewall
Docker insère ses règles, mais la chaîne DOCKER-USER est prévue pour vos règles avant traitement Docker.
Exemple (bloquer l’accès à un port publié depuis l’extérieur, autoriser uniquement un subnet) :
iptables -I DOCKER-USER -i eth0 -p tcp --dport 8080 -s 203.0.113.0/24 -j ACCEPT
iptables -I DOCKER-USER -i eth0 -p tcp --dport 8080 -j DROP
5) Attention au Macvlan en environnement entreprise
- Certains switches limitent le nombre de MAC par port (port-security).
- Le DHCP, l’ARP inspection, ou NAC peuvent bloquer.
- Prévoir une plage IP dédiée et documentée.
6) Overlay : surveiller MTU et performance
VXLAN ajoute de l’en-tête (overhead). Si vous observez des timeouts ou des paquets fragmentés :
- Vérifiez MTU sur interfaces
- Ajustez MTU Docker si nécessaire (selon votre infra)
- Testez avec
ping -M do -s <taille>
Exemple :
ping -M do -s 1472 <ip> # 1472 + 28 = 1500 (ICMP+IP)
Conclusion
- Bridge (surtout user-defined) est le meilleur choix général sur un hôte unique : isolation, DNS interne, simplicité.
- Host supprime une couche d’abstraction : utile pour certains services, mais attention à l’isolation et aux conflits de ports.
- Macvlan donne une présence L2 “native” sur le LAN : idéal pour l’intégration réseau, mais implique des contraintes (host↔container, politiques switch).
- Overlay est la solution Docker “native” pour le multi-hôtes via Swarm : encapsulation VXLAN, découverte de services, et options de chiffrement.
Si vous me donnez votre contexte (un seul serveur vs cluster, besoin d’IP LAN, contraintes firewall, VLAN, performance), je peux proposer une architecture réseau Docker complète avec un plan d’adressage, des règles de filtrage et une procédure de validation.