Module 9 · 9.1
Français
Comprendre les conteneurs
Module 9: Docker et docker compose · Temps de lecture : 10 minutes
Objectif pédagogique : À l'issue de cette leçon, vous saurez expliquer ce qu'est un conteneur, en quoi il diffère d'une machine virtuelle, où sont conservées les données d'un conteneur et dans quels cas Docker est utile sur votre serveur.
Notions clés : image, conteneur, couche, registry (Docker Hub), tag, digest, namespaces, cgroups, noyau partagé, système de fichiers éphémère, volume, bind mount, publication de port, image officielle
Pourquoi des conteneurs ?
Imaginons que vous souhaitiez faire tourner sur votre VPS une page de statut qui indique si votre site web fonctionne. Le programme est écrit en Node.js, il a besoin d'une version précise de Node.js, ainsi que de quelque deux cents bibliothèques. Sans conteneurs, vous installez tout cela sur votre serveur, à côté de votre serveur web et de votre base de données. Un an plus tard, vous voulez un deuxième programme qui exige une autre version de Node.js. C'est là que les casse-têtes commencent.
Un conteneur résout ce problème. L'auteur du programme livre le programme avec tout ce dont il a besoin, dans un seul paquet : une image. Sur votre serveur, vous lancez cette image en tant que conteneur. Le programme voit ses propres fichiers, son propre Node.js, ses propres bibliothèques, et n'entre pas en conflit avec le reste de votre serveur. Vous n'en voulez plus ? Vous supprimez le conteneur et l'image, et il ne reste rien dans /usr ni dans /etc.
Docker est l'outil le plus connu pour récupérer des images et faire tourner des conteneurs. Il existe des alternatives (Podman, containerd lui-même), mais les notions sont partout les mêmes.
Image, conteneur et registry
Trois mots que vous rencontrerez sans cesse :
- Image : un modèle en lecture seule contenant un système de fichiers (programme, bibliothèques, paramètres) et la commande à lancer. Une image est constituée de couches : une couche de base (par exemple un Debian minimal), par-dessus une couche avec Node.js, puis par-dessus le programme. Deux images ayant la même couche de base partagent cette couche sur votre disque.
- Conteneur : une instance en cours d'exécution (ou arrêtée) d'une image. Au-dessus des couches en lecture seule, le conteneur reçoit sa propre fine couche d'écriture. Vous pouvez lancer dix conteneurs à partir d'une seule image.
- Registry : l'endroit où sont stockées les images, comme Docker Hub (
docker.io) ou la registry de GitHub (ghcr.io). Docker récupère une image avecdocker pull.
Le nom d'une image se présente ainsi :
louislam/uptime-kuma:2
caddy:2
vaultwarden/server:latestLa partie après les deux-points est le tag : une étiquette pour une version. Un tag peut changer : caddy:2 pointe aujourd'hui vers un autre build que dans trois mois, dès qu'une nouvelle version 2.x sort. Si vous voulez fixer précisément l'image que vous utilisez, servez-vous du digest : une empreinte du contenu, comme caddy@sha256:.... Celle-ci ne change jamais. Le tag latest n'est qu'un nom choisi par l'auteur ; il ne signifie pas automatiquement « la dernière version stable » et constitue donc un mauvais choix si vous voulez savoir ce qui tourne.
Pas une machine virtuelle
Un conteneur ressemble à une petite machine virtuelle, mais n'en est pas une. Cette différence est importante pour la sécurité.
| Machine virtuelle (comme votre VPS) | Conteneur | |
|---|---|---|
| Noyau | Son propre noyau | Partage le noyau de l'hôte |
| Démarrage | De quelques secondes à quelques minutes, un système d'exploitation complet | Généralement en une seconde, uniquement le programme |
| Isolation | Par l'hyperviseur, au niveau matériel | Par le noyau : namespaces et cgroups |
| Taille | Des gigaoctets | Souvent de quelques dizaines à quelques centaines de mégaoctets |
Un conteneur est en réalité un processus ordinaire sur votre serveur, que le noyau place dans un environnement isolé :
- les namespaces font en sorte que le processus ait sa propre vue des fichiers, des processus, du réseau et des utilisateurs. Dans le conteneur, le programme semble être le processus numéro 1 et ne voit pas le reste de votre serveur ;
- les cgroups limitent la quantité de processeur et de mémoire qu'il peut utiliser.
Comme tous les conteneurs partagent le même noyau, l'isolation est moins stricte qu'entre deux VPS. Une faille dans le noyau ou un conteneur qui reçoit trop de droits peut atteindre l'hôte. D'où les règles de ce module : n'exécutez que des images en lesquelles vous avez confiance, ne donnez pas aux conteneurs plus de droits que nécessaire, et ne montez jamais /var/run/docker.sock ni / dans un conteneur (leçons 9.3 et 10.2).
Où restent vos données ?
C'est le piège classique des débutants. La couche d'écriture d'un conteneur est éphémère : si vous supprimez le conteneur (par exemple lors d'une mise à jour, leçon 9.4), tout ce que le programme y a écrit disparaît. Les données qui doivent être conservées ont donc leur place en dehors du conteneur :
- Volume : un espace de stockage géré par Docker lui-même (sous
/var/lib/docker/volumes/). Vous lui donnez un nom, par exempleuptime-kuma, et vous le reliez à un dossier dans le conteneur :-v uptime-kuma:/app/data. - Bind mount : un dossier ordinaire de votre serveur que vous montez dans le conteneur :
-v /srv/vaultwarden:/data. Pratique, car vous voyez directement les fichiers et vous les intégrez facilement à votre sauvegarde (module 8).
Un conteneur doté de bons volumes peut être supprimé et recréé sans rien perdre. C'est exactement ainsi que fonctionne une mise à jour : récupérer la nouvelle image, supprimer l'ancien conteneur, lancer un nouveau conteneur sur les mêmes volumes. Intégrez donc les volumes à votre plan de sauvegarde (leçon 8.1).
Publier des ports
Un conteneur dispose de son propre réseau. Un programme web qui écoute sur le port 3001 dans le conteneur n'est pas joignable depuis l'extérieur du serveur, tant que vous ne publiez pas ce port : -p 3001:3001 (port hôte:port conteneur). Attention : sans adresse, Docker publie le port sur toutes les adresses de votre serveur, donc 0.0.0.0 et [::]. Cela signifie qu'il est joignable depuis tout Internet, et Docker le fait en contournant ufw (leçon 9.3). La bonne habitude consiste à publier sur l'interface de bouclage (loopback), -p 127.0.0.1:3001:3001, avec un reverse proxy en https devant (leçon 9.4).
Qui crée l'image ?
Une image est un logiciel écrit par quelqu'un d'autre, qui peut tourner en tant que root sur votre serveur. Vérifiez donc qui en est l'auteur :
- les Docker Official Images (comme
caddy,nginx,postgres) sont maintenues par Docker en collaboration avec les auteurs ; - les images publiées par l'auteur lui-même (comme
louislam/uptime-kumaetvaultwarden/server), reconnaissables au nom indiqué sur le site du projet ; - les images d'inconnus aux noms qui ressemblent aux originaux : à ne pas utiliser.
Utilisez toujours le nom indiqué sur le site officiel du projet, et non le premier résultat d'une recherche.
Quand oui, quand non ?
Docker est pratique pour les programmes que l'auteur livre sous forme d'image, pour les services que vous voulez pouvoir supprimer ou déplacer rapidement, et pour faire tourner côte à côte plusieurs programmes aux exigences différentes. Pour la base de votre serveur (SSH, pare-feu, mises à jour), vous n'utilisez pas de conteneurs. Et un simple site web avec nginx et PHP issus des dépôts de paquets (leçon 7.2) fonctionne très bien sans Docker. Un conteneur ajoute une couche que vous devez comprendre et maintenir à jour ; n'y recourez que s'il apporte quelque chose.
Résumé
- Une image est un modèle en lecture seule composé de couches ; un conteneur en est une instance en cours d'exécution, avec sa propre couche d'écriture.
- Les conteneurs partagent le noyau de l'hôte et sont isolés par les namespaces et les cgroups : plus légers qu'une VM, mais moins strictement séparés.
- La couche d'écriture est éphémère : les données persistantes vont dans un volume ou un bind mount, qui doivent figurer dans votre sauvegarde.
- Un tag peut changer, un digest non ;
latestn'indique pas grand-chose. - Publiez les ports sur 127.0.0.1 et n'utilisez que des images de l'auteur ou des images officielles.
Quiz
Exercice
Exercice O9.1: Conteneur ou pas ? Choisissez deux programmes que vous souhaitez faire tourner sur votre serveur (ou prenez Uptime Kuma et un site WordPress comme exemple). Pour chaque programme, recherchez si l'auteur fournit une image officielle et sous quel nom, quel tag vous choisiriez, quel dossier contient les données persistantes et sur quel port il écoute. Expliquez ensuite si vous le feriez tourner dans un conteneur ou depuis les dépôts de paquets, et pourquoi.
Exercice O9.1: Conteneur ou pas ?
Cet exercice, vous le faites vous-même ; personne ne le vérifie. Cochez ce que vous avez fait et marquez l'exercice comme terminé.
Uptime Kuma : louislam/uptime-kuma avec un tag de version, données dans /app/data, port 3001, publié sur 127.0.0.1 derrière un reverse proxy. Choisissez une image de l'éditeur ou une Official Image, avec un tag de version et un dossier de données nommé.
Vos cases cochées et vos notes restent uniquement dans ce navigateur ; nous ne les envoyons nulle part. Si vous êtes connecté, nous enregistrons dans Mes formations uniquement le fait que vous avez terminé l'exercice.
Pour aller plus loin
- Documentation Docker, What is a container? : https://docs.docker.com/get-started/docker-concepts/the-basics/what-is-a-container/
- Documentation Docker, Volumes : https://docs.docker.com/engine/storage/volumes/
- Documentation Docker, Port publishing and mapping : https://docs.docker.com/engine/network/port-publishing/
- Docker Official Images : https://docs.docker.com/docker-hub/repos/manage/trusted-content/official-images/
