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.
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 virtuelle | Conteneur | |
|---|---|---|
| Ce qui est embarqué | un système d'exploitation entier | l'application et ses dépendances seulement |
| Noyau | le sien | celui de la machine hôte, partagé |
| Taille typique | plusieurs gigaoctets | quelques dizaines de mégaoctets |
| Démarrage | dizaines de secondes | moins d'une seconde |
| Isolation | très forte | forte, 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.
| Ce qu'on mesure | Ordre de grandeur |
|---|---|
| une machine virtuelle Debian installée | plusieurs gigaoctets |
l'image Docker debian | une centaine de mégaoctets |
l'image Docker alpine | moins 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.
- 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.
- 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. - Attendre que la baleine de la barre de menus cesse de s'animer.
En ligne de commande, si Homebrew est installé :
brew install --cask dockerDocker 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.
- 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.
- Dans un PowerShell administrateur :
wsl --install
wsl --set-default-version 2- Redémarrer.
- Installer Docker Desktop for Windows depuis docker.com, en laissant cochée l'option « Use WSL 2 instead of Hyper-V ».
- 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.
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.
# 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-pluginPuis, pour ne plus écrire sudo devant chaque commande :
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 seulementdocker équivaut à rootQui 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 :
sudo systemctl status docker
sudo systemctl enable --now docker # le demarrer, et au demarrage de la machineLes autres cas
Un serveur Linux quelconque, en une commande
curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.shLe 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
docker --version
docker infodocker --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 daemonLa 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
docker run hello-worldLa 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 ?
| Image | Conteneur | Volume | |
|---|---|---|---|
| Ce que c'est | un modèle figé | une exécution de ce modèle | une zone de stockage |
| Modifiable | non, lecture seule | oui, pendant qu'il vit | oui |
| Persistant par défaut | oui — elle reste dans le cache | non — ce qu'on y écrit meurt avec lui | oui — il survit au conteneur |
| On en crée avec | docker pull | docker run |
docker volume create |
| On en supprime avec | docker rmi | docker rm |
docker volume rm |
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.
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
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 unedocker images donne cinq colonnes. Les quatre premières suffisent à
identifier une image sans ambiguïté :
| Colonne | Ce que c'est |
|---|---|
REPOSITORY | le nom de l'image — nginx |
TAG | la version — latest, 1.21… |
IMAGE ID | l'identifiant réel, une empreinte |
CREATED | la date de fabrication de l'image, pas du téléchargement |
SIZE | la taille, couches partagées comprises |
Le tag : une image, plusieurs versions
docker pull nginx:1.21 # une version precise et ancienne
docker images # DEUX lignes « nginx » maintenantDeux 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éeimage 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.
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
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 tournentdocker ps # ceux qui tournent
docker ps -a # TOUS, y compris les arretesUn 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
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.
docker ps -a --filter name=mon-serveur # son statut, sans lire toute la liste
docker inspect -f '{{.State.Status}}' mon-serveurLa 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
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 lancerun crée, exec entredocker 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
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 forcestop/startC'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.
docker run -d --name web -p 8080:80 nginx
docker run -d --name web2 -p 8081:80 nginxOn 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.
curl http://localhost:8080 # ou simplement ouvrir la pageC'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.
port is already allocateddocker: 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.
docker volume create donnees-web
docker run -d --name web-persistant -p 8082:80 \
-v donnees-web:/usr/share/nginx/html nginxOn 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.
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 conteneurLa 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.
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| Écriture | Ce que c'est | Quand |
|---|---|---|
-v donnees-web:/chemin | un volume nommé, géré par Docker | des données qui appartiennent au service — une base, des fichiers envoyés |
-v /home/eleve/site:/chemin | un 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 /.
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.
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
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
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 occupedocker system prune -a --volumes efface les donnéesAjouter --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
docker network lsNETWORK ID NAME DRIVER SCOPE
6bca5b86a5e3 bridge bridge local
a647ec3084f5 host host local
b002c30b9b60 none null local| Réseau | Ce qu'il donne au conteneur |
|---|---|
bridge | Une 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. |
host | Rien à lui : il partage la pile réseau de la machine. Pas de port à publier, pas d'isolation non plus. |
none | Aucune 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 :
$ 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.
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
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 c2PING c2 (192.168.50.2): 56 data bytes
64 bytes from 192.168.50.2: seq=0 ttl=64 time=0.097 msSur 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.
--ip n'est accepté que sur un réseau personnalisé — le
réseau par défaut la refuse, quelle que soit l'adresse :
docker: Error response from daemon: invalid config for network bridge:
user-specified IP address is supported on user-defined networks onlyElle 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 :
docker network connect reseau-srv passerelle11: 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.
$ docker exec passerelle wget -qO- http://serveur -> la page nginx
$ curl http://localhost:8080 -> Connection refuseddocker 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 :
$ docker port serveur-pub
80/tcp -> 0.0.0.0:80800.0.0.0, et non 127.0.0.1Le 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.
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
| Commande | Rô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 images | lister les images locales |
docker rmi <image> | supprimer une image |
docker run [options] <image> | créer et lancer un conteneur |
docker ps · docker ps -a | les conteneurs actifs · tous |
docker start · docker stop | dé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 / rm | gérer les volumes |
-d | détacher : rendre la main |
-it | interactif, avec un terminal |
--name | nommer le conteneur |
-p hôte:conteneur | publier un port |
-v volume:chemin | monter un volume |
-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.