Wi-Fi, Cloud et Technologies Réseau

Réseaux de conteneurs et Docker

Chaque conteneur Docker possède sa propre pile réseau. Pilotes bridge, host, macvlan et overlay, DNS intégré, publication de ports et interaction avec le pare-feu de l'hôte : ce qu'il faut savoir pour exploiter sereinement.

Conteneurs Docker reliés à un pont virtuel sur l'hôte avec ports publiés vers l'extérieur

Docker isole chaque conteneur dans son propre espace de noms réseau (network namespace) : interfaces, adresses, table de routage et règles de filtrage propres. Pour relier les conteneurs entre eux et avec l'extérieur, Docker crée des ponts virtuels, des paires d'interfaces et des règles de traduction d'adresses sur l'hôte. Comprendre ces mécanismes est indispensable pour diagnostiquer et, surtout, pour éviter d'exposer involontairement des services.

Objectif : comprendre les pilotes réseau de Docker, la résolution de noms entre conteneurs, la publication de ports et son interaction avec le pare-feu, et diagnostiquer les problèmes courants.

Les commandes concernent Docker Engine sur Linux (versions récentes). Docker Desktop (Windows, macOS) exécute les conteneurs dans une machine virtuelle, ce qui modifie certains comportements réseau, notamment le mode host. Les noms et adresses sont des exemples.

Les briques Linux sous-jacentes

  • Espaces de noms réseau : chaque conteneur a sa propre pile réseau isolée.
  • Paires veth : interfaces virtuelles reliées deux à deux, une extrémité dans le conteneur (eth0), l'autre sur l'hôte.
  • Pont Linux (bridge) : relie les extrémités côté hôte, comme un commutateur virtuel (docker0 par défaut).
  • Règles NAT et de filtrage (iptables ou nftables) : traduction des adresses en sortie, redirection des ports publiés.

Voir Commutateurs virtuels et réseaux de machines virtuelles pour le fonctionnement des ponts.

Les pilotes réseau

