Docker — images, conteneurs et volumes

Lancer un serveur web en une commande, sans l'installer. C'est ce que fait un conteneur — et le TP d'initiation ne demande rien d'autre que de comprendre trois mots : image, conteneur, volume. Le chapitre commence par l'installation, parce qu'elle n'est pas la même sur un Mac, sous Windows et sur un serveur Linux.

📌

Résumé flash

Une image est un modèle figé, en lecture seule : on la télécharge avec docker pull. Un conteneur est une exécution de cette image : docker run en crée un, docker rm le détruit — et tout ce qu'on y a écrit disparaît avec lui. Un volume est une zone de stockage qui vit en dehors des conteneurs : c'est la seule façon de garder des données.

Trois commandes à ne pas confondre : -p 8080:80 publie un port, -v nom:/chemin monte un volume, -d détache le conteneur et rend la main.

🔑 #image #conteneur #volume #docker-run #docker-exec #tag #port #persistance #prune

1Pourquoi des conteneurs

« Ça marche chez moi. » La phrase est une plaisanterie de métier, et elle décrit un vrai problème : un programme ne dépend pas que de son code. Il dépend d'une version de bibliothèque, d'un fichier de configuration, d'une variable d'environnement, d'une version de système. Déplacez-le, il casse.

📦 Le conteneur maritime

Avant le conteneur, on chargeait des caisses, des sacs et des fûts, chacun manipulé à sa façon. Depuis, tout voyage dans la même boîte normalisée : le navire, le portique et le camion n'ont plus à savoir ce qu'il y a dedans.

Docker fait exactement ça avec un logiciel : on emballe l'application et tout ce dont elle a besoin, et la machine d'accueil n'a plus besoin de rien savoir.

Conteneur ou machine virtuelle ?

Machine virtuelleConteneur
Ce qui est embarquéun système d'exploitation entier l'application et ses dépendances seulement
Noyaule siencelui de la machine hôte, partagé
Taille typiqueplusieurs gigaoctetsquelques dizaines de mégaoctets
Démarragedizaines de secondesmoins d'une seconde
Isolationtrès forteforte, mais le noyau est commun

Le chapitre 6 montait des machines virtuelles sous VirtualBox. Ce n'est pas un concurrent : on fait souvent tourner des conteneurs dans une machine virtuelle. Ce qui change, c'est l'unité qu'on déplace.

💡 Trois tailles, et il faut savoir laquelle on compare
Ce qu'on mesureOrdre de grandeur
une machine virtuelle Debian installéeplusieurs gigaoctets
l'image Docker debianune centaine de mégaoctets
l'image Docker alpinemoins de 10 Mo

Alpine est une distribution Linux réduite à l'essentiel, et c'est pour cela qu'on la choisit comme base : chaque mégaoctet se télécharge, se stocke et se transfère à chaque déploiement.

Attention à ne pas mélanger les deux premières lignes : l'écart entre une VM et un conteneur n'est pas l'écart entre deux images.

2Installer Docker

L'installation n'est pas la même selon la machine, et c'est la première chose qui bloque un TP. Choisissez votre système : le reste du chapitre est identique pour tout le monde, parce que les commandes docker sont les mêmes partout.

macOS — Docker Desktop

macOS n'a pas de noyau Linux. Docker Desktop installe donc une petite machine virtuelle Linux et vous donne la commande docker qui lui parle — c'est transparent, mais c'est ce qui explique que le premier démarrage prenne une minute.

  1. Télécharger Docker Desktop sur docker.com en choisissant la bonne puce : Apple silicon (M1 à M4) ou Intel. Le menu → « À propos de ce Mac » donne la réponse.
  2. Ouvrir le .dmg, glisser Docker dans Applications, puis lancer l'application une fois : elle demande votre mot de passe pour installer son composant système.
  3. Attendre que la baleine de la barre de menus cesse de s'animer.

En ligne de commande, si Homebrew est installé :

bash
brew install --cask docker

Docker Desktop doit être lancé pour que la commande docker réponde. C'est la cause nº 1 de Cannot connect to the Docker daemon sur un Mac.

Windows — Docker Desktop et WSL 2

