Développer du NetDevOps dans des conteneurs Docker

Une question m’a été posée : « comment développer des applications NetDevOps directement dans des conteneurs ? ». Si la question peut sembler orienter le débat vers des sujets compliqués, il n’en est rien. Il existe une façon très simple de répondre.

Le contexte de la question doit être précisé. Il s’agissait de conteneurs Docker qui tournaient sur une VM Linux Ubuntu 20.04 distante. Les conteneurs étaient lancés avec de la persistance de stockage sur des volumes externes. C’est une bien meilleure pratique que d’utiliser des points de montage dans des répertoires de la VM (Virtual Machine).

Alors que les points de montages dépendent de la structure du répertoire et du système d’exploitation de la machine hôte, les volumes sont entièrement gérés par Docker. Les volumes présentent plusieurs avantages par rapport aux points de montages :

  • Les volumes sont plus faciles à sauvegarder ou à migrer que les points de montages sur des répertoires.
  • Il est possible de gérer les volumes à l’aide des commandes Docker CLI ou de l’API Docker.
  • Les volumes fonctionnent sur les conteneurs Linux et Windows.
  • Les volumes peuvent être partagés de manière plus sûre entre plusieurs conteneurs.
  • Les drivers de volume permettent de stocker des volumes sur des hôtes distants ou des fournisseurs de cloud, de chiffrer le contenu des volumes ou d’ajouter d’autres fonctionnalités.
  • Les nouveaux volumes peuvent avoir leur contenu pré-rempli par un conteneur.
  • Les volumes sur Docker Desktop ont des performances bien supérieures à celles des points de montages des hôtes Mac et Windows.

De plus, les volumes sont souvent un meilleur choix que les données directement stockées dans le conteneur, car un volume n’augmente pas la taille des conteneurs qui l’utilisent et le contenu du volume existe en dehors du cycle de vie d’un conteneur donné.

Pour reproduire la question sous forme d’une expérimentation, il convient de lancer une VM Linux Ubuntu 20.04 sur VMWare (Fusion sur MAC dans le cas démontré ici). Sur cette VM, Docker est installé facilement à l’aide des commandes suivantes :

sudo apt install apt-transport-https ca-certificates curl software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable"
sudo apt install docker-ce
sudo usermod -aG docker ${USER}

Pour démontrer le fonctionnement, l’utilisation d’une simple image nginx suffit à mettre en place le contexte nécessaire. Les commandes Docker sont lancées à la main pour analyser chaque étape, mais un fichier compose pourrait automatiser tout ceci.

Pour créer un volume persistant, la commande docker volume create nginx-vol est utilisée. Pour analyser où Docker a enregistré ce volume, la commande suivante donne les informations : docker volume inspect nginx-vol.

Docker volume inspect
Volume Docker

On peut constater que le volume Docker a été stocké dans /var/lib/docker/volumes. Pour lancer un conteneur nginx qui utilise le volume afin de stocker ses fichiers html, la commande suivante est utilisée : docker run -d --name=nginxtest -p 80:80 -v nginx-vol:/usr/share/nginx/html nginx:latest.

Welcome to nginx
Page d’accueil de nginx

Si on regarde le contenu du volume externe au conteneur, on peut constater que les fichiers qu’utilise le conteneur nginx dans /usr/share/nginx/html sont en fait présents dans le volume.

Contenu du volume Docker
Contenu du volume Docker

L’idée n’est pas d’aller directement travailler dans ce volume car, outre le fait que ce n’est pas une bonne pratique, on se confronterait à des problèmes de droits d’accès en permanence. Chaque fois qu’on interviendra dans le répertoire /usr/share/nginx/html du conteneur, c’est en fait dans le volume persistant que les données seront enregistrées.

Pour le prouver, il convient de commencer à mettre en place la connexion avec Visual Studio Code. Le plugin « Remote Development » continent tous les outils nécessaires. La fonction « Remote-SSH » permet dans un premier temps de se connecter sur la VM qui porte Docker. Ensuite, la fonction « Remote-Containers » permet de visualiser les conteneurs qui sont lancés sur la VM et de se connecter au conteneur nommé nginxtest. L’ouverture du répertoire /usr/share/nginx/html affiche les deux fichiers html disponibles.

Visual Studio Code Conteneur
Contenu du répertoire du conteneur Docker

Une simple modification dans le titre <h1> de la page d’accueil va permettre de mettre en évidence le fonctionnement.

Welcome to nginx by Gilbert
Index.html modifié
Welcome to nginx installed by Gilbert
Page d’accueil de nginx modifiée

Si on vérifie le fichier index.html qui est stocké dans le volume Docker externe, on peut constater que la modification est bien enregistrée.

index.html enregistré dans le Volume Docker
Index.html enregistré dans le volume Docker

Si on détruit le conteneur et qu’on le recrée avec le même volume externe, il retrouvera la donnée telle qu’elle avait été modifiée… CQFD !

Une question complémentaire pourrait se poser : « comment précharger des fichiers sur le conteneur avant même de commencer à développer avec Visual Studio Code ? ».

La méthode la plus répandue consiste à recréer une image dérivée de l’image de base en rajoutant les fichiers désirés. Voici un exemple simple avec l’image nginx sur laquelle on charge un fichier index.html différent de celui d’origine.

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Bootstrap demo</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-0evHe/X+R7YkIZDRvuzKMRqM+OrBnVFBL6DOitfPri4tjfHxaWutUpFmBp4vmVor" crossorigin="anonymous">
  </head>
  <body>
    <h1>Hello, world!</h1>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-pprn3073KE6tl6bjs2QrFaJGz5/SUsLqktiwsUTF55Jfv3qYSDhgCecCxMW52nD2" crossorigin="anonymous"></script>
  </body>
</html>
FROM nginx:latest

COPY ./index.html /usr/share/nginx/html/index.html

Le fichier Dockerfile est exécuté avec la commande : docker build -t mynginx . et la nouvelle image ainsi créée est lancée avec la commandé précédente légèrement modifiée : docker run -d --name=nginxtest -p 80:80 -v nginx-vol:/usr/share/nginx/html mynginx:latest.

Il faut noter que dans la mesure où un des rôles du volume est d’offrir de la persistance de la donnée, si le volume existe déjà avec un fichier index.html, ce dernier sera prioritaire sur celui embarqué dans le conteneur.

La deuxième méthode, très simple et rapide, consiste à utiliser le cli de Docker : docker cp index.html nginxtest:/usr/share/nginx/html et le fichier est copié dans le volume nginx-vol au travers du conteneur.

Si vous essayez de reproduire la même expérience avec Docker Desktop sur MAC, ne cherchez pas le volume sur le File System de votre MAC. Il faut savoir que Docker Desktop fait tourner les conteneurs dans une VM, c’est donc dans cette VM que sont stockés les volumes.