Pour gérer vos données persistantes, qui sont générées et utilisées par vos conteneurs, vous allez devoir mettre en place une politique de gestion de votre donnée. Avec par exemple, l'utilisation des volumes. Mais connaissez-vous bien les différentes façon de déclarer un volume ?

Je ne vais pas m'attarder dans cet article sur la création même d'un volume. Mais plus sur les différentes possibilités offertes par Docker pour gérer de la donnée persistante. Nous pourrons ainsi comprendre quand et comment utiliser ces différents types !

Quelles différences existent t-ils par exemple entre ces trois façons de stocker une donnée de façon persistante :

volumes:
        - ./letsencrypt:/letsencrypt
volumes:
        - /letsencrypt
volumes:
        - traefik_ssl:/letsencrypt

Est-ce que ces trois lignes offrent le même résultat ? Que se passe t-il en coulisse dans ces trois cas ? La même chose ?

Pas vraiment, regardons ça de plus près !

Un volume c'est quoi finalement ?

Je vous l'accorde, dans ces trois exemples, le résultat final est le même. Les données seront identiques à l'intérieur de votre conteneur et elles seront présentes sous forme de répertoire ou de fichiers individuels.

Mais je pense qu'il est nécessaire de bien préciser ce qu'est un volume. Car effectivement ( et moi le premier ), nous utilisons parfois cette notion de volume à tord. Et il faut être honnête, la syntaxe de Docker parfois ne nous aide pas à y voir plus clair !

Reprenons tout simplement la description de la documentation sur les volumes :

Volumes are the preferred mechanism for persisting data generated by and used by Docker containers. While bind mounts are dependent on the directory structure of the host machine, volumes are completely managed by Docker.

Retenons tout simplement que les volumes doivent être indépendants d'une structure de dossier de la machine hôte et qu'ils sont managés directement par Docker.

Donc si je reprends mon premier exemple :

volumes:
        - ./letsencrypt:/letsencrypt

Qui peut également s'écrire avec la commande docker run :

docker run -v ./letsencrypt:/letsencrypt

Et bien cette façon de déclarer une donnée persistante n'est pas un volume ... Il s'agit d'un bind mounts ou en français, d'un point de montage. Logique ? Oui ... Mais la documentation n'est pas claire, par exemple :

https://success.docker.com/article/different-types-of-volumes

On parle ici de host volumes ...

Mais la documentation de docker-compose peut nous mettre d'accord :

Compose file version 3 reference
Compose file reference

Voici comment déclarer cet échange de données avec la syntaxe longue d'un volume :

version: "3.8"
services:
  web:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - type: volume <--- Et ici un "volume" 
        source: mydata
        target: /data
        volume:
          nocopy: true
      - type: bind <----------------------- Ici c'est clair !
        source: ./static
        target: /opt/app/static

networks:
  webnet:

volumes:
  mydata:

Est-ce qu'il faut pour autant ne jamais utiliser de bind mounts ? Faut-il privilégier les volumes ?

Bind mounts

Alors quand utiliser un volume en lieu et place d'un bind et vice-versa !

Pour comprendre quand utiliser ce type de stockage, il faut d'abord connaître son principal atout :

Si vous réalisez un bind-mount dans un répertoire existant ( non vide bien sûr ) de votre conteneur, le contenu de ce répertoire va être surchargé par les données de votre point de montage.

De mon côté, j'utilise ce type de montage lorsque j'ai besoin d'accéder et de modifier fréquemment un fichier. Et que mon conteneur lui ne doit pas le modifier ou alors de façon peu fréquente.

Ce type de montage est ainsi principalement utilisé pour accéder à des configurations de votre système, exemple :

/etc/resolv.conf

Globalement, cette utilisation de stockage sera donc privilégié pour les fichiers de configuration.

Mais le gros désavantage de cette solution est donc, d'être dépendant d'un fichier ou d'un répertoire présent sur votre hôte. Pour le côté portabilité de votre application, cela va compliquer votre tâche ...

Les volumes

On pourrait presque dire que dans tous les autres cas, pour stocker vos données, un volume sera nécessaire. Et franchement, c'est presque vrai ! 😂

La documentation Docker apporte la précision suivante autour des volumes :

Volumes have several advantages over bind mounts:

  • Volumes are easier to back up or migrate than bind mounts.
  • You can manage volumes using Docker CLI commands or the Docker API.
  • Volumes work on both Linux and Windows containers.
  • Volumes can be more safely shared among multiple containers.
  • Volume drivers let you store volumes on remote hosts or cloud providers, to encrypt the contents of volumes, or to add other functionality.
  • New volumes can have their content pre-populated by a container.

