Contexte et besoins
Dans le cadre de mon alternance, le lab interne dispose d’une VM Debian dédiée à l’expérimentation Docker, son hostname est DOCKER-MICROSERVICES. L’objectif de cette intervention est limité mais structurant : comprendre ce qu’est un conteneur, installer Docker proprement depuis le dépôt officiel, et valider l’installation avec deux conteneurs typiques (hello-world puis nginx).
Je veux comprendre concrètement la différence entre une image et un conteneur, comment Docker récupère ses images depuis le Hub, et comment exposer un service sur un port de l’hôte. Pas encore de Dockerfile sur mesure ni de compose multi-services : ce sera l’objet d’une intervention ultérieure. Ici, je reste dans la prise en main.
Rappel théorique sur Docker
Conteneur, ce n’est pas une VM
Un conteneur est un processus isolé sur la machine hôte, qui partage le noyau Linux de l’hôte mais voit son propre arbre de fichiers, ses propres interfaces réseau, ses propres limites de ressources. Cette isolation est obtenue par des fonctionnalités du noyau Linux :
- namespaces (PID, NET, MNT, UTS, IPC, USER) qui cloisonnent ce que le processus voit ;
- cgroups qui limitent ce qu’il peut consommer (CPU, mémoire, I/O) ;
- capabilities Linux qui restreignent les privilèges root.
| Aspect | Conteneur Docker | Machine virtuelle |
|---|---|---|
| Noyau | Partagé avec l’hôte | Propre noyau invité |
| Démarrage | < 1 seconde | 30 secondes à plusieurs minutes |
| Empreinte disque | Quelques Mo à quelques centaines | Plusieurs Go |
| Isolation | Processus + namespaces + cgroups | Matérielle (hyperviseur) |
| Cas d’usage typique | Service applicatif, micro-service | OS complet, charge non-Linux |
Note
Docker n’est pas la seule techno de conteneurs Linux : containerd, Podman, LXC existent aussi. Docker s’est imposé par son écosystème (Docker Hub, Docker Compose, ergonomie de la CLI), mais sous le capot c’est containerd qui pilote l’exécution depuis Docker 19.
Architecture de Docker
- Docker Engine : le démon
dockerdqui tourne en arrière-plan (côté hôte). C’est lui qui parle aux namespaces et aux cgroups. - Docker CLI : le client
dockerqu’on utilise au terminal. Il dialogue avec le démon via une socket Unix (/var/run/docker.sock). - Image : un modèle en lecture seule, composé de couches (layers). Une image
nginxcontient le système de fichiers minimal, le binaire nginx, sa configuration par défaut. - Conteneur : une instance en exécution d’une image, avec une couche d’écriture par-dessus.
- Registry : un dépôt d’images. Docker Hub est le registry public par défaut. On peut aussi héberger son propre registry privé.
Topologie
La VM DOCKER-MICROSERVICES tourne sur l’hyperviseur du lab interne, branchée sur le segment d’expérimentation des outils.
| Équipement | Rôle |
|---|---|
| Passerelle du lab | Routage, DHCP, accès Internet contrôlé |
| Mon poste d’admin | Client SSH et navigateur |
VM DOCKER-MICROSERVICES (Debian 12) | Hôte Docker |
Prérequis
- Une VM Debian 12 fonctionnelle (
DOCKER-MICROSERVICES), accès SSH avec un compte admin. - Connectivité Internet (via le proxy applicatif du lab si présent) pour atteindre
download.docker.cometregistry-1.docker.io. - Un
aptà jour côté Debian.
Installation de Docker
Ajout du dépôt officiel
Plutôt que d’installer le paquet docker.io du dépôt Debian (souvent en retard), j’ajoute le dépôt officiel Docker pour avoir Docker CE à jour.
# Mise à jour des paquets de base
apt update && apt upgrade -y
# Outils nécessaires pour ajouter un dépôt signé
apt install -y ca-certificates curl
# Création du dossier de clés et téléchargement de la clé GPG Docker
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg \
-o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
# Ajout du dépôt Docker dans les sources APT
cat > /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/debian
Suites: $(. /etc/os-release && echo "$VERSION_CODENAME")
Components: stable
Signed-By: /etc/apt/keyrings/docker.asc
EOF
# Mise à jour de l'index APT
apt updateExplications ligne par ligne :
ca-certificates curl: outils de base pour valider les certificats HTTPS et télécharger des fichiers. Souvent déjà présents, mais on s’assure.install -m 0755 -d /etc/apt/keyrings: crée le dossier où on stocke les clés des dépôts tiers. Permissions0755(lecture par tous, écriture root).curl -fsSL ... -o /etc/apt/keyrings/docker.asc: télécharge la clé GPG officielle de Docker.-fsSL= fail on error, silent, location follow.chmod a+r: rend la clé lisible par tous (sinonaptne pourra pas la consulter).- Le bloc
cat > docker.sourcesutilise le format DEB822 moderne (recommandé sur Debian 12) plutôt que l’ancien.listune-ligne. Plus lisible, mêmes effets. Suites: $(. /etc/os-release && echo "$VERSION_CODENAME"): injecte le nom de code de la distribution (bookwormpour Debian 12). Pratique pour rendre le snippet portable d’une version de Debian à l’autre.
Installation des paquets
apt install -y \
docker-ce \
docker-ce-cli \
containerd.io \
docker-buildx-plugin \
docker-compose-plugin
# Vérification de la version installée
docker --version
docker compose versionExplications ligne par ligne :
docker-ce: le démon Docker Engine.docker-ce-cli: le client en ligne de commande.containerd.io: le runtime de conteneur sous-jacent. Docker lui délègue le cycle de vie des conteneurs.docker-buildx-plugin: extension de build (multi-arch, BuildKit).docker-compose-plugin: sous-commandedocker composepour orchestrer plusieurs services. C’est la v2 de Compose, intégrée comme plugin (l’ancien binairedocker-composeest déprécié).
Premier conteneur : hello-world
Test canonique pour valider l’installation. L’image hello-world est minuscule (≈ 13 ko) et son seul rôle est d’écrire un message si tout fonctionne.
docker run hello-world
La sortie m’apprend deux choses :
- l’image
hello-world:latestn’était pas locale : Docker l’a téléchargée depuis Docker Hub (Pulling from library/hello-world) ; - le conteneur a été créé puis exécuté, et son
stdoutest revenu jusqu’à ma console.
Le message Hello from Docker! détaille le chemin parcouru par la requête : client → daemon → pull du Hub → création du conteneur → exécution → flux vers le terminal. Pédagogiquement parfait pour un premier test.
Lister les images et conteneurs
# Conteneurs en cours d'exécution
docker ps
# Conteneurs y compris ceux qui ont fini (Exited)
docker ps -a
docker ps est vide : c’est attendu, le conteneur hello-world a fini son travail et s’est arrêté. docker ps -a le montre encore avec le statut Exited (0) (sortie sans erreur), un nom auto-généré (awesome_diffie), et un ID court. Tant que je ne fais pas docker rm, le conteneur reste sur disque, prêt à être relancé.
Astuce
Les noms automatiques (awesome_diffie, hopeful_curie, etc.) suivent un pattern « adjectif_scientifique ». Sympa, mais en pratique on nomme ses conteneurs avec --name pour pouvoir les retrouver sans deviner.
Deuxième conteneur : nginx en arrière-plan
Lancer un conteneur qui rend un service sur le réseau, c’est l’usage le plus typique. Je télécharge l’image nginx officielle et je la lance en mode démon.
# Téléchargement préalable (optionnel, docker run le fait sinon)
docker pull nginx
# Lancement du conteneur en arrière-plan, port 80 du conteneur
# mappé sur le port 8080 de l'hôte
docker run -d -p 8080:80 --name mon-nginx nginxExplications ligne par ligne :
-d: detached. Le conteneur tourne en tâche de fond, on récupère le prompt immédiatement.-p 8080:80: mapping de ports<hôte>:<conteneur>. nginx écoute sur 80 dans le conteneur, je l’expose sur 8080 sur l’hôte. Depuis n’importe quel poste autorisé du segment, l’URLhttp://<ip-de-la-vm>:8080arrive sur le nginx.--name mon-nginx: nom explicite. Indispensable pour les commandes suivantes (logs,exec,stop,rm).nginx: nom d’image, sans tag, doncnginx:latestest utilisé.
Vérification HTTP
Depuis mon poste d’admin, j’ouvre http://<ip-de-la-vm>:8080. La page Welcome to nginx! s’affiche.

