Guillaume Fenollar DevOps et SysAdmin Freelance

Guillaume FENOLLAR

Ingénieur Linux/DevOps Indépendant

− Montpellier −

Les différences entre volumes et mounts dans Docker

Il y a plusieurs façons de stocker de la donnée persistante dans une architecture Docker. L'idée étant bien sûr de ne pas perdre ses données à la destruction de ses conteneurs Docker, qu'elle soit volontaire ou non. En effet, la bonne pratique dans l'utilisation de conteneurs Docker quand un redémarrage du service est requis, est de regénérer un conteneur neuf à partir de son image au lieu de le stopper/redémarrer comme un nouveau-venu serait tenté de faire. Ce comportement est d'ailleurs le seul possible dans le cas d'une infrastructure Kubernetes.

Afin de pouvoir suivre cette bonne pratique, il est indispensable en amont de la création d’un conteneur de décider quelle donnée localiser sur un volume pour la sauvegarder à le recréation du-dit conteneur. Trois options s’offrent alors à nous.

  • Utiliser un bind mount depuis l’hôte
  • Créer un volume Docker
  • Générer une partition tmpfs pour des données non-persistantes

Dans les deux premiers cas, il est possible de monter un même volume dans plusieurs conteneurs, par exemple pour leur offrir un espace d’écriture commun.

Utiliser un bind mount

Il s’agissait de la toute première option disponible. J’ai fait mes armes avec celle-ci et c’est l’option que je continue d’utiliser le plus.

Pour utiliser un bind mount, il faut, à la création d’un conteneur, spécifier un dossier ou fichier avec un chemin absolu après l’option -v, ou utiliser --mount avec un type=bind.

# Cas d'un fichier avec -v
docker run -v /etc/hostname:/etc/hostname bash cat /etc/hostname
# Cas d'un dossier avec -v
docker run -v /srv/telegraf:/srv/telegraf bash find /srv/telegraf
# Cas d'un fichier avec --mount
docker run --mount type=bind,src=/etc/hostname,dst=/etc/hostname bash cat /etc/hostname
# Cas d'un dossier avec --mount
docker run --mount type=bind,src=/srv/telegraf,dst=/srv/telegraf bash find /srv/telegraf

À noter que si la destination est un dossier ou fichier déjà existant, la source se substituera à la destination, de la même manière qu’une partition montée sur un chemin (dossier) existant d’un système Linux ne l’écrasera pas mais le rendra inaccessible.

Utiliser un volume nommé

Un volume nommé est géré entièrement par Docker, quel que soit le système (Linux ou Windows par exemple), c’est donc la solution à privilégier dans le cas de système hétérogènes. Un volume nommé sera créé à la demande si son nom (la source, ou ‘src’) n’existe pas, et sera réutilisé s’il existe.

# Cas d'un dossier avec -v
docker run -v telegraf-conf:/srv/telegraf telegraf
# Cas d'un dossier avec --mount
docker run --mount type=volume,src=telegraf-conf,dst=/srv/telegraf telegraf
Différence très importante avec un bind-mount, si un volume nommé vide est monté sur un conteneur où le point d’accroche (destination) n’est pas vide et contient fichiers et/ou dossiers, alors ces fichiers sont copiés dans le volume hôte en question avant démarrage du conteneur. C’est extrémement pratique dans le cas de bases de données ou autres application ou des fichiers applicatifs initiaux sont présents dans l’image.

Une fois créé, un volume nommé ne sera nettoyé que par une action d’un administrateur, attention à la surutilisation de l’espace !

Dans les coulisses, le volume est tout simplement un dossier, par défaut sous Linux stocké dans /var/lib/docker/volumes. Comme il s’agit d’un objet géré par l’API Docker, plusieurs commandes sont alors accessibles pour la gestion de ces volumes nommés :

docker volume ls →  Lister les volumes
docker volume create →  Créer manuellement un volume (simple dossier vide)
docker volume rm →  Supprimer un volume s'il n'est utilisé par aucun conteneur existant
docker volume prune →  Nettoyer les volumes non utilisés

Générer un espace tmpfs

Seulement disponible sur Linux, cette option permet créer un espace de travail temporaire en mémoire, qui sera donc perdu à l’arrêt du conteneur. Les performances sont alors maximales en sacrifiant toute résilience des données.

Deux façons de créer un tmpfs, utiliser --tmpfs ou --mount. Encore une fois, --mount est plus flexible avec des options de configuration, qui n’existent tout simplement pas avec --tmpfs.

# Cas avec --tmpfs, où on créé un fichier random dans l'espace tmpfs monté
sudo docker run --tmpfs /tmp bash -- dd if=/dev/zero of=/tmp/test bs=1000 count=10000
# Cas avec --mount où on limite la taille et les droits de l'espace partagé en mémoire
sudo docker run --mount type=tmpfs,dst=/tmp/,tmpfs-size=50M,tmpfs-mode=0770 bash

Différences entre -v et –mount

Ces deux options peuvent permettre le même résultat. La version --mount est plus récente, et conseillée pour les débutants car elle ne laisse moins la place aux erreurs.

La syntaxe de -v est plus courte et plus légère :

# Dans le cas d'un bind mount
-v <dossier_hôte>:<dossier_conteneur>[:ro]
# Dans le cas d'un volume nommé
-v <volume_nommé>:<dossier_conteneur>[:ro]

Alors que la syntaxe de –mount est plus complète :

--mount type=bind,src=<source>,dst=<destination>,readonly
--mount type=volume,src=<source>,dst=<destination>
--mount type=tmpfs,dst=<destination>

Avec l’utilisation de bind-mounts, la différence est majeure dans le cas où le volume source n’existe pas :

  • Avec -v, le dossier source est créé s’il n’existe pas. La destination dans le conteneur est également créée, sous forme de dossier systématiquement.
  • Avec --mount, une erreur sera renvoyée si le dossier source n’existe pas On peut donc estimer que l’option --mount est plus propre car ne permettra pas de laisser démarrer un conteneur si typo il y a eu dans la spécification de son bind mount côté hôte.