Comme sur macOS, les conteneurs Linux tournent dans une machine virtuelle. Sous Windows, cette machine est fournie par WSL 2, le sous-système Linux de Windows : il faut donc l'installer d'abord.

  1. Vérifier que la virtualisation est activée : Gestionnaire des tâches → Performance → Processeur, ligne « Virtualisation : Activé ». Si elle est désactivée, cela se corrige dans le BIOS/UEFI, pas dans Windows.
  2. Dans un PowerShell administrateur :
PowerShell
wsl --install
wsl --set-default-version 2
  1. Redémarrer.
  2. Installer Docker Desktop for Windows depuis docker.com, en laissant cochée l'option « Use WSL 2 instead of Hyper-V ».
  3. Rouvrir une session, lancer Docker Desktop, attendre que l'icône se stabilise.

Les commandes docker se tapent ensuite indifféremment dans PowerShell, dans l'invite de commandes ou dans un terminal WSL.

⚠️ Windows Famille, Pro, et Hyper-V

Hyper-V n'existe que sur Windows Pro, Entreprise et Éducation. C'est précisément pour cela que l'on passe par WSL 2, qui fonctionne aussi sur Windows Famille. Si un tutoriel vous demande d'activer Hyper-V, il date d'avant WSL 2.

Linux — Docker Engine, directement sur le noyau

Pas de machine virtuelle ici : les conteneurs utilisent le noyau de la machine. C'est le cas le plus rapide, et celui d'un serveur. On installe depuis le dépôt officiel de Docker, jamais depuis apt install docker.io — ce paquet-là est une version plus ancienne, maintenue par la distribution.

Les commandes ci-dessous sont celles de Debian ; pour Ubuntu, remplacer les deux occurrences de debian par ubuntu.

bash
# 1. retirer d'eventuels paquets concurrents
for p in docker.io docker-doc docker-compose podman-docker containerd runc; do
    sudo apt-get remove -y $p
done

# 2. la cle de signature du depot Docker
sudo apt-get update
sudo apt-get install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# 3. le depot
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] \
https://download.docker.com/linux/debian $(. /etc/os-release && echo $VERSION_CODENAME) stable" \
| sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# 4. l'installation
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io \
                        docker-buildx-plugin docker-compose-plugin

Puis, pour ne plus écrire sudo devant chaque commande :

bash
sudo usermod -aG docker $USER
# il faut FERMER puis rouvrir la session pour que le groupe soit pris en compte
newgrp docker        # ou, pour le terminal courant seulement
⚠️ Le groupe docker équivaut à root

Qui peut lancer un conteneur peut monter / dedans et en sortir administrateur de la machine. Ajouter un utilisateur au groupe docker est donc une décision de sécurité, pas une commodité. Sur un serveur partagé, on garde sudo.

Vérifier que le service tourne :

bash
sudo systemctl status docker
sudo systemctl enable --now docker   # le demarrer, et au demarrage de la machine

Les autres cas

Un serveur Linux quelconque, en une commande

bash
curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh

Le script officiel détecte la distribution et fait le travail. Il est pratique pour une machine de test ; en production, on préfère le dépôt de paquets, qui se met à jour avec le reste du système. Et la règle générale tient toujours : on lit un script avant de le passer à sh.

Pas les droits d'installer ? Le TP se fait en ligne

Play with Docker donne un terminal Docker dans le navigateur pour quelques heures. Toutes les commandes de ce chapitre y fonctionnent, sauf l'ouverture de http://localhost:8080 — le site tourne sur leur machine, pas sur la vôtre ; le service se joint par les liens de ports que la page affiche.

Les conteneurs Windows

Docker Desktop sait aussi exécuter des conteneurs Windows, qui embarquent une base Windows Server au lieu d'une base Linux. Ce n'est pas l'objet de ce chapitre, et les deux modes ne cohabitent pas : on bascule de l'un à l'autre par un menu, et les images ne sont pas interchangeables.

Une machine sans virtualisation

Sur un Mac ou un PC où la virtualisation est désactivée ou interdite, Docker Desktop ne démarrera pas. Il n'y a pas de contournement : c'est le noyau Linux qui manque, et il doit bien tourner quelque part.

Vérifier l'installation, partout pareil

bash
docker --version
docker info

docker --version ne prouve qu'une chose : la commande est installée. docker info prouve que le moteur répond — et c'est lui qu'il faut regarder. Deux lignes de sa sortie méritent d'être notées avant de commencer : Containers et Images. Sur une installation neuve, elles valent zéro — et les relever maintenant permet, à la fin, de voir ce qu'on a oublié de nettoyer.

