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

Volumes

Les volumes sont des magasins de données persistants pour les conteneurs, créés et gérés par Docker. Vous pouvez créer un volume explicitement en utilisant la commande docker volume create, ou Docker peut créer un volume pendant la création du conteneur ou du service.

Lorsque vous créez un volume, il est stocké dans un répertoire sur l'hôte Docker. Lorsque vous montez le volume dans un conteneur, ce répertoire est ce qui est monté dans le conteneur. Ceci est similaire à la façon dont fonctionnent les montages bind, sauf que les volumes sont gérés par Docker et sont isolés de la fonctionnalité centrale de la machine hôte.

Quand utiliser les volumes

Les volumes sont le mécanisme préféré pour persister les données générées par et utilisées par les conteneurs Docker. Bien que les montages bind dépendent de la structure de répertoire et du système d'exploitation de la machine hôte, les volumes sont complètement gérés par Docker. Les volumes sont un bon choix pour les cas d'usage suivants :

  • Les volumes sont plus faciles à sauvegarder ou migrer que les montages bind.
  • Vous pouvez gérer les volumes en utilisant les commandes CLI Docker ou l'API Docker.
  • Les volumes fonctionnent sur les conteneurs Linux et Windows.
  • Les volumes peuvent être partagés plus sûrement entre plusieurs conteneurs.
  • Les nouveaux volumes peuvent avoir leur contenu pré-rempli par un conteneur ou une construction.
  • Lorsque votre application nécessite des E/S haute performance.

Les volumes ne sont pas un bon choix si vous devez accéder aux fichiers depuis l'hôte, car le volume est complètement géré par Docker. Utilisez les montages bind si vous devez accéder aux fichiers ou répertoires depuis les conteneurs et l'hôte.

Les volumes sont souvent un meilleur choix que l'écriture de données directement dans un conteneur, car un volume n'augmente pas la taille des conteneurs qui l'utilisent. L'utilisation d'un volume est également plus rapide ; l'écriture dans la couche modifiable d'un conteneur nécessite un pilote de stockage pour gérer le système de fichiers. Le pilote de stockage fournit un système de fichiers union, utilisant le noyau Linux. Cette abstraction supplémentaire réduit les performances par rapport à l'utilisation des volumes, qui écrivent directement dans le système de fichiers de l'hôte.

Si votre conteneur génère des données d'état non persistantes, envisagez d'utiliser un montage tmpfs pour éviter de stocker les données de manière permanente, et pour augmenter les performances du conteneur en évitant d'écrire dans la couche modifiable du conteneur.

Les volumes utilisent la propagation de liaison rprivate (privée récursive), et la propagation de liaison n'est pas configurable pour les volumes.

Cycle de vie d'un volume

Le contenu d'un volume existe en dehors du cycle de vie d'un conteneur donné. Lorsqu'un conteneur est détruit, la couche modifiable est détruite avec lui. L'utilisation d'un volume assure que les données persistent même si le conteneur qui l'utilise est supprimé.

Un volume donné peut être monté dans plusieurs conteneurs simultanément. Lorsqu'aucun conteneur en cours d'exécution n'utilise un volume, le volume est toujours disponible pour Docker et n'est pas supprimé automatiquement. Vous pouvez supprimer les volumes inutilisés en utilisant docker volume prune.

Montage d'un volume sur des données existantes

Si vous montez un volume non vide 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, et ensuite 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.

Si vous montez un volume vide dans un répertoire du conteneur dans lequel des fichiers ou répertoires existent, ces fichiers ou répertoires sont propagés (copiés) dans le volume par défaut. De même, si vous démarrez un conteneur et spécifiez un volume qui n'existe pas déjà, un volume vide est créé pour vous. C'est un bon moyen de pré-remplir des données dont un autre conteneur a besoin.

Pour empêcher Docker de copier les fichiers préexistants d'un conteneur dans un volume vide, utilisez l'option volume-nocopy, voir Options pour --mount.

Volumes nommés et anonymes

Un volume peut être nommé ou anonyme. Les volumes anonymes reçoivent un nom aléatoire qui est garanti être unique dans un hôte Docker donné. Tout comme les volumes nommés, les volumes anonymes persistent même si vous supprimez le conteneur qui les utilise, sauf si vous utilisez le drapeau --rm lors de la création du conteneur, auquel cas le volume anonyme associé au conteneur est détruit. Voir Supprimer les volumes anonymes.

Si vous créez plusieurs conteneurs consécutivement qui utilisent chacun des volumes anonymes, chaque conteneur crée son propre volume. Les volumes anonymes ne sont pas réutilisés ou partagés entre conteneurs automatiquement. Pour partager un volume anonyme entre deux ou plusieurs conteneurs, vous devez monter le volume anonyme en utilisant l'ID de volume aléatoire.

