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
ouro
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. |
$ 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. |
$ 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.
NoteMount 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.
ImportantWhen 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
- En savoir plus sur les volumes.
- En savoir plus sur les montages tmpfs.
- En savoir plus sur les pilotes de stockage.