Aller au contenu
Réussir mon BTS SIO

Tape une notion, une commande ou le nom d'une épreuve.

Par exemple

Chapitre 712 minIntermédiaire

Réseaux Docker : bridge, DNS interne et publication de ports

Par Josselyn C., prof de BTS SIO. Mis à jour le .

À la fin de ce chapitre, tu sauras

  • faire communiquer des conteneurs par leur nom sur un réseau personnalisé ;
  • publier un port sur la bonne adresse, et seulement s'il le faut ;
  • isoler une base de données sur un réseau interne ;
  • filtrer l'accès aux conteneurs avec la chaîne DOCKER-USER.

4 exercices corrigés1 schéma

Un réseau Docker est un réseau virtuel auquel on branche des conteneurs pour qu'ils communiquent entre eux, par leur nom, tout en restant isolés des autres ; publier un port (-p) rend ensuite un service joignable depuis l'extérieur de l'hôte. Ce chapitre explique le réseau bridge par défaut et ses limites, les réseaux personnalisés et leur DNS interne, la publication de ports, les réseaux internes sans accès extérieur, les pilotes host et macvlan, puis le filtrage avec la chaîne DOCKER-USER.

Les pilotes de réseau

PiloteCe que voit le conteneurUsage
bridgeUne interface sur un pont virtuel de l'hôte, une adresse privée, une sortie vers l'extérieur par NATLe cas général, sur un seul hôte
hostDirectement les interfaces de l'hôte, sans isolation réseauUn agent de supervision qui doit voir le réseau de l'hôte
noneAucune interface, sauf la boucle localeUn traitement qui ne doit rien joindre
macvlan, ipvlanUne adresse IP dans le réseau physique, comme une machine à partUn service qui doit apparaître dans un VLAN de l'entreprise
overlayUn réseau qui s'étend sur plusieurs hôtesDocker Swarm
bash
docker network ls
text
NETWORK ID     NAME      DRIVER    SCOPE
8c1d7e2f4a90   bridge    bridge    local
1f3b5a7c9e21   host      host      local
6a8c0e2f4b13   none      null      local

Le réseau bridge par défaut et ses limites

