Docker et les volumes de données (2/2)

Avec le premier article nous avons pu créer des volumes de données et les exploiter dans nos conteneurs. Maintenant, que se passe-t-il lorsque le conteneur doit être détruit pour être remplacer par un autre ? Que deviennent les données considérées comme « persistantes » ? Comme nous l’avons vu, le volume de données ne sera pas détruit automatiquement par Docker. Le volume sera donc « orphelin ».

Dans ce deuxième article sur la gestion des données persistantes avec Docker, nous allons voir ce qui tourne autour du recyclage des volumes, des conteneurs de données et des volumes nommés.

Recyclage d’un volume

Vous avez lancé un conteneur avec un volume de données. Vous détruisez le conteneur. Avec Docker, il est possible de rattacher ce volume « orphelin » au nouveau conteneur que vous aurez créé.

Exemple, je crée un conteneur avec un volume /mydata :

# docker run -d -v /mydata debian:stable /bin/sleep infinity
708ee12a0318242ec515c5eaea856c207670f596fe504a6d9b08bae8c85fde55

Je récupère l’identifiant du volume (paramètre Name) :

# docker inspect 708
        "Mounts": [
            {
                "Name": "5153a7014ed42e49e37132f7ce610d484161a1dc461bcb33e5436ee6f91b7e0b",
                "Source": "/var/lib/docker/volumes/5153a7014ed42e49e37132f7ce610d484161a1dc461bcb33e5436ee6f91b7e0b/_data",
                "Destination": "/mydata",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ],

Je détruit le conteneur :

# docker rm -f 708

Le volume existe toujours :

# ls -l /var/lib/docker/volumes/5153a7014ed42e49e37132f7ce610d484161a1dc461bcb33e5436ee6f91b7e0b
total 4
drwxr-xr-x 2 root root 4096 Oct 11 23:21 _data

J’y crée un fichier :

# touch /var/lib/docker/volumes/5153a7014ed42e49e37132f7ce610d484161a1dc461bcb33e5436ee6f91b7e0b/_data/JeSuisRecycle

Pour utiliser ce volume dans un nouveau conteneur, il me suffit de l’indiquer dans l’option -v, comme pour monter un répertoire du serveur hôte Docker dans un conteneur :

# docker run -d -v 5153a7014ed42e49e37132f7ce610d484161a1dc461bcb33e5436ee6f91b7e0b:/mydata debian:stable /bin/sleep infinity
a18b4a75bde36e1ef875b825c6c9a02dd15e7d4b3d74151f05a44116c6bdad43

J’ai ici monté le volume dans le répertoire /mydata du conteneur. Si je regarde à l’intérieur, je dois retrouver le fichier que j’ai créé précédemment :

# docker exec a18 ls -l /mydata
total 0
-rw-r--r-- 1 root root 0 Oct 11 21:27 JeSuisRecycle

C’est bien le cas ! Le volume « orphelin » a ainsi été recyclé sur un nouveau conteneur qui peut alors travailler avec les données du conteneur précédent.

Les conteneurs de données

La méthode précédente à l’inconvénient de devoir gérer la couche « basse » du volume. Pour rattacher un volume existant, je dois trouver son nom « physique » à travers les arborescences Docker. Une pratique courante dans le monde des conteneurs Docker est d’utiliser plutôt la notion de « conteneur de données » (Data Volume Container officiellement)

Un conteneur de données est un conteneur auquel est attaché un volume et qui ne fait rien d’autre. Il n’a même pas besoin d’être démarré. Il représente en fait une couche d’abstraction supplémentaire au-dessus du volume. Ainsi, les autres conteneurs ne vont plus attachés un volume mais un conteneur de données. L’utilisateur n’a donc pas à se préoccuper du volume et de son emplacement physique sur le serveur hôte Docker. Ce type de conteneur est parfois appelé Data Only Container.

Par exemple je crée un conteneur, sans le démarrer, et j’y attache un volume :

# docker create -v /mydata --name mystore debian:stable
8b542b3ddf4fe9394972bfee6f0d6e6257c5c683e3caa939464317820b81cd12

Ce conteneur baptisé mystore sera mon conteneur de données. Je lance maintenant un nouveau conteneur qui utilise le volume /mydata à partir du conteneur de données mystore :

# docker run -d --volumes-from mystore debian:stable /bin/sleep infinity
e4a3cca106a1cf4d9210f956546ab323f11ea8dbb798140568406e477bd6425c

Normalement, ce nouveau conteneur doit contenir le répertoire correspondant au volume /mydata du conteneur de données :

# docker exec e4a ls -l /mydata
total 0

C’est bien le cas ! Le premier conteneur auquel est attaché le volume est appelé « conteneur de données ». Je n’ai pas à préciser le nom du volume, le nom du conteneur de données seul suffit. Je peux ensuite créer autant de conteneurs que je le souhaite en rattachant toujours ce même conteneur de données.

Par exemple, j’ajoute un fichier dans le volume à travers du conteneur précédent :

# docker exec e4a touch /mydata/monfichier

Et je crée encore un autre conteneur qui utilise le volume attaché au conteneur de données mystore :

# docker run -d --volumes-from mystore debian:stable /bin/sleep infinity
52074e5cd3db3625a470e346e4827e4a8da66c8e9d84ac4440f94d3d2b73965b

Si je regarde le contenu du répertoire /mydata de ce nouveau conteneur, je vais retrouver mon fichier créé précédemment :

# docker exec 520 ls -l /mydata
total 0
-rw-r--r-- 1 root root 0 Oct 11 21:42 monfichier

Ainsi par cette méthode, le volume /mydata attaché au conteneur de données mystore peut être utilisé par tout un tas de nouveaux conteneurs, sans avoir à se préoccuper directement du volume.

Attention à la cohérence des données si plusieurs conteneurs écrivent dans le même volume !

Les volumes nommés

La version 1.9 de Docker amène une nouveauté dans la gestion des volumes : le volume nommé. Désormais, lorsque l’on crée un conteneur et qu’on y rattache un volume, on peut définir explicitement le nom du volume plutôt que de se retrouver avec une chaine de 64 caractères. Quel intérêt ? L’intérêt principal est de pouvoir plus facilement manipuler ce volume entre différents conteneurs non permanents.

Rappelez-vous du début de cet article dans lequel nous recyclions un volume. Il fallait d’abord inspecter le conteneur pour trouver cette fameuse chaine de caractères aléatoires. Et si le conteneur avait été supprimé avant de noter le nom du volume, c’était perdu ! Le volume nommé reprend en fait les avantages du conteneur de données vu précédemment sans ses inconvénients. L’avantage de faire abstraction des informations techniques et aléatoires du volume sans l’inconvénient d’avoir des conteneurs data only qui ne sont finalement que des coquilles vides.

Pour créer un volume un volume nommé lors du lancement d’un conteneur, on utilise toujours l’option -v en spécifiant d’abord le nom du volume, puis son point de montage dans le conteneur. Exemple :

# docker run -d -v myvol:/var/log debian:stable /bin/sleep infinity
9e8c6376b312983d16868ee1db42c84ad3d67a6b407cfc09542bda5d9286855b

J’ai ici lancé un conteneur avec un volume nommé myvol qui sera monté à l’intérieur du conteneur dans /var/log. Si j’inspecte le conteneur, je vois que le nom et la source du volume ne comporte plus une chaine de 64 caractères mais le nom myvol :

# docker inspect 9e8
        "Mounts": [
            {
                "Name": "myvol",
                "Source": "/var/lib/docker/volumes/myvol/_data",
                "Destination": "/var/log",
                "Driver": "local",
                "Mode": "z",
                "RW": true,
                "Propagation": "rslave"
            }
        ],

Il n’est pas obligatoire de lancer un conteneur pour créer un volume. Un volume peut être créé directement par la commande docker volume create [--name <volume name>]. On peut aussi voir la liste de tous les volumes créés avec la commande docker volume ls.

Je peux désormais utiliser le nom de volume que j’ai défini pour l’ajouter facilement à d’autres conteneurs. Par exemple, je crée un nouveau conteneur en montant le même volume que précédemment :

# docker run -d -v myvol:/var/log debian:stable /bin/sleep infinity
a21724d1f638484667aa8b28b28e0437e2382d3c8145fc65e78e2949203d2742

C’est exactement la même commande que précédemment. Les deux conteneurs 9e8 et a21 partagent le même volume myvol monté chacun dans leur répertoire /var/log respectif.

Mon usage des volumes Docker

Pour ma part je jongle entre les différentes possibilités offertes par les volumes Docker selon mes besoins :

  • pour des données que je veux externaliser mais qui ne sont pas persistantes au-delà de la durée de vie du ou des conteneur(s) (par exemple, des logs ou fichiers de configuration), je crée simplement des volume anonymes (voir la première partie de l’article)
  • j’ai parfois besoin de partager des données de mon serveur hôte Docker dans un conteneur, j’utilise alors la fonctionnalité permettant de monter un répertoire comme volume de données (voir la première partie de l’article)
  • j’ai abandonné l’usage des conteneurs de données au profit des volumes nommés pour les cas de données qui ont une durée de vie supérieure à leur(s) conteneur(s) de rattachement (par exemple, une base de données)

Voilà pour un tour des fonctionnalités offertes par les volumes Docker à travers ces deux articles. Il y aurait bien d’autres choses à en dire, cela viendra probablement dans d’autres articles 🙂

Laisser un commentaire