TP d'initiation — question 1.1.

⚠️ Cannot connect to the Docker daemon

La commande existe, le moteur ne répond pas. Trois causes, dans cet ordre de fréquence : Docker Desktop n'est pas lancé (macOS, Windows) · le service est arrêté (sudo systemctl start docker, Linux) · l'utilisateur n'est pas dans le groupe docker et la session n'a pas été rouverte.

Le premier conteneur

bash
docker run hello-world

La première fois, Docker annonce Unable to find image 'hello-world:latest' locally, puis télécharge l'image. Relancez la même commande : ces lignes disparaissent et l'exécution est instantanée — l'image est désormais dans le cache local.

C'est la première leçon du chapitre, et elle a une conséquence pratique immédiate : le temps de la première exécution est presque entièrement du téléchargement, pas du démarrage. Un conteneur, lui, démarre en quelques dizaines de millisecondes. Sur un serveur, on fait donc le docker pull avant la fenêtre de déploiement, pour que la bascule soit immédiate.

TP d'initiation — question 1.2.

3Image, conteneur, volume

Tout le chapitre tient dans ces trois mots, et une seule propriété les sépare : qu'est-ce qui survit ?

ImageConteneurVolume
Ce que c'estun modèle figéune exécution de ce modèle une zone de stockage
Modifiablenon, lecture seuleoui, pendant qu'il vitoui
Persistant par défautoui — elle reste dans le cache non — ce qu'on y écrit meurt avec lui oui — il survit au conteneur
On en crée avecdocker pulldocker run docker volume create
On en supprime avecdocker rmidocker rm docker volume rm
🍰 Le moule, le gâteau, le congélateur

L'image est le moule : on ne le mange pas, et il sert autant de fois qu'on veut. Le conteneur est le gâteau : il existe, on le modifie, on le jette. Le volume est le congélateur : ce qu'on y range survit au gâteau.

D'où la question qui revient toujours : un fichier modifié dans un conteneur survit-il à un stop puis un start ? Oui — le gâteau n'a pas été jeté, seulement posé. Il ne survivrait pas à un rm.

💡 Une image est faite de couches, et elles se partagent

nginx et httpd reposent tous deux sur une base Debian : cette base n'est téléchargée et stockée qu'une fois. C'est pourquoi la somme des tailles affichées par docker images dépasse largement la place réellement occupée sur le disque.

4Les images

bash
docker pull alpine          # telecharger, sans executer
docker pull nginx
docker pull httpd           # le serveur Apache
docker images               # lister celles qui sont ici
docker rmi httpd            # en supprimer une

docker images donne cinq colonnes. Les quatre premières suffisent à identifier une image sans ambiguïté :

ColonneCe que c'est
REPOSITORYle nom de l'image — nginx
TAGla version — latest, 1.21…
IMAGE IDl'identifiant réel, une empreinte
CREATEDla date de fabrication de l'image, pas du téléchargement
SIZEla taille, couches partagées comprises

Le tag : une image, plusieurs versions

bash
docker pull nginx:1.21      # une version precise et ancienne
docker images               # DEUX lignes « nginx » maintenant

Deux lignes apparaissent, de même REPOSITORY et de TAG différents : latest et 1.21, avec deux IMAGE ID distincts. La leçon tient en une phrase — le tag fait partie de l'identité de l'image. nginx et nginx:1.21 ne désignent pas la même chose, et docker rmi nginx ne supprime que la première.

TP d'initiation — question 2.4.

⚠️ latest ne veut pas dire « la plus récente »

C'est le tag utilisé par défaut quand on n'en précise aucun — rien de plus. Un éditeur peut parfaitement publier une version neuve sans déplacer latest. En production, on épingle toujours une version : nginx:1.27, jamais nginx.

C'est aussi la différence entre un déploiement reproductible et un déploiement qui change tout seul la nuit.

⚠️ rmi refuse de supprimer une image utilisée

image is being used by running container … : une image dont un conteneur — même arrêté — est issu ne peut pas disparaître. Il faut supprimer les conteneurs d'abord. C'est volontaire : sans l'image, le conteneur ne serait plus redémarrable.

🤔 Après docker pull nginx puis docker pull nginx:1.21, combien d'images nginx ?

