Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Volumes et réseaux

APERTO-NOTA

Réseaux

Par défaut, chaque conteneur Docker est connecté à un réseau virtuel interne géré par le moteur. Ce réseau permet aux conteneurs de communiquer entre eux et avec l’extérieur, sans modifier la configuration réseau de la machine hôte.

Docker crée pour chaque réseau une interface virtuelle sur l’hôte (de type bridge) et attribue automatiquement une adresse IP à chaque conteneur connecté. Le trafic entre conteneurs transite par ce bridge ; le trafic vers l’extérieur passe par les règles NAT du système.

Trois drivers couvrent les cas d’usage courants :

La différence entre le réseau bridge créé par défaut et un réseau bridge personnalisé est importante en pratique : le réseau par défaut ne propose pas de résolution DNS par nom de conteneur, ce qui oblige à manipuler des adresses IP. Un réseau personnalisé active automatiquement un serveur DNS interne : les conteneurs se joignent par leur nom, ce qui est plus robuste et lisible.

Séparer les conteneurs sur des réseaux distincts permet également de cloisonner les flux : une base de données placée sur un réseau backend ne sera pas joignable depuis un conteneur qui n’est connecté qu’au réseau frontend. C’est le principe de moindre privilège appliqué au réseau.

01. Pile réseau Docker et drivers

Solution to Exercise #

Résultat attendu du ping par IP (étape 2) :

PING 172.17.0.3 (172.17.0.3): 56 data bytes
64 bytes from 172.17.0.3: seq=0 ttl=64 time=0.108 ms

Résultat attendu du ping par nom (étape 2 — bridge par défaut) :

ping: bad address 'cont-b'

Sur le réseau bridge par défaut, la résolution DNS par nom de conteneur n’est pas disponible. Elle nécessite un réseau personnalisé (voir exercice 02).

DriverDNS par nomIsolationUsage
bridge (défaut)NonPartielleTests rapides
réseau personnaliséOuiOuiProduction
hostN/AAucunePerformance maximale
noneN/ATotaleSécurité maximale

02. Réseaux personnalisés

Solution to Exercise #

Résultat attendu du ping par nom (étape 3) :