Syntaxe

Pour monter un volume avec la commande docker run, vous pouvez utiliser soit le drapeau --mount soit --volume.

$ docker run --mount type=volume,src=<nom-volume>,dst=<chemin-montage>
$ docker run --volume <nom-volume>:<chemin-montage>

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.

Vous devez utiliser --mount si vous voulez :

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=volume[,src=<nom-volume>],dst=<chemin-montage>[,<clé>=<valeur>...]

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

Option Description
source, src La source du montage. Pour les volumes nommés, c'est le nom du volume. Pour les volumes anonymes, ce champ est omis.
destination, dst, target Le chemin où le fichier ou répertoire est monté dans le conteneur.
volume-subpath Un chemin vers un sous-répertoire dans le volume à monter dans le conteneur. Le sous-répertoire doit exister dans le volume avant que le volume soit monté dans un conteneur. Voir Monter un sous-répertoire de volume.
readonly, ro Si présent, fait que le volume est monté dans le conteneur en lecture seule.
volume-nocopy Si présent, les données à la destination ne sont pas copiées dans le volume si le volume est vide. Par défaut, le contenu à la destination cible est copié dans un volume monté s'il est vide.
volume-opt Peut être spécifié plus d'une fois, prend une paire clé-valeur constituée du nom de l'option et de sa valeur.
Exemple
$ docker run --mount type=volume,src=monvolume,dst=/data,ro,volume-subpath=/foo

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 [<nom-volume>:]<chemin-montage>[:opts]

Dans le cas des volumes nommés, le premier champ est le nom du volume, et est unique sur une machine hôte donnée. Pour les volumes anonymes, le premier champ est omis. 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 volume de données incluent :

Option Description
readonly, ro Si présent, fait que le volume est monté dans le conteneur en lecture seule.
volume-nocopy Si présent, les données à la destination ne sont pas copiées dans le volume si le volume est vide. Par défaut, le contenu à la destination cible est copié dans un volume monté s'il est vide.
Exemple
$ docker run -v monvolume:/data:ro

Créer et gérer des volumes

Contrairement à un montage bind, vous pouvez créer et gérer des volumes en dehors de la portée de tout conteneur.

Créer un volume :

$ docker volume create my-vol

Lister les volumes :

$ docker volume ls

local               my-vol

Inspecter un volume :

$ docker volume inspect my-vol
[
    {
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/my-vol/_data",
        "Name": "my-vol",
        "Options": {},
        "Scope": "local"
    }
]

Supprimer un volume :

$ docker volume rm my-vol

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 exemples -v et --mount suivants produisent le même résultat. Vous ne pouvez pas les exécuter tous les deux à moins de supprimer le conteneur devtest et le volume myvol2 après avoir exécuté le premier.

$ docker run -d \
  --name devtest \
  --mount source=myvol2,target=/app \
  nginx:latest
$ docker run -d \
  --name devtest \
  -v myvol2:/app \
  nginx:latest

Utilisez docker inspect devtest pour vérifier que Docker a créé le volume et qu'il est monté correctement. Regardez la section Mounts :

"Mounts": [
    {
        "Type": "volume",
        "Name": "myvol2",
        "Source": "/var/lib/docker/volumes/myvol2/_data",
        "Destination": "/app",
        "Driver": "local",
        "Mode": "",
        "RW": true,
        "Propagation": ""
    }
],

Cela montre que le montage est un volume, cela montre la source et la destination 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 séparée.

$ docker container stop devtest

$ docker container rm devtest

$ docker volume rm myvol2

Utiliser un volume avec Docker Compose

L'exemple suivant montre un seul service Docker Compose avec un volume :

services:
  frontend:
    image: node:lts
    volumes:
      - myapp:/home/node/app
volumes:
  myapp:

Exécuter docker compose up pour la première fois crée un volume. Docker réutilise le même volume lorsque vous exécutez la commande par la suite.

Vous pouvez créer un volume directement en dehors de Compose en utilisant docker volume create et ensuite le référencer dans compose.yaml comme suit :

services:
  frontend:
    image: node:lts
    volumes:
      - myapp:/home/node/app
volumes:
  myapp:
    external: true

Pour plus d'informations sur l'utilisation des volumes avec Compose, consultez la section Volumes dans la spécification Compose.

Démarrer un service avec des volumes