Deux, avec deux IMAGE ID différents. Le tag fait partie de l'identité : nginx (c'est-à-dire nginx:latest) et nginx:1.21 sont deux images distinctes, qui partagent seulement certaines couches.

5Les conteneurs

Entrer dedans

bash
docker run -it alpine sh

-i garde l'entrée ouverte, -t alloue un terminal : ensemble, ils donnent un shell interactif. À l'intérieur, ls et cat /etc/os-release montrent qu'on est bien dans une Alpine, puis exit rend la main — et arrête le conteneur, puisque son processus principal était ce shell.

⚠️ docker ps ne montre que les conteneurs qui tournent
bash
docker ps        # ceux qui tournent
docker ps -a     # TOUS, y compris les arretes

Un conteneur qu'on vient de quitter n'apparaît que dans le second. Il n'a pas disparu — il est Exited, il garde tout ce qu'on y a modifié, et il occupe toujours de la place sur le disque jusqu'à un docker rm.

TP d'initiation — question 3.2.

Un conteneur vit tant que son processus principal vit. Il ne s'arrête pas parce qu'on ferme la fenêtre, mais parce que ce processus se termine.

Le lancer en arrière-plan, et le nommer

bash
docker run -d --name mon-serveur nginx

-d (detached) rend la main immédiatement ; --name donne un nom lisible, qu'on emploiera partout à la place de l'identifiant. Sans lui, Docker invente quelque chose comme nostalgic_hopper.

bash
docker ps -a --filter name=mon-serveur     # son statut, sans lire toute la liste
docker inspect -f '{{.State.Status}}' mon-serveur

La question 3.4 demande le statut « sans utiliser docker ps » : docker inspect est la réponse attendue. Il rend toute la fiche du conteneur en JSON, et -f n'en extrait qu'un champ.

Lire les journaux, et travailler dedans

bash
docker logs mon-serveur            # ce que le conteneur a ecrit
docker logs -f mon-serveur         # et le suivre en direct

docker exec -it mon-serveur bash   # ouvrir un shell DANS un conteneur deja lance
⚠️ run crée, exec entre

docker run -it nginx bash crée un deuxième conteneur, et le serveur n'y tourne même pas. Pour entrer dans celui qui existe, c'est docker exec. C'est la faute la plus coûteuse du chapitre, parce qu'elle ne produit aucun message : on modifie un fichier dans un conteneur, et on s'étonne de ne rien voir dans l'autre.

Et bash n'existe pas dans toutes les images : Alpine n'a que sh. docker exec -it alpine bash échoue avec executable file not found.

Arrêter, redémarrer, supprimer

bash
docker stop mon-serveur     # demande poliment l'arret, puis force apres 10 s
docker start mon-serveur    # redemarre LE MEME conteneur
docker restart mon-serveur

docker rm mon-serveur       # supprime — le conteneur doit etre arrete
docker rm -f mon-serveur    # ... ou alors on force
💡 Pourquoi le fichier modifié survit à stop/start

C'est la question 3.7, et la réponse est au cœur du chapitre : stop arrête le processus, il ne détruit pas le conteneur. La couche d'écriture du conteneur — celle qui garde tout ce qu'on a modifié — est toujours là, et start la retrouve.

Un docker rm, lui, efface cette couche. La modification disparaît alors définitivement : c'est ce qui motive les volumes, à la section 7.

6Exposer un port

Un conteneur nginx écoute sur le port 80 — chez lui. Tant qu'on ne publie rien, ce port n'est joignable depuis la machine hôte par aucun navigateur.

bash
docker run -d --name web  -p 8080:80 nginx
docker run -d --name web2 -p 8081:80 nginx

On lit -p hôte:conteneur — de gauche à droite, du dehors vers le dedans. Le premier nombre est celui qu'on tape dans le navigateur, le second celui sur lequel le service écoute à l'intérieur.

bash
curl http://localhost:8080       # ou simplement ouvrir la page
💡 Deux conteneurs peuvent écouter le port 80 en même temps

C'est la question 4.3, et elle surprend. Chaque conteneur a sa propre pile réseau : son port 80 n'est pas le port 80 de la machine. Il n'y a donc aucun conflit tant qu'ils sont publiés sur deux ports différents de l'hôte — 8080 et 8081.

C'est exactement la notion du chapitre NAT & PAT : une redirection de port. Ce qui doit être unique, c'est le couple adresse/port côté hôte.

