Docker pour les nuls : Introduction
Un guide d'introduction complet pour Docker, les conteneurs et les images. Quelques concepts théoriques pour affronter le monde des conteneurs.
Ce guide est destiné aux développeurs débutants qui souhaitent comprendre les principes de Docker et la conteneurisation, sans prérequis techniques avancés.
Salut les pabios !
Tu en as marre d’entendre : “Pourtant ça marche sur ma machine !” Bienvenue dans le monde de Docker , où ton application tourne partout de la même manière.
Et aussi si ton ordinateur n'a pas d'espace disque, et que tu change de techno tout les 2 ou 3 jours, Docker est la solution, car plus besoin d'installer ton nouveau hype Langage en dur sur ta machine.
Donc si un week-end, tu as envie de tester une nouvelle techno, tu peux le faire dans un conteneur Docker, sans installer rien sur ta machine.
Pourquoi apprendre Docker ?
Oulaaa, je sens que tu n’es pas encore convaincu… alors prenons un cas réel.
Imagine : vous êtes 3 développeurs sur un même projet : Une application React qui dit “Bonjour Humanity” avec un backend API Platform.
Petit détail : API Platform a besoin de PHP.
- Toi, tu es à jour → tu bosses avec PHP 8.4, bien typé, tout propre.
- Ton collègue, lui, a encore PHP 5 sur sa machine.
Résultat : tu pushes ton code sur GitHub, il le pull, il lance… et boom rien ne marche.
Solutions classiques :
- “Monsieur Titi, upgrade sa version de PHP…” → il va passer 3 heures à tout réinstaller.
- Ou alors, tu sors ta carte magique :
“Attends, j’ai une meilleure idée : on va containeriser l’application !”
La magie Docker
Avec Docker :
- Tu emballes ton code + PHP 8.4 + toutes les dépendances dans une image.
- Ton collègue n’a plus rien à installer → il lance juste le conteneur.
- Et ça marche exactement pareil sur sa machine, la tienne, et même en prod.
C’est ça la promesse de Docker : Fini les galères de compatibilité → ton appli marche partout, tout le temps, pour tout le monde.
Les containers : la révolution venue des ports
Dans les années 1950, transporter des marchandises par bateau, c'était le bazar. Chaque type de cargaison avait sa méthode → pertes, casse, lenteur.
Puis l'idée géniale : tout mettre dans des containers maritimes standardisés . Même taille, mêmes attaches, mêmes engins de levage → interopérabilité mondiale.
Docker fait pareil pour les applis : on emballe le code et ses dépendances dans un conteneur standardisé et portable. Résultat : fini les "chez moi ça marche".
VM vs Conteneur
Avant de parler de conteneurs, petit rappel. Un système d’exploitation (OS), c’est le chef d’orchestre entre ton matériel (CPU, RAM, disque) et tes applications. Sans lui, ton appli ne peut pas tourner.
L’arrivée des machines virtuelles (VMware & co)
Dans les années 2000, un géant arrive : VMware.
Leur idée : plutôt que d’avoir un seul OS par serveur, on va pouvoir faire tourner plusieurs OS en parallèle sur la même machine physique.
Concrètement, avec un logiciel comme VirtualBox, tu peux installer :
- ton OS principal (ex. Windows),
- et dedans, une VM avec un autre OS complet (ex. Ubuntu).
C'est comme à l'école lorsque tu voulais tourner Ubuntu sur Windows sans dual boot, tu utilisais des outils comme VirtualBox ou VMware avec des images ISO.
On appelle ça : un OS dans un OS. Révolution à l’époque → meilleure utilisation des serveurs.
Et les entreprises ont tout de suite compris l’intérêt :
- Chaque VM est indépendante,
- On peut isoler les applis,
- On peut mettre à jour sans risque.
Et aussi economie d’argent : moins de serveurs (ordinateurs) à acheter.
Mais il y a un problème : Chaque VM embarque son propre noyau, ses drivers, ses services… bref un OS entier.
Résultat : ça consomme beaucoup de ressources, c’est lent à démarrer, et pas hyper portable.
Et bien pourquoi acheter une maison entière hors que tu n'as besoin que de juste une chambre ?
L’arrivée des conteneurs
Les conteneurs viennent résoudre ça :
- Ils partagent le noyau de l’OS hôte,
- Ils embarquent juste ce qu’il faut pour l’application (binaires + dépendances).
Conséquences :
- Plus légers,
- Plus rapides à démarrer,
- Plus portables.
Image mentale :
- Une VM, c’est comme construire une maison entière à chaque fois.
- Un conteneur, c’est juste une chambre prête à l’emploi dans une maison déjà existante.
Docker n’a pas inventé les conteneurs
Attention : Si à chaque fois que tu entends “conteneur” tu penses à Docker, sache que c'est normal mais Docker n’a pas inventé la technologie c'est un peu comme React qui n'a pas inventé le JavaScript ou Apple qui n'a pas inventé le telephone.
Les conteneurs existaient déjà depuis longtemps dans le monde Linux (LXC, chroot, zones Solaris…). Mais c’était complexe à utiliser.
Ce que Docker a fait en 2013, c’est démocratiser les conteneurs :
- avec une interface simple,
- un système d’images standard,
- et une compatibilité partout.
Et c’est là que l’histoire moderne commence…
Installer Docker
Avant de jouer avec les conteneurs (instance d'une image), il faut installer Docker. Bonne nouvelle : c’est simple et bien documenté.
-
Linux → installation directe (paquets officiels) Guide officiel Docker Linux
-
Mac / Windows → passe par Docker Desktop (qui tourne en fait dans une petite VM Linux sous le capot). Télécharger Docker Desktop
Une fois installé, ouvre un terminal et tape :
docker version
Si tu vois un retour avec Client et Server, félicitations ton Docker fonctionne !
Image vs Conteneur
Dans Docker, les deux notions à maîtriser absolument sont : image et conteneur. Comme tu viens de voir la différence VM vs conteneur, celle-ci va couler de source.
Définition express
- Image = la recette (plan de construction) : dépendances, binaires, configuration, code de l’app.
- Conteneur = l’exécution réelle de cette recette (un processus isolé qui tourne).
Image = recette
Conteneur = plat cuisiné
Version POO (pour les devs) :
Bon tu as certainement réussi à faire le parallèle, lorsque tu as entendu recette et plat cuisiné, tu as pensé à la POO (Programmation Orientée Objet), et tu as compris que :
- Image = classe
- Conteneur = instance
C'est bien simple non ? Car avec une classe tu peux créer plusieurs objets (instances), et c'est pareil avec Docker avec une image on peut lancer plusieurs conteneurs (instances).
Exemple :
class Tarte {
public function __construct(private $recette, private $ingredients, private $moule) {}
public function preparer() {/* ... */}
}
// Une image → plusieurs conteneurs (instances)
$tarte1 = new Tarte($recette, $ingredients, $moule);
$tarte2 = new Tarte($recette, $ingredients, $moule);
Ce que contient (et ne contient pas) une image
- Elle n’embarque pas de noyau : le conteneur utilisera le noyau de l’OS hôte.
- Elle contient “just enough OS” : système de fichiers minimal + libs nécessaires + ton appli.
- Vise des images slim (ex.
-alpine) → plus rapides à télécharger, plus sûres.
Note :
Si un jour tu veux faire du Node.js, et que tu prends l’image node sur Docker Hub, sache que cette image contient déjà :
- le moteur Node.js installé,
- npm ou yarn pour gérer les dépendances,
- un système minimal (souvent basé sur Debian, Ubuntu, ou Alpine).
Résultat : tu n’as pas besoin d’installer Node à la main → tu peux directement copier ton projet à l’intérieur et lancer node app.js.
Exemple : dans la section Supported tags and respective Dockerfile links du Docker Hub :

Tu peux cliquer sur un tag (comme 24-alpine3.21). Tu verras alors le Dockerfile officiel qui montre ce que l’image contient :
FROM alpine:3.21
ENV NODE_VERSION 24.9.0
RUN addgroup -g 1000 node && adduser -u 1000 -G node -s /bin/sh -D node
...
ENV YARN_VERSION 1.22.22
RUN apk add --no-cache ...
COPY docker-entrypoint.sh /usr/local/bin/
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["node"]
Points clés :
FROM alpine:3.21→ le système d’exploitation qui est utilisé comme base (3 Mo environ)ENV NODE_VERSION 24.9.0→ version de NodeRUN apk add --no-cache ...→ installation de dépendancesCMD ["node"]→ commande par défaut (tu peux la redéfinir)
Question ?
Mais attends… tu m’avais dit qu’une image n’embarque pas d’OS.
Alors pourquoi l’image officielle de Node commence par FROM alpine:3.21 (et Alpine est bien une distribution Linux, donc un OS non) ?
Réponse avec un peu de déconstruction
En réalité, il faut déconstruire une idée reçue :
Linux tout seul n’est pas un système d’exploitation complet. C’est juste un noyau (le kernel).
Ce qu’on appelle “un OS Linux” (Debian, Ubuntu, Alpine, Fedora, etc.) = Linux (le noyau) + un userland (système de fichiers, shells, outils, bibliothèques, gestionnaire de paquets…).
Autrement dit, c’est la combinaison des deux qui crée l’expérience d’un “OS”.
Dans Docker :
-
Les conteneurs partagent le noyau de l’hôte → donc pas besoin de répliquer le kernel dans chaque image.
-
Mais pour que ton app tourne correctement, tu as quand même besoin de quelques outils et libs. C’est là qu’intervient Alpine ou Debian → une base minimaliste qu’on appelle “just enough OS”.
En résumé :
Pas de noyau dans une image (c’est celui de ton hôte qui est utilisé).
hôte = ordinateur dans lequel tu travaille
Oui, un système de fichiers minimal pour que ton app respire (par ex. Alpine apporte musl + busybox, juste assez pour Node).
musl = libc (bibliothèque C) pour Alpine Linux
busybox = collection d’outils de base (ls, cat, echo, etc.)
C’est ça le fameux “just enough OS” que tu entendras souvent.
Bon Tu n’as pas besoin de tout connaître sur BusyBox, musl ou le kernel pour utiliser Docker au quotidien : dans la plupart des cas, tu te contenteras de partir d’une image officielle (ex : node, php, redis), d’ajouter ton code avec un Dockerfile, puis de lancer ton conteneur.
Avoir un aperçu de ce qu’il y a sous le capot reste utile pour comprendre la puissance de Docker et savoir dépanner, mais pas d’inquiétude : créer ta première image sera bien plus simple que tout ça.
Petit “cheat” : à quoi sert un Dockerfile ?
Tu trouveras souvent un fichier Dockerfile à la racine d’un projet GitHub. C’est lui qui décrit comment construire l’image (la recette).
Idée générale :
- Tu pars d’une base adaptée (directive FROM) — par ex. une image officielle Node.
- Tu ajoutes tes dépendances et ton code.
- Tu définis la commande qui lance l’app.
Exemple minimal pour une petite app Node.js :
# Base légère avec Node
FROM node:20-alpine
# Dossier de travail dans l’image
WORKDIR /app
# Copy package files
COPY package*.json ./
# Install dependencies
RUN npm install
# Copy source code
COPY . .
# Expose port
EXPOSE 3000
# Start the application
CMD ["npm", "run", "dev"]
Points clés :
FROM node:20-alpine→ tu réutilises une base avec Node déjà installé, construite sur Alpine (donc tu as aussi les commandes de base comme ls ou echo).- On copie d’abord
package*.jsonpuis on installe → npm install. CMD→ dit comment exécuter ton application quand le conteneur démarre.EXPOSE 3000→ dit que ton application écoute sur le port 3000.
C'est comme si tu avais un petit script qui lance ton application, mais qui est exécuté automatiquement quand le conteneur démarre.
Construire et lancer (situer les mots)
# Construire l'image (recette → image nommée)
docker build -t bonjour-node .
# Lancer un conteneur à partir de l'image
docker run --rm -p 3000:3000 bonjour-node
Ici, la même image peut servir à lancer plusieurs conteneurs identiques et indépendants.
À retenir
- Image = description immuable (recette).
- Conteneur = processus isolé qui tourne à partir de l’image.
- Les images n’ont pas de noyau ; les conteneurs utilisent le noyau de l’hôte.
- Le
Dockerfileest la manière standard de fabriquer tes images. - Commence simple, vise des images slim, et versionne toujours tes bases (
node:20-alpineplutôt quelatest).
T'en fais pas on verra comment faire pour créer une belle image dans le prochain Guide.
Concepts théoriques
Bon, soyons clairs : ce chapitre, tu ne vas pas t’en servir tous les jours. C’est un peu comme les fichiers de configuration avancés dans ton langage ou framework préféré. La plupart du temps, tu n’y touches jamais… mais le jour où ton application plante, tu es bien content de savoir où chercher.
- (Exemple : en PHP [et oui, j'adore PHP :) ], on a le fichier php.ini pour ajuster la mémoire ou la taille des fichiers uploadés. Tu ne l’ouvres presque jamais, mais si un problème arrive, tu es content de savoir qu’il existe.)
Ici, c’est pareil avec Docker. Tu peux l’utiliser sans jamais connaître ces détails. Mais si un jour tu veux dépanner, optimiser ou comprendre en profondeur, tu seras content d’avoir cette culture.
1) Standards & gouvernance
Le monde des conteneurs ne repose pas uniquement sur Docker. Pour éviter le chaos (chacun qui invente son format), des standards ont été créés :
- OCI (Open Container Initiative) Organisation neutre (Linux Foundation) qui a défini les règles de base.
3 spécifications :
- image-spec : format des images
- runtime-spec : comment exécuter un conteneur
- distribution-spec : comment partager une image dans un registre
Imagine des rails de train standardisés : grâce à ça, tous les trains (Docker, Podman, Kubernetes…) roulent sur la même voie.
-
CNCF (Cloud Native Computing Foundation) Fondation qui héberge et gouverne des projets cloud-native comme Kubernetes, Prometheus, ou containerd.
-
Moby Project Projet open source lancé par Docker. C’est un peu le laboratoire : Docker (le produit) assemble ses briques à partir de Moby pour livrer un outil clé en main.
2) Architecture du Docker Engine
Sous le capot, Docker est une mécanique modulaire :
- docker (client CLI) : la télécommande (ex.
docker run ...). - dockerd (daemon) : le chef d’orchestre qui expose l’API.
- containerd : (il se prononce comme "conteiner-dii") gère les images et le cycle de vie des conteneurs (créer, démarrer, stopper, supprimer).
- runc : runtime bas-niveau qui parle au noyau Linux pour exécuter les conteneurs.
- shim : petit processus tampon. Il garde le conteneur vivant même si
dockerdredémarre, et maintient les entrées/sorties ouvertes.
Schéma simplifié
docker (client) → dockerd → containerd → shim → runc → kernel → conteneur

En clair :
- Toi → tu parles au client docker
- Le client → parle au daemon dockerd
- Le daemon → délègue à containerd
- containerd → demande à runc de lancer le conteneur
- Et shim reste en arrière-plan pour garantir que ton conteneur continue de tourner même si le daemon s’arrête.
Tu n’as pas besoin de retenir tout ça par cœur. Mais le jour où tu vois passer un mystérieux
docker: Error response from daemon: runtime "io.containerd.runc.v2" binary not installed "containerd-shim-runc-v2": file does not exist: unknown.
ERRO[0000] error waiting for container: context canceled
dans les processus de ta machine, tu sauras enfin ce que c’est !
3) Images slim et layers
Comme tu le sais maintenant, une image Docker n’embarque pas de noyau : ton conteneur utilise celui de l’OS hôte. Elle contient seulement ce qu’il faut pour ton appli : dépendances + fichiers nécessaires.
Résultat : certaines images sont très légères. Exemple : Alpine Linux fait environ 3 Mo → idéale pour des applis rapides.
Autre concept clé : les layers (couches).
- Chaque instruction dans un Dockerfile crée une couche.
- Si une couche existe déjà en local, Docker la réutilise.
- Quand tu tires une image, Docker ne télécharge que les couches manquantes.
Bénéfice : builds plus rapides, images plus petites, réseau économisé.
Pour visualiser les couches d'une image, tu peux utiliser la commande suivante :
Mais avant, on va pull redis (base de données NoSQL) une première fois, pour voir les couches :
docker pull redis:7
Lors du pull on peut voir les couches téléchargées :
7: Pulling from library/redis
0878ecc8b0af: Already exists
0490ce7da6f8: Pull complete
362cab1f9007: Pull complete
b5f3601f6637: Pull complete
fe5e6dfd62e9: Pull complete
77f7e42359fc: Pull complete
4f4fb700ef54: Pull complete
a9496266a78f: Pull complete
Digest: sha256:edfad62e79bbbad4bc6efd528f6a7ca95546f4c0ab5ca504a83952a8cbdc13fe
Status: Downloaded newer image for redis:7
docker.io/library/redis:7
Ici, on voit que la couche 0878ecc8b0af existe déjà en local (dans mon ordinateur), et que les autres ont été téléchargées.
Tu peux aussi voir les couches d'une image avec la commande suivante :
docker inspect redis:7
Dans le champ RootFS du json retourné, tu trouveras les couches de l'image dans la clef Layers.
Et si on re-pull redis une seconde fois, tu verras que Docker n'a rien téléchargé, car toutes les couches existent déjà en local :
7: Pulling from library/redis
Digest: sha256:edfad62e79bbbad4bc6efd528f6a7ca95546f4c0ab5ca504a83952a8cbdc13fe
Status: Image is up to date for redis:7
docker.io/library/redis:7
En gros, c'est comme si tu essayais d'installer deux fois le même logiciel.
Pour l'instant retient juste que lorsque tu pull une image, tu récupères plusieurs couches dont la premiere est par exemple l'OS et la seconde ton langage par ex. PHP, Node, Python etc.... et que si une couche existe déjà en local, Docker la réutilise.
4) Registries
Bon, maintenant que tu sais ce qu’est une image, une question logique arrive : où et comment va-t-on les récupérer ?
Parce que tu ne vas pas réinventer la roue à chaque fois. Si ton projet a besoin de Java, PHP, ou Node.js, tu peux directement récupérer une image de base déjà prête :
Toutes ces images viennent d’un registry : un entrepôt d’images Docker.
Les plus connus :
- Docker Hub (par défaut)
- Harbor (souvent utilisé en entreprise)
- Quay (utilisé par Red Hat)
- Github Container Registry (utilisé par Github)
Mais cette diversité de registries est un avantage : tu peux choisir celui qui te convient le mieux. C'est un peu comme choisir entre Github, Gitlab, Bitbucket pour héberger ton code, avec un seul standard : Git.
Et ici, c'est pareil, grace au Standard OCI qu'on a vu dans le chapitre Concepts & gouvernance, tu peux utiliser les images de n'importe quel registry, car la plupart des registries adoptent la norme OCI distribution-spec.
Donc comme avec Git, tu pourras faire un docker pull d'une image de n'importe quel registry.
Mais bon disons que la plupart du temps, on utilisera Docker Hub, car c'est le plus connu, et il y a des images officielles.
Sur Docker Hub, tu trouveras des Official Images (badge vert) → elles sont vérifiées, sûres, et maintenues.
Exemple : nginx, redis, alpine
Les tags (aperçu)
Quand tu choisis une image, tu dois aussi choisir un tag (sa version).
nginx:stable-perl→ version stable avec Perlnginx:1.27-alpine→ version 1.27 basée sur Alpine (très légère)nginx:latest→ la toute dernière version peut changer demain
Voici un aperçu depuis Docker Hub :

