Nous continuons notre série d’articles et de tutoriels Docker avec cet article et dans celui-ci nous allons aborder le Docker volume.
Lorsque l’on exécute une application, qu’elle soit conteneurisée ou non, on génère souvent des données. Ces dernières sont en général utiles lors des prochaines exécutions, ce qui veut dire qu’il est important de les sauvegarder quelque part. En outre, on peut également effectuer des modifications sur l’application une fois que celle-ci est transformée en conteneur. Et dans ce cas-ci, il faut également enregistrer les changements qui sont survenus.
Les volumes Docker sont justement créés afin de gérer ce genre de situation. Dans cet article, nous allons voir ce qu’est exactement docker volume et apprendre à l’utiliser à l’aide d’un mini-tutoriel exhaustif.
Qu’est-ce qu’un volume Docker ?
Docker volume est un mécanisme de fichiers géré par Docker permettant de sauvegarder des données générées lors de l’exécution d’un conteneur. Il permet également de monter les données dont le conteneur a besoin à l’intérieur de ce dernier pour qu’il puisse fonctionner correctement lors de son lancement.
Les volumes ne dépendent pas du cycle de vie du conteneur. Ainsi, on peut l’utiliser lors de la réexécution du conteneur ou le partager à d’autres conteneurs qui en ont besoin. C’est donc le moyen le plus adéquat pour faire persister des données au sein de Docker.
Cette fonctionnalité est souvent utilisée lorsque l’application conteneurisée comporte une base de données afin de sauvegarder les différentes informations d’authentification. Elle est aussi très sollicitée lors des tests d’application, car on peut modifier le code source de cette dernière sans avoir à générer l’image à chaque modification apportée.
Comment fonctionne le système de fichiers de Docker ?
Il faut savoir qu’une image est composée d’un ensemble de couches en lecture seule qu’on appelle Layers. À chaque fois que l’on exécute un conteneur avec cette image, une couche en lecture-écriture s’ajoute à cette pile afin de former ce qu’on appelle l’Union File System. Cette dernière couche permet de faire fonctionner le conteneur correctement. Lorsque l’on effectue des traitements sur le conteneur, Docker ne touche qu’à cette couche supérieure, que ce soit un ajout de fichier, une modification ou une suppression. Cela veut dire que toutes les données sont perdues dès lors que l’on arrête le conteneur.
C’est la raison pour laquelle on opte pour l’utilisation de docker volume afin d’éviter la perte de données nécessaires à l’application conteneurisée.
Pourquoi utiliser Docker volume ?
Outre le fait d’offrir une solution à ce fonctionnement du système de fichier de base qui peut s’avérer problématique, l’utilisation de docker volume offre plusieurs autres avantages à savoir :
- Il est simple à mettre en place. En effet, la création et l’exécution d’un conteneur faisant appel à un volume sont faites à l’aide d’une simple commande ;
- Docker volume prévient les éventuelles erreurs de manipulation. Lorsque les volumes sont stockés à l’intérieur même de Docker, les risques de pertes de données dues par exemple à la suppression accidentelle des données ou au changement de répertoire sont quasi nuls ;
- L’utilisation des volumes permet de séparer le conteneur et les données sans pour autant dédier un conteneur à cet effet, conteneur qui risque de subir lui aussi quelques changements ;
- Puisque les données sont directement accessibles à l’intérieur de Docker, l’accès se fait plus rapidement, ce qui augmente considérablement la performance de l’application conteneurisée ;
- On peut se servir du même volume sur plusieurs conteneurs, qu’ils soient situés sur le même hôte, sur des clusters séparés ou même sur le cloud. D’ailleurs, plusieurs fournisseurs cloud acceptent l’utilisation des volumes. Pareillement, un conteneur peut se servir de différents volumes selon le besoin de l’application au moment voulu. Cela permet donc d’obtenir une application conteneurisée plus polyvalente, sans pour autant changer l’image de base ;
- Les volumes docker sont utilisables, peu importe le système ou la plateforme que l’on utilise.
Comment utiliser Docker volume ?
Dans cette section, nous allons voir sous forme de mini-tutoriel les différentes manières d’utiliser docker volume au sein d’un conteneur.
Créer un volume
Tout d’abord, il faut que nous sachions créer un volume. Pour effectuer cette tâche, la syntaxe à utiliser est la suivante :
docker volume create [nom_du_volume]
Par exemple, créons un volume nommé test-volume et pour cela, nous allons exécuter cette commande :
docker volume create test-volume
Pour vérifier que le volume a bien été créé, on peut lister tous les volumes existants en tapant la commande suivante :
docker volume ls
Comme vous pouvez le constater, notre volume a bien été créé.
Pour obtenir plus de détails sur le volume que nous venons de créer, voici la commande à exécuter :
docker volume inspect test-volume
Avec cette commande, nous obtenons un résultat sous un format JSON contenant les informations sur le volume que nous venons de créer. On retrouve par exemple l’emplacement où il est stocké, son nom, l’hôte, etc.
Exécuter un conteneur avec un volume docker
On peut créer un volume indépendamment d’un conteneur et il existe deux syntaxes permettant de le faire à savoir –mount et -v. Cependant, malgré le fait que ces derniers servent à faire persister les données d’un conteneur, ils présentent quelques différences. En effet, –mount stocke et puise les données au sein même du système hôte. Cette approche présente quelques risques de fausse manipulation ou de perte de données, car on peut toucher par inadvertance le fichier ou le dossier. Par contre, la syntaxe -v, quant à lui, crée un fichier à l’intérieur de docker pour y stocker ces données. Les données sont beaucoup sécurisées de cette manière.
Voici donc les deux commandes permettant de monter un volume lors de l’exécution d’un conteneur :
docker run --name [nom_du_conteneur] --mount source=[lien_de_la_source],destination=[lien_de_destination] [nom_de_l_image]
ou encore :
docker run --name [nom_du_conteneur] -v [lien_de_la_source]:[lien_de_destination] [nom_de_l_image]
Comme vous pouvez le constater, la commande –mount est beaucoup plus explicite tandis que -v utilise une syntaxe propre à docker. Pour le reste de ce mini-tutoriel, nous allons utiliser la syntaxe -v afin d’utiliser toute la performance de docker volume.
Prenons comme exemple l’image de l’application que l’on a utilisée pour les précédents tutoriels que nous avons publiés. Le lien de l’application de base est le suivant : https://github.com/docker/getting-started/tree/master/app
Créer le conteneur
Pour construire le conteneur, créer tout d’abord un fichier vide et sans extension nommé dockerfile et coller les instructions suivantes à l’intérieur de ce dernier :
FROM node:12-alpine
WORKDIR /app
RUN apk add --no-cache python2 g++ make
COPY . .
RUN yarn install --production
CMD ["node", "src/index.js"]
EXPOSE 3000
Maintenant, à l’aide de ce dockerfile, créons une image avec la commande suivante :
docker build -t mon-image .
Une fois notre image prête, essayons tout d’abord de le lancer avec cette commande :
docker run -dp 3000:3000 mon-image
Pour vérifier que tout marche parfaitement, on peut se rendre sur un navigateur et taper le lien localhost:3000 :
Nous allons maintenant arrêter le conteneur et pour cela, il faut récupérer l’ID du conteneur avec la commande docker ps puis exécuter la commande suivante :
docker stop 311b5f3a291b
où 311b5f3a291b est l’ID en question.
Exécuter un conteneur avec un volume
À présent, nous allons relancer notre conteneur, mais cette fois-ci, en l’exécutant avec un volume. Pour ce faire, il faut exécuter la commande suivante :
docker run -dp 3000:3000 -v test-volume:/etc/todos mon-image
Si vous vous rendez sur le lien précédent, vous verrez que l’application fonctionne. Cependant, puisque lors du lancement précédent, nous n’avons pas utilisé de volume, toutes nos insertions sont perdues.
Ajoutez quelques éléments à notre application, stoppez le conteneur et relancez-le. Vous verrez que les données que vous avez précédemment ajoutées sont toujours visibles.
Monter un volume dans docker-compose
Il est également possible de spécifier le volume dans un docker compose. Docker compose est un moyen de lancer une application multiconteneur à l’aide d’une seule commande. Parfois, ce genre d’application nécessite des données à persister. Pour ce faire, il suffit d’ajouter le paramètre volume à l’intérieur du fichier docker-compose.yml qui gère le lancement des conteneurs liés à l’application.
Pour illustrer cela, nous allons toujours utiliser l’application de l’exemple précédent. Toutefois, nous allons y effectuer quelques modifications. Nous allons tout d’abord ajouter un autre conteneur nommé nginx avec son fichier conf et son dockerfile. Les instructions pour le fichier nginx.conf sont :
server {
listen [::]:80;
listen 80;
server_name nodeserver;
charset utf-8;
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://nodeserver:3000;
}
}
Et celles pour le dockerfile sont :
FROM nginx
COPY nginx.conf /etc/nginx/conf.d/default.conf
Nous allons ensuite créer le fichier docker-compose.yml et y ajouter les lignes de codes suivantes :
version: "3.8"
services:
nodeserver:
build:
context: .
volumes:
- ./src:/app/src
environment:
NODE_ENV: production
ports:
- "3000:3000"
nginx:
restart: always
build:
context: ./nginx
ports:
Ici, le volume sert à stocker le code source de l’application afin que l’on puisse modifier notre application sans avoir à recréer tout le conteneur.
Pour lancer l’application, il faut exécuter la commande suivante puis taper le lien localhost sur un navigateur :
docker-compose up
Maintenant, on va effectuer une modification sur notre code. Et si l’on actualise la page, nous verrons que notre modification a pris effet.
Utiliser un volume en lecture seule
Il faut savoir qu’un volume peut être utilisé par différents conteneurs. Il est donc parfois nécessaire de le protéger afin qu’aucune modification ne soit permise si le conteneur qui se sert de lui n’a pas les autorisations nécessaires pour cela. Donc, utiliser un volume en lecture seule peut s’avérer important dans ce cas-ci.
Pour ce faire, il faut exécuter le conteneur à l’aide de la commande suivante :
docker run -dp -v --name=[nom_du_conteneur] [nom_volume]:[lien_destination]:ro [nom_de_l_image]
C’est le mot-clé ro qui spécifie que le volume sera exécuté en lecture seule.
Si l’on reprend notre exemple précédent, voici la commande à exécuter :
docker run -dp 3000:3000 --name=mon-conteneur -v test-volume:/etc/todos:ro mon-image
Pour vérifier si l’instruction a bien été prise en compte, on peut obtenir le détail de notre conteneur. Pour cela, il faut exécuter la commande suivante :
docker inspect mon-conteneur
Rendez-vous à la section Mounts du résultat et vous verrez que le volume est bien exécuté en readonly.
Supprimer des volumes
Pour supprimer un volume, il suffit de lancer la commande suivante :
docker volume rm [nom_du_volume]
Voilà, nous arrivons à la fin de cet article sur docker volume. Vous connaissez maintenant plusieurs manières de persister des données dans une application conteneurisée. Si vous souhaitez apprendre d’autres fonctionnalités docker, vous pouvez vous rendre sur notre blog, car nous avons plusieurs articles dédiés à cela. Et si vous voulez en apprendre sur le Big Data, nous vous invitons à télécharger gratuitement notre tutoriel sur Spark avec Scala.