⚠️ Réutiliser 8080 : port is already allocated
sortie
docker: Error response from daemon: driver failed programming external
connectivity on endpoint web3: Bind for 0.0.0.0:8080 failed: port is already allocated.

C'est la question 4.4. Le message est explicite une fois qu'on sait le lire : Docker a demandé au système de réserver le port 8080 de l'hôte, et le système a refusé parce que le conteneur web l'occupe déjà. Côté conteneur, en revanche, rien n'empêchait le troisième d'écouter sur 80.

Le conteneur est tout de même créé, à l'état Created. Il faudra le supprimer : il compte dans docker ps -a.

7Faire survivre les données

Le TP l'a montré à l'étape 3.8 : supprimez le conteneur, et la page d'accueil modifiée disparaît avec lui. C'est le comportement voulu — un conteneur est jetable. Mais une base de données jetable n'a aucun intérêt.

bash
docker volume create donnees-web

docker run -d --name web-persistant -p 8082:80 \
           -v donnees-web:/usr/share/nginx/html nginx

On lit -v nom:/chemin — le volume, puis l'endroit où il est monté dans le conteneur. Tout ce qui est écrit sous /usr/share/nginx/html va désormais dans le volume, pas dans le conteneur.

bash
docker exec -it web-persistant bash
# cd /usr/share/nginx/html && echo "Bonjour NetSolutions" > index.html && exit

docker stop web-persistant && docker rm web-persistant      # on DETRUIT le conteneur

docker run -d --name web-persistant-v2 -p 8082:80 \
           -v donnees-web:/usr/share/nginx/html nginx       # un AUTRE conteneur

La page modifiée est toujours là. C'est la question 5.4, et la démonstration est complète : le volume ne dépend d'aucun conteneur. Il leur survit, et plusieurs conteneurs peuvent monter le même.

bash
docker volume ls
docker volume inspect donnees-web     # ou il est range sur l'hote
docker volume rm donnees-web          # apres avoir supprime les conteneurs qui l'utilisent
💡 Volume nommé ou dossier de la machine ?
ÉcritureCe que c'estQuand
-v donnees-web:/cheminun volume nommé, géré par Docker des données qui appartiennent au service — une base, des fichiers envoyés
-v /home/eleve/site:/cheminun dossier de l'hôte, monté tel quel du code qu'on édite depuis son éditeur pendant que le conteneur tourne

Le TP n'emploie que le premier. Le second est ce qu'on utilise en développement — et c'est aussi lui qui rend le groupe docker si dangereux : rien n'interdit de monter /.

⚠️ Monter un volume sur un dossier qui contient déjà quelque chose

Au premier montage d'un volume vide, Docker y recopie le contenu existant du dossier : la page d'accueil nginx par défaut s'y retrouve. Aux montages suivants, le volume n'est plus vide et il masque complètement le contenu de l'image. C'est voulu, et c'est déroutant la première fois.

🤔 On supprime un conteneur qui utilisait un volume nommé. Que devient le volume ?

Il reste, avec ses données. docker rm ne touche pas aux volumes nommés — il faut un docker volume rm explicite, ou docker rm -v pour emporter les volumes anonymes. C'est exactement ce qui fait leur utilité, et aussi ce qui fait qu'on finit par en avoir des dizaines d'oubliés.

8Nettoyer

bash
docker ps -a                       # tout ce qui reste
docker stop $(docker ps -q)        # arreter tout ce qui tourne
docker rm $(docker ps -aq)         # supprimer tous les conteneurs
docker rmi $(docker images -q)     # supprimer toutes les images

-q (quiet) ne rend que les identifiants, un par ligne : c'est ce qui permet de passer la liste à la commande suivante. Sans lui, on passerait aussi les en-têtes de colonnes.

Les commandes de ménage de Docker

bash
docker container prune     # les conteneurs arretes
docker image prune         # les images sans nom (« dangling »)
docker image prune -a      # TOUTES les images inutilisees
docker volume prune        # les volumes qu'aucun conteneur n'utilise
docker system prune        # les trois premiers d'un coup
docker system df           # ce que tout cela occupe
⚠️ docker system prune -a --volumes efface les données

Ajouter --volumes supprime les volumes inutilisés — c'est-à-dire la base de données du projet sur lequel vous ne travaillez pas aujourd'hui. La commande demande confirmation ; c'est le seul garde-fou, et il ne protège que de la distraction.