Lorsque vous démarrez un service et définissez un volume, chaque conteneur de service utilise son propre volume local. Aucun des conteneurs ne peut partager ces données si vous utilisez le pilote de volume local. Cependant, certains pilotes de volume supportent le stockage partagé.

L'exemple suivant démarre un service nginx avec quatre répliques, chacune utilisant un volume local appelé myvol2.

$ docker service create -d \
  --replicas=4 \
  --name devtest-service \
  --mount source=myvol2,target=/app \
  nginx:latest

Utilisez docker service ps devtest-service pour vérifier que le service fonctionne :

$ docker service ps devtest-service

ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE            ERROR               PORTS
4d7oz1j85wwn        devtest-service.1   nginx:latest        moby                Running             Running 14 seconds ago

Vous pouvez supprimer le service pour arrêter les tâches en cours d'exécution :

$ docker service rm devtest-service

Supprimer le service ne supprime aucun volume créé par le service. La suppression de volume est une étape séparée.

Peupler un volume en utilisant un conteneur

Si vous démarrez un conteneur qui crée un nouveau volume, et que le conteneur a des fichiers ou répertoires dans le répertoire à monter tel que /app/, Docker copie le contenu du répertoire dans le volume. Le conteneur monte ensuite et utilise le volume, et les autres conteneurs qui utilisent le volume ont également accès au contenu pré-rempli.

Pour le démontrer, l'exemple suivant démarre un conteneur nginx et peuple le nouveau volume nginx-vol avec le contenu du répertoire /usr/share/nginx/html du conteneur. C'est là que Nginx stocke son contenu HTML par défaut.

Les exemples --mount et -v ont le même résultat final.

$ docker run -d \
  --name=nginxtest \
  --mount source=nginx-vol,destination=/usr/share/nginx/html \
  nginx:latest
$ docker run -d \
  --name=nginxtest \
  -v nginx-vol:/usr/share/nginx/html \
  nginx:latest

Après avoir exécuté l'un de ces exemples, exécutez les commandes suivantes pour nettoyer les conteneurs et volumes. Notez que la suppression de volume est une étape séparée.

$ docker container stop nginxtest

$ docker container rm nginxtest

$ docker volume rm nginx-vol

Utiliser un volume en lecture seule

Pour certaines applications de développement, le conteneur doit écrire dans le montage bind afin que les changements soient propagés vers l'hôte Docker. À d'autres moments, le conteneur n'a besoin que d'un accès en lecture aux données. Plusieurs conteneurs peuvent monter le même volume. Vous pouvez simultanément monter un seul volume en lecture-écriture pour certains conteneurs et en lecture seule pour d'autres.

L'exemple suivant modifie le précédent. Il monte le répertoire comme un volume en lecture seule, en ajoutant ro à la liste d'options (vide par défaut), après le point de montage dans le conteneur. Lorsque plusieurs options sont présentes, vous pouvez les séparer en utilisant des virgules.

Les exemples --mount et -v ont le même résultat.

$ docker run -d \
  --name=nginxtest \
  --mount source=nginx-vol,destination=/usr/share/nginx/html,readonly \
  nginx:latest
$ docker run -d \
  --name=nginxtest \
  -v nginx-vol:/usr/share/nginx/html:ro \
  nginx:latest

Use docker inspect nginxtest to verify that Docker created the read-only mount correctly. Look for the Mounts section:

"Mounts": [
    {
        "Type": "volume",
        "Name": "nginx-vol",
        "Source": "/var/lib/docker/volumes/nginx-vol/_data",
        "Destination": "/usr/share/nginx/html",
        "Driver": "local",
        "Mode": "",
        "RW": false,
        "Propagation": ""
    }
],

Stop and remove the container, and remove the volume. Volume removal is a separate step.

$ docker container stop nginxtest

$ docker container rm nginxtest

$ docker volume rm nginx-vol

Mount a volume subdirectory

When you mount a volume to a container, you can specify a subdirectory of the volume to use, with the volume-subpath parameter for the --mount flag. The subdirectory that you specify must exist in the volume before you attempt to mount it into a container; if it doesn't exist, the mount fails.

Specifying volume-subpath is useful if you only want to share a specific portion of a volume with a container. Say for example that you have multiple containers running and you want to store logs from each container in a shared volume. You can create a subdirectory for each container in the shared volume, and mount the subdirectory to the container.

The following example creates a logs volume and initiates the subdirectories app1 and app2 in the volume. It then starts two containers and mounts one of the subdirectories of the logs volume to each container. This example assumes that the processes in the containers write their logs to /var/log/app1 and /var/log/app2.

$ docker volume create logs
$ docker run --rm \
  --mount src=logs,dst=/logs \
  alpine mkdir -p /logs/app1 /logs/app2