À l'installation, Docker crée l'interface docker0 (172.17.0.1/16) et le réseau bridge. Un conteneur lancé sans --network y est branché : il reçoit une adresse en 172.17.0.x, sa passerelle est 172.17.0.1 (l'hôte), et ses connexions vers l'extérieur sont traduites (NAT) avec l'adresse de l'hôte, comme les postes d'un réseau privé derrière une box.

Ce réseau par défaut a deux défauts :

  • pas de résolution de noms : deux conteneurs ne se joignent que par leur adresse IP, qui change à chaque recréation ;
  • pas d'isolation : tous les conteneurs lancés sans option se retrouvent sur le même réseau et peuvent se joindre.

Les réseaux personnalisés et leur DNS interne

bash
docker network create gestion
docker run -d --name bdd --network gestion -e MYSQL_ROOT_PASSWORD='Test-Labo-2026!' mysql:8.4
docker run --rm --network gestion alpine:3.24 nslookup bdd
text
Server:		127.0.0.11
Address:	127.0.0.11:53

Non-authoritative answer:
Name:	bdd
Address: 172.20.0.2

Sur un réseau personnalisé, Docker fournit un serveur DNS interne (127.0.0.11 vu depuis chaque conteneur) qui résout le nom de chaque conteneur du réseau, et ses alias. Les autres noms (Internet, ad.sorbier.example) sont transmis aux serveurs DNS de l'hôte : c'est pour cela que srv-gestion utilise les DNS de l'annuaire. L'adresse 172.20.0.2 vient de la plage default-address-pools réglée au chapitre 2.

L'API se connecte donc à bdd:3306, jamais à une adresse IP. Et surtout pas à localhost :

Deux réseaux personnalisés sont isolés l'un de l'autre. Un conteneur branché sur deux réseaux sert de pont applicatif entre eux : c'est la place du reverse proxy, branché à la fois sur le réseau public de l'application et sur le réseau de chaque service qu'il publie.

bash
docker network connect gestion proxy       # ajoute un réseau à un conteneur qui tourne
docker network disconnect gestion proxy
docker network inspect gestion             # sous-réseau, passerelle, conteneurs branchés

Publier un port

Publier un port, c'est demander à Docker de rediriger un port de l'hôte vers un port du conteneur. Docker ajoute une règle de NAT de destination : un paquet qui arrive sur 192.168.10.179:443 est réécrit vers 172.20.0.5:443, l'adresse du conteneur.

ÉcritureEffet
-p 8080:80Port 8080 de toutes les adresses de l'hôte, en IPv4 et en IPv6, vers le port 80 du conteneur
-p 127.0.0.1:8080:80Seulement sur la boucle locale : invisible depuis le réseau
-p 192.168.10.179:443:443Seulement sur cette adresse de l'hôte
-p 5514:514/udpUn port UDP (TCP par défaut)
-p 8080 ou -PUn port de l'hôte choisi au hasard ; docker port le donne

Deux conteneurs ne peuvent pas publier le même port sur la même adresse de l'hôte : le second échoue avec port is already allocated (ou address already in use si un service de l'hôte l'occupe déjà). En revanche, ils peuvent écouter tous les deux sur leur port 80 interne, chacun dans son espace de noms réseau.

Un réseau interne pour la base de données

L'option --internal crée un réseau sans passerelle vers l'extérieur : ses conteneurs se parlent entre eux, mais ne peuvent joindre ni Internet ni le réseau de l'entreprise, et aucun port ne peut y être publié.

bash
docker network create --internal gestion-donnees

C'est la place de la base de données : même compromise, elle ne peut rien envoyer à l'extérieur. L'API est branchée sur ce réseau et sur le réseau du reverse proxy ; la base, seulement sur le réseau interne.

Postesport 443 publiéproxyCaddyfrontNginxréseau frontalproxy, front, apiapisur les deuxréseau donneesinterne : aucune sortiebddMySQLInternet, proxy,front : injoignablesSeul le proxy publie un port sur l'hôte ; la base n'est jointe que par l'API.Les conteneurs d'un même réseau se trouvent par leur nom (DNS interne de Docker).
Un réseau par usage : la base n'est joignable que par l'API, et ne sort nulle part

Les pilotes host et macvlan

Avec --network host, le conteneur partage la pile réseau de l'hôte : il écoute directement sur les ports de srv-gestion, sans NAT ni -p (les options de publication sont ignorées). C'est plus simple pour un agent de supervision qui doit voir les interfaces de l'hôte, mais il n'y a plus aucune isolation réseau : le conteneur voit tout le trafic et peut ouvrir n'importe quel port.

Avec macvlan, chaque conteneur reçoit sa propre adresse MAC et une adresse IP dans un réseau physique, par exemple un VLAN de l'entreprise ; il apparaît comme une machine de plus sur le switch. C'est utile pour un service qui doit avoir son adresse à lui. Il faut alors réserver ses adresses dans le plan d'adressage (pour éviter les conflits avec le DHCP), et savoir que, par conception, l'hôte ne joint pas directement ses propres conteneurs macvlan.

Docker et le pare-feu de l'hôte

Les règles que Docker ajoute pour publier les ports passent avant celles d'ufw (chapitre 2). Pour filtrer l'accès aux ports publiés sur l'hôte lui-même, Docker réserve la chaîne DOCKER-USER, qu'il consulte avant ses propres règles et ne modifie jamais. Pour n'accepter de nouvelles connexions vers les conteneurs que depuis les réseaux de Sorbier (le siège, l'entrepôt de Mâcon par le tunnel IPsec et les utilisateurs du VPN), sur l'interface ens18 de la VM :

bash
sudo iptables -I DOCKER-USER -i ens18 -m conntrack --ctstate NEW -j DROP
sudo iptables -I DOCKER-USER -i ens18 -s 10.8.0.0/24 -j RETURN
sudo iptables -I DOCKER-USER -i ens18 -s 192.168.20.0/24 -j RETURN
sudo iptables -I DOCKER-USER -i ens18 -s 192.168.10.0/24 -j RETURN

-I insère chaque règle en tête de la chaîne : les trois RETURN (réseaux du siège, de Mâcon et du VPN), ajoutés après, passent donc avant le DROP. RETURN rend la main aux règles de Docker, qui laissent passer le trafic vers les ports publiés.

La condition --ctstate NEW ne vise que les connexions entrantes nouvelles : les réponses aux connexions que les conteneurs ouvrent vers Internet (mises à jour, API externes) passent toujours. Une règle ajoutée ainsi disparaît au redémarrage : enregistre-la avec le paquet iptables-persistent, ou mieux, gère-la avec un outil d'automatisation.

Diagnostiquer un problème de réseau

