⚠️ Traduction non officielle - Cette documentation est une traduction communautaire non officielle de Docker.

Montages bind

Lorsque vous utilisez un montage bind, un fichier ou répertoire sur la machine hôte est monté depuis l'hôte dans un conteneur. En revanche, lorsque vous utilisez un volume, un nouveau répertoire est créé dans le répertoire de stockage de Docker sur la machine hôte, et Docker gère le contenu de ce répertoire.

Quand utiliser les montages bind

Les montages bind sont appropriés pour les types de cas d'usage suivants :

  • Partager du code source ou des artefacts de construction entre un environnement de développement sur l'hôte Docker et un conteneur.

  • Lorsque vous voulez créer ou générer des fichiers dans un conteneur et persister les fichiers sur le système de fichiers de l'hôte.

  • Partager des fichiers de configuration depuis la machine hôte vers les conteneurs. C'est ainsi que Docker fournit la résolution DNS aux conteneurs par défaut, en montant /etc/resolv.conf depuis la machine hôte dans chaque conteneur.

Les montages bind sont également disponibles pour les constructions : vous pouvez lier du code source depuis l'hôte dans le conteneur de construction pour tester, analyser ou compiler un projet.

Montage bind sur des données existantes

Si vous montez bind un fichier ou répertoire dans un répertoire du conteneur dans lequel des fichiers ou répertoires existent, les fichiers préexistants sont obscurcis par le montage. Ceci est similaire à si vous deviez enregistrer des fichiers dans /mnt sur un hôte Linux, puis monter une clé USB dans /mnt. Le contenu de /mnt serait obscurci par le contenu de la clé USB jusqu'à ce que la clé USB soit démontée.

Avec les conteneurs, il n'y a pas de moyen simple de supprimer un montage pour révéler les fichiers obscurcis à nouveau. Votre meilleure option est de recréer le conteneur sans le montage.

Considérations et contraintes

  • Les montages bind ont un accès en écriture aux fichiers sur l'hôte par défaut.

    Un effet de bord de l'utilisation des montages bind est que vous pouvez modifier le système de fichiers hôte via des processus s'exécutant dans un conteneur, y compris créer, modifier ou supprimer des fichiers ou répertoires système importants. Cette capacité peut avoir des implications de sécurité. Par exemple, cela peut affecter les processus non-Docker sur le système hôte.

    Vous pouvez utiliser l'option readonly ou ro pour empêcher le conteneur d'écrire dans le montage.

  • Les montages bind sont créés vers l'hôte du démon Docker, pas le client.

    Si vous utilisez un démon Docker distant, vous ne pouvez pas créer un montage bind pour accéder aux fichiers sur la machine client dans un conteneur.

    Pour Docker Desktop, le démon s'exécute à l'intérieur d'une VM Linux, pas directement sur l'hôte natif. Docker Desktop a des mécanismes intégrés qui gèrent de manière transparente les montages bind, vous permettant de partager les chemins du système de fichiers de l'hôte natif avec les conteneurs s'exécutant dans la machine virtuelle.

  • Les conteneurs avec des montages bind sont fortement liés à l'hôte.

    Les montages bind dépendent du fait que le système de fichiers de la machine hôte ait une structure de répertoire spécifique disponible. Cette dépendance signifie que les conteneurs avec des montages bind peuvent échouer s'ils sont exécutés sur un hôte différent sans la même structure de répertoire.

Syntaxe

Pour créer un montage bind, vous pouvez utiliser soit le drapeau --mount soit --volume.

$ docker run --mount type=bind,src=<chemin-hôte>,dst=<chemin-conteneur>
$ docker run --volume <chemin-hôte>:<chemin-conteneur>

En général, --mount est préféré. La principale différence est que le drapeau --mount est plus explicite et prend en charge toutes les options disponibles.

Si vous utilisez --volume pour monter bind un fichier ou répertoire qui n'existe pas encore sur l'hôte Docker, Docker crée automatiquement le répertoire sur l'hôte pour vous. Il est toujours créé comme un répertoire.

--mount ne crée pas automatiquement un répertoire si le chemin de montage spécifié n'existe pas sur l'hôte. Au lieu de cela, il produit une erreur :

$ docker run --mount type=bind,src=/dev/noexist,dst=/mnt/foo alpine
docker: Error response from daemon: invalid mount config for type "bind": bind source path does not exist: /dev/noexist.

Options pour --mount

Le drapeau --mount se compose de plusieurs paires clé-valeur, séparées par des virgules et chacune constituée d'un tuple <clé>=<valeur>. L'ordre des clés n'est pas significatif.

$ docker run --mount type=bind,src=<chemin-hôte>,dst=<chemin-conteneur>[,<clé>=<valeur>...]

Les options valides pour --mount type=bind incluent :