Retiens : Image = famille (nginx), Tag = version précise (nginx:1.27-alpine)
Bonne pratique : évite :latest. Utilise toujours une version précise (node:20-alpine, redis:7).
Tu peux déjà aller jeter un œil sur Docker Hub pour explorer un peu : tape le nom de ta techno préférée (Python, PHP, Node, MongoDB…) et regarde les images officielles disponibles. Une simple visite vaut déjà une première bonne immersion dans l’écosystème !
Attention car un petit malin peut publier une image PHP remplie de virus et te promettre que c'est la version la plus récente, alors prends garde aux images non-officielles !
Premier test pratique
On va lancer Redis (une base de données clé-valeur (NoSQL) ultra légère). Pas besoin de tout comprendre, suis juste les étapes :
Ouvre un terminal :
- Tirer une image (la télécharger)
docker pull redis:7
- Lister les images disponibles en local
docker images
- Lancer un conteneur Redis
docker run --name mon-redis -d -p 6379:6379 redis:7
Explications :
--name mon-redis: nom du conteneur-d: mode détaché (en arrière-plan)-p 6379:6379: expose le port 6379 du conteneur sur le port 6379 de la machine hôteredis:7: image à utiliser
- Voir les conteneurs actifs
docker ps
- Tester la connexion
docker exec -it mon-redis redis-cli ping
Réponse attendue → PONG
Nettoyer
Quand tu as fini, pense à tout arrêter/nettoyer :
docker stop mon-redis # Arrête le conteneur
docker rm mon-redis # Supprime le conteneur
docker rmi redis:7 # Supprime l'image
Pense à toujours nettoyer derrière toi !
Environnement propre
Pas de conteneurs fantômes qui traînent
Bravo : tu viens de tirer ta première image, lancer ton premier conteneur, et interagir avec lui. C’est ton “Hello World” dans le monde Docker
Et la suite ?
Prochain Guide : écrire ton vrai premier Dockerfile pour construire ta propre image, et démystifier la notion de container.
Conclusion
Félicitations ! Tu viens de faire tes premiers pas avec Docker .
Dans ce guide, nous avons couvert :
- Les concepts fondamentaux : conteneurs vs machines virtuelles
- La différence entre images et conteneurs (classe vs instance)
- L'écosystème Docker : registries, tags, architecture
- La pratique : installation, premier conteneur, commandes de base
Docker révolutionne le développement en résolvant le fameux "ça marche sur ma machine". Avec les conteneurs, notre application fonctionne de manière identique partout : développement, test, production.
Exercice
Avant le prochain guide, voici un exercice pour s'entraîner à lancer des conteneurs Docker.
- Lance un conteneur Nginx (un serveur web léger) et vérifie qu'il est bien en cours d'exécution.
- Vérifie que le port 80 du conteneur est bien exposé sur le port 8080 de ta machine hôte.
- Astuce sur la notion des ports : la partie gauche est le port de la machine hôte, la partie droite est le port du conteneur.
- Exemple :
-p 8080:80signifie que le port 80 du conteneur est exposé sur le port 8080 de la machine hôte.
- Vérifie que tu peux accéder à la page d'accueil de Nginx via ton navigateur en allant sur http://localhost:8080
- Arrête le conteneur et supprime-le.
Le voyage ne fait que commencer ! Docker est un outil puissant qui transformera notre façon de développer et déployer des applications.
Maj : 2025-09-28