Découverte de Docker

Découverte de Docker

Atelier d'introduction à Docker sur une VM dédiée du lab interne ANSSI : ajout du dépôt officiel, installation des paquets Docker CE, validation par hello-world, exposition d'un nginx en conteneur et tour des commandes de base.
Publié le
Statut
Terminé

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.
AspectConteneur DockerMachine virtuelle
NoyauPartagé avec l’hôtePropre noyau invité
Démarrage< 1 seconde30 secondes à plusieurs minutes
Empreinte disqueQuelques Mo à quelques centainesPlusieurs Go
IsolationProcessus + namespaces + cgroupsMatérielle (hyperviseur)
Cas d’usage typiqueService applicatif, micro-serviceOS complet, charge non-Linux

Architecture de Docker

  • Docker Engine : le démon dockerd qui tourne en arrière-plan (côté hôte). C’est lui qui parle aux namespaces et aux cgroups.
  • Docker CLI : le client docker qu’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 nginx contient 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.

ÉquipementRôle
Passerelle du labRoutage, DHCP, accès Internet contrôlé
Mon poste d’adminClient 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.com et registry-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.

BASH
# 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 update
Cliquez pour développer et voir plus

Explications 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. Permissions 0755 (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 (sinon apt ne pourra pas la consulter).
  • Le bloc cat > docker.sources utilise le format DEB822 moderne (recommandé sur Debian 12) plutôt que l’ancien .list une-ligne. Plus lisible, mêmes effets.
  • Suites: $(. /etc/os-release && echo "$VERSION_CODENAME") : injecte le nom de code de la distribution (bookworm pour Debian 12). Pratique pour rendre le snippet portable d’une version de Debian à l’autre.

Installation des paquets

BASH
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 version
Cliquez pour développer et voir plus

Explications 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-commande docker compose pour orchestrer plusieurs services. C’est la v2 de Compose, intégrée comme plugin (l’ancien binaire docker-compose est 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.

BASH
docker run hello-world
Cliquez pour développer et voir plus

Sortie de la commande docker run hello-world : pull complete, message Hello from Docker!

La sortie m’apprend deux choses :

  • l’image hello-world:latest n’é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 stdout est 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

BASH
# Conteneurs en cours d'exécution
docker ps

# Conteneurs y compris ceux qui ont fini (Exited)
docker ps -a
Cliquez pour développer et voir plus

docker ps vide, docker ps -a montre le conteneur hello-world Exited (0)

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é.

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.

BASH
# 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 nginx
Cliquez pour développer et voir plus

Explications 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’URL http://<ip-de-la-vm>:8080 arrive sur le nginx.
  • --name mon-nginx : nom explicite. Indispensable pour les commandes suivantes (logs, exec, stop, rm).
  • nginx : nom d’image, sans tag, donc nginx:latest est utilisé.

Vérification HTTP

Depuis mon poste d’admin, j’ouvre http://<ip-de-la-vm>:8080. La page Welcome to nginx! s’affiche.

Page Welcome to nginx servie par le conteneur

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

BASH
# 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/bash
Cliquez pour développer et voir plus

Explications :

  • 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. -i pour interactif (stdin attaché), -t pour pseudo-terminal. Indispensable pour debugger.

Vérifications

Trois contrôles classiques pour valider que l’installation tient debout.

Statut du démon

BASH
systemctl status docker --no-pager
Cliquez pour développer et voir plus

Le 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

BASH
# 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:8080
Cliquez pour développer et voir plus

curl 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

BASH
# Activer le démarrage automatique du conteneur
docker update --restart unless-stopped mon-nginx

# Reboot
reboot
Cliquez pour développer et voir plus

Aprè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ômeCauseCorrection
apt install docker-ce retourne un paquet introuvableDépôt officiel non ajouté ou clé GPG manquanteReprendre la procédure d’ajout du dépôt depuis l’étape curl ... gpg
permission denied while trying to connect to the Docker daemon socketUtilisateur non-root pas dans le groupe dockerusermod -aG docker <user> puis se reconnecter (la session courante n’est pas mise à jour)
docker run -p 8080:80 échoue avec port already allocatedUn autre service (nginx hôte, autre conteneur) écoute déjà sur 8080Choisir un autre port hôte, ou arrêter le service qui occupe
L’image nginx:latest ne se télécharge pasPas 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 CPUPas de limites configuréesLancer avec --cpus="1.0" --memory="512m" pour borner les ressources

Compétences du bloc 1 mobilisées

Compétence officielleMobilisation concrète
Mettre à disposition aux utilisateurs un service informatiqueDéploiement d’un service web nginx en conteneur, exposé via un port mappé sur la VM.
Installer et configurer des éléments d’infrastructureAjout du dépôt Docker officiel, installation des paquets Docker CE, configuration de la persistance des conteneurs.
Gérer le patrimoine informatique de l’organisationDocumentation 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 serviceValidation 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 -p sont 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 docker n’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

Commencer la recherche

Saisissez des mots-clés pour rechercher des articles

↑↓
ESC
⌘K Raccourci