SSD Nodes Learn Hosting plans →
Guides Matt ConnorPar Matt Connor · Mis à jour le 2026-08-25

Docker Compose : bind mount ou named volume ?

Choisissez entre bind mount et named volume selon vos fichiers : permissions, inspection, sauvegarde et migration des données Docker Compose, avec les bonnes syntaxes.

Bind mount ou named volume : réponse courte

Les volumes Docker Compose sont de deux types. Le choix dépend de la gestion des fichiers. Utilisez un bind mount pour les fichiers que vous écrivez et lisez vous-même, par exemple une configuration, des templates ou un site statique. Utilisez un named volume pour les données gérées par l’application, par exemple les fichiers d’une base de données, les index de recherche ou les médias importés. Un bind mount pointe vers un chemin de l’hôte que vous pouvez ouvrir dans un éditeur. Un named volume correspond à un espace de stockage que Docker crée et gère pour vous. Vous y accédez via Docker.

Les deux types utilisent la même clé volumes: dans un service, ce qui explique la confusion. La différence se trouve à gauche des deux-points. Une valeur qui commence par . ou / désigne un chemin sur l’hôte : il s’agit donc d’un bind mount. Toute autre valeur est un nom : il s’agit d’un named volume, et ce nom doit également être déclaré dans le bloc volumes: de niveau supérieur.

Les deux syntaxes dans un fichier Compose

services:
  db:
    image: postgres:17
    environment:
      POSTGRES_PASSWORD: changeme
    volumes:
      - pgdata:/var/lib/postgresql/data
  web:
    image: nginx:1.27
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./site:/usr/share/nginx/html:ro

volumes:
  pgdata:

pgdata:/var/lib/postgresql/data est un volume nommé. ./nginx.conf:/etc/nginx/nginx.conf est un bind mount et :ro le monte en lecture seule. C’est le bon réglage par défaut pour une configuration qu’un conteneur ne doit jamais réécrire. Si vous oubliez l’entrée volumes: de niveau supérieur, Compose s’arrête avec service "db" refers to undefined volume pgdata.

Lancez les services et listez les éléments créés par Docker :

docker compose up -d
docker volume ls

Le volume ne s’appelle pas pgdata. Il s’appelle <project>_pgdata, car le nom du projet correspond par défaut au nom du répertoire qui contient le fichier Compose. Un répertoire nommé myapp produit myapp_pgdata. Ce point est important : si vous renommez le répertoire, vous obtenez un nouveau volume vide et l’application semble avoir perdu ses données. Ce n’est pas le cas : l’ancien volume apparaît toujours dans la liste renvoyée par docker volume ls. Fixez le nom avec name: dans le fichier Compose, ou définissez COMPOSE_PROJECT_NAME si le répertoire est susceptible d’être déplacé. Ces paramètres doivent figurer avec vos autres fichiers d’environnement et secrets Compose.

Pourquoi les erreurs de permissions concernent surtout les bind mounts

C’est la principale différence pratique. Elle découle d’une règle : un named volume vide lors de sa première utilisation est initialisé depuis l’image, contrairement à un bind mount.

Lorsque Docker monte un named volume vide sur un répertoire qui contient déjà des données dans l’image, il copie ces données dans le volume, avec le propriétaire et les modes définis par l’image. L’image officielle Postgres fournit /var/lib/postgresql/data, qui appartient à son propre utilisateur postgres. Le volume appartient donc au même identifiant numérique, et la base de données démarre.

Un bind mount fonctionne à l’inverse. Le contenu présent sur l’hôte est celui que voit le conteneur, propriétaire inclus, et le contenu de l’image à cet emplacement est masqué. Si le répertoire de l’hôte n’existe pas, le daemon Docker le crée et s’exécute en tant que root. Vous obtenez donc un répertoire appartenant à root:root. Un processus du conteneur exécuté avec un utilisateur non-root ne peut alors pas y écrire :

PermissionError: [Errno 13] Permission denied: '/data/app.db'

La solution consiste à faire correspondre les identifiants numériques. Les permissions sur un bind mount sont comparées selon l’identifiant numérique de l’utilisateur, et non selon son nom, car le conteneur possède son propre /etc/passwd. Un utilisateur nommé app dans le conteneur ne correspond à rien sur l’hôte. L’UID 1000 désigne l’UID 1000 des deux côtés.

id -u
mkdir -p ./data
docker compose exec web id
sudo chown -R 1000:1000 ./data

docker compose exec web id affiche l’UID avec lequel le processus du conteneur s’exécute réellement. Alignez le propriétaire du répertoire de l’hôte sur cette valeur, ou imposez votre propre UID au conteneur avec user: "1000:1000" dans le service. Imposer user: est plus propre pour une application que vous avez écrite vous-même. Modifier le propriétaire du répertoire de l’hôte avec chown est plus sûr pour une image que vous n’avez pas écrite, car certaines images démarrent un entrypoint en tant que root, abandonnent ensuite les privilèges et attendent une propriété précise des fichiers et répertoires.

