Introduction
Les volumes nommés dans Docker constituent une couche essentielle pour les données persistantes, mais de nombreux développeurs les traitent comme une boîte noire. Il en résulte des pertes de données, des montages confus et des conteneurs qui échouent mystérieusement après des reconstructions. Ce guide vous propose un environnement de laboratoire local pratique pour maîtriser les volumes nommés : vous les créerez, les inspecterez, testerez la persistance et les droits d'accès, puis les supprimerez en toute sécurité. Chaque étape comprend des commandes, des sorties attendues et des signaux d'échec afin que vous puissiez valider votre propre environnement avant d'utiliser des volumes en production.
Nous construirons un laboratoire avec quelques conteneurs, utiliserons des volumes nommés et des montages de liaison côte à côte, et sonderons intentionnellement les cas limites qui causent couramment des problèmes. À la fin, vous disposerez d'un ensemble d'exercices reproductibles pour garantir que vos applications Dockerisées conservent leurs données là où vous les attendez.
Prérequis et configuration de l'environnement
Avant de commencer, confirmez que vous disposez d'une installation Docker fonctionnelle et d'une compréhension de base des conteneurs. Cet article suppose Docker 20.10 ou version ultérieure et Docker Compose v2. Exécutez les commandes suivantes pour vérifier votre environnement :
docker --version
# Attendu : Docker version 20.10.21, build baeda1f
docker compose version
# Attendu : Docker Compose version v2.12.2
Nous allons créer un répertoire de laboratoire propre pour isoler les expériences. Ouvrez un terminal et exécutez :
mkdir -p docker-volumes-lab && cd docker-volumes-lab
Toutes les commandes suivantes doivent être exécutées à partir de ce répertoire.
Étape 1 : Créer un volume nommé et l'attacher à un conteneur
Commençons par l'opération la plus simple : créer un volume nommé et l'utiliser dans un conteneur.
Créez un volume nommé app_data :
docker volume create app_data
# Sortie attendue : app_data
Inspectez les métadonnées du volume :
docker volume inspect app_data
# Sortie attendue (champs clés) :
# [
# {
# "CreatedAt": "2023-09-01T12:00:00Z",
# "Driver": "local",
# "Labels": null,
# "Mountpoint": "/var/lib/docker/volumes/app_data/_data",
# "Name": "app_data",
# "Options": null,
# "Scope": "local"
# }
# ]
Exécutez maintenant un conteneur Alpine qui écrit des données dans le volume. Nous monterons le volume sur /data à l'intérieur du conteneur :
docker run --rm -d --name writer --mount type=volume,src=app_data,dst=/data alpine \
sh -c 'echo "Hello from $(date)" > /data/greeting.txt; sleep infinity'
Dans cette commande :
--rmsupprime le conteneur lorsqu'il s'arrête, mais le volume persiste.--mount type=volume,src=app_data,dst=/dataattache le volume nommé au chemin du conteneur.- Le conteneur écrit un fichier et reste actif pour inspection.
Vérifiez le fichier dans le volume en exécutant une commande dans le conteneur en cours d'exécution :
docker exec writer cat /data/greeting.txt
# Sortie attendue : Hello from <horodatage>
Arrêtez et supprimez maintenant le conteneur :
docker rm -f writer
Le volume existe toujours. Vérifiez-le :
docker volume ls
# La sortie attendue inclut app_data
Cela démontre la fonctionnalité principale : les données écrites dans le volume nommé survivent au conteneur.
Étape 2 : Tester la persistance à travers les reconstructions de conteneurs
En production, vous devez souvent mettre à jour une image d'application. L'ancien conteneur est arrêté, un nouveau est démarré et le volume est réattaché. Les données doivent survivre. Simulons cela.
Tout d'abord, vérifiez que le volume contient toujours le fichier de salutation en démarrant un conteneur temporaire :
docker run --rm -v app_data:/data alpine cat /data/greeting.txt
# Sortie attendue : Hello from <horodatage précédent>
Notez que nous n'avons pas spécifié de nom de conteneur ; le conteneur se supprime automatiquement après la lecture. Les données ont persisté.
Ensuite, simulez une mise à niveau de version. Nous allons exécuter un nouveau conteneur avec le même volume mais une commande différente pour ajouter une nouvelle ligne :
docker run --rm -v app_data:/data alpine \
sh -c 'echo "Version 2 update $(date)" >> /data/greeting.txt'
Lisez maintenant l'intégralité du fichier :
docker run --rm -v app_data:/data alpine cat /data/greeting.txt
# Sortie attendue : deux lignes, la première ancienne, la seconde nouvelle
Cela confirme que le volume contient des données accumulées.
Étape 3 : Inspecter où les données résident réellement sur l'hôte
Les volumes nommés sont stockés dans un répertoire géré par Docker sur l'hôte, généralement /var/lib/docker/volumes/<nom>/_data. Vous pouvez le vérifier en exécutant :
docker volume inspect app_data --format '{{ .Mountpoint }}'
# Sortie attendue : /var/lib/docker/volumes/app_data/_data
Si vous avez accès à l'hôte, vous pouvez lister les fichiers à cet endroit (mais faites attention aux permissions) :
sudo ls -l /var/lib/docker/volumes/app_data/_data
# Sortie attendue : greeting.txt
Cependant, Docker déconseille de modifier les fichiers directement depuis l'hôte pendant que le volume est utilisé par un conteneur ; cela peut entraîner des incohérences. Pour le débogage, utilisez un conteneur temporaire pour inspecter les fichiers.
Étape 4 : Comparer les volumes nommés et les montages de liaison
Les montages de liaison mappent un répertoire hôte directement dans le conteneur, tandis que les volumes nommés sont gérés par Docker. Dans un laboratoire local, les montages de liaison sont courants pour l'édition de code ; les volumes nommés sont préférables pour les fichiers de base de données et l'état applicatif. Comparons leur comportement.
Créez un répertoire hôte et un fichier :
mkdir -p ./hostdata
echo "Host file" > ./hostdata/host.txt
Exécutez un conteneur avec un montage de liaison :
docker run --rm -v "$(pwd)"/hostdata:/data alpine sh -c 'ls /data && cat /data/host.txt'
# Sortie attendue : host.txt et Host file
Créez maintenant un conteneur avec un volume nommé et listez son contenu :
docker run --rm -v app_data:/data alpine sh -c 'ls /data'
# Sortie attendue : greeting.txt
Observez que le montage de liaison a exposé exactement le répertoire hôte, tandis que le volume nommé a démarré avec son propre contenu. Cet isolement est l'une des raisons pour lesquelles les volumes nommés sont préférés pour les données avec état.
Quand utiliser lequel :
- Utilisez un volume nommé lorsque les données doivent être gérées par Docker, montées à des chemins fixes ou partagées entre conteneurs.
- Utilisez un montage de liaison lorsque vous avez besoin d'une édition en direct du code source, des fichiers de configuration pendant le développement, ou d'un accès direct aux fichiers hôtes.
Étape 5 : Partager un volume nommé entre conteneurs
Un volume nommé peut être monté par plusieurs conteneurs simultanément. Cela est utile pour partager des données ou pour des modèles de side-car. Créons deux conteneurs qui accèdent au même volume.
Démarrez un conteneur qui écrit un fichier, puis un autre qui le lit après un court délai :
# Premier conteneur écrit un fichier
# Deuxième conteneur démarre après 2 secondes et lit le fichier
Pour plus de simplicité, nous réutiliserons app_data. Exécutez un écrivain :
docker run -d --name writer1 -v app_data:/shared alpine \
sh -c 'echo "Shared data from writer1" > /shared/shared.txt; sleep 300'
Exécutez un lecteur qui attend le fichier :
docker run --rm -v app_data:/shared alpine \
sh -c 'while [ ! -f /shared/shared.txt ]; do sleep 1; done; cat /shared/shared.txt'
# Sortie attendue : Shared data from writer1
Les deux conteneurs accèdent au même volume, démontrant une persistance partagée. Après le test, nettoyez l'écrivain :
docker rm -f writer1
Étape 6 : Tester les problèmes de propriété et de permissions des volumes
Un échec courant en production survient lorsqu'un conteneur s'exécute en tant qu'utilisateur non root mais que les fichiers du volume appartiennent à root. Cela peut entraîner des erreurs de permission refusée. Reproduisons cela.
Exécutez un conteneur Alpine qui écrit un fichier en tant que root dans un nouveau volume perm_vol :
docker run --rm -v perm_vol:/data alpine sh -c 'echo "root file" > /data/rootfile.txt'
Exécutez maintenant un autre conteneur en tant qu'utilisateur non root (par exemple, 1000) et essayez d'écraser ce fichier :
docker run --rm --user 1000:1000 -v perm_vol:/data alpine \
sh -c 'echo "user file" > /data/rootfile.txt'
# Sortie attendue : /bin/sh: can't create /data/rootfile.txt: Permission denied
L'erreur de permission refusée se produit car le fichier appartient à root et l'utilisateur 1000 du conteneur n'a pas les permissions d'écriture.
Correctif en pratique : Initialisez le volume avec la propriété correcte. Par exemple, en utilisant un conteneur d'initialisation qui s'exécute en tant que root et effectue un chown du répertoire :
docker run --rm -v perm_vol:/data alpine sh -c 'chown -R 1000:1000 /data'
Ensuite, l'écriture non root réussit :
docker run --rm --user 1000:1000 -v perm_vol:/data alpine \
sh -c 'echo "user file" > /data/rootfile.txt'
# Aucune erreur ; fichier écrasé
Dans Compose, vous pouvez y parvenir avec un service d'initialisation ou en construisant l'image avec USER et en préparant le chemin du volume.
Étape 7 : Utiliser un volume nommé dans Docker Compose
Compose simplifie la gestion des volumes. Créez un fichier docker-compose.yml avec un service et un volume nommé :
services:
app:
image: alpine
command: sh -c 'echo "Hello from Compose" > /data/msg.txt; sleep infinity'
volumes:
- app_data:/data
volumes:
app_data:
Exécutez-le :
docker compose up -d
Inspectez la liste des volumes :
docker volume ls
# La sortie attendue inclut <nom_du_projet>_app_data
Par défaut, Compose préfixe le nom du projet au volume. Vous pouvez vérifier les données :
docker compose exec app cat /data/msg.txt
# Sortie attendue : Hello from Compose
Détruisez maintenant et vérifiez la persistance du volume :
docker compose down # arrête et supprime les conteneurs, mais le volume reste
Vérifiez que le volume existe toujours :
docker volume ls | grep app_data
Si vous souhaitez supprimer également le volume, utilisez le drapeau -v :
docker compose down -v
Mais utilisez -v avec prudence ; il supprime définitivement les données du volume nommé.
Étape 8 : Sauvegarder et restaurer un volume nommé
Les données de production dans les volumes doivent être sauvegardées. Une technique simple consiste à utiliser un conteneur temporaire qui monte le volume et archive son contenu dans un fichier tar sur l'hôte.
Commande de sauvegarde :
docker run --rm -v app_data:/data -v "$(pwd)":/backup alpine \
tar cvf /backup/app_data_backup.tar /data
Cela monte le volume source sur /data et le répertoire hôte actuel sur /backup, puis crée une archive tar. La sortie attendue montre les fichiers ajoutés.
Commande de restauration :
Pour restaurer, créez un nouveau volume et extrayez l'archive dedans :
docker volume create app_data_restored
docker run --rm -v app_data_restored:/data -v "$(pwd)":/backup alpine \
tar xvf /backup/app_data_backup.tar -C /
Vérifiez les données restaurées :
docker run --rm -v app_data_restored:/data alpine cat /data/greeting.txt
# Sortie attendue : le contenu de la sauvegarde
Cette méthode manuelle fonctionne bien pour les petits volumes ; pour des données plus volumineuses, envisagez des outils de sauvegarde dédiés.
Étape 9 : Nettoyer votre laboratoire
Après avoir terminé les exercices, supprimez tous les volumes et conteneurs de test pour garder votre hôte propre.
Listez tous les volumes :
docker volume ls
Supprimez les volumes que nous avons créés :
docker volume rm app_data perm_vol app_data_restored
Si vous avez utilisé Compose, assurez-vous que les services sont arrêtés :
docker compose down -v
Enfin, supprimez le répertoire du laboratoire :
cd .. && rm -rf docker-volumes-lab
Pièges courants et comment les éviter
Même les utilisateurs Docker expérimentés trébuchent avec les volumes. Voici les problèmes les plus fréquents et leurs remèdes.
1. Oublier de monter un volume
Symptôme : Les données disparaissent au redémarrage du conteneur.
Cause : L'application écrit dans un chemin du système de fichiers du conteneur qui n'est pas couvert par un volume.
Comment éviter : Définissez toujours des volumes pour chaque répertoire persistant et inscriptible dans votre fichier Compose ou votre commande Docker run. Testez la persistance avec un redémarrage.
Récupération : Si vous avez encore le conteneur, copiez les données avant la suppression :
docker cp <conteneur>:/chemin/vers/donnees ./backup
Recréez ensuite avec un volume monté à ce chemin.
2. Volume monté au mauvais chemin
Symptôme : L'application démarre mais ne trouve pas ses données ; les journaux indiquent « fichier introuvable ».
Cause : Le volume est monté à un chemin différent de celui attendu par l'application.
Comment éviter : Consultez la documentation de l'application pour le répertoire de données correct. Par exemple, MySQL attend /var/lib/mysql, PostgreSQL attend /var/lib/postgresql/data.
Récupération : Arrêtez le conteneur, supprimez-le et exécutez-le avec le point de montage correct.
3. Problèmes de permissions avec les conteneurs non root
Symptôme : Le conteneur ne démarre pas ou les écritures échouent avec « Permission refusée ».
Cause : Les fichiers initiaux du volume appartiennent à root, mais le conteneur s'exécute en tant qu'utilisateur différent.
Comment éviter : Préparez la propriété du volume avant de démarrer l'application. Utilisez un conteneur d'initialisation ou configurez l'image avec USER et définissez les permissions de répertoire correctes dans le Dockerfile.
Récupération : Exécutez un conteneur root temporaire pour chown le volume, comme illustré à l'étape 6.
4. Utiliser un montage de liaison pour des données avec état
Symptôme : Les données diffèrent entre les machines ou sont difficiles à sauvegarder.
Cause : Les montages de liaison dépendent des chemins et permissions de l'hôte, qui ne sont pas portables.
Comment éviter : Utilisez des volumes nommés pour toutes les données applicatives persistantes, en particulier en production.
Récupération : Migrez vers un volume nommé en copiant les données du répertoire du montage de liaison dans un conteneur temporaire avec le volume attaché.
5. Supprimer accidentellement des volumes
Symptôme : Les données sont perdues après l'exécution de docker volume prune ou docker compose down -v.
Cause : Ces commandes suppriment les volumes inutilisés sans confirmation supplémentaire.
Comment éviter : Vérifiez toujours quels volumes seront supprimés. Évitez prune dans les environnements de production. Mettez en œuvre des sauvegardes régulières.
Récupération : Restaurez à partir de la sauvegarde la plus récente.
Conclusion
Vous avez construit un laboratoire local complet pour les volumes nommés Docker : création, inspection, partage, sauvegarde et gestion des permissions. Les commandes et les tests de ce guide constituent une base solide pour utiliser les volumes en toute confiance dans vos flux de développement et vos déploiements en production.
N'oubliez pas de toujours vérifier quel chemin nécessite une persistance, de choisir le bon type de montage et de tester le comportement au redémarrage. Avec ces habitudes, vous éviterez les pertes de données et les maux de tête de débogage.
Pour aller plus loin, explorez la documentation officielle de Docker sur les volumes, y compris les pilotes de volume et les montages NFS pour le stockage distribué.