📍 Article principal du parcours : Docker de zéro : comprendre et utiliser les conteneurs
Quatrième étape du parcours « Docker de zéro », dans la continuité de débuter avec Docker Compose.
Deux questions reviennent dès qu’une application sérieuse entre en jeu : où vont les données quand un conteneur disparaît, et comment deux conteneurs se parlent-ils ? Vous avez croisé les réponses en passant dans le tutoriel Compose — un volume pour PostgreSQL, un réseau privé pour relier l’API à la base. Il est temps de les maîtriser pour de bon. Un conteneur est jetable par nature ; les volumes et les réseaux sont précisément ce qui permet de bâtir des applications durables et communicantes par-dessus des conteneurs éphémères.
🎯 Ce que vous allez apprendre
- distinguer volume nommé et montage de répertoire (bind mount), et savoir quand utiliser l’un ou l’autre ;
- faire survivre les données d’une base à la suppression de son conteneur ;
- inspecter, sauvegarder et restaurer un volume ;
- comprendre les réseaux Docker et la résolution de noms entre conteneurs ;
- isoler la base sur un réseau interne pour qu’elle ne soit jamais exposée.
🛠️ Ce que vous allez construire
Vous renforcez la pile « Garde » : les données de PostgreSQL deviennent réellement durables et sauvegardables, et vous segmentez le réseau pour que la base ne soit accessible que par l’API. Vous prouverez la persistance en détruisant puis recréant le conteneur de base sans perdre une seule pharmacie.
Prérequis
- La pile « Garde » du tutoriel Compose (API + PostgreSQL).
- Docker et Docker Compose fonctionnels.
- Niveau intermédiaire. Test express : si vous savez lancer
docker compose up, vous êtes prêt. - ⏱️ Temps estimé : ~50 minutes.
Étape 1 — Comprendre pourquoi les données disparaissent
Commençons par observer le problème de nos yeux. Le système de fichiers d’un conteneur est une couche écrivable, mais éphémère : elle naît et meurt avec le conteneur. Lançons une base sans volume, écrivons-y, supprimons le conteneur, recréons-le — et constatons la perte. Laissez à PostgreSQL deux ou trois secondes pour démarrer après chaque docker run avant la commande psql qui suit, sinon la base n’accepte pas encore les connexions.
docker run -d --name test-db -e POSTGRES_PASSWORD=demo postgres:17
docker exec -it test-db psql -U postgres -c "CREATE TABLE essai(x int); INSERT INTO essai VALUES (1);"
docker rm -f test-db
docker run -d --name test-db -e POSTGRES_PASSWORD=demo postgres:17
docker exec -it test-db psql -U postgres -c "SELECT * FROM essai;"
La dernière commande échoue avec « relation \ »essai\ » does not exist ». La table a disparu avec le premier conteneur. C’est le comportement normal et voulu : un conteneur est jetable. Pour conserver des données entre deux vies de conteneur, il faut les stocker hors de cette couche éphémère — dans un volume. Nettoyez avec docker rm -f test-db avant de continuer.
✅ Point d’étape — Vous avez vu de vos yeux qu’une donnée écrite dans un conteneur sans volume est perdue à sa suppression. C’est le problème que les volumes résolvent.
Étape 2 — Le volume nommé : un stockage géré par Docker
Un volume nommé est un espace de stockage que Docker gère pour vous, indépendant du cycle de vie des conteneurs. On le crée, on le monte dans un conteneur à l’emplacement où l’application écrit ses données, et il survit à tout. Reprenons l’expérience, cette fois avec un volume.
docker volume create garde-data
docker run -d --name test-db -e POSTGRES_PASSWORD=demo -v garde-data:/var/lib/postgresql/data postgres:17
docker exec -it test-db psql -U postgres -c "CREATE TABLE essai(x int); INSERT INTO essai VALUES (1);"
docker rm -f test-db
docker run -d --name test-db -e POSTGRES_PASSWORD=demo -v garde-data:/var/lib/postgresql/data postgres:17
docker exec -it test-db psql -U postgres -c "SELECT * FROM essai;"
Cette fois, la dernière commande renvoie bien la ligne contenant 1. Le secret est l’option -v garde-data:/var/lib/postgresql/data : elle monte le volume garde-data à l’emplacement précis où PostgreSQL range ses fichiers. Le conteneur peut être détruit et recréé ; tant que le volume existe et qu’on le remonte, les données sont là. Retenez ce chemin /var/lib/postgresql/data : c’est le répertoire de données de PostgreSQL, celui qu’il faut toujours persister.
✅ Point d’étape — Après suppression et recréation du conteneur, la table
essaiet sa donnée sont toujours présentes. La persistance fonctionne.
Étape 3 — Inspecter et localiser un volume
Un volume n’est pas une boîte noire. On peut le lister, l’inspecter pour savoir où Docker l’entrepose réellement sur le disque hôte, et en mesurer l’usage.
docker volume ls
docker volume inspect garde-data
docker system df -v
docker volume ls liste les volumes ; docker volume inspect garde-data renvoie un bloc JSON dont le champ Mountpoint indique le chemin sur l’hôte (sous Linux, typiquement /var/lib/docker/volumes/garde-data/_data). docker system df -v donne une vue d’ensemble de l’espace consommé par les images, conteneurs et volumes — utile pour repérer ce qui occupe votre disque. On ne modifie pas les fichiers d’un volume à la main : on passe par un conteneur qui le monte.
✅ Point d’étape —
docker volume inspect garde-dataaffiche unMountpoint. Vous savez où vivent physiquement vos données.
Étape 4 — Bind mount : monter un dossier de votre machine
Il existe un second type de montage, le bind mount, qui relie un dossier précis de votre machine à un dossier du conteneur. Contrairement au volume nommé géré par Docker, vous contrôlez exactement l’emplacement. C’est idéal en développement, pour que le conteneur voie vos modifications de code en temps réel.
docker run -d --name web-dev -p 8080:80 -v "$(pwd)/site":/usr/share/nginx/html:ro nginx:alpine
Ici, le dossier site du répertoire courant est monté en lecture seule (:ro) dans le répertoire que sert nginx. Créez un site/index.html, rafraîchissez http://localhost:8080 : votre page s’affiche, et toute modification du fichier est visible immédiatement sans reconstruire l’image. La règle de choix est simple : volume nommé pour les données persistantes (bases, fichiers uploadés), bind mount pour le code en développement. Sous Windows ou en PowerShell, remplacez $(pwd) par ${PWD}.
✅ Point d’étape — Votre
site/index.htmls’affiche via nginx, et une modification du fichier se voit au rafraîchissement, sans rebuild.
Étape 5 — Sauvegarder et restaurer un volume
Données durables ne veut pas dire données à l’abri : un disque peut lâcher. Savoir sauvegarder un volume est indispensable. L’astuce consiste à lancer un conteneur temporaire qui monte à la fois le volume et un dossier hôte, et qui archive l’un dans l’autre.
docker run --rm -v garde-data:/data -v "$(pwd)":/sauvegarde alpine \
tar czf /sauvegarde/garde-data-backup.tar.gz -C /data .
Ce conteneur alpine éphémère (--rm le supprime à la fin) monte le volume sous /data et votre dossier courant sous /sauvegarde, puis compresse le contenu du volume dans une archive déposée chez vous. Pour restaurer, on inverse la manœuvre : on décompresse l’archive dans un volume neuf. Cette technique fonctionne pour n’importe quel volume — c’est le filet de sécurité de toute base conteneurisée. Programmée régulièrement, elle constitue votre stratégie de sauvegarde.
✅ Point d’étape — Un fichier
garde-data-backup.tar.gzapparaît dans votre dossier. Vos données sont sauvegardées hors du volume.
Étape 6 — Comprendre les réseaux Docker
Passons à la communication. Par défaut, Docker place les conteneurs sur un réseau bridge. Mais le réseau par défaut ne fournit pas la résolution de noms : pour que les conteneurs se joignent par leur nom, on crée un réseau dédié. C’est ce que Compose fait automatiquement, et qu’on reproduit ici à la main pour bien comprendre.
docker network create garde-net
docker run -d --name db --network garde-net -e POSTGRES_PASSWORD=demo postgres:17
docker run --rm --network garde-net alpine ping -c 2 db
On crée un réseau garde-net, on y attache la base sous le nom db, puis un conteneur alpine éphémère sur le même réseau réussit à joindre db par son nom — le ping répond. Cette résolution de noms est le mécanisme exact qui permettait, dans le tutoriel Compose, à l’API d’écrire DB_HOST: db. Deux conteneurs sur le même réseau se voient par leur nom ; deux conteneurs sur des réseaux différents sont isolés l’un de l’autre.
✅ Point d’étape — Le
ping dbdepuis un conteneur du même réseau répond. La résolution de noms par réseau dédié est comprise.
Étape 7 — Isoler la base sur un réseau interne
Mettons cette connaissance au service de la sécurité. On peut découper la pile en deux réseaux : un réseau « public » où l’API expose son port, et un réseau « interne » où vit la base, sans aucune route vers l’extérieur. Voici la pile « Garde » durcie, en Compose.
services:
api:
build: .
ports:
- "3000:3000"
environment:
DB_HOST: db
DB_USER: garde
DB_PASSWORD: secret
DB_NAME: garde
networks:
- public
- interne
db:
image: postgres:17
environment:
POSTGRES_USER: garde
POSTGRES_PASSWORD: secret
POSTGRES_DB: garde
volumes:
- db-data:/var/lib/postgresql/data
networks:
- interne # uniquement le reseau interne, pas de port publie
networks:
public:
interne:
internal: true # aucun acces vers ou depuis l'exterieur
volumes:
db-data:
L’API est sur les deux réseaux : public (pour être joignable depuis l’hôte) et interne (pour parler à la base). La base, elle, n’est que sur interne, déclaré internal: true — ce réseau n’a aucune passerelle vers l’extérieur. Même si quelqu’un connaissait le mot de passe, il ne pourrait pas atteindre la base depuis Internet : il n’existe tout simplement aucune route. C’est le principe de moindre exposition appliqué au réseau, et c’est gratuit. Lancez docker compose up -d --build et vérifiez que l’API répond toujours pendant que la base reste injoignable de l’extérieur.
✅ Point d’étape — L’API répond sur le port 3000, la base fonctionne, et aucun port de base n’est publié. La segmentation réseau est en place.
Trois façons de gérer le stockage, et quand les employer
Pour fixer durablement les idées, récapitulons les trois manières dont un conteneur peut manipuler des données, du plus éphémère au plus durable. Premièrement, la couche écrivable du conteneur : tout ce qu’on écrit sans montage particulier y atterrit. C’est rapide, mais ça meurt avec le conteneur. On s’en sert pour des fichiers temporaires sans valeur. Deuxièmement, le volume nommé : un espace géré par Docker, indépendant des conteneurs, idéal pour les données qui doivent persister — une base, des fichiers téléversés par les utilisateurs. C’est l’option par défaut en production. Troisièmement, le bind mount : un dossier précis de l’hôte relié au conteneur, parfait en développement pour voir son code en direct, ou pour injecter un fichier de configuration comme on le fera avec le proxy en production.
Le choix n’est pas qu’esthétique. Un volume nommé est portable : il fonctionne de la même façon sous Linux, macOS ou Windows, et Docker en optimise les performances. Un bind mount, lui, dépend de l’arborescence de la machine hôte et de ses permissions, ce qui le rend moins portable mais plus transparent. La règle pratique tient en une phrase : données applicatives durables → volume nommé ; code ou configuration depuis l’hôte → bind mount ; reste éphémère → on ne fait rien. Cette grille de lecture vous évitera l’erreur classique du débutant, qui monte un bind mount sur le répertoire de données d’une base — et se retrouve avec des problèmes de permissions et de portabilité qu’un simple volume nommé aurait évités.
Côté réseau, une idée structurante mérite d’être explicitée : Docker traite le réseau comme un périmètre de confiance. Deux conteneurs sur le même réseau se font implicitement confiance et communiquent librement par leur nom ; deux conteneurs sur des réseaux séparés sont étanches. Concevoir ses réseaux, c’est donc dessiner qui a le droit de parler à qui. La segmentation que vous avez mise en place — une base sur un réseau interne sans sortie — n’est rien d’autre que l’application de ce principe : on n’ouvre que les chemins strictement nécessaires. C’est une démarche de sécurité par conception, gratuite et puissante, que les déploiements sérieux adoptent systématiquement.
🐞 Pièges fréquents
| Symptôme / erreur | Cause probable | Correctif |
|---|---|---|
| Données perdues à chaque redémarrage | Aucun volume sur le répertoire de données | Monter un volume sur /var/lib/postgresql/data. |
| « no such host » entre conteneurs | Conteneurs sur des réseaux différents | Les placer sur un même réseau dédié pour la résolution de noms. |
| Modifs de code invisibles dans le conteneur | Code copié dans l’image, pas monté | Utiliser un bind mount en développement. |
| Volume qui « ne se vide pas » | down conserve les volumes |
docker compose down -v ou docker volume rm. |
| Permissions refusées sur un bind mount | Droits du dossier hôte | Ajuster les permissions, ou monter en lecture seule (:ro) si l’écriture est inutile. |
Sauvegardes et coupures de courant
La sauvegarde de volumes prend un relief particulier là où le matériel vieillit et où les coupures électriques peuvent corrompre un disque. Une archive tar.gz du volume de la base, copiée régulièrement sur un stockage distant ou même sur une clé, sépare un incident matériel d’une catastrophe pour un commerce d’Abidjan ou de Cocody. Pensez la sauvegarde dès le premier jour, pas après le premier crash. Côté réseau, la segmentation que vous venez de mettre en place est une protection à coût nul, précieuse quand on déploie sur un VPS mutualisé exposé en permanence : une base qui n’a aucune route vers l’extérieur ne peut pas être attaquée depuis l’extérieur. Enfin, les bind mounts en lecture seule (:ro) évitent qu’un conteneur compromis n’altère vos fichiers source — un réflexe simple qui ne coûte rien.
✅ Récapitulatif
Vous savez maintenant rendre des données durables avec un volume nommé, distinguer volume et bind mount selon l’usage, inspecter et sauvegarder un volume, créer des réseaux dédiés pour que les conteneurs se joignent par leur nom, et isoler une base sur un réseau interne sans route vers l’extérieur. La pile « Garde » est désormais durable et bien cloisonnée. Reste à la rendre transportable : la publier sur un registre et l’alléger pour des déploiements rapides, ce que couvre le tutoriel suivant.
🧾 Aide-mémoire
| Commande | Rôle |
|---|---|
docker volume create / ls / inspect |
Créer, lister, inspecter un volume |
-v nom:/chemin/conteneur |
Monter un volume nommé |
-v "$(pwd)/dossier":/chemin:ro |
Monter un dossier hôte (bind mount), lecture seule |
docker network create nom |
Créer un réseau dédié |
--network nom |
Attacher un conteneur à un réseau |
internal: true (Compose) |
Réseau sans accès extérieur |
docker volume rm nom |
Supprimer un volume |
💪 À vous de jouer
Sauvegardez le volume de la base « Garde », supprimez-le entièrement (down -v), puis restaurez la sauvegarde dans un volume neuf et vérifiez que les pharmacies sont de retour.
Voir une solution
# Sauvegarde
docker run --rm -v db-data:/data -v "$(pwd)":/bak alpine tar czf /bak/db.tar.gz -C /data .
# Tout supprimer
docker compose down -v
# Recreer un volume vide et y restaurer
docker volume create cluster-docker_db-data
docker run --rm -v cluster-docker_db-data:/data -v "$(pwd)":/bak alpine sh -c "tar xzf /bak/db.tar.gz -C /data"
docker compose up -d
Le nom réel du volume créé par Compose est préfixé par celui du projet (le dossier). Vérifiez-le avec docker volume ls avant de restaurer. Une fois la pile relancée, les pharmacies sont là : la sauvegarde a tenu.
Tutoriels frères
- Débuter avec Docker Compose — d’où viennent ce volume et ce réseau.
- Publier et optimiser ses images — l’étape suivante du parcours.
Sur le même thème
- 🔝 Retour au guide principal : Docker de zéro : comprendre et utiliser les conteneurs
- Documentation officielle : les volumes et les réseaux.
Ressources et références
FAQ
Volume nommé ou bind mount, lequel choisir ?
Volume nommé pour les données que l’application produit et doit conserver (bases, fichiers uploadés) : Docker les gère, c’est portable et performant. Bind mount pour relier un dossier précis de votre machine, surtout en développement, afin de voir vos changements de code en direct. En production, on privilégie les volumes nommés.
Où sont stockés physiquement les volumes ?
Sous Linux, dans /var/lib/docker/volumes/. docker volume inspect donne le chemin exact via le champ Mountpoint. On évite d’y toucher directement : on passe toujours par un conteneur qui monte le volume.
Un docker compose down efface-t-il mes données ?
Non, par défaut il conserve les volumes : vos données survivent. C’est l’option -v (down -v) qui supprime aussi les volumes et efface donc les données. Cette distinction est l’une des plus importantes à retenir.
Pourquoi mes conteneurs ne se voient-ils pas par leur nom ?
Parce qu’ils ne sont pas sur le même réseau dédié, ou qu’ils utilisent le réseau bridge par défaut qui ne fournit pas la résolution de noms. Créez un réseau avec docker network create et attachez-y les deux conteneurs ; avec Compose, c’est automatique.