Introduction
Par défaut, tous les fichiers créés à l'intérieur d'un conteneur sont stockés sur une couche de conteneur modifiable. Cela signifie que :
- Si le conteneur n'existe plus, les données sont perdues,
- La couche modifiable du conteneur est étroitement couplée à la machine hôte, et
- Pour gérer le système de fichiers, vous avez besoin d'un pilote de stockage qui fournit un système de fichiers union, utilisant le noyau Linux. Cette abstraction supplémentaire réduit les performances par rapport aux
data volumesqui écrivent directement dans le système de fichiers.
Docker propose deux options pour stocker des fichiers dans la machine hôte : volumes et bind mounts. Si vous exécutez Docker sur Linux, vous pouvez également utiliser un tmpfs mount, et avec Docker sur Windows, vous pouvez également utiliser un named pipe.

- Les
Volumessont stockés dans le système de fichiers hôte géré par Docker. - Les
Bind mountssont stockés n'importe où dans le système hôte. - Les
tmpfs mountssont stockés uniquement en mémoire de l'hôte.
À l'origine, le drapeau --mount était utilisé pour les services Docker Swarm et le drapeau --volume était utilisé pour les conteneurs autonomes. Depuis Docker 17.06 et versions ultérieures, vous pouvez également utiliser --mount pour les conteneurs autonomes et il est généralement plus explicite et verbeux que --volume.
Volumes
Un data volume ou volume est un répertoire qui circule le Union File System de Docker.
Il existe trois types de volumes :
- volume anonyme,
- volume nommé, et
- volume hôte.
Volume anonyme
Créons une instance d'une base de données NoSQL open source populaire appelée CouchDB et utilisons un volume anonyme pour stocker les fichiers de données de la base de données.
Pour exécuter une instance de CouchDB, utilisez l'image CouchDB sur Docker Hub à https://hub.docker.com/_/couchdb. Les docs disent que la valeur par défaut pour CouchDB est d'écrire les fichiers de base de données sur le disque du système hôte en utilisant sa propre gestion de volume interne.
Exécutez la commande suivante :
docker run -d -p 5984:5984 --name my-couchdb -e COUCHDB_USER=admin -e COUCHDB_PASSWORD=passw0rd1 couchdb:3.1
CouchDB créera un volume anonyme et générera un nom haché. Vérifiez les volumes sur votre système hôte :
labex:~/ $ docker volume ls
DRIVER VOLUME NAME
local 1d292aca855adb9de9be7acea88f6d3f8e6a08eef5bfd986a81f073f1906b82f
Définissez une variable d'environnement VOLUME avec la valeur du nom généré :
export VOLUME=<VOLUME NAME>
Et inspectez le volume qui a été créé, utilisez le nom haché généré pour le volume :
$ docker volume inspect $VOLUME
[
{
"CreatedAt": "2020-09-24T14:10:07Z",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/f543c5319ebd96b7701dc1f2d915f21b095dfb35adbb8dc851630e098d526a50/_data",
"Name": "f543c5319ebd96b7701dc1f2d915f21b095dfb35adbb8dc851630e098d526a50",
"Options": null,
"Scope": "local"
}
]
Vous voyez que Docker a créé et gère un volume dans le système de fichiers hôte Docker sous /var/lib/docker/volumes/$VOLUME_NAME/_data. Notez que ce n'est pas un chemin sur la machine hôte, mais une partie du système de fichiers géré par Docker.
Créez une nouvelle base de données mydb et insérez un nouveau document avec un message hello world.
curl -X PUT -u admin:passw0rd1 http://127.0.0.1:5984/mydb
curl -X PUT -u admin:passw0rd1 http://127.0.0.1:5984/mydb/1 -d '{"msg": "hello world"}'
Arrêtez le conteneur et redémarrez le conteneur :
docker stop my-couchdb
docker start my-couchdb
Récupérez le document dans la base de données pour tester que les données ont été conservées.
curl -X GET -u admin:passw0rd1 http://127.0.0.1:5984/mydb/_all_docs
curl -X GET -u admin:passw0rd1 http://127.0.0.1:5984/mydb/1
Sortie :
## $ curl -X GET -u admin:passw0rd1 http://127.0.0.1:5984/mydb/_all_docs
{"total_rows":1,"offset":0,"rows":[
{"id":"1","key":"1","value":{"rev":"1-c09289617e06b96bc747fb1201fea7f1"}}
]}
## $ curl -X GET -u admin:passw0rd1 http://127.0.0.1:5984/mydb/1
{"_id":"1","_rev":"1-c09289617e06b96bc747fb1201fea7f1","msg":"hello world"}
Partage de volumes
Vous pouvez partager un volume anonyme avec un autre conteneur en utilisant l'option --volumes-from.
Créez un conteneur busybox avec un volume anonyme monté sur un répertoire /data dans le conteneur et, en utilisant des commandes shell, écrivez un message dans un fichier de journal.
$ docker run -it --name busybox1 -v /data busybox sh
/ ## echo "hello from busybox1" > /data/hi.log
/ ## ls /data
hi.log
/ ## exit
Vérifiez que le conteneur busybox1 est arrêté mais pas supprimé.
labex:~/ $ docker ps -a | grep busybox1
f4dbf9ee7513 busybox "sh" 2 minutes ago Exited (0) About a minute ago busybox1
Ensuite, créez un deuxième conteneur busybox nommé busybox2 en utilisant l'option --volumes-from pour partager le volume créé par busybox1 :
$ docker run --rm -it --name busybox2 --volumes-from busybox1 busybox sh
/ ## ls -al /data
total 12
drwxr-xr-x 2 root root 4096 Jan 23 07:20.
drwxr-xr-x 1 root root 4096 Jan 23 07:24..
-rw-r--r-- 1 root root 20 Jan 23 07:20 hi.log
/ ## cat /data/hi.log
hello from busybox1
/ ## exit
Docker a créé le volume anonyme que vous avez pu partager en utilisant l'option --volumes-from et a créé un nouveau volume anonyme.
labex:~/ $ docker volume ls
DRIVER VOLUME NAME
local 0f971b2477d5fc0d0c2b31fc908ee59d6b577b4887e381964650ce6853890dc9
local 1d292aca855adb9de9be7acea88f6d3f8e6a08eef5bfd986a81f073f1906b82f
Nettoyez les volumes et les conteneurs existants.
docker stop my-couchdb
docker rm my-couchdb
docker rm busybox1
docker volume rm $(docker volume ls -q)
docker system prune -a
clear
Volume nommé
Un volume nommé et un volume anonyme sont similaires en ce sens que Docker gère où ils sont situés. Cependant, un volume nommé peut être référencé par son nom lors de son montage sur un répertoire de conteneur. Cela est utile si vous voulez partager un volume entre plusieurs conteneurs.
Tout d'abord, créez un volume nommé :
docker volume create my-couchdb-data-volume
Vérifiez que le volume a été créé :
$ docker volume ls
DRIVER VOLUME NAME
local my-couchdb-data-volume
Maintenant, créez le conteneur CouchDB nommé my-couchdb-name-vol en utilisant le volume nommé :
docker run -d -p 59840:5984 --name my-couchdb-name-vol -v my-couchdb-data-volume:/opt/couchdb/data -e COUCHDB_USER=admin -e COUCHDB_PASSWORD=passw0rd1 couchdb:3.1
Attendez que le conteneur CouchDB soit en cours d'exécution et que l'instance soit disponible.
Créez une nouvelle base de données mydb et insérez un nouveau document avec un message hello world.
curl -X PUT -u admin:passw0rd1 http://127.0.0.1:59840/mydb
curl -X PUT -u admin:passw0rd1 http://127.0.0.1:59840/mydb/1 -d '{"msg": "hello world"}'
Il est maintenant facile de partager le volume avec un autre conteneur. Par exemple, lisez le contenu du volume en utilisant l'image busybox et partagez le volume my-couchdb-data-volume en montant le volume sur un répertoire dans le conteneur busybox.
labex:~/ $ docker run --rm -it --name busybox -v my-couchdb-data-volume:/myvolume busybox sh
/ #
/ ## ls -al /myvolume
total 40
drwxr-xr-x 4 5984 5984 4096 Jan 23 07:30.
drwxr-xr-x 1 root root 4096 Jan 23 07:31..
drwxr-xr-x 2 5984 5984 4096 Jan 23 07:29.delete
-rw-r--r-- 1 5984 5984 8388 Jan 23 07:30 _dbs.couch
-rw-r--r-- 1 5984 5984 8385 Jan 23 07:29 _nodes.couch
drwxr-xr-x 4 5984 5984 4096 Jan 23 07:30 shards
/ ## exit
Vous pouvez vérifier le système de fichiers géré par Docker pour les volumes en exécutant un conteneur busybox avec des autorisations privilégiées et en définissant l'identifiant de processus sur host pour inspecter le système hôte et naviguer vers les répertoires gérés par Docker.
docker run -it --privileged --pid=host busybox nsenter -t 1 -m -u -n -i sh
/ ## ls -l /var/lib/docker/volumes
total 28
-rw------- 1 root root 32768 Nov 10 15:54 metadata.db
drwxr-xr-x 3 root root 4096 Nov 10 15:54 my-couchdb-data-volume
/ ## exit
Nettoyage :
docker stop my-couchdb
docker rm my-couchdb
docker volume rm my-couchdb-data-volume
docker system prune -a
docker volume prune
clear
Volume hôte
Lorsque vous voulez accéder facilement au répertoire de volume depuis la machine hôte directement au lieu d'utiliser les répertoires gérés par Docker, vous pouvez créer un volume hôte.
Utilisons un répertoire dans le répertoire de travail actuel (indiqué avec la commande pwd) appelé data, ou choisissez votre propre répertoire de données sur la machine hôte, par exemple /home/couchdb/data. Nous laissons Docker créer le répertoire $(pwd)/data s'il n'existe pas encore. Nous montons le volume hôte à l'intérieur du conteneur CouchDB sur le répertoire de conteneur /opt/couchdb/data, qui est le répertoire de données par défaut pour CouchDB.
Exécutez la commande suivante :
cd /home/labex/project
docker run -d -p 5984:5984 --name my-couchdb -v $(pwd)/data:/opt/couchdb/data -e COUCHDB_USER=admin -e COUCHDB_PASSWORD=passw0rd1 couchdb:3.1
Vérifiez qu'un répertoire data a été créé :
$ ls -al
total 20
drwxrwxr-x 3 labex labex 4096 Aug 29 14:14.
drwxr-x--- 25 labex labex 4096 Aug 29 14:14..
drwxr-xr-x 3 5984 5984 4096 Aug 29 14:14 data
et que CouchDB a créé des fichiers de données ici :
$ ls -al data
total 32
drwxr-xr-x 3 5984 5984 4096 Aug 29 14:14.
drwxrwxr-x 3 labex labex 4096 Aug 29 14:14..
-rw-r--r-- 1 5984 5984 4257 Aug 29 14:14 _dbs.couch
drwxr-xr-x 2 5984 5984 4096 Aug 29 14:14.delete
-rw-r--r-- 1 5984 5984 8385 Aug 29 14:14 _nodes.couch
Vérifiez également qu'aucun volume géré n'a été créé par docker, car nous utilisons maintenant un volume hôte.
docker volume ls
et
docker run -it --privileged --pid=host busybox nsenter -t 1 -m -u -n -i sh
sh-5.1## ls -l /var/lib/docker/volumes
total 28
brw------- 1 root root 252, 3 Jan 23 15:15 backingFsBlockDev
-rw------- 1 root root 32768 Jan 23 15:33 metadata.db
drwx-----x 3 root root 4096 Jan 23 15:26 my-couchdb-data-volume
sh-5.1## exit
Créez une nouvelle base de données mydb et insérez un nouveau document avec un message hello world.
curl -X PUT -u admin:passw0rd1 http://127.0.0.1:5984/mydb
curl -X PUT -u admin:passw0rd1 http://127.0.0.1:5984/mydb/1 -d '{"msg": "hello world"}'
Notez que CouchDB a créé un dossier shards :
$ ls -al data
total 40
drwxr-xr-x 4 5984 5984 4096 Aug 29 14:15.
drwxrwxr-x 3 labex labex 4096 Aug 29 14:14..
-rw-r--r-- 1 5984 5984 8388 Aug 29 14:15 _dbs.couch
drwxr-xr-x 2 5984 5984 4096 Aug 29 14:14.delete
-rw-r--r-- 1 5984 5984 8385 Aug 29 14:14 _nodes.couch
drwxr-xr-x 4 5984 5984 4096 Aug 29 14:15 shards
Liste le contenu du répertoire shards :
$ ls -al data/shards
total 16
drwxr-xr-x 4 5984 5984 4096 Aug 29 14:15.
drwxr-xr-x 4 5984 5984 4096 Aug 29 14:15..
drwxr-xr-x 2 5984 5984 4096 Aug 29 14:15 00000000-7fffffff
drwxr-xr-x 2 5984 5984 4096 Aug 29 14:15 80000000-ffffffff
et le premier shard :
$ ls -al data/shards/00000000-7fffffff/
total 20
drwxr-xr-x 2 5984 5984 4096 Aug 29 14:15.
drwxr-xr-x 4 5984 5984 4096 Aug 29 14:15..
-rw-r--r-- 1 5984 5984 8346 Aug 29 14:15 mydb.1693289721.couch
Un shard est une partition horizontale des données dans une base de données. La partitionnement des données en shards et la distribution des copies de chaque shard sur différents nœuds dans un cluster confère une plus grande durabilité aux données face à la perte d'un nœud. CouchDB sharde automatiquement les bases de données et distribue les sous-ensembles de documents entre les nœuds.
Nettoyage :
docker stop my-couchdb
docker rm my-couchdb
sudo rm -rf $(pwd)/data
docker system prune -a
Bind Mounts
La syntaxe mount est recommandée par Docker plutôt que la syntaxe volume. Les bind mounts ont une fonctionnalité limitée par rapport aux volumes. Un fichier ou un répertoire est référencé par son chemin complet sur la machine hôte lorsqu'il est monté dans un conteneur. Les bind mounts dépendent de la structure de répertoire spécifique du système de fichiers de la machine hôte et vous ne pouvez pas utiliser l'interface de ligne de commande Docker pour gérer les bind mounts. Notez que les bind mounts peuvent modifier le système de fichiers hôte via des processus exécutés dans un conteneur.
Au lieu d'utiliser la syntaxe -v avec trois champs séparés par le séparateur deux-points (:), la syntaxe mount est plus verbeuse et utilise plusieurs paires clé-valeur :
- type : bind, volume ou tmpfs,
- source : chemin vers le fichier ou le répertoire sur la machine hôte,
- destination : chemin dans le conteneur,
- readonly,
- bind-propagation : rprivate, private, rshared, shared, rslave, slave,
- cohérence : cohérente, déléguée, mise en cache,
- montage.
cd /home/labex/project
mkdir data
docker run -it --name busybox --mount type=bind,source="$(pwd)"/data,target=/data busybox sh
Tapez la commande dans le conteneur :
echo "hello busybox" > /data/hi.txt
exit
Vérifiez que le fichier a été créé sur la machine hôte.
cat data/hi.txt
[Optionnel] OverlayFS
OverlayFS est une implémentation de union mount filesystem pour Linux. Pour comprendre ce qu'est un volume Docker, il est utile de comprendre comment les couches et le système de fichiers fonctionnent dans Docker.
Pour démarrer un conteneur, Docker prend l'image en lecture seule et crée une nouvelle couche en lecture-écriture au-dessus. Pour visualiser les couches comme une seule, Docker utilise un système de fichiers Union ou OverlayFS (Overlay File System), plus précisément le pilote de stockage overlay2.
Pour voir les fichiers gérés par l'hôte Docker, vous avez besoin d'accéder au système de fichiers du processus Docker. En utilisant les drapeaux --privilégié et --pid=host, vous pouvez accéder à l'espace de noms d'identifiant de processus de l'hôte depuis l'intérieur d'un conteneur comme busybox. Vous pouvez ensuite naviguer vers le répertoire /var/lib/docker/overlay2 de Docker pour voir les couches téléchargées qui sont gérées par Docker.
Pour afficher la liste actuelle des couches dans Docker :
$ docker run -it --privilégié --pid=host busybox nsenter -t 1 -m -u -n -i sh
/ ## ls -l /var/lib/docker/overlay2
total 16
drwx------ 3 root root 4096 Sep 25 19:44 0e55ecaa4d17c353191e68022d9a17fde64fb5e9217b07b5c56eb4c74dad5b32
drwx------ 5 root root 4096 Sep 25 19:44 187854d05ccd18980642e820b0d2be6a127ba85d8ed96315bb5ae37eb1add36d
drwx------ 4 root root 4096 Sep 25 19:44 187854d05ccd18980642e820b0d2be6a127ba85d8ed96315bb5ae37eb1add36d-init
drwx------ 2 root root 4096 Sep 25 19:44 l
/ ## exit
Téléchargez l'image ubuntu et vérifiez à nouveau :
docker pull ubuntu
docker run -it --privilégié --pid=host busybox nsenter -t 1 -m -u -n -i sh
Tapez la commande pour voir à nouveau la liste des couches :
ls -l /var/lib/docker/overlay2/ & exit
Vous voyez que le téléchargement de l'image ubuntu a implicitement téléchargé 4 nouvelles couches :
- a611792b4cac502995fa88a888261dfba0b5d852e72f9db9e075050991423779
- d181f1a41fc35a45c16e8bfcb8eee6f768f3b98f82210a43ea65f284a45fcd65
- dac2f37f6280a076836d39b87b0ae5ebf5c0d386b6d8b991b103aadbcebaa7c6
- f3e921b440c37c86d06cd9c9fb70df50edad553c36cc87f84d5eeba734aae709
Le pilote de stockage overlay2 combine en fait différents répertoires sur l'hôte et les présente comme un seul répertoire.
- couche de base ou lowerdir,
- couche
diffou upperdir, - couche d'overlay (vue de l'utilisateur), et
- répertoire
work.
OverlayFS réfère aux répertoires inférieurs comme lowerdir, qui contient l'image de base et les couches en lecture seule (R/O) qui sont téléchargées.
Le répertoire supérieur est appelé upperdir et est la couche de conteneur en lecture-écriture (R/W).
La vue unifiée ou couche overlay est appelée merged.
Enfin, un workdir est requis, qui est un répertoire vide utilisé par overlay pour son utilisation interne.
Le pilote overlay2 prend en charge jusqu'à 128 couches OverlayFS inférieures. Le répertoire l contient des identifiants de couche raccourcis sous forme de liens symboliques.

Nettoyage :
docker system prune -a
clear
Résumé
Dans ce laboratoire, vous avez appris à gérer les données dans les conteneurs en utilisant les volumes et les bind mounts. Vous avez également appris à propos du pilote de stockage overlay2 et à la manière dont il utilise le système de fichiers union pour gérer les couches.