PING serveur-web (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.098 ms
64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.071 ms

La résolution DNS fonctionne par nom de conteneur sur un réseau personnalisé — contrairement au réseau bridge par défaut (EX-10).

Résultat attendu de docker network inspect reseau-app (extrait) :

"Containers": {
    "abc...": { "Name": "serveur-web", "IPv4Address": "172.18.0.2/16" },
    "def...": { "Name": "client",      "IPv4Address": "172.18.0.3/16" }
}
Solution to Exercise #

Étape 1 — Créer le réseau

docker network create wp-net    # reseau bridge personnalise
docker network ls

Étape 2 — Lancer MariaDB

docker run -d \                        # mode detach
  --name wp-db \                       # nom du conteneur (utilise comme nom DNS)
  --network wp-net \                   # reseau personnalise
  -e MYSQL_ROOT_PASSWORD=rootpass \    # mot de passe root
  -e MYSQL_DATABASE=wordpress \        # base a creer au demarrage
  -e MYSQL_USER=wp \                   # utilisateur applicatif
  -e MYSQL_PASSWORD=wppass \           # mot de passe utilisateur
  mariadb:10.11                        # image

docker logs wp-db   # attendre la ligne "ready for connections"

Étape 3 — Lancer WordPress

docker run -d \                              # mode detach
  --name wp-app \                            # nom du conteneur
  --network wp-net \                         # meme reseau que wp-db
  -p 8080:80 \                               # port-hote:port-conteneur
  -e WORDPRESS_DB_HOST=wp-db \              # nom DNS du conteneur MariaDB
  -e WORDPRESS_DB_USER=wp \                 # utilisateur de la base
  -e WORDPRESS_DB_PASSWORD=wppass \         # mot de passe
  -e WORDPRESS_DB_NAME=wordpress \          # nom de la base
  wordpress:latest                           # image

Étape 4 — Vérifier

# Ouvrir http://localhost:8080 dans le navigateur

# Tester la resolution DNS depuis wp-app
docker exec wp-app ping -c 2 wp-db

Résultat attendu du ping :

PING wp-db (192.168.x.2): 56 data bytes
64 bytes from 192.168.x.2: seq=0 ttl=64 time=0.091 ms

Étape 5 — Nettoyer

docker stop wp-app wp-db
docker rm wp-app wp-db
docker network rm wp-net
docker image prune -f
docker volume prune -f

03. Isolation réseau entre piles (Namespace net)

Solution to Exercise #

Étape 3 — ping intra-réseau (succès attendu) :

PING web-2 (192.168.x.3): 56 data bytes
64 bytes from 192.168.x.3: seq=0 ttl=64 time=0.091 ms

Étape 4 — ping inter-réseaux (isolation attendue) :

ping: bad address 'db-1'

db-1 est inaccessible depuis web-1. Ils partagent le même hôte physique mais leurs Namespaces net sont distincts — aucune route ne les relie.

Étape 5 — après docker network connect :

Le conteneur proxy dispose de deux interfaces réseau (une par réseau) et peut joindre les deux piles. web-1 reste isolé de db-1.

Étape 6 — Résultat attendu :

pile-frontend : web-1 web-2 proxy
pile-backend  : db-1 proxy

web-1 n’apparaît que dans pile-frontend : il ne peut pas joindre db-1. proxy, connecté aux deux réseaux, apparaît dans les deux listes.

SituationRésultat
Conteneurs sur le même réseauCommunication par nom DNS
Conteneurs sur réseaux différentsIsolation totale
Conteneur connecté aux deux réseauxPasserelle contrôlée
Solution to Exercise #

Étape 1 — Créer les réseaux

docker network create wp-frontend   # reseau web
docker network create wp-backend    # reseau base de donnees
docker network ls

Étape 2 — Lancer MariaDB sur le backend uniquement

docker run -d \                        # mode detach
  --name wp-db \                       # nom du conteneur
  --network wp-backend \               # reseau backend uniquement
  -e MYSQL_ROOT_PASSWORD=rootpass \    # mot de passe root
  -e MYSQL_DATABASE=wordpress \        # base a creer
  -e MYSQL_USER=wp \                   # utilisateur applicatif
  -e MYSQL_PASSWORD=wppass \           # mot de passe
  mariadb:10.11

docker logs wp-db   # attendre "ready for connections"

Étape 3 — Lancer WordPress et le connecter aux deux réseaux

docker run -d \                              # mode detach
  --name wp-app \                            # nom du conteneur
  --network wp-frontend \                    # reseau frontend au lancement
  -p 8080:80 \                               # port-hote:port-conteneur
  -e WORDPRESS_DB_HOST=wp-db \             # nom DNS de MariaDB
  -e WORDPRESS_DB_USER=wp \                # utilisateur
  -e WORDPRESS_DB_PASSWORD=wppass \        # mot de passe
  -e WORDPRESS_DB_NAME=wordpress \         # nom de la base
  wordpress:latest

# Connecter wp-app au reseau backend pour joindre MariaDB
docker network connect wp-backend wp-app

Étape 4 — Vérifier

# WordPress joignable depuis le navigateur : http://localhost:8080

# wp-db joignable depuis wp-app (deux reseaux)
docker exec wp-app ping -c 2 wp-db

Résultat attendu du ping depuis wp-app :

PING wp-db (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.091 ms

Étape 5 — Nettoyer

docker stop wp-app wp-db
docker rm wp-app wp-db
docker network rm wp-frontend wp-backend
docker image prune -f
docker volume prune -f

Architecture des réseaux :

[wp-frontend]          [wp-backend]
   wp-app    <-------> wp-app <-------> wp-db
   (port 8080)         (pont entre
                        les deux reseaux)

WordPress joue le rôle de passerelle contrôlée : seul lui peut joindre MariaDB. Le trafic web (port 8080) reste sur le réseau frontend.


Volumes

04. Bind mount

Solution to Exercise #

Résultat attendu après modification :

<h1>Modified from host</h1>

La modification est immédiate — pas de redémarrage du conteneur nécessaire. C’est le comportement attendu d’un bind mount : le système de fichiers hôte est monté directement dans le conteneur via le Namespace mnt.

alert - Unknown Directive
Portez votre attention sur le chemin du dossier à monter

05. Volumes de données

Solution to Exercise #

Résultat attendu de docker volume inspect data-app :

[
    {
        "CreatedAt": "2026-06-15T10:00:00Z",
        "Driver": "local",
        "Mountpoint": "/var/lib/docker/volumes/data-app/_data",
        "Name": "data-app",
        "Scope": "local"
    }
]

Résultat attendu de l’étape 6 (restauration) :

Initial entry - Mon Jun 15 10:00:00 UTC 2026

Les données sont intégralement restaurées sur un volume distinct.

CommandeAction
docker volume create NOMCréer un volume
docker volume lsLister les volumes
docker volume inspect NOMDétails et chemin hôte
docker volume rm NOMSupprimer (si non utilisé)
docker volume pruneSupprimer tous les volumes inutilisés
Solution to Exercise #

Étape 1 — Créer les volumes et le réseau

docker volume create wp-data    # donnees MariaDB
docker volume create wp-logs    # logs Apache
docker network create wp-net    # reseau prive
docker volume ls
docker network ls

Étape 2 — Lancer MariaDB avec volume de données

docker run -d \                        # mode detach
  --name wp-db \                       # nom du conteneur
  --network wp-net \                   # reseau prive
  -v wp-data:/var/lib/mysql \          # volume de donnees : chemin interne MariaDB
  -e MYSQL_ROOT_PASSWORD=rootpass \    # mot de passe root
  -e MYSQL_DATABASE=wordpress \        # base a creer
  -e MYSQL_USER=wp \                   # utilisateur applicatif
  -e MYSQL_PASSWORD=wppass \           # mot de passe utilisateur
  mariadb:10.11

docker logs wp-db   # attendre "ready for connections"

Étape 3 — Lancer WordPress avec volume de logs

docker run -d \                              # mode detach
  --name wp-app \                            # nom du conteneur
  --network wp-net \                         # meme reseau que wp-db
  -p 8080:80 \                               # port-hote:port-conteneur
  -v wp-logs:/var/log/apache2 \             # volume de logs : chemin interne Apache
  -e WORDPRESS_DB_HOST=wp-db \             # nom DNS du conteneur MariaDB
  -e WORDPRESS_DB_USER=wp \                # utilisateur
  -e WORDPRESS_DB_PASSWORD=wppass \        # mot de passe
  -e WORDPRESS_DB_NAME=wordpress \         # nom de la base
  wordpress:latest

Étape 4 — Générer du trafic et lire les logs

curl -s http://localhost:8080 > /dev/null
curl -s http://localhost:8080 > /dev/null
curl -s http://localhost:8080/wp-login.php > /dev/null

docker run --rm -v wp-logs:/logs alpine ls -lh /logs
docker run --rm -v wp-logs:/logs alpine tail -5 /logs/access.log
docker run --rm -v wp-data:/data alpine ls -lh /data

Étape 5 — Sauvegarde et restauration

docker run --rm \
  -v wp-data:/data \
  -v /tmp:/backup \
  alpine tar czf /backup/wp-data-backup.tar.gz -C /data .

ls -lh /tmp/wp-data-backup.tar.gz

docker stop wp-app wp-db && docker rm wp-app wp-db
docker volume create wp-data-restored

docker run --rm \
  -v wp-data-restored:/data \
  -v /tmp:/backup \
  alpine tar xzf /backup/wp-data-backup.tar.gz -C /data

docker run --rm -v wp-data-restored:/data alpine ls -lh /data

Étape 6 — Nettoyer

docker volume rm wp-data wp-logs wp-data-restored
docker network rm wp-net
rm /tmp/wp-data-backup.tar.gz
docker image prune -fa
docker volume prune -fa
VolumeConteneurChemin interneContenu
wp-datawp-db/var/lib/mysqlFichiers de la base MariaDB
wp-logswp-app/var/log/apache2Logs Apache

06. Conteneurs liés à un volume partagé

Solution to Exercise #

Résultat attendu de docker logs consommateur :

Mon Jun 15 10:00:05 UTC 2026
Mon Jun 15 10:00:10 UTC 2026
Mon Jun 15 10:00:15 UTC 2026

Les deux conteneurs accèdent au même volume de façon concurrente. Le consommateur est en lecture seule (:ro) : il ne peut pas modifier log.txt, même accidentellement.

Solution to Exercise #

Étape 1 — Créer les ressources

docker volume create nginx-logs
docker network create analyse-net

Étape 2 — Lancer Nginx

docker run -d \                        # mode detach
  --name web \                         # nom du conteneur
  --network analyse-net \              # reseau dedie
  -p 8090:80 \                         # port-hote:port-conteneur
  -v nginx-logs:/var/log/nginx \       # volume de logs : chemin interne Nginx
  nginx:alpine                          # image

Étape 4 — Lancer GoAccess

docker run -d \                                         # mode detach
  --name analyse \                                      # nom du conteneur
  --network analyse-net \                               # meme reseau
  -p 7890:7890 \                                        # port du tableau de bord
  -v nginx-logs:/var/log/nginx:ro \                     # logs en lecture seule
  allinurl/goaccess \                                   # image GoAccess
  /var/log/nginx/access.log \                           # fichier de log a analyser
  --log-format=COMBINED \                               # format des logs Nginx
  --real-time-html \                                    # mise a jour en temps reel
  -o /dev/null                                          # sortie HTML vers /dev/null (dashboard websocket uniquement)

Rôle des paramètres GoAccess :

ParamètreRôle
--log-format=COMBINEDFormat de log Apache/Nginx standard
--real-time-htmlActive la mise à jour via WebSocket
-p 7890:7890Port du tableau de bord et du WebSocket
:roLe conteneur ne peut pas modifier les logs

Tableau de bord GoAccess — panneaux principaux :

  • Unique visitors : nombre de visites par heure

  • Requested files : pages les plus demandées

  • HTTP status codes : répartition 200 / 301 / 404 / 500

  • Hosts : adresses IP des clients

  • Browsers / OS : détection du navigateur et du système

Étape 7 — Nettoyer

docker stop web analyse
docker rm web analyse
docker network rm analyse-net
docker volume rm nginx-logs
docker image prune -fa
docker volume prune -fa

Exercice final — WordPress en load balancing derrière Nginx

Solution to Exercise #

Étape 1 — Créer les ressources

docker network create wp-frontend
docker network create wp-backend
docker volume create wp-data
docker volume create wp-logs

Étape 2 — Lancer MariaDB

docker run -d \                        # mode detach
  --name wp-db \                       # nom du conteneur
  --network wp-backend \               # reseau backend uniquement
  -v wp-data:/var/lib/mysql \          # volume de donnees
  -e MYSQL_ROOT_PASSWORD=rootpass \    # mot de passe root
  -e MYSQL_DATABASE=wordpress \        # base a creer
  -e MYSQL_USER=wp \                   # utilisateur applicatif
  -e MYSQL_PASSWORD=wppass \           # mot de passe
  mariadb:10.11

docker logs wp-db   # attendre "ready for connections"

Étape 3 — Lancer WordPress (sans port exposé)

docker run -d \                              # mode detach
  --name wp-app-1 \                          # nom du conteneur
  --network wp-frontend \                    # reseau frontend
  -v wp-logs:/var/log/apache2 \             # volume de logs
  -e WORDPRESS_DB_HOST=wp-db \             # nom DNS de MariaDB
  -e WORDPRESS_DB_USER=wp \                # utilisateur
  -e WORDPRESS_DB_PASSWORD=wppass \        # mot de passe
  -e WORDPRESS_DB_NAME=wordpress \         # nom de la base
  wordpress:latest
  # pas de -p : Nginx sera le seul point d entree

# Connecter WordPress au backend pour joindre MariaDB
docker network connect wp-backend wp-app-1

Étape 4 — Configuration Nginx et lancement

Créer le fichier de configuration Nginx :

mkdir -p /tmp/nginx-lb

Contenu de /tmp/nginx-lb/nginx.conf :

events {
    worker_connections 1024;
}

http {
    # Declaration du groupe de serveurs upstream (load balancing)
    upstream wordpress_pool {
        server wp-app-1:80;   # instance WordPress 1
        # server wp-app-2:80; # decommenter pour le load balancing
    }

    server {
        listen 80;

        location / {
            # Transmettre les requetes a l upstream WordPress
            proxy_pass         http://wordpress_pool;

            # En-tetes transmis a WordPress pour qu il connaisse l IP du client
            proxy_set_header   Host              $host;
            proxy_set_header   X-Real-IP         $remote_addr;
            proxy_set_header   X-Forwarded-For   $proxy_add_x_forwarded_for;
            proxy_set_header   X-Forwarded-Proto $scheme;
        }
    }
}

Lancer Nginx :

docker run -d \                                    # mode detach
  --name nginx-lb \                                # nom du conteneur
  --network wp-frontend \                          # reseau frontend
  -p 8080:80 \                                     # seul port expose sur l hote
  -v /tmp/nginx-lb/nginx.conf:/etc/nginx/nginx.conf:ro \ # configuration en bind mount
  nginx:alpine                                     # image legere

Étape 5 — Vérifier

# Navigateur : http://localhost:8080
curl -s http://localhost:8080 | head -5

# Logs de Nginx
docker logs nginx-lb

# Verifier que MariaDB est inaccessible depuis le frontend
docker run --rm --network wp-frontend alpine ping -c 2 wp-db

Logs Nginx attendus :

172.18.0.1 - - [17/Jun/2026:10:00:01 +0000] "GET / HTTP/1.1" 302 0 "-" "curl/7.88.1" "-"

Étape 6 (avancé) — Load balancing sur deux WordPress

# Lancer un second WordPress
docker run -d \                              # mode detach
  --name wp-app-2 \                          # deuxieme instance
  --network wp-frontend \                    # reseau frontend
  -v wp-logs:/var/log/apache2 \             # meme volume de logs
  -e WORDPRESS_DB_HOST=wp-db \             # meme base de donnees
  -e WORDPRESS_DB_USER=wp \
  -e WORDPRESS_DB_PASSWORD=wppass \
  -e WORDPRESS_DB_NAME=wordpress \
  wordpress:latest

docker network connect wp-backend wp-app-2

# Mettre a jour nginx.conf : decommenter la ligne wp-app-2
# Puis recharger Nginx sans interruption
docker exec nginx-lb nginx -s reload

# Generer du trafic et observer la distribution
for i in $(seq 1 6); do curl -s http://localhost:8080 > /dev/null; done
docker logs wp-app-1
docker logs wp-app-2

Rôle des directives Nginx :

DirectiveRôle
upstream wordpress_poolDéfinit le groupe de serveurs en amont
server wp-app-1:80Ajoute une instance au pool (nom DNS Docker)
proxy_pass http://wordpress_poolEnvoie les requêtes vers le pool
proxy_set_header HostTransmet le nom de domaine à WordPress
proxy_set_header X-Real-IPTransmet l’IP réelle du client
proxy_set_header X-Forwarded-ForHistorique des proxies traversés

Par défaut, Nginx utilise round-robin : les requêtes sont distribuées à tour de rôle entre les instances du pool. D’autres algorithmes sont disponibles : least_conn (instance la moins chargée), ip_hash (affinité de session par IP client).

Étape 7 — Nettoyer

docker stop nginx-lb wp-app-1 wp-app-2 wp-db 2>/dev/null
docker rm nginx-lb wp-app-1 wp-app-2 wp-db 2>/dev/null
docker network rm wp-frontend wp-backend
docker volume rm wp-data wp-logs
rm -rf /tmp/nginx-lb
docker image prune -fa
docker volume prune -fa

Architecture finale :

[Client]
    |
    v
[nginx-lb] port 8080         reseau : wp-frontend
    |  \
    |   \
    v    v
[wp-app-1] [wp-app-2]        reseaux : wp-frontend + wp-backend
    |    /                   volumes : wp-logs
    v   /
[wp-db]                      reseau : wp-backend
                             volume : wp-data

Annexe — Namespaces et isolation avancée

Ces exercices approfondissent les mécanismes internes de Docker. Ils sont indépendants du fil directeur WordPress et s’adressent aux stagiaires souhaitant aller plus loin.


07. Volume tmpfs — données sensibles en mémoire (Namespace mnt)

Solution to Exercise #

Étape 2 — lecture du secret :

temp-password

Étape 3 — grep tmpfs dans /proc :

tmpfs /run/secrets tmpfs rw,nosuid,noexec,size=10240k 0 0

Le montage est bien de type tmpfs — aucun bloc disque alloué, aucune trace dans /var/lib/docker/volumes/.

Étape 4 — après redémarrage :

cat: can't open '/run/secrets/db_password': No such file or directory

Étape 5 — après redémarrage avec volume nommé :

persisted-password
Type de montagePersisté sur disqueSurvit au redémarrageUsage typique
tmpfsNon (RAM)NonSecrets, tokens, cache temporaire
Volume nomméOuiOuiBases de données, uploads
Bind mountOui (hôte)OuiDéveloppement, config

08. Partage de Namespace entre conteneurs — pattern sidecar

Solution to Exercise #

Partie A — ip addr sur les deux conteneurs (résultat identique) :

1: lo: <LOOPBACK,UP>
18: eth0@if19: inet 172.17.0.2/16

Les deux conteneurs partagent la même interface réseau — ils sont dans le même Namespace net. Toute connexion à localhost depuis le sidecar atteint le processus du conteneur principal.

Partie A — wget depuis le sidecar :

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>

Partie B — ps aux depuis sidecar-pid :

PID   USER   COMMAND
1     root   nginx: master process
29    nginx  nginx: worker process
30    root   sleep 3600

Le sidecar voit les processus de app-pid — ils partagent le Namespace PID. Son propre processus sleep est également visible.

Namespace partagéOption DockerCas d’usage
réseau--network container:NOMProxy, collecteur de métriques réseau
PID--pid container:NOMDébogage, profiling, injection de tracing
les deuxles deux options combinéesPattern sidecar complet (Kubernetes)

09. Conteneurs rootless — héritage LXC et User Namespace

Solution to Exercise (Note) #

Étape 1 — id dans le conteneur :

uid=0(root) gid=0(root) groups=0(root)

Étape 1 — ps depuis l’hôte :

PID   UID  USER   COMM
3842    0  root   sleep

En mode standard, le root du conteneur est le root de l’hôte. Si un processus s’échappe du conteneur, il a les droits root sur la machine.

Étape 2 — avec --user 1000 :

uid=1000 gid=1000
touch: /test: Permission denied

Étape 4 — uid_map sans remappage :

0  0  4294967295

Mapping identité : UID 0 dans le conteneur = UID 0 sur l’hôte.

Étape 5 — uid_map avec userns-remap :

0  100000  65536

UID 0 dans le conteneur est mappé à l’UID 100000 sur l’hôte. Un processus échappé n’a aucun privilège sur la machine.

ModeUID dans le conteneurUID sur l’hôteRisque
Standard0 (root)0 (root)Élevé
--user 100010001000Faible
userns-remap0 (root apparent)100000+Faible
Docker rootless0 (root apparent)UID courantMinimal