Option Description
source, src L'emplacement du fichier ou répertoire sur l'hôte. Cela peut être un chemin absolu ou relatif.
destination, dst, target Le chemin où le fichier ou répertoire est monté dans le conteneur. Doit être un chemin absolu.
readonly, ro Si présent, fait que le montage bind est monté dans le conteneur en lecture seule.
bind-propagation Si présent, modifie la propagation bind.
Exemple
$ docker run --mount type=bind,src=.,dst=/project,ro,bind-propagation=rshared

Options pour --volume

Le drapeau --volume ou -v se compose de trois champs, séparés par des caractères deux-points (:). Les champs doivent être dans le bon ordre.

$ docker run -v <chemin-hôte>:<chemin-conteneur>[:opts]

Le premier champ est le chemin sur l'hôte à monter bind dans le conteneur. Le deuxième champ est le chemin où le fichier ou répertoire est monté dans le conteneur.

Le troisième champ est optionnel, et est une liste d'options séparées par des virgules. Les options valides pour --volume avec un montage bind incluent :

Option Description
readonly, ro Si présent, fait que le montage bind est monté dans le conteneur en lecture seule.
z, Z Configure l'étiquetage SELinux. Voir Configurer l'étiquette SELinux
rprivate (défaut) Définit la propagation bind à rprivate pour ce montage. Voir Configurer la propagation bind.
private Définit la propagation bind à private pour ce montage. Voir Configurer la propagation bind.
rshared Définit la propagation bind à rshared pour ce montage. Voir Configurer la propagation bind.
shared Définit la propagation bind à shared pour ce montage. Voir Configurer la propagation bind.
rslave Définit la propagation bind à rslave pour ce montage. Voir Configurer la propagation bind.
slave Définit la propagation bind à slave pour ce montage. Voir Configurer la propagation bind.
Exemple
$ docker run -v .:/project:ro,rshared

Démarrer un conteneur avec un montage bind

Considérez un cas où vous avez un répertoire source et que lorsque vous construisez le code source, les artefacts sont sauvegardés dans un autre répertoire, source/target/. Vous voulez que les artefacts soient disponibles pour le conteneur à /app/, et vous voulez que le conteneur ait accès à une nouvelle construction chaque fois que vous construisez le source sur votre hôte de développement. Utilisez la commande suivante pour monter bind le répertoire target/ dans votre conteneur à /app/. Exécutez la commande depuis le répertoire source. La sous-commande $(pwd) se développe vers le répertoire de travail actuel sur les hôtes Linux ou macOS. Si vous êtes sur Windows, voir aussi Conversions de chemin sur Windows.

Les exemples --mount et -v suivants produisent le même résultat. Vous ne pouvez pas les exécuter tous les deux à moins de supprimer le conteneur devtest après avoir exécuté le premier.

$ docker run -d \
  -it \
  --name devtest \
  --mount type=bind,source="$(pwd)"/target,target=/app \
  nginx:latest
$ docker run -d \
  -it \
  --name devtest \
  -v "$(pwd)"/target:/app \
  nginx:latest

Use docker inspect devtest to verify that the bind mount was created correctly. Look for the Mounts section:

"Mounts": [
    {
        "Type": "bind",
        "Source": "/tmp/source/target",
        "Destination": "/app",
        "Mode": "",
        "RW": true,
        "Propagation": "rprivate"
    }
],

This shows that the mount is a bind mount, it shows the correct source and destination, it shows that the mount is read-write, and that the propagation is set to rprivate.

Stop and remove the container:

$ docker container rm -fv devtest

Mount into a non-empty directory on the container

If you bind-mount a directory into a non-empty directory on the container, the directory's existing contents are obscured by the bind mount. This can be beneficial, such as when you want to test a new version of your application without building a new image. However, it can also be surprising and this behavior differs from that of volumes.

This example is contrived to be extreme, but replaces the contents of the container's /usr/ directory with the /tmp/ directory on the host machine. In most cases, this would result in a non-functioning container.

The --mount and -v examples have the same end result.

$ docker run -d \
  -it \
  --name broken-container \
  --mount type=bind,source=/tmp,target=/usr \
  nginx:latest

docker: Error response from daemon: oci runtime error: container_linux.go:262:
starting container process caused "exec: \"nginx\": executable file not found in $PATH".
$ docker run -d \
  -it \
  --name broken-container \
  -v /tmp:/usr \
  nginx:latest

docker: Error response from daemon: oci runtime error: container_linux.go:262:
starting container process caused "exec: \"nginx\": executable file not found in $PATH".

The container is created but does not start. Remove it:

$ docker container rm broken-container

Use a read-only bind mount

For some development applications, the container needs to write into the bind mount, so changes are propagated back to the Docker host. At other times, the container only needs read access.

This example modifies the previous one, but mounts the directory as a read-only bind mount, by adding ro to the (empty by default) list of options, after the mount point within the container. Where multiple options are present, separate them by commas.

The --mount and -v examples have the same result.

$ docker run -d \
  -it \
  --name devtest \
  --mount type=bind,source="$(pwd)"/target,target=/app,readonly \
  nginx:latest