Commencer par docker system df : on voit ce qui occupe la place avant de décider de l'effacer.

9Le réseau : comment les conteneurs se parlent

Un conteneur seul ne sert presque jamais : il y a un site et sa base, une application et son cache. La question devient alors comment ils se trouvent — et la réponse dépend entièrement d'un choix qu'on fait sans s'en rendre compte, celui du réseau.

Les trois réseaux livrés avec Docker

bash
docker network ls
sortie
NETWORK ID     NAME      DRIVER    SCOPE
6bca5b86a5e3   bridge    bridge    local
a647ec3084f5   host      host      local
b002c30b9b60   none      null      local
Ce que chacun fait
RéseauCe qu'il donne au conteneur
bridgeUne adresse privée sur un commutateur virtuel, et une sortie vers l'extérieur par traduction d'adresse. C'est celui qu'on obtient sans rien demander.
hostRien à lui : il partage la pile réseau de la machine. Pas de port à publier, pas d'isolation non plus.
noneAucune interface sauf lo. Pour un traitement qui ne doit parler à personne.

Le réseau par défaut a deux défauts, et ils vont ensemble

Deux conteneurs lancés sans rien préciser atterrissent sur bridge. Ils se joignent par adresse — et seulement par adresse :

sortie
$ docker exec c1 ping -c 2 172.17.0.3
64 bytes from 172.17.0.3: seq=0 ttl=64 time=0.110 ms

$ docker exec c1 ping -c 2 c2
ping: bad address 'c2'

Or ces adresses ne tiennent pas. Arrêtez les deux conteneurs, redémarrez-les dans l'autre ordre : ils échangent leurs adresses. L'adresse ne suit pas le conteneur, elle suit l'ordre de démarrage.

⚠️ Les deux défauts se renforcent

Le nom ne résout pas, et l'adresse bouge : il ne reste aucun moyen fiable de désigner un conteneur. Une application configurée avec BDD_HOST=172.17.0.2 marche jusqu'au premier redémarrage — et tombe un jour où personne n'a touché au code.

Un réseau qu'on crée soi-même règle les deux

bash
docker network create --subnet 192.168.50.0/24 --gateway 192.168.50.254 reseau-lan
docker run -dit --name c1 --network reseau-lan alpine
docker run -dit --name c2 --network reseau-lan alpine
docker exec c1 ping -c 2 c2
sortie
PING c2 (192.168.50.2): 56 data bytes
64 bytes from 192.168.50.2: seq=0 ttl=64 time=0.097 ms

Sur un réseau personnalisé, Docker active un résolveur interne à l'adresse 127.0.0.11, qui connaît le nom de chaque conteneur du réseau. Le nom devient l'identité stable que l'adresse n'était pas. C'est la raison pour laquelle, en production, on ne laisse jamais les conteneurs sur le réseau par défaut.

💡 L'adresse fixe, quand elle sert vraiment

--ip n'est accepté que sur un réseau personnalisé — le réseau par défaut la refuse, quelle que soit l'adresse :

sortie
docker: Error response from daemon: invalid config for network bridge:
user-specified IP address is supported on user-defined networks only

Elle sert quand quelque chose d'extérieur à Docker doit viser le conteneur : une règle de pare-feu, une route, un équipement sans DNS. Partout ailleurs, le nom suffit et vaut mieux.

Deux réseaux ne se parlent pas — et un conteneur à deux pattes ne les relie pas

Chaque réseau est un commutateur séparé. Un conteneur de reseau-lan ne joint pas un conteneur de reseau-srv, bien qu'ils soient sur la même machine : il n'a ni route ni routeur. On peut raccorder un conteneur aux deux :

bash
docker network connect reseau-srv passerelle
sortie
11: eth0   inet 192.168.50.3/24 ... (reseau-lan)
12: eth1   inet 172.16.10.2/24 ... (reseau-srv)

Il parle alors aux deux côtés. Mais les autres ne passent toujours pas à travers lui : parler n'est pas router. Il faudrait activer le transfert de paquets sur ce conteneur et donner une route au client et une route de retour au serveur. C'est exactement le TP de routage, transposé.

Publier un port, c'est percer une frontière

Un conteneur du même réseau atteint un serveur sans aucune option. Le navigateur de la machine, lui, ne l'atteint pas : il est dehors.

