Docker a dix ans… et pourtant, c’est toujours lui qui fait tourner 90 % des environnements modernes.
Ce n’est pas un “outil de dev”. C’est le socle de tout ce qui vient derrière : CI/CD, microservices, Kubernetes, cloud public, edge… même les modèles IA tournent dans des conteneurs.
Le problème ? La plupart des équipes utilisent Docker mais ne le maîtrisent pas : images de 2 Go, builds interminables, dépendances cachées, conteneurs qui tournent en root, et pipelines qui reproduisent les bugs… à l’identique.
👉 Docker n’est pas difficile. Mais mal utilisé, il coûte du temps, de l’argent, et de la fiabilité.
Dans ce guide, on va à l’essentiel : comprendre ce que Docker fait vraiment, construire sa première image propre, éviter les pièges de débutant et adopter les bonnes pratiques qui rendent un produit reproductible partout - du laptop à la prod.
Docker : c’est quoi (et ce que ce n’est pas) ?
Avant de parler Dockerfile, images ou pipelines, il faut clarifier un point : Docker n’est pas une mini-VM.
C’est une couche d’isolation légère qui vous garantit que votre application tourne exactement de la même manière sur tous les environnements : votre machine, la CI, la préprod, la prod… sans “chez moi ça marche”.
👉 Dit autrement : Docker = votre code + ses dépendances + son système minimal empaquetés dans une image reproductible.
Pas d’OS complet, pas d’hyperviseur, pas de surcouche inutile.
Ce que Docker résout
Docker apporte trois garanties fondamentales :
- Reproductibilité : même version de Python/Node/Java, mêmes libs, mêmes binaires.
- Isolation légère : chaque conteneur a son propre FS, réseau, process tree.
- Portabilité : l’image tourne partout où Docker tourne (cloud, CI, laptop, Kubernetes…).
C’est pour ça que toutes les chaînes modernes (GitHub Actions, GitLab CI, Fly.io, Render, AWS ECS…) l’ont adopté comme standard.
Ce que Docker ne résout pas
Et c’est là que beaucoup d’équipes se trompent :
- Docker ne gère pas la sécurité pour vous → un conteneur root reste un conteneur root.
- Docker ne remplace pas un orchestrateur → dès qu’on a plusieurs conteneurs, il faut Compose ou K8s.
- Docker ne garantit pas la performance → une mauvaise image reste une mauvaise image.
- Docker ne versionne pas vos configs → c’est le job de Git, IaC ou Helm.
Le malentendu n°1
“80 % des problèmes qu’on voit ne viennent pas de Docker… mais de ce que les équipes mettent dedans. Une image trop lourde ou un RUN mal pensé crée plus de dette qu’un mauvais serveur.”
— Hugo, Engineering Manager @ Yield Studio
Les concepts essentiels (et ceux que tout débutant confond)
Pour utiliser Docker proprement, il faut maîtriser six briques. Pas besoin d’être DevOps : juste comprendre ce qui se passe réellement quand vous faites docker build ou docker run.
Images - le “package” de votre application
Une image Docker, c’est un snapshot immuable : votre code, vos dépendances, un système minimal (Debian Slim, Alpine, Distroless…).
On construit une image → on ne la modifie jamais.
Une nouvelle version = une nouvelle image.
Containers - l’exécution d’une image
Un conteneur, c’est une image en train de tourner.
Même image → mêmes résultats.
10 conteneurs, c’est 10 exécutions isolées qui partagent le même noyau machine.
Layers - le secret du cache Docker
Chaque instruction du Dockerfile crée une couche.
Si une couche n’a pas changé, Docker la réutilise.
C’est ça qui fait passer un build de 90 secondes… à 8 secondes.
Registry - l’endroit où vivent vos images
Pour partager vos images, il faut un registry : Docker Hub, GitHub Container Registry, GitLab, ECR (AWS), GCR (GCP)…
C’est votre “NPM, mais pour les conteneurs”.
Volumes - persister les données
Un conteneur est éphémère. Un volume permet de garder les données quand il disparaît : bases locales, fichiers, caches, index…
Networks — faire discuter vos services
Docker crée un réseau isolé où vos conteneurs se parlent via leurs noms : api:3000, db:5432… C’est la base de Docker Compose.
📌 Les 6 briques Docker à connaître
- Image → la recette immuable.
- Conteneur → l’image en action.
- Layers → le cache qui accélère vos builds.
- Registry → où vivent et transitent vos images.
- Volumes → les données qui doivent survivre.
- Network → comment vos services communiquent.
Construire sa première image Docker (exemple concret)
La meilleure façon de comprendre Docker… c’est de construire une image propre.
On va prendre un exemple simple : une API Node.js minimaliste.
L’objectif : un Dockerfile clair, reproductible, et sans les erreurs classiques (images lourdes, cache cassé, dépendances mal copiées).
Le Dockerfile (version propre 2025)
FROM node:20-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
USER node
EXPOSE 3000
CMD ["node", "server.js"]
Ce que fait chaque ligne (et pourquoi)
Voici la logique derrière chaque instruction. L’optimisation du cache et de la sécurité commence ici.
- FROM node:20-slim
On utilise une base légère. Pasnode:latest, pasnode:alpine(soucis de build). - WORKDIR /app
Répertoire de travail isolé. - COPY package.json ./*
On copie d'abord les dépendances pour profiter du cache Docker. - RUN
npm ci --omit=dev
Installation déterministe, sans les dépendances dev → image plus légère. - COPY . .
On copie le code après les deps pour ne pas casser le cache à chaque commit. - USER node
On arrête de tourner en root (erreur fréquente). - EXPOSE 3000
Documente le port attendu. - CMD ["node", "server.js"]
Commande de démarrage.
Build & run
docker build -t my-api .
docker run -p 3000:3000 my-api
Les 5 erreurs qu’on voit souvent
- Utiliser
latest→ builds imprévisibles. - Copier tout le projet avant les deps → cache inefficace.
- Installer via
npm install→ résultats non déterministes. - Laisser l’utilisateur root → faille de sécurité.
- Une image de 1,5 Go “parce que ça marche”.
Les bonnes pratiques 2025 pour un Docker propre
Docker n’est pas compliqué. Ce qui est compliqué, c’est d’éviter les pièges invisibles qui transforment une simple image en bombe à retardement : builds lents, images obèses, failles sécurité, pipelines imprévisibles.
Voilà les bonnes pratiques qui conditionnent la qualité de votre prod.
Utiliser des images slim ou distroless (et arrêter les images de 2 Go)
Les images “complètes” embarquent un OS entier… inutile pour 95 % des apps.
→ debian-slim, ubi-micro, distroless (pour Go, Java, Node) divisent la surface d’attaque et la taille.
Une image fine = moins de vulnérabilités, moins de transfert, moins de temps de build.
Passer en multi-stage build dès qu’il y a compilation
TypeScript, Go, Java, Python compilé… → le multi-stage évite d’embarquer les outils de build en prod.
👉 Une image finale propre, minimaliste, impossible à “bidouiller”.
Ne jamais tourner en root
Toutes les images modernes offrent un user non-root. Utilisez-le. Toujours.
Un conteneur root n’est pas une petite faille : c’est un accès direct au host si une vulnérabilité fuit.
Externaliser les secrets (et arrêter de les mettre dans l’image)
.env embarqué, ARG SECRET_KEY=…, fichiers copiés dans la couche → catastrophe garantie.
Secrets = Vault, Secret Manager, Doppler, SOPS.
Optimiser le cache Docker (sinon vos builds vont rester lents à vie)
L'ordre du Dockerfile change tout :
deps → install deps → code → build → artefact final.
Un seul COPY . . au mauvais endroit = cache cassé → build ×10 plus longs.
Scanner et signer systématiquement vos images
Trivy, Grype, Cosign. Ce n’est plus un bonus. Les registres cloud bloquent déjà certaines images vulnérables.
Retour d’XP
“On a repris une app dont l’image faisait 1,8 Go. Rien d’exotique : juste des outils de build copiés au mauvais endroit. Après un multi-stage propre, l’image finale faisait… 118 Mo.
Moins de transferts, moins de failles, moins de temps perdu. Rien qu’en CI, ils ont gagné 14 minutes par pipeline.”
— Lucie, DevOps @ Yield Studio
🚫 Stop aux mauvaises pratiques
- Copier tout le projet avant les dépendances.
- Faire des RUN de 10 lignes impossibles à relire.
- Laisser des fichiers temporaires dans l’image.
- Construire en local “parce que c’est plus rapide que la CI”.
- Publier des images non taguées (ou taguées latest).
👉 Moderniser ses conteneurs, ce n’est pas être DevOps.
C’est juste éviter de se tirer une balle dans le pied avant d’arriver en CI/CD.
Quand Docker montre ses limites (et quoi faire à la place)
Docker est parfait pour empaqueter et exécuter une application. Mais il atteint vite ses limites dès que votre produit grossit, que la sécurité devient critique ou que la chaîne d’exécution se complexifie.
Le pire scénario, c’est de vouloir lui faire porter ce qu’il ne peut pas encaisser.
Voici les cas où Docker n’est plus la bonne réponse, même si “ça marche en local” :
- Trop de conteneurs à gérer : au-delà de 5–10 services, le réseau, les volumes et les redémarrages deviennent ingérables → besoin d’un orchestrateur (Kubernetes, Nomad).
- Builds lourds ou compilés : Java, Go, Python scientifique… → privilégier Buildpacks pour générer des images reproductibles sans Dockerfile complexe.
- Secrets sensibles : Docker ne gère pas le chiffrement ni la rotation → passer à Vault, Secret Manager ou SOPS.
- Besoins de perfs extrêmes : latence microseconde, workloads GPU avancés → exécuter sur bare metal ou orchestrateurs spécialisés.
- Haute disponibilité ou scaling automatique : Docker tout seul ne sait pas “reprendre”, “répliquer”, “équilibrer” → orchestrateur obligatoire.
“La règle est simple : si vous commencez à écrire des scripts pour ‘gérer vos conteneurs’, c’est que vous êtes déjà en train de bricoler un orchestrateur. Et ça finit toujours mal.”
— Julien, DevOps @ Yield Studio
Conclusion - Docker accélère… ou il explose
Docker, c’est simple jusqu’au jour où ça ne l’est plus. Tant que votre produit tient en quelques services, c’est un super-pouvoir : environnements reproductibles, onboarding éclair, déploiements propres.
Mais mal cadré, ça devient vite un nid à problèmes : images obèses, builds interminables, failles dans les layers, secrets embarqués, comportements différents entre machines… et personne ne comprend pourquoi “ça marchait chez moi”.
👉 La différence, c’est la rigueur : un Dockerfile propre, des bases images maîtrisées, des tests qui tournent en conteneur, et une CI/CD qui verrouille tout.
Docker n’est pas une fin en soi. C’est un socle. Si votre architecture grossit, il doit s’intégrer dans quelque chose de plus solide (Kubernetes, Nomad, ECS…).
Chez Yield, on ne “fait pas du Docker”. On construit des produits qui tournent en prod sans drama. Vous voulez en faire autant ? On peut vous y amener.
