3.4. Partage de données
Les données des containers en cours d’exécution sont enregistrées dans la couche supérieure inscriptible de leur filesystem. Ces données seront liées au cycle de vie du container, ce qui n’est pas une garantie à long terme, puisque les containers sont susceptibles de se crasher.
De plus, ces données sont difficilement exploitables en dehors du container, et, à l’inverse, les containers pourraient avoir besoin de données situées ailleurs que sur leur système de fichiers. Pour ces raisons, des mécanismes ont été imaginés pour permettre le transfert/partage de fichiers depuis et vers les containers. Nous allons ici en voir deux : les “bind mounts” et les “volumes”.
Une des motivations derrière la conteneurisation étant l’isolation des ressources, il est important de garder en tête que le partage de données va à l’encontre de ce principe d’isolation, et peut donc constituer une faille de sécurité. Il faut donc bien choisir le mécanisme correspondant aux fonctionnalités nécessaires, et prendre les mesures nécessaires pour garantir la sécurité des données et des services.
Le partage des données entre l’hôte et le container
Une première technique consiste à lever partiellement la restriction d’accès au système de fichiers de l’hôte, en permettant à un container d’accéder en lecture et/ou écriture à un répertoire situé en dehors de son namespace. L’accès à ce répertoire est appelé “Bind Mount”.
En pratique, le fichier ou le répertoire ciblé pour le partage va être monté sur le système de fichiers du container, le rendant ainsi disponible aussi bien par l’hôte que par le container. Ce répertoire est donc susceptible d’être modifié par des processus tournant sur les deux “machines”.
Les cas d’utilisation des bind mounts couvrent essentiellement les phases de développement. Ils peuvent être utilisés pour permettre à l’utilisateur d’accéder aux fichiers du container depuis la machine hôte, éventuellement via des éditeurs de texte ou IDEs plus ergonomiques que ce qui est disponible dans un container.
Cela peut être par exemple le cas d’un développeur Web travaillant sur un site web, site lui-même déployé dans un container pour pouvoir être testé en direct. Ou encore, les bind mounts peuvent servir pour accéder à un répertoire de configuration et débugger des configurations directement dans le container, sans devoir reconstruire une image et relancer un nouveau container à chaque modification.
Dans la commande ci-dessous, correspondant à la situation illustrée plus haut, un bind mount est créé pour pouvoir travailler sur les fichiers web gérés par un serveur nginx. Le type du montage est “bind”, la source est le répertoire src dans le répertoire courant de l’hôte et la destination est le répertoire /app à la racine du container.
docker run -d \
--name web \
--mount type=bind,source="$(pwd)"/src,target=/app nginx
Notez que le répertoire source doit être spécifié comme chemin absolu, ce qui rend l’utilisation de ce mécanisme dépendante de l’OS de l’hôte.
Quant au répertoire de destination sur le container, s’il existe déjà, son éventuel contenu sera écrasé par le contenu du répertoire source. C’est assez logiquement le répertoire sur l’hôte qui est considéré comme persistant, et qui subsistera même en cas de disparition du container.
Comme n’importe quel répertoire de l’hôte pourrait être utilisé pour un tel partage, même des répertoires sensibles, et que le container peut les modifier, il faut utiliser ce mécanisme avec beaucoup de prudence!
Partage de données entre containers
Une autre technique, fonctionnellement plus riche, plus souple et plus sécurisée que les bind mounts, consiste à attribuer un répertoire spécifique au partage de données, et à laisser Docker en assumer la gestion et le contrôle d’accès.
Cela permet d’en limiter l’accès à l’hôte, et d’en faciliter l’utilisation, par exemple via l’utilisation d’un nom de volume plutôt que d’un chemin d’accès spécifique à l’hôte. Un tel stockage dédié s’appelle un “volume”. En plus de leur souplesse et de leur inter-opérabilité, les volumes sont également plus performants que les bind mounts sur les systèmes Windows ou MacOs utilisant Docker Desktop, car ils sont stockés dans la VM. Ils sont également plus sécurisés que les bind mounts car ils n’existent que dans un répertoire spécifique de l’hôte (ou de la VM), non critique et géré par Docker.
Les volumes servent typiquement à sauvegarder les données des containers, ou à les partager entre containers pouvant éventuellement tourner simultanément. On stockera ainsi souvent les répertoires contenant les fichiers de données des bases de données dans un volume, afin d’éviter de les perdre en cas de crash du SGBD.
Enfin, dans des cas plus complexes, des containers tournant sur des machines différentes peuvent avoir besoin d’utiliser un stockage partagé. Les volumes peuvent être créés sur des stockages partagés et/ou distants (systèmes de fichiers réseaux ou services cloud).
Contrairement aux bind mounts, lorsqu’un volume est monté sur un répertoire possédant déjà du contenu sur le container, les données ne sont pas écrasées mais seront au contraire copiées dans le volume.
Les volumes sont des objets qui sont créés et manipulés explicitement via des commandes Docker (ou via l’API) :
docker volume create <vol-name>
docker volume ls
docker volume inspect <vol-name>
docker volume rm <vol-name>
Récapitulatif des cas d’utilisation des Bind Mount et des volumes
Les Bind Mounts sont adéquats dans les cas suivants :
- le partage de fichiers de configuration entre l’hôte et le container. C’est par exemple le cas du fichier /etc/resolv.conf qui est par défaut “mappé” sur le fichier correspondant de l’hôte.
- le partage de code source ou d’artefact entre un environnement de développement sur la machine du développeur et le container sur lequel le code est exécuté
- lorsqu’on est certain que le chemin du répertoire partagé de l’hôte existera toujours
Quant aux volumes, on les utilisera quand :
- il faut partager des données entre plusieurs containers et ces données doivent persister au delà du cycle de vie du/des containers qui l’utilisent
- lorsque l’on n’est pas sûr que l’hôte possède le chemin préconisé pour le répertoire partagé (ex : utilisation de Docker sur des OS différentes)
- les données doivent être stockées de manière distante (stockage cloud).
Illustration
Reprenons notre exemple d’une application web constituée d’un container pour le serveur web et un autre pour la DB.
L’utilisateur souhaite accéder facilement aux fichiers de son site web avec son IDE, à des fins de développement et de débugging. Il va donc, dans ce cas de figure, utiliser un “bind mount” pour que les fichiers soient accessibles depuis l’hôte. Pour la DB, un volume est plus adéquat, car les fichiers seront isolés de l’hôte et gérés par Docker.
<figcaption>
Voici un exemple de commandes qui permettent de créer les deux containers et les lier aux données nécessaires, selon les deux types de partage vus plus haut.
docker run -d \
--name web \
--mount type=bind,source="$(pwd)"/src,target=/app nginx
docker volume create db-vol
docker run -d \
--name db \
--mount source=db-vol,target=/var/lib/mysql \
mysql:latest