Je ne vais pas détailler ici comment créer et utiliser un volume. La documentation officielle est explicite sur le sujet :

Use volumes
Using volumes

Il faut juste retenir qu'il existe deux façon de déclarer un volume.

Le volume nominatif :

volumes:
        - traefik_ssl:/letsencrypt

Le volume anonyme :

volumes:
        - /letsencrypt

Aucun intérêt au volume anonyme ? Son intérêt est de posséder un nom forcément unique et géré directement par Docker. Si vous avez une application scalable avec un grand nombre d'instance, ce choix peut être très pertinent.

Enfin il existe encore deux solutions pour stocker des données, ces solutions sont uniquement disponibles sur les hôtes linux ( tmpfs ) et windows ( named pipe ).

Je ne vais pas aborder ce dernier car je manque clairement de retour sur son utilisation... Et je ne parle sur ce blog que de choses que je connais ou que je découvre avec vous ! 😀

TMPFS

Ces points de montage sont stockés uniquement sur la mémoire de l'hôte et ne sont jamais écrits sur le système de fichiers.

Les points de montage tmpfs peuvent être utilisés lorsque vous ne souhaitez pas rendre persistant une donnée sur votre hôte mais la rendre tout de même partageable entre différents conteneurs.

Cela peut être pour des raisons de sécurité mais aussi pour conserver un niveau de performance élevée. Par exemple si votre application a besoin d'écrire des volumes importants de données qui n'ont pas d'état persistants et sont très souvent modifiés.

Il m'arrive d'utiliser ce point de montage pour de la gestion de cache HTTP avec varnish. Cela permet à mon cache de garder des performances élevées même devant un afflux massif de requêtes.

Alors à quel moment utilisez ces différentes solutions !?

L'utilisation des volumes

Les volumes doivent rester votre choix préféré pour stocker des données persistantes. La plupart des cas d'utilisation vont inclure :

  • Le partage de données entre différents conteneurs.
  • Indépendant vis à vis de votre hôte Docker, les volumes ne sont pas associés à des chemins de votre hôte.
  • Pouvoir stocker vos données sur des hôtes distants ou avec des cloud provider ( je n'ai pas abordé l'utilisation des plugins ).
  • Vos données restent présentent dans le répertoire /var/lib/docker/volumes/<volume-name> , cela vous permet de réaliser des sauvegardes facilement.

Utilisation du bind

Son utilisation n'est pas à privilégier mais peut être nécessaire dans les cas suivants :

  • Partager des fichiers de configuration entre votre hôte et les conteneurs ( DNS avec resolv.conf ou les timezones par exemple ).
  • Faciliter le partage de code entre votre hôte et les conteneurs, dans le cadre d'un environnement de développement.
  • Si votre parc d'hôte est complétement homogène.

Volumes ou bind mounts ?

Afin de faire un choix entre les deux possibilités, gardez les éléments suivants en tête :

  • Si vous montez un  vide dans le répertoire d'un conteneur existant, ces fichiers seront copiés dans votre volume. De même, si vous démarrez votre conteneur avec un volume vers un dossier qui n'existe pas. Celui-ci sera créé automatiquement.
  • Un point de montage de type bind dans un dossier existant sur votre conteneur, va surcharger ce dossier avec le contenu de votre dossier hôte ( c'est finalement très similaire au principe du /mnt sous linux ).

Nous avons donc pu voir au cours de cet article les différentes façon de stocker des données de façon persistantes. Et surtout à quel moment utilisez les différentes solutions mises à dispositions par Docker.

Il s'agit de mon point de vue - et il n'engage que moi et mon expérience - mais je me pose généralement les questions suivantes avant de faire un choix :

  • Est-ce que je dois régulièrement modifier des fichiers en dehors du process de mon conteneur ?
  • Un autre conteneur doit-il accéder aux données ?
  • Fréquence d'accès ( hors processus conteneur ) aux données du volume ?
  • Besoin de sécurité ou de rapidité ?

Le choix du type de volume, n'est pas toujours évident mais le plus important reste de comprendre les principales mécaniques mises à disposition afin de faire le choix le plus judicieux qui se fera aussi en fonction de votre application ... !

En tout cas  n'hésitez pas à m'apporter des remarques ou des commentaires sur Twitter ! C'est toujours un plaisir d'avoir des retours ! 😇