$ docker run -d \
  -it \
  --name devtest \
  -v "$(pwd)"/target:/app:ro \
  nginx:latest

Use docker inspect devtest to verify that the bind mount was created correctly. Look for the Mounts section:

"Mounts": [
    {
        "Type": "bind",
        "Source": "/tmp/source/target",
        "Destination": "/app",
        "Mode": "ro",
        "RW": false,
        "Propagation": "rprivate"
    }
],

Stop and remove the container:

$ docker container rm -fv devtest

Recursive mounts

When you bind mount a path that itself contains mounts, those submounts are also included in the bind mount by default. This behavior is configurable, using the bind-recursive option for --mount. This option is only supported with the --mount flag, not with -v or --volume.

If the bind mount is read-only, the Docker Engine makes a best-effort attempt at making the submounts read-only as well. This is referred to as recursive read-only mounts. Recursive read-only mounts require Linux kernel version 5.12 or later. If you're running an older kernel version, submounts are automatically mounted as read-write by default. Attempting to set submounts to be read-only on a kernel version earlier than 5.12, using the bind-recursive=readonly option, results in an error.

Supported values for the bind-recursive option are:

Value Description
enabled (default) Read-only mounts are made recursively read-only if kernel is v5.12 or later. Otherwise, submounts are read-write.
disabled Submounts are ignored (not included in the bind mount).
writable Submounts are read-write.
readonly Submounts are read-only. Requires kernel v5.12 or later.

Configure bind propagation

Bind propagation defaults to rprivate for both bind mounts and volumes. It is only configurable for bind mounts, and only on Linux host machines. Bind propagation is an advanced topic and many users never need to configure it.

Bind propagation refers to whether or not mounts created within a given bind-mount can be propagated to replicas of that mount. Consider a mount point /mnt, which is also mounted on /tmp. The propagation settings control whether a mount on /tmp/a would also be available on /mnt/a. Each propagation setting has a recursive counterpoint. In the case of recursion, consider that /tmp/a is also mounted as /foo. The propagation settings control whether /mnt/a and/or /tmp/a would exist.

Note

Mount propagation doesn't work with Docker Desktop.

Propagation setting Description
shared Sub-mounts of the original mount are exposed to replica mounts, and sub-mounts of replica mounts are also propagated to the original mount.
slave similar to a shared mount, but only in one direction. If the original mount exposes a sub-mount, the replica mount can see it. However, if the replica mount exposes a sub-mount, the original mount cannot see it.
private The mount is private. Sub-mounts within it are not exposed to replica mounts, and sub-mounts of replica mounts are not exposed to the original mount.
rshared The same as shared, but the propagation also extends to and from mount points nested within any of the original or replica mount points.
rslave The same as slave, but the propagation also extends to and from mount points nested within any of the original or replica mount points.
rprivate The default. The same as private, meaning that no mount points anywhere within the original or replica mount points propagate in either direction.

Before you can set bind propagation on a mount point, the host filesystem needs to already support bind propagation.

For more information about bind propagation, see the Linux kernel documentation for shared subtree.

The following example mounts the target/ directory into the container twice, and the second mount sets both the ro option and the rslave bind propagation option.

The --mount and -v examples have the same result.

$ docker run -d \
  -it \
  --name devtest \
  --mount type=bind,source="$(pwd)"/target,target=/app \
  --mount type=bind,source="$(pwd)"/target,target=/app2,readonly,bind-propagation=rslave \
  nginx:latest
$ docker run -d \
  -it \
  --name devtest \
  -v "$(pwd)"/target:/app \
  -v "$(pwd)"/target:/app2:ro,rslave \
  nginx:latest

Now if you create /app/foo/, /app2/foo/ also exists.

Configure the SELinux label

If you use SELinux, you can add the z or Z options to modify the SELinux label of the host file or directory being mounted into the container. This affects the file or directory on the host machine itself and can have consequences outside of the scope of Docker.

  • The z option indicates that the bind mount content is shared among multiple containers.
  • The Z option indicates that the bind mount content is private and unshared.

Use extreme caution with these options. Bind-mounting a system directory such as /home or /usr with the Z option renders your host machine inoperable and you may need to relabel the host machine files by hand.

Important

When using bind mounts with services, SELinux labels (:Z and :z), as well as :ro are ignored. See moby/moby #32579 for details.

This example sets the z option to specify that multiple containers can share the bind mount's contents:

It is not possible to modify the SELinux label using the --mount flag.

$ docker run -d \
  -it \
  --name devtest \
  -v "$(pwd)"/target:/app:z \
  nginx:latest

Utiliser un montage bind avec Docker Compose

Un seul service Docker Compose avec un montage bind ressemble à ceci :

services:
  frontend:
    image: node:lts
    volumes:
      - type: bind
        source: ./static
        target: /opt/app/static
volumes:
  myapp:

Pour plus d'informations sur l'utilisation des volumes de type bind avec Compose, voir Référence Compose sur les volumes. et Référence Compose sur la configuration des volumes.

Étapes suivantes