Persister les données d'un conteneur
Préambule
Question:
Comment gérer la persistance des données dans un conteneur Docker ?
En effet, tous les modifications aux fichiers d’un conteneur sont annulées lorsque celui-ci est recréé. Il y a des cas où il est important de conserver ces modifications, par exemple pour garder en mémoire les changements dans une base de données.
Aussi, Picasoft n'utilise pas la directive VOLUME des Dockerfile
.
Quels dossiers persister ?
La première étape est d’identifier les dossiers ou fichiers qui ont besoin de persistance. En général, ce sont les dossiers qui vont contenir les données du service.
Note:
On entend donnée au sens large :
- Messages des utilisateurs
- Configuration de l’application
- Extensions installées
- etc.
En bref, tout ce qu’on ne veut pas perdre et qui n’est pas dans l’image de base.
Principe général
Une fois que l’on a identifié les fichiers ou dossiers qui ont besoin de persistence, il y a plusieurs manières de procéder :
- Utiliser un dossier de l’hôte comme stockage, via un bind mount,
- Utiliser un volume Docker.
Chacun a ses avantages et inconvénients, voilà ce que l’on fait chez Picasoft :
- Pour monter un ou des fichiers existants dans un conteneur, on utilise un bind mount,
- Pour assurer la persistance d’un dossier du conteneur, qui est initialement vide, on utilise un volume Docker.
Cas particulier
Ce paragraphe va un peu semer la confusion, désolé.
Note:
Les volumes Docker sont situés dans /var/lib/docker/volumes
, en interne. En général, sur les machines qui accueillent des services publics, /var/lib/docker
est sur une partition qui utilise le SSD, pour obtenir de bonnes performances.
Or, certains services demandent un stockage assez conséquent, notamment lorsqu’il s’agit de médias. Dans ce cas, il est préférable d’utiliser une partition provenant d’un HDD. La capacité des SSD est beaucoup plus faible et pas forcément pertinente pour stocker des vidéos.
Dans le cas précis où :
- On veut persister des médias de grande taille dans un conteneur
- Que
/var/lib/docker
est stocké sur un SSD
Alors on utilisera un bind-mount sur un dossier qui utilise un HDD. Le chemin du dossier à monter sera donc codé en dur et sera absolu, ce qui est dommage, mais on a pas le choix.
Note:
Si la machine virtuelle n’a qu’un seul disque virtuel, qui utilise le SSD (à vérifier dans Proxmox), on pourra ajouter un disque virtuel qui utilise le HDD et monter le système de fichier qu’on créera dans un dossier arbitraire, qui sera utilisé pour le bind mount.
Bind mount
Si le fichier à monter est versionné sur le dépôt, on utilisera un chemin relatif. Sinon, on utilisera des chemins absolus, ce qui enlève du côté “indépendant des machines”, mais parfois on ne peut pas faire autrement. Par exemple, quand des certificats sont stockés sur une machine de production dans un dossier spécifique, on est obligés d’y faire référence.
Important:
Il convient de ne pas monter de volume sensible (par exemple /etc
) dans un conteneur, parce que les conteneurs peuvent par défaut modifier les volumes montés avec des privilèges root
. Ainsi, il ne faut surtout pas monter la socket Docker (/var/run/docker.sock
) dans un conteneur (sauf raison exceptionnelle, i.e. Traefik).
- snippet.yaml
[...] services: exemple: [...] volumes: # Dossier contenant les certificats sur les machines de production : utilisation du chemin absolu - /DATA/docker/certs/example.picasoft.net:/certs # Fichier de configuration versionné dans le même dossier : utilisation du chemin relatif - ./config.json:/etc/config.json
Note:
L’inconvénient des bind mounts est qu’ils dépendent de l’existence d’un dossier sur l’hôte. C’est pourquoi on ne s’en sert pas pour les données, qui lors du premier lancement du conteneur n’existent pas. De plus, ils sont facilement modifiables par d’autres processus de l’hôte, tandis que les volumes Docker sont stockés dans /var/lib/docker/volumes
.
C’est aussi plus facile de contrôler la taille des volumes Docker, en les mettant dans une partition à part. Aussi, ils peuvent être gérés grâce aux commandes docker volume
, et sont donc plus faciles à administrer.
Volumes Docker
Si on veut indiquer qu’un des dossiers du conteneur doit persister au fil des recréations, alors on utilise des volumes Docker. C’est typiquement le cas pour le dossier /var/lib/postgresql/data
d’une base PostgreSQL, qui ne doit pas être remis à zéro à chaque recréation du conteneur.
Exemple :
- snippet.yaml
[...] volumes: # Alias du volume pour le fichier Compose db: # On spécifie le nom exact name: db services: exemple: volumes: # On fait référence au "db" défini ci-dessus, et on le monte sur /mount_point - db:/mount_point
Attention:
Éviter les volumes déclarés external
:
- Un volume créé en dehors de Compose peut être utilisé sans être déclaré
external
; - En revanche un volume non-créé et déclaré
external
fera échouer les commandes Compose.