Les volumes sont le mécanisme privilégié pour la persistance des données générées et utilisées par les conteneurs Docker. Alors que les bind mounts dépendent de la structure des répertoires et du système d'exploitation de la machine hôte, les volumes sont entièrement gérés par Docker. Les volumes présentent plusieurs avantages par rapport aux bind mounts :
- Les
volumessont plus faciles à sauvegarder ou à migrer que lesbind mounts. - Vous pouvez gérer les
volumesà l'aide descommandes Docker CLIou de l'API Docker. - Les
volumesfonctionnent sur les conteneursLinuxetWindows. - Les
volumespeuvent être partagés de manière plus sûre entre plusieurs conteneurs. - Les
drivers de volumevous permettent de stocker desvolumessur des hôtes ou des fournisseurs de clouds distants, de chiffrer le contenu desvolumesou d'ajouter d'autres fonctionnalités. - Les nouveaux
volumespeuvent avoir leur contenu pré-rempli par un conteneur. - Les
volumessurDocker Desktopsont beaucoup plus performants que lesbind mountsdes hôtesMacetWindows.
En outre, les volumes sont souvent un meilleur choix que la persistance des données dans la couche inscriptible d'un conteneur, car un volume n'augmente pas la taille des conteneurs qui l'utilisent et le contenu du volume existe en dehors du cycle de vie d'un conteneur donné.
Choisissez l'option -v ou --mount
En général, --mount est plus explicite et verbeux. La plus grande différence est que la syntaxe -v regroupe toutes les options dans un seul champ, alors que la syntaxe --mount les sépare. Voici une comparaison de la syntaxe pour chaque option.
Si vous devez spécifier les options du pilote de volume, vous devez utiliser --mount.
-vou--volume: Consiste en trois champs, séparés par des caractères deux-points (:). Les champs doivent être dans le bon ordre, et la signification de chaque champ n'est pas immédiatement évidente.- Dans le cas des
volumes nommés, le premier champ est lenom du volume, et il est unique sur une machine hôte donnée. Pour lesvolumes anonymes, le premier champ est omis. - Le deuxième champ est le chemin où le fichier ou le répertoire est monté dans le conteneur.
- Le troisième champ est facultatif. Il s'agit d'une liste d'options, telles que
ro, séparées par des virgules. Ces options sont présentées ci-dessous.
- Dans le cas des
-
--mount: Consiste en plusieurs paires clé-valeur, séparées par des virgules et consistant chacune en un tuple<key>=<value>. La syntaxe--mountest plus verbeuse que-vou--volume, mais l'ordre des clés n'est pas significatif, et la valeur de l'indicateur est plus facile à comprendre.- Le
type de montage, qui peut êtrebind,volume, outmpfs. Cet article traite desvolumes, donc le type est toujoursvolume. - La
source du montage. Pour lesvolumes nommés, il s'agit dunom du volume. Pour lesvolumes anonymes, ce champ est omis. Peut être spécifié commesourceousrc. - La
destinationprend comme valeur le chemin où le fichier ou le répertoire est monté dans le conteneur. Peut être spécifié commedestination,dst, outarget. - L'option
readonly, si elle est présente, fait en sorte que le montage lié soit monté dans le conteneur en lecture seule. - L'option
volume-opt, qui peut être spécifiée plusieurs fois, prend une paire clé-valeur constituée du nom de l'option et de sa valeur.
- Le
Créer et gérer des volumes
Contrairement à un bind mount, vous pouvez créer et gérer des volumes en dehors de tout conteneur.
- Créez un volume :
$ docker volume create my-vol
- Lister les volumes :
$ docker volume ls DRIVER VOLUME NAME local 0dd1fc1cb2f4a6d047cebcb7de3947e947df9a474eb45d8457e754ae68ae99e5 (# volume anonyme) local d3d2b3b0884719e39839e99e2f31ed5fdb641c2171481ecc9b187af096340f6f local d21654e6ba1a69a25f517a22d2d2b8cd1b9303f484ebde0fa42009342294b5fb local my-volx local my_volume (# volume nommé)
- Inspecter un volume :
# On notera le point de montage de "my_volume" : "/var/lib/docker/volumes/my_volume/_data"
# Le répertoire "/var/lib/docker/volumes" contient tous les volumes (nommés ou anonymes) de Docker
$ docker volume inspect my_volume
[
{
"CreatedAt": "2021-08-20T18:05:08+02:00",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/my_volume/_data",
"Name": "my_volume",
"Options": {},
"Scope": "local"
}
]
- Supprimez un volume :
$ docker volume rm my_volume
Démarrer un conteneur avec un volume
Si vous démarrez un conteneur avec un volume qui n'existe pas encore, Docker crée le volume pour vous. L'exemple suivant monte le volume myvol2 dans /app/ dans le conteneur.
Les syntaxes -v et --mount ci-dessous produisent le même résultat. Vous ne pouvez pas les exécuter toutes les deux, sauf si vous supprimez le conteneur devtest et le volume myvol2 après avoir exécuté la première.
# Syntaxe --mount $ docker run -d \ --name devtest \ --mount source=myvol2,target=/app \ nginx:latest # Syntaxe -v $ docker run -d \ --name devtest \ -v myvol2:/app \ nginx:latest
Utilisez docker inspect devtest pour vérifier que le volume a été créé et monté correctement. Recherchez la section Mounts :
"Mounts" : [
{
"Type" : "Volume",
"Nom" : "monvol2",
"Source" : "/var/lib/docker/volumes/myvol2/_data",
"Destination" : "/app",
"Pilote" : "local",
"Mode" : "",
"RW" : true,
"Propagation" : ""
}
],
Cela montre que le montage est un volume, que la source et la destination sont correctes et que le montage est en lecture-écriture.
Arrêtez le conteneur et supprimez le volume. Notez que la suppression du volume est une étape distincte.
$ docker container stop devtest $ docker container rm devtest $ docker volume rm myvol2
Supprimer des volumes
Un volume de données Docker persiste après la suppression d'un conteneur. Il existe deux types de volumes à prendre en compte :
- Les
volumes nommésont une source spécifique depuis l'extérieur du conteneur, par exemple awesome:/bar. - Les
volumes anonymesn'ont pas de source spécifique, donc lorsque le conteneur est supprimé, demandez audémon Docker Enginede les supprimer.
Suppression des volumes anonymes
Pour supprimer automatiquement les volumes anonymes, utilisez l'option --rm. Par exemple, cette commande crée un volume anonyme /foo. Lorsque le conteneur est supprimé, le moteur Docker supprime le volume /foo mais pas le volume awesome.
$ docker run --rm -v /foo -v awesome:/bar busybox top
Suppression de tous les volumes
Pour supprimer tous les volumes inutilisés et libérer de l'espace :
$ docker volume prune
Comparaison avec les bind mounts
Les bind mounts (montages liés) existent depuis les premiers jours de Docker. Les bind mounts ont une fonctionnalité limitée par rapport aux volumes. Lorsque vous utilisez un bind mount, un fichier ou un répertoire sur la machine hôte est monté dans un conteneur. Le fichier ou le répertoire est référencé par son chemin absolu sur la machine hôte. 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.
Il n'est pas nécessaire que le fichier ou le répertoire existe déjà sur l'hôte Docker. Il est créé à la demande s'il n'existe pas encore. Les bind mounts sont très performants, mais ils dépendent du fait que le système de fichiers de la machine hôte dispose d'une structure de répertoire spécifique. Si vous développez de nouvelles applications Docker, envisagez plutôt d'utiliser des volumes nommés. Vous ne pouvez pas utiliser les commandes Docker CLI pour gérer directement les bind mounts.
Choisissez l'option -v ou --mount
En général, --mount est plus explicite et verbeux. La plus grande différence est que la syntaxe -v regroupe toutes les options dans un seul champ, alors que la syntaxe --mount les sépare. Voici une comparaison de la syntaxe pour chaque option.
Conseil : Les nouveaux utilisateurs devraient utiliser la syntaxe --mount. Les utilisateurs expérimentés peuvent être plus familiers avec la syntaxe -v ou --volume, mais sont encouragés à utiliser --mount, car la recherche a montré qu'elle est plus facile à utiliser.
-vou--volume: Consiste en trois champs, séparés par des caractères deux-points (:). Les champs doivent être dans le bon ordre, et la signification de chaque champ n'est pas immédiatement évidente.- Dans le cas des
bind mounts, le premier champ est le chemin d'accès au fichier ou au répertoire sur la machine hôte. - Le deuxième champ est le chemin d'accès où le fichier ou le répertoire est monté dans le conteneur.
- Le troisième champ est facultatif et consiste en une liste d'options séparées par des virgules, telles que
ro,zetZ.
- Dans le cas des
--mount: Consiste en plusieurs paires clé-valeur, séparées par des virgules et consistant chacune en un tuple<key>=<value>. La syntaxe--mountest plus verbeuse que-vou--volume, mais l'ordre des clés n'est pas significatif, et la valeur de l'indicateur est plus facile à comprendre.- Le
type de montage, qui peut êtrebind,volume, outmpfs. Dans ce cas précis, ce sera toujoursbind. - La source du montage. Pour les montages liés, il s'agit du chemin d'accès au fichier ou au répertoire sur l'hôte du démon Docker. Peut être spécifié comme source ou src.
- La
destinationprend comme valeur le chemin où le fichier ou le répertoire est monté dans le conteneur. Peut être spécifié commedestination,dst, outarget. - L'option
readonly, si elle est présente, fait en sorte que lemontage bindsoit monté dans le conteneur en lecture seule. - L'option
bind-propagation, si elle est présente, modifie la propagation dubind. Peut être l'un des éléments suivants :rprivate,private, rshared,shared,rslave,slave. - L'indicateur
--mountne supporte pas les optionszouZpour modifier les étiquettes selinux.
- Le
Démarrer un conteneur avec un bind mount
Considérons un cas où vous avez un répertoire source et que lorsque vous construisez le code source, les artefacts sont enregistrés dans un autre répertoire, source/target/. Vous voulez que les artefacts soient disponibles pour le conteneur dans /app/, et vous voulez que le conteneur ait accès à une nouvelle construction chaque fois que vous construisez la source sur votre hôte de développement. Utilisez la commande suivante pour monter le répertoire target/ dans votre conteneur à /app/. Exécutez la commande depuis le répertoire source. La sous-commande $(pwd) s'étend au répertoire de travail actuel sur les hôtes Linux ou macOS.
Les syntaxes --mount et -v ci-dessous produisent le même résultat. Vous ne pouvez pas les exécuter toutes les deux, sauf si vous supprimez le conteneur devtest après avoir exécuté la première.
# Syntaxe --mount $ docker run -d \ -it \ --name devtest \ --mount type=bind,source="$(pwd)"/target,target=/app \ nginx:latest # Syntaxe -v $ docker run -d \ -it \ --name devtest \ -v "$(pwd)"/target:/app \ nginx:latest
Utilisez docker inspect devtest pour vérifier que le montage bind a été créé correctement. Recherchez la section Mounts :
"Mounts": [
{
"Type": "bind",
"Source": "/tmp/source/target",
"Destination": "/app",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
],
Cela montre que le montage est un bind mount, il montre la source et la destination correctes, il montre que le montage est en lecture-écriture, et que la propagation est définie sur rprivate.
Intruction VOLUME dans un Dockerfile
Il est possible d'utiliser une intruction VOLUME dans un fichier Dockerfile, de la manière suivante :
VOLUME ["/home/user/my_dir"]
L'instruction VOLUME crée un point de montage avec le nom spécifié et le marque comme contenant des volumes montés en externe depuis l'hôte natif ou d'autres conteneurs. La valeur peut être un tableau JSON, VOLUME ["/var/log/"], ou une chaîne simple avec plusieurs arguments, comme VOLUME /var/log ou VOLUME /var/log /var/db.
On notera toutefois qu'aucun volume n'est créé lors du build de l'image ; la création du volume se fera uniquement lorsqu'on génèrera un conteneur à partir de cette image, au moyen de la commande docker run. C'est dans cette commande docker run que l'on pourra préciser, au moyen des instructions -v ou --mount, si l'on doit créer un volume anonyme, un volume nommé ou un bind mount :
- si la commande ne possède aucune instruction
-vou--mount(elle est de la forme :docker run --name my_container my_image), c'est unvolume anonymequi est créé automatiquement, et visible dans le répertoire/var/lib/docker/volumes:
/var/lib/docker/volumes# ls -al
total 60
drwx-----x 3 root root 4096 août 21 12:35 .
drwx--x--x 14 root root 4096 août 21 12:35 ..
drwx-----x 3 root root 4096 août 20 21:28 5dc6dd5c31189b0764f0a31f5c8406d51fa1503d9d73aadcc7cf5118e27104fe
- si la commande possède une instruction
-vou--mountavec un nom de volume (elle est de la forme :docker run --name my_container -v my_vol:/home/user/my_dir my_image), c'est unvolume nomméqui est créé avec le nom déclaré, et visible dans le répertoire/var/lib/docker/volumes:
/var/lib/docker/volumes# ls -al
total 60
drwx-----x 3 root root 4096 août 21 12:35 .
drwx--x--x 14 root root 4096 août 21 12:35 ..
drwx-----x 3 root root 4096 août 20 21:28 my_vol
- si la commande possède une instruction
-vou--mountavec un chemin d'accès à un répertoire dans le système de fichier de l'hôte (elle est de la forme :docker run --name my_container -v /var/www/vhosts/my_host_dir:/home/user/my_dir my_image), c'est unbind mountqui est créé : le contenu du répertoire hôte/var/www/vhosts/my_host_direst mappé dans le conteneur, à l'emplacement prévu/home/user/my_dir. Il est à noter que dans ce cas, ce n'est pas unvolume Dockerqui est créé, mais simplement unbind mountentre un répertoire de l'hôte et un répertoire du conteneur ; on ne peut pas utiliser les commandesDocker CLIpour gérer ce point de montage.