QuestionCommande
Sur quels réseaux est ce conteneur, avec quelle adresse ?docker inspect -f '{{range $n, $c := .NetworkSettings.Networks}}{{$n}} {{$c.IPAddress}} {{end}}' api
Quels conteneurs sont sur ce réseau ?docker network inspect gestion
Le nom se résout-il depuis le réseau ?docker run --rm --network gestion alpine:3.24 nslookup bdd
Le port répond-il ?docker run --rm --network gestion alpine:3.24 nc -zv bdd 3306
Quels ports sont publiés ?docker port proxy ou ss -tlnp sur l'hôte

Un conteneur jetable branché sur le même réseau évite d'installer des outils de diagnostic dans les images de production.

Exercices

Exercice 1 sur 4 Le nom qui ne se résout pas Réussi À revoir

Un technicien lance docker run -d --name bdd mysql:8.4 … puis docker run -d --name api -e DB_HOST=bdd monapi:1.0, sans autre option. L'API journalise getaddrinfo ENOTFOUND bdd. Explique et corrige.

Voir la réponseMasquer la réponse de l'exercice 1

Sans --network, les deux conteneurs sont sur le réseau bridge par défaut, qui ne fournit pas de résolution de noms : bdd est inconnu. Il faut un réseau personnalisé, dont le DNS interne résout les noms des conteneurs :

bash
docker network create gestion
docker network connect gestion bdd
docker network connect gestion api
docker restart api

(ou recréer les deux conteneurs avec --network gestion). Avec Compose, ce réseau est créé automatiquement.

Tu avais trouvé ?

Exercice 2 sur 4 Lire des publications de ports Réussi À revoir

Pour chaque option, dis depuis où le service est joignable, et sur quel port.

  1. -p 8443:443 sur srv-gestion.
  2. -p 127.0.0.1:3306:3306.
  3. Aucun -p, conteneur sur le réseau gestion.
  4. --network host, Nginx écoutant sur 80 dans le conteneur.
Voir la réponseMasquer la réponse de l'exercice 2
  1. Depuis tout réseau qui peut joindre srv-gestion (si les pare-feu le permettent), sur 192.168.10.179:8443, qui mène au port 443 du conteneur.
  2. Seulement depuis srv-gestion lui-même, sur 127.0.0.1:3306 : invisible depuis le réseau.
  3. Seulement depuis les autres conteneurs du réseau gestion, par le nom du conteneur et son port interne.
  4. Sur le port 80 de toutes les interfaces de srv-gestion, directement, sans NAT : le conteneur partage la pile réseau de l'hôte.

Tu avais trouvé ?

Exercice 3 sur 4 Concevoir les réseaux Réussi À revoir

L'application de gestion comprend un reverse proxy, un front web, une API et une base MySQL. Propose les réseaux Docker, dis quels conteneurs sont branchés sur lesquels, et quels ports publier. Justifie au regard de la sécurité.

Voir la réponseMasquer la réponse de l'exercice 3
RéseauTypeConteneurs
frontalbridge personnaliséproxy, front, API
donneesbridge personnalisé, --internalAPI, base MySQL

Seul le proxy publie des ports : 443 (HTTPS) et 80 (redirection vers HTTPS). Le front et l'API ne sont joints que par le proxy ; la base n'est jointe que par l'API.

Justification : chaque composant n'est joignable que par ceux qui en ont besoin (moindre privilège, cloisonnement). La base, la plus sensible, est sur un réseau interne : même si elle était compromise, elle ne pourrait ni joindre Internet ni être atteinte depuis le proxy. Un attaquant qui prendrait la main sur le front ne verrait pas la base.

Tu avais trouvé ?

Exercice 4 sur 4 Le port déjà pris Réussi À revoir

Sur srv-gestion, docker run -d -p 80:80 --name web2 nginx:1.30-alpine échoue avec Bind for 0.0.0.0:80 failed: port is already allocated. Donne deux causes possibles et la commande qui permet de trancher.

Voir la réponseMasquer la réponse de l'exercice 4

Le message port is already allocated vient de Docker : un autre conteneur publie déjà le port 80 de l'hôte (par exemple le reverse proxy). docker ps --format '{{.Names}} {{.Ports}}' montre lequel. Si c'est un service de l'hôte (un Apache installé par paquet), l'erreur parle plutôt de address already in use ; sudo ss -tlnp | grep ':80 ' montre le processus qui écoute.

Solutions : publier web2 sur un autre port de l'hôte (-p 8081:80), ou mieux, ne pas le publier et le placer derrière le reverse proxy, qui route selon le nom demandé.

Tu avais trouvé ?

Chapitre terminé !

Fais les 4 exercices avant de passer à la suite : c'est en t'entraînant que tout se fixe.

chapitres
–
de série
–
du cours
–
Chapitre suivant : Docker Compose : écrire un fichier compose.yamlRevoir le sommaire du cours