sortie
$ docker exec passerelle wget -qO- http://serveur     ->  la page nginx
$ curl http://localhost:8080                          ->  Connection refused
bash
docker run -d --name serveur-pub --network reseau-srv -p 8080:80 nginx

-p ne sert donc jamais à faire communiquer deux conteneurs — seulement à ouvrir un passage depuis la machine. Et ce passage est plus large qu'il n'y paraît :

sortie
$ docker port serveur-pub
80/tcp -> 0.0.0.0:8080
⚠️ 0.0.0.0, et non 127.0.0.1

Le service est offert sur toutes les interfaces de la machine, Wi-Fi compris : ce qu'on croyait « en local » est visible de toute la salle. Pour ne l'ouvrir qu'à soi-même : -p 127.0.0.1:8080:80.

La règle tient en une phrase : on publie la façade, on garde le reste à l'intérieur. Une base de données publiée par confort est la fuite de données de l'année suivante.

🛠️ L'ordre du nettoyage n'est pas au choix

Un réseau qui porte encore des conteneurs ne se supprime pas — Docker répond has active endpoints. Les conteneurs d'abord, les réseaux ensuite.

Les sept parties du TP réseau corrigé reprennent tout ceci commande par commande, avec les sorties obtenues sur une machine.

10L'aide-mémoire

CommandeRôle
docker --version · docker info la commande est installée · le moteur répond
docker pull <image>télécharger une image sans la lancer
docker imageslister les images locales
docker rmi <image>supprimer une image
docker run [options] <image>créer et lancer un conteneur
docker ps · docker ps -ales conteneurs actifs · tous
docker start · docker stopdémarrer · arrêter un conteneur existant
docker rm <conteneur>supprimer un conteneur
docker logs <conteneur>afficher ses journaux
docker exec -it <conteneur> <cmd>exécuter une commande dans un conteneur actif
docker volume create / ls / rmgérer les volumes
-ddétacher : rendre la main
-itinteractif, avec un terminal
--namenommer le conteneur
-p hôte:conteneurpublier un port
-v volume:cheminmonter un volume
🔧 Les deux lectures à ne jamais inverser

-p 8080:80 → hôte puis conteneur.

-v donnees:/usr/share/nginx/html → volume puis point de montage dans le conteneur.

Dans les deux cas, le dehors est à gauche. C'est la seule chose à retenir, et elle évite les deux inversions les plus fréquentes : -p 80:8080 au lieu de -p 8080:80, et le point de montage écrit avant le volume.

⚡ Récap 2 minutes

  • Un conteneur partage le noyau de l'hôte : c'est ce qui le rend petit et rapide, et ce qui le distingue d'une machine virtuelle.
  • Image → modèle figé · conteneur → exécution · volume → stockage. Seuls l'image et le volume persistent.
  • docker info prouve que le moteur répond ; docker --version ne prouve que l'installation.
  • Le tag fait partie de l'identité d'une image. nginx et nginx:1.21 sont deux images.
  • latest veut dire « par défaut », pas « la plus récente ».
  • docker ps cache les conteneurs arrêtés ; il faut -a pour les voir, et ils occupent de la place.
  • run crée un conteneur, exec entre dans un conteneur existant. Confondre les deux, c'est modifier le mauvais.
  • Alpine n'a pas bash, seulement sh.
  • stop puis start garde les modifications ; rm les efface.
  • -p hôte:conteneur — le dehors à gauche. Deux conteneurs peuvent écouter le port 80 : seul le port de l'hôte doit être unique.
  • -v volume:chemin — le volume survit au conteneur, et docker rm n'y touche pas.
  • Le groupe docker équivaut à root : y ajouter un utilisateur est une décision de sécurité.

Sources exploitées

  • « TP d'initiation — Manipuler Docker », Réseaux & Systèmes, 5 pages, six parties et son aide-mémoire de commandes
  • Documentation officielle docs.docker.com — procédures d'installation par système, relevées le 9 octobre 2026
  • Demande de JustAkhiraa : « faire un tuto complet au début avec trois boutons pour choisir si on veut la config sur Mac, Windows, Linux ou autre »

Les procédures d'installation vieillissent plus vite que le reste d'un cours : elles portent leur date, et c'est docs.docker.com qui fait foi le jour où elles divergent.