Deux autres pièges méritent d’être connus. Sur Fedora, RHEL et les autres systèmes où SELinux (security-enhanced Linux) est activé en mode enforcing, un bind mount est refusé tant qu’il n’a pas été réétiqueté. Ajoutez donc :z pour un chemin partagé entre plusieurs conteneurs, ou :Z pour un chemin utilisé par un seul conteneur, sous la forme - ./data:/data:Z. Par ailleurs, un bind mount portant sur un seul fichier, plutôt que sur un répertoire, cesse de fonctionner lorsqu’un éditeur remplace le fichier au lieu d’écrire directement dedans, car le mount suit l’inode d’origine. Le conteneur continue alors de voir l’ancien contenu jusqu’à son redémarrage. Montez le répertoire parent lorsque le fichier est modifié fréquemment.

Performances : là où l’écart est réel

Sur un serveur Linux, les deux types de montages passent par le même chemin dans le kernel. La différence de débit est donc suffisamment faible pour que vous ne choisissiez pas sur ce seul critère. Les named volumes utilisant le driver local par défaut résident sur le même système de fichiers que le reste de Docker, sous /var/lib/docker/volumes/. Un bind mount réside à l’emplacement que vous avez indiqué.

L’écart apparaît avec Docker Desktop sur macOS et Windows, où les conteneurs s’exécutent dans une machine virtuelle. Un bind mount y traverse le système de fichiers de l’hôte vers cette machine virtuelle, via une couche de partage de fichiers. Les workloads comportant de nombreuses opérations sur de petits fichiers, comme un arbre de dépendances Node.js ou le cache d’un framework PHP, ralentissent alors sensiblement. Les named volumes restent dans la machine virtuelle et n’ont pas ce coût. C’est pourquoi de nombreux fichiers Compose de développement montent le répertoire source avec un bind mount, tout en déclarant un named volume sur node_modules.

L’autre différence réelle concerne l’emplacement des données. Un bind mount vers /mnt/backup place les données sur ce disque. Un named volume utilise le système de fichiers qui contient /var/lib/docker, généralement le disque racine sur un VPS. Une base de données qui grossit dans un named volume remplit le même disque que celui qui contient les journaux du système. Vérifiez-le avant qu’un incident ne survienne :

docker system df -v
df -h /var/lib/docker

docker system df -v liste tous les volumes avec leur taille et indique ceux auxquels plus aucun conteneur ne fait référence.

Inspection d’un volume nommé

Un volume nommé n’est pas une boîte noire. Demandez à Docker où il se trouve :

docker volume inspect myapp_pgdata

Le champ Mountpoint fournit un chemin réel sur l’hôte, normalement /var/lib/docker/volumes/myapp_pgdata/_data. Vous pouvez le lire avec sudo ls, ce qui est utile pour une vérification rapide. Ne l’utilisez pas pour modifier des fichiers. Écrire à cet emplacement avec root recrée le problème de propriétaire décrit plus haut. De plus, ce chemin est une caractéristique du driver local que les autres drivers de volume ne partagent pas.

La méthode sûre pour consulter le contenu consiste à utiliser un conteneur temporaire qui monte le volume :

docker run --rm -v myapp_pgdata:/vol alpine ls -la /vol

Cette méthode fonctionne avec n’importe quel driver. Elle utilise les mêmes permissions que celles vues par le conteneur réel et ne laisse rien derrière elle grâce à --rm.

Sauvegarder chaque type

Un bind mount est un répertoire ordinaire. Tous les outils de sauvegarde au niveau des fichiers le prennent donc déjà en charge. Indiquez le chemin de l’hôte comme source de sauvegarde. C’est tout. Un named volume nécessite une étape supplémentaire, car l’outil doit accéder à son contenu. Montez le volume et un répertoire de l’hôte dans le même conteneur temporaire, puis créez une archive :

docker run --rm \
  -v myapp_pgdata:/data:ro \
  -v "$PWD":/backup \
  alpine tar czf /backup/pgdata.tar.gz -C /data .

Restaurez les données en inversant l’opération dans un nouveau volume :

docker volume create myapp_pgdata_restored
docker run --rm \
  -v myapp_pgdata_restored:/data \
  -v "$PWD":/backup \
  alpine tar xzf /backup/pgdata.tar.gz -C /data

tar préserve la propriété numérique lorsqu’il s’exécute en tant que root dans le conteneur. C’est ce qui permet à l’application d’utiliser le volume restauré.

Un avertissement s’applique aux deux types. Copier les fichiers d’une base de données pendant son fonctionnement crée une archive d’un état qui évolue en permanence. La restauration peut alors produire un état corrompu. Arrêtez d’abord le service ou effectuez un dump avec l’outil fourni par la base de données, comme dans docker compose exec -T db pg_dump -U postgres appdb > appdb.sql. Vous obtenez ainsi un fichier ordinaire que vous pouvez ensuite inclure dans une routine de sauvegarde restic chiffrée normale avec vos fichiers Compose.