$ docker run -d \
  --name=app1 \
  --mount src=logs,dst=/var/log/app1,volume-subpath=app1 \
  app1:latest
$ docker run -d \
  --name=app2 \
  --mount src=logs,dst=/var/log/app2,volume-subpath=app2 \
  app2:latest

With this setup, the containers write their logs to separate subdirectories of the logs volume. The containers can't access the other container's logs.

Share data between machines

When building fault-tolerant applications, you may need to configure multiple replicas of the same service to have access to the same files.

shared storage

There are several ways to achieve this when developing your applications. One is to add logic to your application to store files on a cloud object storage system like Amazon S3. Another is to create volumes with a driver that supports writing files to an external storage system like NFS or Amazon S3.

Volume drivers let you abstract the underlying storage system from the application logic. For example, if your services use a volume with an NFS driver, you can update the services to use a different driver. For example, to store data in the cloud, without changing the application logic.

Use a volume driver

When you create a volume using docker volume create, or when you start a container which uses a not-yet-created volume, you can specify a volume driver. The following examples use the rclone/docker-volume-rclone volume driver, first when creating a standalone volume, and then when starting a container which creates a new volume.

Note

If your volume driver accepts a comma-separated list as an option, you must escape the value from the outer CSV parser. To escape a volume-opt, surround it with double quotes (") and surround the entire mount parameter with single quotes (').

For example, the local driver accepts mount options as a comma-separated list in the o parameter. This example shows the correct way to escape the list.

$ docker service create \
 --mount 'type=volume,src=<VOLUME-NAME>,dst=<CONTAINER-PATH>,volume-driver=local,volume-opt=type=nfs,volume-opt=device=<nfs-server>:<nfs-path>,"volume-opt=o=addr=<nfs-address>,vers=4,soft,timeo=180,bg,tcp,rw"'
 --name myservice \
 <IMAGE>

Initial setup

The following example assumes that you have two nodes, the first of which is a Docker host and can connect to the second node using SSH.

On the Docker host, install the rclone/docker-volume-rclone plugin:

$ docker plugin install --grant-all-permissions rclone/docker-volume-rclone --aliases rclone

Create a volume using a volume driver

This example mounts the /remote directory on host 1.2.3.4 into a volume named rclonevolume. Each volume driver may have zero or more configurable options, you specify each of them using an -o flag.

$ docker volume create \
  -d rclone \
  --name rclonevolume \
  -o type=sftp \
  -o path=remote \
  -o sftp-host=1.2.3.4 \
  -o sftp-user=user \
  -o "sftp-password=$(cat file_containing_password_for_remote_host)"

This volume can now be mounted into containers.

Start a container which creates a volume using a volume driver

Note

If the volume driver requires you to pass any options, you must use the --mount flag to mount the volume, and not -v.

$ docker run -d \
  --name rclone-container \
  --mount type=volume,volume-driver=rclone,src=rclonevolume,target=/app,volume-opt=type=sftp,volume-opt=path=remote, volume-opt=sftp-host=1.2.3.4,volume-opt=sftp-user=user,volume-opt=-o "sftp-password=$(cat file_containing_password_for_remote_host)" \
  nginx:latest

Create a service which creates an NFS volume

The following example shows how you can create an NFS volume when creating a service. It uses 10.0.0.10 as the NFS server and /var/docker-nfs as the exported directory on the NFS server. Note that the volume driver specified is local.

NFSv3

$ docker service create -d \
  --name nfs-service \
  --mount 'type=volume,source=nfsvolume,target=/app,volume-driver=local,volume-opt=type=nfs,volume-opt=device=:/var/docker-nfs,volume-opt=o=addr=10.0.0.10' \
  nginx:latest

NFSv4

$ docker service create -d \
    --name nfs-service \
    --mount 'type=volume,source=nfsvolume,target=/app,volume-driver=local,volume-opt=type=nfs,volume-opt=device=:/var/docker-nfs,"volume-opt=o=addr=10.0.0.10,rw,nfsvers=4,async"' \
    nginx:latest

Create CIFS/Samba volumes

You can mount a Samba share directly in Docker without configuring a mount point on your host.

$ docker volume create \
	--driver local \
	--opt type=cifs \
	--opt device=//uxxxxx.your-server.de/backup \
	--opt o=addr=uxxxxx.your-server.de,username=uxxxxxxx,password=*****,file_mode=0777,dir_mode=0777 \
	--name cif-volume

The addr option is required if you specify a hostname instead of an IP. This lets Docker perform the hostname lookup.

Block storage devices

You can mount a block storage device, such as an external drive or a drive partition, to a container. The following example shows how to create and use a file as a block storage device, and how to mount the block device as a container volume.

Important

The following procedure is only an example. The solution illustrated here isn't recommended as a general practice. Don't attempt this approach unless you're confident about what you're doing.

How mounting block devices works

Under the hood, the --mount flag using the local storage driver invokes the Linux mount syscall and forwards the options you pass to it unaltered. Docker doesn't implement any additional functionality on top of the native mount features supported by the Linux kernel.

If you're familiar with the Linux mount command, you can think of the --mount options as forwarded to the mount command in the following manner:

$ mount -t <mount.volume-opt.type> <mount.volume-opt.device> <mount.dst> -o <mount.volume-opts.o>

To explain this further, consider the following mount command example. This command mounts the /dev/loop5 device to the path /external-drive on the system.

$ mount -t ext4 /dev/loop5 /external-drive

The following docker run command achieves a similar result, from the point of view of the container being run. Running a container with this --mount option sets up the mount in the same way as if you had executed the mount command from the previous example.

$ docker run \
  --mount='type=volume,dst=/external-drive,volume-driver=local,volume-opt=device=/dev/loop5,volume-opt=type=ext4'

You can't run the mount command inside the container directly, because the container is unable to access the /dev/loop5 device. That's why the docker run command uses the --mount option.

Example: Mounting a block device in a container

The following steps create an ext4 filesystem and mounts it into a container. The filesystem support of your system depends on the version of the Linux kernel you are using.

  1. Create a file and allocate some space to it:

    $ fallocate -l 1G disk.raw
    
  2. Build a filesystem onto the disk.raw file:

    $ mkfs.ext4 disk.raw
    
  3. Create a loop device:

    $ losetup -f --show disk.raw
    /dev/loop5
    
    Note

    losetup creates an ephemeral loop device that's removed after system reboot, or manually removed with losetup -d.

  4. Run a container that mounts the loop device as a volume:

    $ docker run -it --rm \
      --mount='type=volume,dst=/external-drive,volume-driver=local,volume-opt=device=/dev/loop5,volume-opt=type=ext4' \
      ubuntu bash
    

    When the container starts, the path /external-drive mounts the disk.raw file from the host filesystem as a block device.

  5. When you're done, and the device is unmounted from the container, detach the loop device to remove the device from the host system:

    $ losetup -d /dev/loop5
    

Back up, restore, or migrate data volumes

Volumes are useful for backups, restores, and migrations. Use the --volumes-from flag to create a new container that mounts that volume.

Back up a volume

For example, create a new container named dbstore:

$ docker run -v /dbdata --name dbstore ubuntu /bin/bash

In the next command:

  • Launch a new container and mount the volume from the dbstore container
  • Mount a local host directory as /backup
  • Pass a command that tars the contents of the dbdata volume to a backup.tar file inside the /backup directory.
$ docker run --rm --volumes-from dbstore -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata

When the command completes and the container stops, it creates a backup of the dbdata volume.

Restore volume from a backup

With the backup just created, you can restore it to the same container, or to another container that you created elsewhere.

For example, create a new container named dbstore2:

$ docker run -v /dbdata --name dbstore2 ubuntu /bin/bash

Then, un-tar the backup file in the new container's data volume:

$ docker run --rm --volumes-from dbstore2 -v $(pwd):/backup ubuntu bash -c "cd /dbdata && tar xvf /backup/backup.tar --strip 1"

You can use these techniques to automate backup, migration, and restore testing using your preferred tools.

Supprimer les volumes

Un volume de données Docker persiste après la suppression d'un conteneur. Il y a deux types de volumes à considérer :

  • Les volumes nommés ont une source spécifique depuis l'extérieur du conteneur, par exemple, awesome:/bar.
  • Les volumes anonymes n'ont pas de source spécifique. Par conséquent, lorsque le conteneur est supprimé, vous pouvez demander au démon Docker Engine de les supprimer.

Supprimer les volumes anonymes

Pour supprimer automatiquement les volumes anonymes, utilisez l'option --rm. Par exemple, cette commande crée un volume anonyme /foo. Lorsque vous supprimez le conteneur, Docker Engine supprime le volume /foo mais pas le volume awesome.

$ docker run --rm -v /foo -v awesome:/bar busybox top
Note

Si un autre conteneur lie les volumes avec --volumes-from, les définitions de volume sont copiées et le volume anonyme reste également après la suppression du premier conteneur.

Supprimer tous les volumes

Pour supprimer tous les volumes inutilisés et libérer de l'espace :

$ docker volume prune

Étapes suivantes