Voici le dixième volet de la formation Docker. Dans mon précédent article, nous avons construit nos premières images de conteneurs. Aujourd’hui nous allons voir en détail la gestion des volumes avec Docker et leur montage dans un ou plusieurs conteneurs.
Quel est l’intérêt des volumes ?
En règle générale, les images sont construites de manière à ce que les conteneurs basés sur elles soient compacts, portables et jetables.
Les images ne contiennent généralement que les paquets indispensables pour fournir le service prévu par l’image. Les petits fichiers de configuration qui changent rarement sont également inclus dans ces images.
Il vaut mieux pouvoir se débarrasser d’un conteneur sans pour autant craindre de perdre les données importantes. Dans la mesure du possible, il faut éviter que les données d’un conteneur – la partie data si l’on veut – résident uniquement dans le conteneur.
Dans ce cas, si vous voulez rendre persistantes – ou sauvegarder – les données générées ou utilisées par un conteneur, il faudra utiliser un volume.
Si vous souhaitez partager des données entre plusieurs conteneurs, un volume est également le meilleur choix pour ce genre de cas.
Deux approches différentes
Voyons de plus près les différents types de volumes gérés par Docker.
Dans notre atelier pratique sur l’exposition des ports nous avons utilisé l’option -v
avec la commande docker run
pour définir l’utilisation d’un volume avec le conteneur :
$ mkdir -v ~/pagesweb mkdir: création du répertoire '/home/kikinovak/pagesweb' $ echo '<h1>Le site web de Nico</h1>' > ~/pagesweb/index.html $ docker run --name autre_nginx -d -p 8080:80 \ -v ~/pagesweb:/usr/share/nginx/html:ro nginx 6b456addfb69fb9fe5acdec3dd4e5e7fbad0808edaac0ac28293979b036e4c0d
L’option courte -v
est l’équivalent exact de l’option longue --volume
:
$ docker run --name autre_nginx -d -p 8080:80 \ --volume ~/pagesweb:/usr/share/nginx/html:ro nginx
La nouvelle manière préférée de monter des volumes dans un conteneur est l’option --mount
. Docker recommande d’utiliser --mount
plutôt que -v
ou --volume
. Quoi qu’il en soit, l’une ou l’autre méthode fonctionne parfaitement. Puisque --mount
est la méthode recommandée à l’avenir, c’est celle que nous allons voir plus en détail.
Créer un volume
On utilisera la sous-commande docker volume
pour gérer les volumes :
$ docker volume --help Usage: docker volume COMMAND Manage volumes Commands: create Create a volume inspect Display detailed information on one or more volumes ls List volumes prune Remove all unused local volumes rm Remove one or more volumes Run 'docker volume COMMAND --help' for more information on a command.
Créez un premier volume :
$ docker volume create testdata testdata
Vérifiez s’il a bien été créé :
$ docker volume ls DRIVER VOLUME NAME local testdata
Si vous voyez une liste de volumes avec des noms à coucher dehors, invoquez la commande docker volume prune
pour faire un peu de ménage. Cette commande supprime tous les volumes locaux qui ne sont pas en cours d’utilisation.
Supprimez le volume testdata
:
$ docker volume rm testdata testdata $ docker volume ls DRIVER VOLUME NAME
À présent, créez un nouveau volume mesdata1
:
$ docker volume create mesdata1 mesdata1 $ docker volume ls DRIVER VOLUME NAME local mesdata1
Pour en savoir plus sur un volume, utilisez la commande inspect
:
$ docker volume inspect mesdata1 [ { "CreatedAt": "2023-07-07T07:20:35+02:00", "Driver": "local", "Labels": null, "Mountpoint": "/var/lib/docker/volumes/mesdata1/_data", "Name": "mesdata1", "Options": null, "Scope": "local" } ]
Notez que nous voyons ici l’emplacement réel du volume dans l’arborescence du système de fichiers de l’hôte. En l’occurrence, les données stockées dans le volume mesdata1
sont enregistrées dans le répertoire /var/lib/docker/volumes/mesdata1/_data
du système hôte.
Attacher un volume
La prochaine étape consiste à démarrer un conteneur en attachant un volume à ce conteneur de manière à ce que le conteneur ait accès aux données du volume :
$ docker run -d --name avecvolume --mount \ source=mesdata1,destination=/root/volume nginx b15b836717e9d4462ffbebcdbe6fb111f86490a0bedc9b21ad25aab142091f8a
Veillez à ne pas utiliser d’espaces dans les arguments à --mount
.
Inspectez le conteneur et jetez un œil à la section Mounts
:
$ docker inspect avecvolume | grep -A 10 Mounts
...
"Mounts": [
{
"Type": "volume",
"Name": "mesdata1",
"Source": "/var/lib/docker/volumes/mesdata1/_data",
"Destination": "/root/volume",
"Driver": "local",
"Mode": "z",
"RW": true,
"Propagation": ""
}
- La section
Mounts
nous affiche que/root/volume
est la destination du volume à l’intérieur du conteneur, avec des droits en lecture/écriture comme indiqué par la ligne"RW": true
. - Le chemin d’accès
/var/lib/docker/volumes/mesdata1/_data
correspond au chemin du volume que Docker a mis en place sur le disque du système hôte. C’est donc la source.
Utiliser les abréviations
Au lieu d’utiliser source=
et destination=
, nous pouvons utiliser les formes brèves correspondantes src=
et dst=
:
$ docker run -d --name avecvolume --mount src=mesdata1,dst=/root/volume nginx
On peut également utiliser target=
au lieu de destination=
ou dst=
.
Supprimer un volume
Lorsque vous arrêtez un conteneur, le volume reste intact, et vous devez le supprimer séparément si vous le souhaitez. Pour ce faire, vous utiliserez la commande docker volume rm
avec le nom du volume en argument.
Ajouter un fichier depuis l’hôte
Ajoutez un fichier au volume depuis le système hôte :
$ echo 'Coucou depuis le volume mesdata1 !' | > sudo tee /var/lib/docker/volumes/mesdata1/_data/index.html Coucou depuis le volume mesdata1 !
Utilisez la commande exec
pour vous connecter au conteneur et vérifiez si le fichier index.html
se trouve bien à l’emplacement attendu :
$ docker exec -it avecvolume bash root@480fadc6bbb2:/# cd /root/volume root@480fadc6bbb2:~/volume# ls -l total 4 -rw-r--r--. 1 root root 35 Jul 7 05:35 index.html root@480fadc6bbb2:~/volume# cat index.html Coucou depuis le volume mesdata1 ! root@480fadc6bbb2:~/volume# exit
Un volume pour plusieurs conteneurs
Docker permet de monter le même volume sur plusieurs conteneurs. Essayez :
$ docker run -d --name avecvolume2 --mount \ src=mesdata1,dst=/root/volume nginx 046c17291d106720eca84ab5bbf60370406c676a884b7a5eb852d7dde8b8307b $ docker exec -it avecvolume2 bash root@046c17291d10:/# cat /root/volume/index.html Coucou depuis le volume mesdata1 ! root@046c17291d10:/# exit
Un volume en lecture seule
Admettons que vous ne voulez pas que le conteneur puisse modifier le contenu d’un volume donné. Autrement dit, vous souhaitez que le conteneur accède au volume en lecture seule :
$ docker run -d --name conteneurenlecture --mount \ src=nouveauvolume,dst=/usr/share/nginx/html,ro nginx 8b5210c998c4d33a80cc1cfbc4a85510cfc2cb4b454ce8e209e487a353703fc9
Si le volume n’existe pas lors du lancement du conteneur, Docker se charge de le créer automatiquement :
$ docker volume ls DRIVER VOLUME NAME local mesdata1 local nouveauvolume
Inspectez la section Mounts
de ce conteneur :
$ docker inspect conteneurenlecture | grep -A 10 Mounts
...
"Mounts": [
{
"Type": "volume",
"Name": "nouveauvolume",
"Source": "/var/lib/docker/volumes/nouveauvolume/_data",
"Destination": "/usr/share/nginx/html",
"Driver": "local",
"Mode": "z",
"RW": false,
"Propagation": ""
}
Notez bien le paramètre "RW": false
qui indique que le conteneur est en lecture seule. L’utilisation de cette option fait partie des bonnes pratiques en matière de sécurité lorsque l’accès en écriture n’est pas requis. Ainsi, lorsqu’un conteneur est compromis dans le contexte d’une attaque informatique, les données du ou des volumes correspondants restent intactes.
Vous pouvez très bien autoriser certains conteneurs à accéder en lecture/écriture à un volume donné, alors que d’autres conteneurs n’y accèderont qu’en lecture seule. En effet, la possibilité d’écrire sur un volume est définie au niveau du conteneur et non pas au niveau du volume.
Vérifions si notre volume est effectivement monté en lecture seule à l’intérieur du conteneur :
$ docker exec -it conteneurenlecture bash root@8b5210c998c4:/# touch /usr/share/nginx/html/test touch: cannot touch '/usr/share/nginx/html/test': Read-only file system root@8b5210c998c4:/# exit
Utiliser un volume éphémère
Lorsqu’on utilise des volumes qui sont censés être détruits après utilisation, on peut très bien utiliser ce qu’on appelle les volumes éphémères de type tmpfs
. Voici à quoi cela peut ressembler :
$ docker run -dit --name ephemere --mount \ type=tmpfs,dst=/root/volume nginx 943e634f246a34c97c6e4b239204232239598d8c947aa7668319b41673e13af3
Jetez un œil dans la section Mounts
de ce conteneur et notez bien le type tmpfs
:
$ docker inspect ephemere | grep -A 10 Mounts
...
"Mounts": [
{
"Type": "tmpfs",
"Source": "",
"Destination": "/root/volume",
"Mode": "",
"RW": true,
"Propagation": ""
}
Un volume éphémère à taille prédéfinie
Vous pouvez prédéfinir une taille statique pour un volume éphémère, ce qui vous permet de garder le contrôle sur l’espace disque utilisé :
$ docker run -dit --name ephemere2 --mount \ type=tmpfs,tmpfs-size=256M,dst=/root/volume nginx a7bf7dec6fb5da992800d18db81ba2229fe0a29c7d1205b0f31314d26b32a1a9
Vérifions si l’espace disque de notre volume éphémère est effectivement limité à 256 Mo :
$ docker exec -it ephemere2 df -h
Filesystem Size Used Avail Use% Mounted on
overlay 1.8T 457G 1.3T 27% /
tmpfs 64M 0 64M 0% /dev
tmpfs 7.8G 0 7.8G 0% /sys/fs/cgroup
shm 64M 0 64M 0% /dev/shm
/dev/md127 1.8T 457G 1.3T 27% /etc/hosts
tmpfs 256M 0 256M 0% /root/volume
tmpfs 7.8G 0 7.8G 0% /proc/asound
tmpfs 7.8G 0 7.8G 0% /proc/acpi
tmpfs 7.8G 0 7.8G 0% /proc/scsi
tmpfs 7.8G 0 7.8G 0% /sys/firmware
Du point de vue du conteneur, nous ne pouvons pas ajouter plus de 256 Mo de données dans /root/volume
.
L’utilisation de volumes éphémères est considéré comme une bonne pratique lorsqu’on a besoin d’espace de stockage temporaire pour un conteneur et qu’on souhaite faire le ménage une fois que le conteneur s’arrête.
Utiliser l’approche classique
Même si l’option --mount
est la méthode recommandée pour gérer les volumes, l’option -v
reste une syntaxe valide, et vous la verrez régulièrement dans la documentation :
$ docker run -dit -p 8080:80 --name nginx-avec-vol \ -v ~/pagesweb:/usr/share/nginx/html:ro nginx f3eedd7b4ba996626aa096a8608ca536ab613b5bdadbcaaa28572f10602da1d8
Inspectez la section Mounts
de ce conteneur :
$ docker inspect nginx-avec-vol | grep -A 10 Mounts
...
"Mounts": [
{
"Type": "bind",
"Source": "/home/kikinovak/pagesweb",
"Destination": "/usr/share/nginx/html",
"Mode": "ro",
"RW": false,
"Propagation": "rprivate"
}
Notez le type de montage bind
qui correspond à l’ancienne méthode pour accéder aux répertoires du système hôte. Ce genre de volume offre moins de fonctionnalités que l’option --mount
.
Un brin de ménage
Arrêtez tous les conteneurs en état de marche :
$ docker stop nginx-avec-vol ephemere ephemere2 \ conteneurenlecture avecvolume avecvolume2 nginx-avec-vol ephemere ephemere2 conteneurenlecture avecvolume avecvolume2
Supprimez tous ces conteneurs :
$ docker rm nginx-avec-vol ephemere ephemere2 \ conteneurenlecture avecvolume avecvolume2 nginx-avec-vol ephemere ephemere2 conteneurenlecture avecvolume avecvolume2
Affichez les volumes disponibles sur notre système :
$ docker volume ls DRIVER VOLUME NAME local mesdata1 local nouveauvolume
Supprimez ces volumes :
$ docker volume rm mesdata1 nouveauvolume mesdata1 nouveauvolume
Exercice 1
- Créez un volume nommé
volumelocal
. - Inspectez le volume et déterminez l’emplacement exact où seront stockées les données du volume sur le système hôte.
- Créez un fichier texte
fichier.txt
dans le volume, avec le contenuCe fichier existe
. - Démarrez un conteneur détaché nommé
montagevolume
basé sur l’image du serveur web Apachehttpd
. Montez le volumevolumelocal
dans le répertoire/data
du conteneur. - Connectez-vous au conteneur
montagevolume
avec un shell Bash. - Vérifiez si le volume est disponible à l’intérieur du conteneur.
- Vérifiez si le fichier
fichier.txt
existe. - Affichez le contenu de ce fichier.
- Depuis le conteneur, créez un fichier texte
conteneur.txt
avec le contenuCoucou depuis le conteneur
. - Toujours depuis le conteneur, vérifiez si le fichier a été créé correctement.
- Détachez-vous du conteneur.
- Vérifiez l’existence et le contenu du fichier
conteneur.txt
depuis le système hôte.
Exercice 2
- Lancez un conteneur détaché nommé
ephemere
et basé sur l’image du serveur Web Apachehttpd
. Attachez un volume éphémère d’une taille de 128 Mo au répertoire/tempdata
du conteneur. - Inspectez le conteneur en affichant les caractéristiques du volume éphémère.
- Connectez-vous au conteneur et affichez la taille de
/tempdata
.
Lire la suite : Conteneurs et réseaux
La rédaction de cette documentation demande du temps et des quantités significatives de café espresso. Vous appréciez ce blog ? Offrez un café au rédacteur en cliquant sur la tasse.
0 commentaire