Pilote Principe Usage
bridge Réseau privé sur l'hôte, NAT vers l'extérieur Cas par défaut sur un hôte unique
host Le conteneur partage la pile réseau de l'hôte Performances, services réseau particuliers ; moins d'isolation
none Aucun réseau (uniquement l'interface de bouclage) Traitements isolés
macvlan / ipvlan Le conteneur obtient une adresse sur le réseau physique Applications qui doivent apparaître comme des machines du LAN
overlay Réseau étendu sur plusieurs hôtes (VXLAN) Docker Swarm
docker network ls
docker network inspect bridge

Le réseau bridge par défaut et les réseaux personnalisés

Un conteneur lancé sans option rejoint le réseau bridge par défaut (pont docker0, souvent en 172.17.0.0/16). Sur ce réseau par défaut, les conteneurs ne se résolvent pas par leur nom.

Bonne pratique : créer des réseaux bridge personnalisés. Ils offrent :

  • un DNS intégré : les conteneurs se joignent par leur nom (ou leurs alias) ;
  • une meilleure isolation : seuls les conteneurs connectés à un même réseau communiquent ;
  • un contrôle de l'adressage.
docker network create --driver bridge --subnet 10.200.10.0/24 reseau-app
docker run -d --name base --network reseau-app postgres:16
docker run -d --name api  --network reseau-app -e DB_HOST=base mon-image-api:1.0
docker exec api getent hosts base      # résolution par le DNS intégré de Docker

Le DNS intégré répond à l'adresse 127.0.0.11 à l'intérieur des conteneurs connectés à un réseau personnalisé.

Choisir des plages sans conflit

Les plages par défaut de Docker (172.17.0.0/16, puis d'autres blocs pour les réseaux suivants) peuvent chevaucher vos réseaux d'entreprise ou de VPN : le serveur ne peut alors plus joindre ces destinations. Définissez des plages adaptées dans /etc/docker/daemon.json :

{
  "bip": "10.199.0.1/24",
  "default-address-pools": [
    { "base": "10.200.0.0/16", "size": 24 }
  ]
}

Redémarrez le démon après modification, de préférence avant de créer les réseaux.

Publier des ports

Un conteneur sur un réseau bridge n'est pas joignable depuis l'extérieur de l'hôte, sauf si un port est publié :

docker run -d --name web -p 8080:80 nginx:stable             # toutes les interfaces de l'hôte
docker run -d --name web-local -p 127.0.0.1:8081:80 nginx:stable   # uniquement en local
docker port web

-p 8080:80 signifie : le port 8080 de l'hôte est redirigé vers le port 80 du conteneur. Sans adresse, le port est publié sur toutes les interfaces de l'hôte, y compris celle exposée à Internet.

Le piège du pare-feu

Docker insère ses propres règles dans le pare-feu de l'hôte pour réaliser la redirection des ports publiés. Ces règles sont traitées avant les règles de filtrage habituelles du trafic entrant de l'hôte : sur de nombreuses configurations, un port publié par Docker est accessible même si un pare-feu de l'hôte (UFW, firewalld en configuration simple) semble le bloquer.

Mesures :

  • publiez uniquement sur l'interface nécessaire (127.0.0.1 derrière un proxy inverse local, ou l'adresse privée de l'hôte) ;
  • ne publiez pas les ports des bases de données et services internes : laissez-les sur un réseau Docker privé, joignable seulement par les conteneurs qui en ont besoin ;
  • pour filtrer le trafic à destination des conteneurs, utilisez la chaîne prévue par Docker (DOCKER-USER avec iptables) ou un pare-feu en amont de l'hôte ;
  • consultez la documentation de Docker sur l'intégration avec iptables/nftables et votre pare-feu, qui évolue selon les versions.

Exemple avec Docker Compose

services:
  proxy:
    image: nginx:stable
    ports:
      - "443:443"
    networks: [frontal]
  api:
    image: mon-image-api:1.0
    networks: [frontal, donnees]
    environment:
      DB_HOST: base
  base:
    image: postgres:16
    networks: [donnees]
    volumes:
      - donnees-pg:/var/lib/postgresql/data
networks:
  frontal: {}
  donnees:
    internal: true
volumes:
  donnees-pg: {}
  • Seul le proxy publie un port.
  • La base n'est connectée qu'au réseau donnees, déclaré internal: true : aucun accès vers l'extérieur, et joignable uniquement par api.
  • api est connectée aux deux réseaux, ce qui segmente les flux comme le ferait une architecture à trois niveaux. Voir Segmentation réseau et réduction de la surface d'attaque.

macvlan : des conteneurs sur le réseau physique

docker network create -d macvlan --subnet 10.10.10.0/24 --gateway 10.10.10.1 \
  -o parent=eno1.10 lan-vlan10
docker run -d --name capteur --network lan-vlan10 --ip 10.10.10.50 mon-image-capteur:1.0

Le conteneur obtient sa propre adresse MAC et apparaît comme une machine du VLAN 10. Limites : par défaut, l'hôte ne peut pas joindre ses propres conteneurs macvlan directement ; certains commutateurs ou points d'accès limitent le nombre d'adresses MAC par port (port security) ; les réseaux Wi-Fi n'acceptent généralement pas plusieurs adresses MAC par client.

Overlay et orchestrateurs

Le pilote overlay relie des conteneurs répartis sur plusieurs hôtes (Docker Swarm) grâce à des tunnels VXLAN, avec un chiffrement optionnel. Dans Kubernetes, le réseau est délégué à un plugin CNI (Calico, Cilium, Flannel…), chaque pod reçoit une adresse, et les NetworkPolicies permettent de filtrer les flux entre pods — à condition que le plugin les prenne en charge.

Diagnostiquer

docker network inspect reseau-app                 # conteneurs connectés, adresses, sous-réseau
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' api
docker exec -it api sh -c 'ip addr; ip route; cat /etc/resolv.conf'
docker run --rm --network container:api nicolaka/netshoot ss -tlnp   # outils réseau dans l'espace de noms du conteneur
sudo ss -tlnp | grep docker-proxy                  # ports publiés sur l'hôte
sudo iptables -t nat -L DOCKER -n -v               # règles de redirection (selon le pare-feu utilisé)
Symptôme Cause probable
Conteneurs qui ne se joignent pas par leur nom Réseau bridge par défaut, ou conteneurs sur des réseaux différents
Service injoignable depuis l'extérieur Port non publié, publié sur 127.0.0.1, ou service qui écoute sur 127.0.0.1 dans le conteneur
Service exposé malgré le pare-feu Règles de Docker prioritaires sur le filtrage de l'hôte
L'hôte ne joint plus certains réseaux de l'entreprise Chevauchement avec les plages Docker
Pas d'accès Internet depuis les conteneurs ip_forward désactivé, règles NAT supprimées par un autre outil, DNS inaccessible

Piège fréquent : une application qui écoute sur 127.0.0.1 à l'intérieur du conteneur n'est pas joignable via un port publié ; elle doit écouter sur 0.0.0.0 (toutes les interfaces du conteneur).

Erreurs courantes

  • Publier les ports des bases de données sur toutes les interfaces.
  • Croire qu'UFW ou firewalld protège les ports publiés.
  • Utiliser le réseau bridge par défaut pour des applications multi-conteneurs.
  • Plages Docker qui chevauchent le réseau de l'entreprise.
  • Mode host par facilité, au détriment de l'isolation.

Conclusion

Des réseaux bridge personnalisés pour l'isolation et le DNS, des publications de ports limitées au strict nécessaire et liées à la bonne interface, des réseaux internes pour les données, des plages d'adresses choisies : ces principes suffisent à exploiter Docker sereinement. À plus grande échelle, les orchestrateurs et leurs plugins réseau prennent le relais avec les mêmes logiques de segmentation.

Références