Chapitre 612 minIntermédiaire
Volumes Docker : conserver les données
Par Josselyn C., prof de BTS SIO. Mis à jour le .
À la fin de ce chapitre, tu sauras
- choisir entre volume nommé, montage de dossier et tmpfs ;
- faire tourner une base de données dont les données survivent au conteneur ;
- corriger un problème de permissions sur un dossier monté ;
- sauvegarder et restaurer une base et un volume.
4 exercices corrigés
Un volume Docker est un espace de stockage géré par Docker, monté dans un conteneur, qui survit à la suppression du conteneur : c'est là que vont les données qui doivent durer, comme les fichiers d'une base de données. Ce chapitre compare les trois façons de monter du stockage (volume nommé, montage de dossier et tmpfs), installe une base MySQL persistante, explique les pièges de permissions et montre comment sauvegarder et restaurer un volume.
Pourquoi les données disparaissent
Tout ce qu'un conteneur écrit hors d'un montage va dans sa couche inscriptible, qui est supprimée avec lui. Lance une base sans volume, crée une table, supprime et recrée le conteneur : la table a disparu. Or on supprime et recrée les conteneurs en permanence : à chaque mise à jour d'image, à chaque changement de configuration.
La règle : un conteneur doit pouvoir être détruit à tout moment sans perte. Les données qui comptent vivent dans un volume ; tout le reste est reconstructible à partir de l'image.
Trois façons de monter du stockage
| Type | Où sont les données | Usage type |
|---|---|---|
| Volume nommé | Un dossier géré par Docker, /var/lib/docker/volumes/<nom>/_data | Les données d'un service : base de données, fichiers déposés par les utilisateurs |
| Montage de dossier (bind mount) | Un dossier ou un fichier précis de l'hôte, choisi par toi | Un fichier de configuration, un certificat, le code source en développement |
tmpfs | En mémoire vive, jamais sur disque | Des fichiers temporaires, avec un système de fichiers de conteneur en lecture seule |
Deux syntaxes existent pour docker run : la courte, -v, et la longue, --mount, plus lisible et plus stricte.
# Volume nommé
docker run -d --name bdd -v mysql-donnees:/var/lib/mysql mysql:8.4
docker run -d --name bdd --mount type=volume,source=mysql-donnees,target=/var/lib/mysql mysql:8.4
# Montage d'un fichier en lecture seule
docker run -d -v /srv/gestion/Caddyfile:/etc/caddy/Caddyfile:ro caddy:2.11
docker run -d --mount type=bind,source=/srv/gestion/Caddyfile,target=/etc/caddy/Caddyfile,readonly caddy:2.11
# tmpfs
docker run -d --mount type=tmpfs,target=/tmp nginx:1.30-alpine
Avec -v, Docker décide seul : si la partie gauche est un nom, c'est un volume ; si c'est un chemin absolu, c'est un montage de dossier, et si le dossier n'existe pas, Docker le crée vide, ce qui masque souvent une faute de frappe. --mount type=bind refuse un chemin qui n'existe pas : l'erreur saute aux yeux.
Gérer les volumes nommés
docker volume create mysql-donnees
docker volume ls
docker volume inspect mysql-donnees
docker volume rm mysql-donnees # refusé si un conteneur l'utilise
[
{
"CreatedAt": "2026-11-03T10:02:41+01:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/mysql-donnees/_data",
"Name": "mysql-donnees",
"Options": null,
"Scope": "local"
}
]
Un volume monté pour la première fois sur un dossier qui contient déjà des fichiers dans l'image reçoit une copie de ces fichiers. Un montage de dossier, lui, masque le contenu de l'image à cet endroit.
Une base MySQL persistante
docker volume create gestion-mysql
docker run -d --name gestion-bdd \
--restart unless-stopped \
-e MYSQL_ROOT_PASSWORD='Test-Labo-2026!' \
-e MYSQL_DATABASE=frais \
-v gestion-mysql:/var/lib/mysql \
mysql:8.4
Au premier démarrage, l'image initialise la base dans le volume vide et crée la base frais. Supprime le conteneur (docker rm -f gestion-bdd) et relance la même commande : MySQL retrouve ses fichiers dans le volume, les données sont intactes, et les variables d'initialisation sont ignorées puisque la base existe déjà.
Chaque image range ses données à un endroit précis, à lire dans sa documentation sur Docker Hub :
| Image | Dossier à monter |
|---|---|
mysql:8.4, mariadb:11.8 | /var/lib/mysql |
postgres:18 | /var/lib/postgresql (et non plus /var/lib/postgresql/data, comme jusqu'à la version 17) |
mongo:8.0 | /data/db |
caddy:2.11 | /data (certificats) et /config |
Monter un dossier : configuration et développement
Le montage de dossier sert surtout à deux choses.
Fournir un fichier de configuration sans reconstruire l'image, en lecture seule :
docker run -d --name proxy \
-v /srv/gestion/Caddyfile:/etc/caddy/Caddyfile:ro \
caddy:2.11
Développer : le code de ton poste est monté dans le conteneur, et chaque modification est visible tout de suite, sans reconstruire l'image. C'est pratique en développement, à proscrire en production, où le code doit être dans l'image, testée et versionnée.
Le piège des permissions. Un montage de dossier garde les propriétaires numériques de l'hôte. Si le processus du conteneur tourne sous l'UID 1000 et que le dossier de l'hôte appartient à root, l'application reçoit EACCES: permission denied. Corrige le propriétaire du dossier côté hôte (sudo chown -R 1000:1000 /srv/gestion/stockage), plutôt que de faire tourner le conteneur en root.
Sauvegarder et restaurer
Pour une base de données, fais un export logique, cohérent même si la base travaille pendant la sauvegarde. Le client de l'image fait le travail ; la redirection écrit le fichier sur l'hôte :
docker exec gestion-bdd sh -c 'exec mysqldump --single-transaction --databases frais -uroot -p"$MYSQL_ROOT_PASSWORD"' \
> /srv/sauvegardes/frais-$(date +%F).sql
La restauration envoie le fichier au client mysql du conteneur :
docker exec -i gestion-bdd sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD"' \
< /srv/sauvegardes/frais-2026-11-03.sql
Les options de mysqldump sont détaillées dans le chapitre Sauvegarder une base.
Pour des fichiers ordinaires (documents déposés, configuration), archive le volume avec un conteneur jetable qui le monte en lecture seule :
docker run --rm \
-v gestion-fichiers:/source:ro \
-v /srv/sauvegardes:/sauvegarde \
alpine:3.24 tar -czf /sauvegarde/fichiers-$(date +%F).tar.gz -C /source .
Et pour restaurer dans un volume vide :
docker run --rm \
-v gestion-fichiers:/cible \
-v /srv/sauvegardes:/sauvegarde:ro \
alpine:3.24 tar -xzf /sauvegarde/fichiers-2026-11-03.tar.gz -C /cible
Des volumes sur le stockage de l'entreprise
Le pilote local peut aussi monter un partage réseau NFS ou SMB comme volume : les données sont alors sur le NAS de l'entreprise, sauvegardées et protégées par ses instantanés, et le conteneur peut redémarrer sur un autre hôte. C'est utile pour des fichiers ; pour une base de données, un disque local (ou un disque iSCSI) reste préférable, car les bases supportent mal les latences et les verrous des partages réseau. Le stockage en réseau, NFS, SMB et iSCSI, est traité côté serveur dans le cours Stockage et NAS avec TrueNAS, et l'instantané de la VM entière dans le cours Virtualisation.
Exercices
Exercice 1 sur 4 Choisir le montage Réussi À revoir
Pour chaque besoin de l'application de gestion, choisis entre volume nommé, montage de dossier et tmpfs.
- Les fichiers de la base MySQL.
- Le
Caddyfiledu reverse proxy, modifié par les administrateurs. - Les justificatifs (PDF) déposés par les salariés.
- Le dossier
/tmpd'une API dont le système de fichiers est en lecture seule. - Le code source pendant le développement sur le poste de la développeuse.
Voir la réponseMasquer la réponse de l'exercice 1
- Volume nommé : données d'un service, gérées par Docker.
- Montage de dossier, en lecture seule (
:ro) : un fichier de configuration que l'on édite sur l'hôte et que l'on versionne. - Volume nommé : des données qui doivent survivre au conteneur et être sauvegardées.
tmpfs: des fichiers temporaires, en mémoire, qui n'ont pas à survivre.- Montage de dossier : les modifications du code sont visibles immédiatement dans le conteneur, sans reconstruire l'image.
Tu avais trouvé ?
Exercice 2 sur 4 La base qui repart à zéro Réussi À revoir
Un technicien a lancé MySQL avec docker run -d --name bdd -e MYSQL_ROOT_PASSWORD=… mysql:8.4. Après docker rm -f bdd et la même commande docker run, toutes les tables ont disparu. Explique et corrige. Les données sont-elles récupérables ?
Voir la réponseMasquer la réponse de l'exercice 2
Aucun volume nommé n'était monté. L'image MySQL déclare VOLUME /var/lib/mysql : Docker a créé un volume anonyme pour le premier conteneur. docker rm -f bdd (sans -v) ne l'a pas supprimé, mais le nouveau conteneur a reçu un nouveau volume anonyme, vide.
Les données sont probablement récupérables : docker volume ls liste les volumes anonymes, et docker volume inspect donne leur date de création. On relance alors MySQL en montant l'ancien volume, puis on fait un export. Si quelqu'un a lancé docker volume prune entre-temps, elles sont perdues.
Correction : toujours nommer le volume : -v gestion-mysql:/var/lib/mysql.
Tu avais trouvé ?
Exercice 3 sur 4 Passer à PostgreSQL 18 Réussi À revoir
Un collègue modifie son déploiement de postgres:17 à postgres:18 en gardant le montage -v pg-donnees:/var/lib/postgresql/data. Le conteneur ne démarre plus correctement. Explique les deux problèmes.
Voir la réponseMasquer la réponse de l'exercice 3
- Le chemin de montage : depuis la version 18, l'image range les données dans un sous-dossier propre à la version, sous
/var/lib/postgresql. Il faut monter le dossier parent :-v pg-donnees:/var/lib/postgresql. - Le changement de version majeure : PostgreSQL 18 ne sait pas ouvrir directement les fichiers de données d'un PostgreSQL 17. Il faut migrer : exporter avec
pg_dumpalldepuis l'ancien conteneur, démarrer PostgreSQL 18 sur un nouveau volume, puis importer (ou utiliserpg_upgrade). Sauvegarde d'abord, toujours.
Tu avais trouvé ?
Exercice 4 sur 4 Écrire la sauvegarde Réussi À revoir
Écris la commande qui archive le volume wiki-donnees dans /srv/sauvegardes/wiki-AAAA-MM-JJ.tar.gz (date du jour), sans risque de modifier le volume.
Voir la réponseMasquer la réponse de l'exercice 4
docker run --rm \
-v wiki-donnees:/source:ro \
-v /srv/sauvegardes:/sauvegarde \
alpine:3.24 tar -czf /sauvegarde/wiki-$(date +%F).tar.gz -C /source .
Le :ro monte le volume en lecture seule : l'archivage ne peut rien y modifier. $(date +%F) est remplacé par le shell de l'hôte avant le lancement, par exemple wiki-2026-11-03.tar.gz. Si le wiki utilise une base de données, ajoute un export logique de la base : l'archive des fichiers ne suffit pas.
Tu avais trouvé ?