Cette page est servie depuis l’arborescence par défaut de l’image (/usr/share/nginx/html/index.html). Pour la remplacer par mon propre contenu, j’utiliserais soit un volume (-v) qui monte un dossier de l’hôte dans le conteneur, soit un Dockerfile qui copie mes fichiers dans une nouvelle image.
Inspection du conteneur
# Logs du conteneur (stdout + stderr)
docker logs mon-nginx
# Détails complets (JSON) : config réseau, volumes, env, etc.
docker inspect mon-nginx
# Top des processus à l'intérieur
docker top mon-nginx
# Une session shell dans le conteneur
docker exec -it mon-nginx /bin/bashExplications :
docker logs: renvoie tout ce que le PID 1 du conteneur a écrit sur stdout/stderr depuis sa création. nginx logge ici les accès HTTP, je vois ma propre requête.docker inspect: vue exhaustive en JSON. Très verbeux, mais utile pour récupérer une IP, un volume, une variable d’environnement.docker exec -it ... /bin/bash: ouvre un shell dans le conteneur.-ipour interactif (stdin attaché),-tpour pseudo-terminal. Indispensable pour debugger.
Vérifications
Trois contrôles classiques pour valider que l’installation tient debout.
Statut du démon
systemctl status docker --no-pagerLe service doit être active (running). Si non, systemctl start docker et systemctl enable docker pour le démarrer maintenant et au prochain reboot.
Connectivité réseau du conteneur
# IP attribuée au conteneur sur le réseau Docker par défaut
docker inspect mon-nginx --format '{{ .NetworkSettings.IPAddress }}'
# Test direct depuis l'hôte
curl -I http://localhost:8080curl doit renvoyer HTTP/1.1 200 OK. Sinon, vérifier que le port 8080 n’est pas déjà occupé sur l’hôte (ss -tlnp | grep 8080).
Persistance après reboot de la VM
# Activer le démarrage automatique du conteneur
docker update --restart unless-stopped mon-nginx
# Reboot
rebootAprès le redémarrage de la VM, docker ps doit montrer mon-nginx à nouveau en Up. Sans --restart, le conteneur reste arrêté tant qu’on ne le relance pas à la main.
Problèmes rencontrés et solutions
| Symptôme | Cause | Correction |
|---|---|---|
apt install docker-ce retourne un paquet introuvable | Dépôt officiel non ajouté ou clé GPG manquante | Reprendre la procédure d’ajout du dépôt depuis l’étape curl ... gpg |
permission denied while trying to connect to the Docker daemon socket | Utilisateur non-root pas dans le groupe docker | usermod -aG docker <user> puis se reconnecter (la session courante n’est pas mise à jour) |
docker run -p 8080:80 échoue avec port already allocated | Un autre service (nginx hôte, autre conteneur) écoute déjà sur 8080 | Choisir un autre port hôte, ou arrêter le service qui occupe |
L’image nginx:latest ne se télécharge pas | Pas de connectivité Docker Hub (proxy, DNS, firewall) | Vérifier curl https://registry-1.docker.io/v2/, configurer un proxy si besoin via /etc/systemd/system/docker.service.d/http-proxy.conf |
| Le conteneur consomme tout le CPU | Pas de limites configurées | Lancer avec --cpus="1.0" --memory="512m" pour borner les ressources |
Compétences du bloc 1 mobilisées
| Compétence officielle | Mobilisation concrète |
|---|---|
| Mettre à disposition aux utilisateurs un service informatique | Déploiement d’un service web nginx en conteneur, exposé via un port mappé sur la VM. |
| Installer et configurer des éléments d’infrastructure | Ajout du dépôt Docker officiel, installation des paquets Docker CE, configuration de la persistance des conteneurs. |
| Gérer le patrimoine informatique de l’organisation | Documentation de l’hôte Docker (DOCKER-MICROSERVICES), des images tirées et des conteneurs créés. |
| Réaliser les tests d’intégration et d’acceptation d’un service | Validation séquentielle (statut du démon, hello-world, nginx exposé, persistance après reboot). |
Bilan
Sortie de la séance, la VM DOCKER-MICROSERVICES héberge un Docker Engine fonctionnel, j’ai validé le cycle complet (image → conteneur → exécution → exposition réseau) avec deux exemples canoniques, et je connais les commandes du quotidien (ps, logs, inspect, exec, stop, rm).
Trois choses que je retiens :
- la différence image vs conteneur est plus importante qu’elle n’en a l’air : une image est un modèle figé, un conteneur est un processus en cours, comprendre cette dualité débloque toute la suite ;
- les ports
-psont la pierre angulaire de l’exposition d’un service : tant qu’on ne les a pas mappés, le conteneur reste cloisonné ; - le démon Docker tourne en root, donc le groupe
dockern’est pas anodin : lui appartenir équivaut quasiment à être root sur l’hôte.
Pour la suite, je prévois d’écrire mon premier Dockerfile custom (image d’un petit service Python), puis d’orchestrer plusieurs conteneurs liés via Docker Compose (par exemple un service web + une base PostgreSQL).
Sources
- Docker Docs — Install Docker Engine on Debian , Docker Inc.
- Docker Docs — Get started with Docker , Docker Inc.
- Docker Docs — Networking overview , Docker Inc.
- containerd Documentation — What is containerd? , CNCF.
- ANSSI — Recommandations de sécurité relatives au déploiement de conteneurs Docker , ANSSI.