Migrer un bind mount vers un volume nommé

La migration consiste en une copie, pas en un renommage. Elle prend environ une minute.

docker compose down
docker volume create myapp_pgdata
docker run --rm \
  -v "$PWD/data":/from \
  -v myapp_pgdata:/to \
  alpine sh -c 'cp -a /from/. /to/'

cp -a conserve le propriétaire, les modes et les horodatages. L’utilisateur du conteneur qui pouvait lire l’ancien répertoire peut donc toujours lire le nouveau volume. Modifiez ensuite le service pour utiliser pgdata:/var/lib/postgresql/data, ajoutez pgdata au début du bloc volumes: de niveau supérieur, exécutez docker compose up -d, puis consultez les journaux de l’application avant de supprimer l’ancien répertoire. Pour faire l’opération inverse, utilisez la même commande en permutant /from et /to.

Gardez un point à l’esprit pendant vos tests. docker compose down laisse les volumes nommés intacts, tandis que docker compose down -v supprime tous les volumes nommés déclarés par le projet, sans possibilité d’annulation. Un bind mount survit aux deux commandes, car Docker n’a jamais géré ce répertoire. Si les commandes de cycle de vie vous sont encore peu familières, le guide des bases de Docker Compose pour un VPS les présente étape par étape.

Choisir service par service

Demandez-vous qui écrit le fichier. Une configuration que vous modifiez dans un éditeur de texte et validez dans git doit utiliser un bind mount, monté :ro, car vous voulez qu’elle soit visible et versionnée. Les données d’état de l’application que vous n’ouvrez jamais manuellement doivent utiliser un volume nommé, car Docker définit correctement les permissions et les données ne dépendent pas d’un chemin de l’hôte.

Le cas mixte concerne les médias. Une photothèque est écrite par l’application, mais vous la gérez également. Elle est souvent suffisamment volumineuse pour nécessiter un disque précis. Utilisez un bind mount vers un chemin situé sur ce disque et définissez volontairement le propriétaire une seule fois. C’est le modèle que suivent la plupart des stacks auto-hébergées : des volumes nommés pour les bases de données et les caches, des bind mounts pour la configuration et pour le répertoire volumineux qui vous importe. Un service d’assistance comme Chatwoot exécuté sur un VPS correspond exactement à ce modèle, avec Postgres dans un volume nommé et les pièces jointes téléversées dans un chemin que vous pouvez inclure dans une sauvegarde.

FAQ

Quelle est la différence entre un bind mount et un named volume ?

Un bind mount mappe un chemin de l’hôte dans le conteneur. Les deux côtés voient donc le même répertoire, que vous pouvez modifier avec les outils habituels. Un named volume est un espace de stockage que Docker crée et gère. Il est référencé par son nom et déclaré dans le bloc volumes: de niveau supérieur. En pratique, la distinction concerne la gestion des données : utilisez les bind mounts pour les fichiers de configuration que vous gérez, et les named volumes pour les données que l’application gère.

Pourquoi obtenez-vous « permission denied » avec un bind mount, mais pas avec un named volume ?

Un named volume vide est initialisé à partir de l’image. Il hérite donc des permissions et du propriétaire définis par l’image, et l’utilisateur du conteneur peut y écrire. Un bind mount présente le répertoire de l’hôte exactement tel qu’il est. Si Docker a dû créer ce répertoire, il l’a créé avec root comme propriétaire. Exécutez docker compose exec <service> id pour afficher l’identifiant numérique utilisé par le conteneur, puis sudo chown -R <uid>:<gid> sur le répertoire de l’hôte, ou définissez user: "1000:1000" sur le service.

Où Docker stocke-t-il les named volumes sur le disque ?

Avec le driver local par défaut, ils sont stockés sous /var/lib/docker/volumes/<volume>/_data. La commande docker volume inspect <volume> affiche le Mountpoint exact. Consultez-le si vous devez effectuer une vérification, mais écrivez dans ce répertoire uniquement depuis un conteneur. Une modification effectuée en tant que root sur l’hôte change le propriétaire des fichiers d’une manière que le conteneur ne prévoira pas.

Comment sauvegarder un named volume ?

Lancez un conteneur temporaire avec le volume et un répertoire de l’hôte montés tous les deux, puis archivez les données de l’un vers l’autre avec docker run --rm -v myvol:/data:ro -v "$PWD":/backup alpine tar czf /backup/myvol.tar.gz -C /data .. Pour une base de données, utilisez l’outil de sauvegarde de la base de données au lieu de copier les fichiers en cours d’utilisation. Une copie effectuée pendant des écritures peut être restaurée dans un état incohérent.

La commande docker compose down supprime-t-elle mes volumes ?

docker compose down supprime les conteneurs et les réseaux, mais conserve les named volumes. docker compose down -v supprime également tous les named volumes déclarés par le projet, de manière définitive. Les bind mounts ne sont supprimés par aucune de ces commandes, car le répertoire appartient à l’hôte et non à Docker.