Docker est une plateforme de conteneurisation : elle permet d'empaqueter une application et toutes ses dépendances dans une unité isolée et portable appelée container. Contrairement à une VM, un container partage le noyau du système hôte — il démarre en millisecondes et consomme très peu de ressources.
En résumé : une Image est un template en lecture seule (comme une recette). Un Container est une instance en cours d'exécution de cette image (le plat cuisiné). Plusieurs containers peuvent tourner depuis la même image.
Docker repose sur 3 primitives Linux : namespaces (isolation des processus, réseau, fichiers), cgroups (limitation CPU/RAM) et Union FS (couches de système de fichiers superposées). Le résultat : isolation quasi-totale sans overhead de virtualisation.
⚡
Démarrage rapide — 5 minutes
1
Installer Docker
Télécharger Docker Desktop (Mac/Windows) ou installer le moteur sur Linux : curl -fsSL https://get.docker.com | sh. Vérifier : docker version
2
Lancer votre premier container
Pas besoin de rien installer — Docker télécharge l'image automatiquement depuis Docker Hub.
Terminal
# Lancer un serveur web Nginx en 1 commandedockerrun-d-p8080:80--namemon-nginxnginx# Ouvrir http://localhost:8080 dans votre navigateur → page Nginx !# Voir les containers en coursdockerps# Arrêter et supprimerdockerstopmon-nginxdockerrmmon-nginx
3
Créer votre première image
Créer un fichier Dockerfile à la racine de votre projet.
Dockerfile (Node.js basique)
# Partir d'une image de base officielleFROMnode:20-alpine# Définir le répertoire de travail dans le containerWORKDIR/app# Copier les fichiers de dépendancesCOPY package*.json ./
# Installer les dépendancesRUN npm install
# Copier le reste du code sourceCOPY . .
# Exposer le port sur lequel l'app tourneEXPOSE 3000
# Commande lancée au démarrage du containerCMD ["node", "server.js"]
4
Builder et lancer
Les deux commandes essentielles : build puis run.
Terminal
# Construire l'image (. = répertoire courant)dockerbuild-tmon-app:1.0 .
# Lancer le container depuis l'imagedockerrun-d-p3000:3000--namemon-appmon-app:1.0# Voir les logsdockerlogs-fmon-app
5
Créer un .dockerignore
Éviter de copier node_modules, .env et autres fichiers inutiles dans l'image.
Conseil : Toujours créer un .dockerignore avant de builder. Sans lui, Docker copie tout le répertoire — y compris node_modules (des centaines de MB) — ce qui ralentit massivement le build et gonfle inutilement l'image.
1
Concepts fondamentaux
Concept
Définition
Analogie
Caractéristique clé
Image
Template immutable composé de couches (layers) superposées
Recette de cuisine
Partagée entre containers, stockée en cache local
Container
Instance en cours d'exécution d'une image, avec sa propre couche d'écriture
Plat cuisiné
Éphémère par défaut (données perdues à l'arrêt)
Dockerfile
Fichier texte décrivant les étapes pour construire une image
La recette écrite
Versionnable, reproductible
Registry
Serveur de stockage et distribution d'images (Docker Hub, ECR, GCR, Harbor)
Bibliothèque de recettes
Public ou privé
Volume
Stockage persistant géré par Docker, monté dans un container
Disque dur externe
Survit à la suppression du container
Network
Réseau virtuel isolé permettant la communication entre containers
Réseau local privé
DNS automatique entre containers sur le même réseau
Layer
Couche de système de fichiers issue d'une instruction Dockerfile (RUN, COPY…)
Couche de peinture
Mise en cache — si non modifiée, réutilisée sans rebuildé
Tag
Étiquette versionnant une image (ex: nginx:1.25-alpine)
Numéro de version
latest = tag par défaut (attention : pas toujours le plus récent)
Piège courant : un container arrêté (docker stop) n'est pas supprimé. Ses données (sans volume) et sa couche d'écriture sont encore présentes sur disque. Utiliser docker rm pour supprimer, ou docker run --rm pour supprimer automatiquement à l'arrêt.
2
CLI — Gestion des images
Commande
Description
Exemple
docker images
Lister les images locales
docker images
docker pull
Télécharger une image depuis un registry
docker pull nginx:1.25-alpine
docker build
Construire une image depuis un Dockerfile
docker build -t monapp:1.0 .
docker push
Envoyer une image vers un registry
docker push monuser/monapp:1.0
docker tag
Créer un alias (tag) pour une image
docker tag monapp:1.0 monapp:latest
docker rmi
Supprimer une image locale
docker rmi nginx:1.25-alpine
docker image prune
Supprimer toutes les images non utilisées
docker image prune -a
docker inspect
Afficher les métadonnées complètes d'une image
docker inspect nginx
docker history
Afficher les couches (layers) d'une image
docker history monapp:1.0
docker save / load
Exporter/importer une image en .tar (sans registry)
docker save monapp:1.0 | gzip > monapp.tar.gz
Commandes de build avancées
# Build avec BuildKit (plus rapide, activé par défaut depuis Docker 23)dockerbuild-tmonapp:1.0 .
# Build avec cache désactivé (forcer la reconstruction complète)dockerbuild--no-cache-tmonapp:1.0 .
# Build depuis un Dockerfile non standarddockerbuild-fdocker/Dockerfile.prod-tmonapp:prod .
# Build avec build arguments (variables passées au build)dockerbuild--build-argNODE_ENV=production-tmonapp:prod .
# Build multi-platform (ex: x86 + ARM pour Apple Silicon)dockerbuildxbuild--platformlinux/amd64,linux/arm64-tmonapp:1.0--push .
# Inspecter la taille de chaque layerdockerhistory--no-truncmonapp:1.0
Convention de nommage :registre/utilisateur/image:tag — ex: docker.io/library/nginx:1.25-alpine. Pour Docker Hub, le préfixe docker.io/library/ est implicite. Pour un registry privé : registry.company.com/team/app:v1.2.3.
Créer une image depuis un container modifié (déconseillé en prod)
docker commit monapp monapp:debug
docker container prune
Supprimer tous les containers arrêtés
docker container prune -f
Options docker run — référence complète
dockerrun \
-d \ # mode détaché (background)--namemon-container \ # nom du container-p8080:80 \ # port hôte:port container-p443:443 \ # plusieurs ports possible-vmon-volume:/data \ # volume nommé-v$(pwd)/config:/app/config \# bind mount (chemin hôte:container)-eDATABASE_URL=postgres://…\ # variable d'environnement--env-file.env \ # charger un fichier .env--networkmon-reseau \ # réseau Docker--restartunless-stopped \ # politique de redémarrage--memory512m \ # limite RAM--cpus1.5 \ # limite CPU--rm \ # supprimer le container à l'arrêt--user1001:1001 \ # utilisateur non-root--read-only \ # filesystem en lecture seulemonimage:tag# image à utiliser# Entrer dans un container en coursdockerexec-itmon-containerbashdockerexec-itmon-containersh# si bash absent (alpine)# Container interactif jetabledockerrun--rm-itubuntu:22.04bash# Suivre les logs en livedockerlogs-f--tail100mon-container
Politiques de redémarrage :no (défaut), on-failure[:n] (si exit code non nul, n fois max), always (toujours, même après reboot), unless-stopped (comme always, sauf si arrêté manuellement). En production, préférer unless-stopped.
4
Écrire un Dockerfile
Instruction
Rôle
Exemple
Notes
FROM
Image de base (obligatoire, en premier)
FROM node:20-alpine
Utiliser des images officielles slim/alpine
WORKDIR
Répertoire de travail courant
WORKDIR /app
Crée le dossier si inexistant
COPY
Copier des fichiers hôte → image
COPY package*.json ./
Respecte .dockerignore
ADD
Comme COPY mais supporte URL et .tar
ADD app.tar.gz /app
Préférer COPY sauf besoin spécifique
RUN
Exécuter une commande pendant le build
RUN npm ci --only=production
Chaque RUN = nouveau layer
ENV
Variable d'environnement persistante
ENV NODE_ENV=production
Visible dans le container au runtime
ARG
Variable disponible uniquement au build
ARG APP_VERSION=1.0
Non présente dans l'image finale
EXPOSE
Documenter le port exposé (indicatif)
EXPOSE 3000
Ne publie pas le port (--publish requis)
CMD
Commande par défaut au démarrage
CMD ["node", "server.js"]
Surchargeable au docker run
ENTRYPOINT
Commande fixe + CMD comme arguments
ENTRYPOINT ["node"]
Plus difficile à surcharger
VOLUME
Déclarer un point de montage
VOLUME ["/data"]
Crée un volume anonyme si non spécifié
USER
Utilisateur pour les instructions suivantes
USER node
Sécurité : éviter root
HEALTHCHECK
Vérification de santé du container
HEALTHCHECK CMD curl -f http://localhost/
Statuts: starting/healthy/unhealthy
LABEL
Métadonnées de l'image
LABEL version="1.0" maintainer="team"
OCI image spec
SHELL
Shell utilisé pour les RUN suivants
SHELL ["/bin/bash", "-c"]
Défaut: /bin/sh -c
ONBUILD
Instruction déclenchée si l'image est utilisée comme base
ONBUILD COPY . /app
Utile pour images de base d'équipe
Bonnes pratiques — optimiser les layers et la taille
Dockerfile optimisé — Node.js production
# ✅ BIEN : image légèreFROMnode:20-alpine# Créer un utilisateur non-root dès le débutRUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR/app# Copier package.json SÉPARÉMENT → meilleur cache# Si le code change mais pas les deps, cette couche reste en cacheCOPY package*.json ./
RUN npm ci --only=production && npm cache clean --force
# Copier le reste du codeCOPY --chown=appuser:appgroup . .
# Passer à l'utilisateur non-rootUSER appuser
EXPOSE3000# Healthcheck intégréHEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD wget -qO- http://localhost:3000/health || exit 1
# Préférer la forme exec (tableau JSON) à la forme shellCMD ["node", "server.js"]
❌ Antipatterns courants
# ❌ Plusieurs RUN séparés = plusieurs layers inutilesRUN apt-get update
RUN apt-get install -y curl
RUN apt-get install -y git
# ✅ Chaîner avec && et nettoyer dans le même RUNRUN apt-get update && apt-get install -y \
curl \
git \
&& rm -rf /var/lib/apt/lists/*
# ❌ COPY tout en premier (invalide le cache à chaque modification de code)COPY . .
RUN npm ci
# ✅ COPY package.json en premier, code source ensuiteCOPY package*.json ./
RUN npm ci
COPY . .
# ❌ Laisser des outils de build dans l'image finaleRUN apt-get install -y build-essential && make && # outils présents dans l'image !# ✅ Utiliser le multi-stage build (section 5)
CMD vs ENTRYPOINT :CMD définit la commande par défaut, facilement surchargeable avec docker run image ma-commande. ENTRYPOINT est fixe, CMD devient ses arguments. Combinaison classique : ENTRYPOINT ["node"] + CMD ["server.js"] → docker run image autre.js lance node autre.js.
5
Multi-stage builds
Le multi-stage build permet d'utiliser plusieurs FROM dans un seul Dockerfile. On compile dans une image lourde, puis on copie uniquement les artefacts produits dans une image finale légère. Résultat : des images de production beaucoup plus petites (souvent 10x moins lourdes) sans outils de build.
Multi-stage — Application React + Node.js
# ─── Stage 1: Dépendances ────────────────────────────FROMnode:20-alpineAS deps
WORKDIR/appCOPY package*.json ./
RUN npm ci
# ─── Stage 2: Build ──────────────────────────────────FROMnode:20-alpineAS builder
WORKDIR/appCOPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
# ─── Stage 3: Tests (optionnel, ciblable séparément) ─FROM builder AS test
RUN npm run test -- --coverage
# ─── Stage 4: Production ─────────────────────────────FROMnode:20-alpineAS production
WORKDIR/appENV NODE_ENV=production
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
# Copier uniquement le build final + deps de prodCOPY --from=builder --chown=appuser:appgroup /app/dist ./dist
COPY --from=deps /app/node_modules ./node_modules
COPY --chown=appuser:appgroup package.json ./
USER appuser
EXPOSE3000CMD ["node", "dist/server.js"]
Cibler un stage spécifique
# Builder jusqu'au stage "production" uniquementdockerbuild--targetproduction-tmonapp:prod .
# Builder jusqu'au stage "test" (utile en CI)dockerbuild--targettest-tmonapp:test .
# Le stage "test" peut être lancé pour validerdockerrun--rmmonapp:test
6
Instructions avancées du Dockerfile
ARG vs ENV
Dockerfile — ARG et ENV
# ARG : disponible uniquement pendant le buildARG APP_VERSION=1.0.0
ARG BUILD_DATE
# ENV : persisté dans l'image, accessible au runtimeENV NODE_ENV=production \
PORT=3000 \
APP_VERSION=${APP_VERSION}
LABEL org.opencontainers.image.version=${APP_VERSION} \
org.opencontainers.image.created=${BUILD_DATE}
# Passer au build# docker build --build-arg APP_VERSION=2.1.0 --build-arg BUILD_DATE=$(date -I) .
HEALTHCHECK
Dockerfile — Healthcheck
# HTTP healthcheck (wget disponible sur alpine)HEALTHCHECK \
--interval=30s \ # fréquence de vérification
--timeout=5s \ # délai max par check
--start-period=30s \# délai avant 1er check (app en démarrage)
--retries=3 \ # nb d'échecs avant unhealthyCMD wget -qO- http://localhost:3000/health || exit 1
# Voir l'état de santé# docker inspect --format='{{.State.Health.Status}}' monapp# docker inspect --format='{{json .State.Health}}' monapp | jq
ENTRYPOINT avec script d'initialisation
docker-entrypoint.sh + Dockerfile
#!/bin/sh # docker-entrypoint.shset -e
# Attendre que la base de données soit prêteuntil nc -z ${DB_HOST:-db}${DB_PORT:-5432}; doecho"Waiting for PostgreSQL..."sleep2done# Lancer les migrationsnode dist/migrate.js
# Lancer l'application avec les arguments passés à docker runexec"$@"
# ─── Volumes nommés ──────────────────────────────────dockervolumecreatemon-volumedockervolumelsdockervolumeinspectmon-volumedockervolumermmon-volumedockervolumeprune# supprimer volumes non utilisés# Monter un volume dans un containerdockerrun-d-vmon-volume:/datapostgres:16-alpine# ─── Bind mount (développement) ──────────────────────# Code source monté en live → hot reloaddockerrun-d \
-v$(pwd)/src:/app/src \
-v$(pwd)/public:/app/public \
-p3000:3000monapp:dev# ─── Partager un volume entre containers ─────────────dockerrun-d--namedb-vpgdata:/var/lib/postgresql/datapostgres:16dockerrun-d--nameapp-vpgdata:/backups:robackup-tool# ─── Sauvegarder / restaurer un volume ───────────────# Backupdockerrun--rm-vmon-volume:/data-v$(pwd):/backupalpine \
tar czf /backup/mon-volume.tar.gz -C /data .
# Restoredockerrun--rm-vmon-volume:/data-v$(pwd):/backupalpine \
tar xzf /backup/mon-volume.tar.gz -C /data
En développement : utiliser des bind mounts (-v $(pwd):/app) pour voir les modifications en temps réel sans rebuilder. En production : utiliser des volumes nommés gérés par Docker — plus portables et indépendants du système de fichiers hôte.
8
Réseaux Docker
Driver
Description
Cas d'usage
bridge
Réseau privé isolé (défaut). Containers sur le même bridge peuvent communiquer via DNS
Containers sur un même hôte
host
Partage le réseau de l'hôte directement (pas d'isolation réseau)
Haute performance, monitoring
none
Aucune interface réseau (totalement isolé)
Jobs batch sans besoin réseau
overlay
Réseau multi-hôtes pour Docker Swarm / Kubernetes
Clusters distribués
macvlan
Attribue une MAC address dédiée, le container semble être sur le LAN
Intégration réseau physique
Gestion des réseaux
# Créer un réseau bridge personnalisédockernetworkcreatemon-reseaudockernetworkcreate--driverbridge--subnet172.20.0.0/16mon-reseau# Lister les réseauxdockernetworklsdockernetworkinspectmon-reseau# Connecter des containers au même réseaudockerrun-d--namedb--networkmon-reseaupostgres:16-alpinedockerrun-d--nameapp--networkmon-reseau-p3000:3000monapp# Depuis "app", accéder à "db" par son nom (DNS automatique)# DATABASE_URL=postgres://user:pass@db:5432/mydb ← "db" résolu automatiquement !# Connecter un container existant à un réseaudockernetworkconnectmon-reseaumon-containerdockernetworkdisconnectmon-reseaumon-container# Supprimer un réseaudockernetworkrmmon-reseaudockernetworkprune# supprimer réseaux non utilisés
DNS automatique : sur un réseau bridge personnalisé (pas le réseau bridge par défaut), les containers se trouvent par leur nom. Si votre container s'appelle db, l'autre container peut l'appeler avec l'hostname db. C'est pour ça que dans Compose, le service name sert directement d'hostname.
Réseau bridge par défaut (legacy) : le réseau bridge créé par défaut par Docker ne supporte pas la résolution DNS par nom de container. Toujours créer un réseau bridge personnalisé (docker network create) pour la communication inter-containers.
9
Docker Compose — Bases
Docker Compose permet de décrire et lancer une stack multi-containers avec un seul fichier docker-compose.yml. Une seule commande remplace une dizaine de docker run avec tous leurs paramètres.
Note : depuis Docker Compose v2 (intégré dans Docker Desktop), la commande est docker compose (avec espace) et non docker-compose (avec tiret). Les deux fonctionnent mais docker compose est la version moderne recommandée.
10
Docker Compose — Avancé
Fichiers multiples — override par environnement
Structure de fichiers Compose
# docker-compose.yml ← base commune (partagée)# docker-compose.override.yml ← dev (chargé automatiquement)# docker-compose.prod.yml ← production (spécifié manuellement)# Développement (override automatique)dockercomposeup# Productiondockercompose-fdocker-compose.yml-fdocker-compose.prod.ymlup-d# CI/CDdockercompose-fdocker-compose.yml-fdocker-compose.ci.ymlup--build--exit-code-fromtests
docker-compose.override.yml (développement)
version: '3.9'services:
app:
build:
target: development# stage dev du multi-stagevolumes:
- .:/app# bind mount pour hot reload
- /app/node_modules# exclure node_modules du bindenvironment:
NODE_ENV: developmentDEBUG: "app:*"ports:
- "9229:9229"# port debug Node.jscommand: npm run dev# surcharger CMD du Dockerfiledb:
ports:
- "5432:5432"# exposer PG en dev seulement
Profiles — services optionnels
docker-compose.yml — profiles
services:
app:
image: monapp# pas de profile = toujours démarréadminer:
image: adminerprofiles: ["tools"] # démarré uniquement si profil activéports:
- "8080:8080"mailhog:
image: mailhog/mailhogprofiles: ["tools", "dev"]
ports:
- "1025:1025"
- "8025:8025"# Activer un profile# docker compose --profile tools up -d# COMPOSE_PROFILES=tools docker compose up -d
# Scaler un service à 3 instancesdockercomposeup-d--scaleworker=3# Dans le compose, déclarer le deploy (pour Swarm aussi)services:
worker:
image: monapp-workerdeploy:
replicas: 3restart_policy:
condition: on-failuremax_attempts: 3resources:
limits:
cpus: '0.5'memory: 256M
11
Registry & gestion des images
Registry
URL
Utilisation
Docker Hub
docker.io
Registry public officiel, images officielles
GitHub Container Registry
ghcr.io
Intégré à GitHub Actions, gratuit pour public
AWS ECR
*.dkr.ecr.*.amazonaws.com
Intégré à AWS ECS/EKS
Google Artifact Registry
*.pkg.dev
Intégré à GCP Cloud Run/GKE
Azure Container Registry
*.azurecr.io
Intégré à Azure AKS
Harbor
Self-hosted
Registry privé open-source, scan de vulnérabilités
# ✅ Tags recommandés par buildIMAGE=ghcr.io/monorg/monappCOMMIT=$(git rev-parse --short HEAD)
VERSION=$(git describe --tags --abbrev=0 2>/dev/null || echo"dev")
dockerbuild \
-t$IMAGE:$VERSION \ # ex: v1.2.3-t$IMAGE:$COMMIT \ # ex: a1b2c3d (traçabilité)-t$IMAGE:latest \ # toujours pointer vers le dernier
.
# ✅ Immutable tags en production : utiliser le sha256 digestdockerpull monapp@sha256:abc123def456...# Garantit qu'on lance exactement cette image, même si le tag change
// Lire le secret depuis le fichier monté par DockerconstreadSecret = (name) => {
const path = `/run/secrets/${name}`;
try {
return require('fs').readFileSync(path, 'utf8').trim();
} catch {
// Fallback sur variable d'environnement (dev sans secret)return process.env[name.toUpperCase()] || null;
}
};
const dbPassword = readSecret('db_password');
Ne jamais faire :COPY .env /app/ dans un Dockerfile, ni RUN export SECRET=valeur. Ces valeurs seraient gravées dans les layers de l'image et visibles par quiconque fait docker history ou docker inspect. Utiliser des build args uniquement pour des valeurs non sensibles.
13
Sécurité & limites de ressources
Limites CPU et mémoire
Limites de ressources
# Limites via docker rundockerrun \
--memory512m \ # max RAM (aussi: 1g, 256m)--memory-swap512m \ # =memory → désactive le swap--cpus1.5 \ # max 1.5 cores--cpu-shares512 \ # priorité relative (défaut 1024)monapp# Vérifier en livedockerstatsmonapp# Dans Composeservices:
app:
deploy:
resources:
limits:
cpus: '1.0'memory: 512Mreservations:
cpus: '0.25'memory: 128M
Checklist sécurité
Règle
Comment
Pourquoi
Utilisateur non-root
USER node dans Dockerfile ou --user 1001
Limite l'impact d'une compromission
Image minimale
Préférer -alpine, -slim, scratch, distroless
Moins de packages = moins de CVE
Scan d'image
docker scout cves monapp:1.0 ou Trivy
Détecter les vulnérabilités connues
Filesystem read-only
--read-only + tmpfs pour /tmp
Empêche l'écriture non autorisée
Capabilities réduites
--cap-drop ALL --cap-add NET_BIND_SERVICE
Principe du moindre privilège
No new privileges
--security-opt no-new-privileges
Empêche l'escalade de privilèges
PID limité
--pids-limit 200
Protection contre fork bombs
Réseau isolé
Réseaux Compose séparés par couche
DB non exposée au monde extérieur
Tags fixes
image: postgres:16.2 pas postgres:latest
Reproductibilité, pas de surprise au redéploiement
# Installer Trivy (scanner de vulnérabilités open-source)dockerrun--rm-v/var/run/docker.sock:/var/run/docker.sock \
aquasec/trivy:latest image monapp:1.0# Rapport en JSONdockerrun--rm-v/var/run/docker.sock:/var/run/docker.sock \
aquasec/trivy:latest image --formatjsonmonapp:1.0 > rapport.json
# Docker Scout (intégré dans Docker Desktop)dockerscoutcvesmonapp:1.0dockerscoutrecommendationsmonapp:1.0
14
Projet complet — Node.js + PostgreSQL + Nginx
Stack production complète : API Node.js avec Express, base de données PostgreSQL, cache Redis, reverse proxy Nginx avec SSL termination, et un dashboard Adminer accessible en dev.
🌐 Nginx :443→🟢 API :3000↔🐘 PostgreSQL :5432+⚡ Redis :6379
# Base de donnéesDB_USER=monappDB_PASS=changemeDB_NAME=monapp_db# ApplicationNODE_ENV=productionJWT_SECRET=changeme_secret_32chars_minimumSESSION_SECRET=changeme_session_secret# RedisREDIS_TTL=3600
Commandes de déploiement
# Premier déploiementcp .env.example .env # adapter les valeurs !dockercomposeup-d--build# Mise à jour sans downtimedockercomposepullappdockercomposeup-d--no-deps--buildapp# Voir l'état de la stackdockercomposepsdockercomposelogs-f--tail50# Backup base de donnéesdockercomposeexecdb pg_dump -U$DB_USER$DB_NAME > backup-$(date +%Y%m%d).sql
# Restaurerdockercomposeexec-Tdb psql -U$DB_USER$DB_NAME < backup.sql
15
Troubleshooting
🔴 Container s'arrête immédiatement (exit code 0 ou 1)
CauseProcessus principal se termine. Avec CMD en shell form (CMD node server.js), le shell wrapper capture mal les signaux. Le container pense que tout est terminé.
SolutionUtiliser la forme exec JSON : CMD ["node", "server.js"]. Vérifier les logs : docker logs monapp. Si exit 0, le processus se termine normalement (ajouter une boucle infinie ou laisser tourner le serveur).
🔴 Port déjà utilisé — "bind: address already in use"
CauseUn autre processus ou container utilise déjà le port 8080 (ou autre) sur l'hôte. Ou un container précédent n'a pas été supprimé.
Solutiondocker ps -a pour voir les containers arrêtés. docker rm ancien-container. Ou utiliser un port différent : -p 8081:80. Sur Linux : lsof -i :8080 pour trouver le processus.
🔴 "Cannot connect to the Docker daemon"
CauseLe daemon Docker n'est pas démarré, ou l'utilisateur n'a pas les permissions pour y accéder (groupe docker manquant sur Linux).
SolutionMac/Windows : démarrer Docker Desktop. Linux : sudo systemctl start docker. Ajouter l'utilisateur au groupe : sudo usermod -aG docker $USER puis se reconnecter.
🔴 Container démarre mais l'app ne répond pas
CauseL'app écoute sur 127.0.0.1 (localhost) au lieu de 0.0.0.0. Docker expose bien le port, mais l'app n'accepte pas les connexions venant de l'extérieur du container.
SolutionConfigurer l'app pour écouter sur 0.0.0.0. Ex Node.js : app.listen(3000, '0.0.0.0'). Vérifier avec docker exec monapp netstat -tlnp.
🔴 Build lent — pas de cache utilisé
CauseLe COPY du code source est fait AVANT npm install. Toute modification de code invalide le layer npm install → tout est reinstallé à chaque build.
SolutionOrdonner les instructions du moins changeant au plus changeant : COPY package*.json ./ puis RUN npm ci puis COPY . .. Les dépendances sont cachées tant que package.json ne change pas.
SolutionUtiliser docker exec -it monapp sh ou docker exec -it monapp /bin/sh. Ou installer bash dans le Dockerfile : RUN apk add --no-cache bash (déconseillé en prod).
🔴 Compose — "service depends_on but won't wait for readiness"
Causedepends_on par défaut attend juste que le container démarre, pas qu'il soit prêt (ex: PostgreSQL peut prendre 3-5s pour accepter des connexions).
SolutionUtiliser depends_on: db: condition: service_healthy avec un healthcheck sur le service db. Ou implémenter un script d'attente wait-for-it.sh dans l'entrypoint.
🔴 Espace disque saturé par les images / layers
CauseAccumulation d'images dangling (non taguées), de containers arrêtés, de volumes orphelins et de build cache.
Solutiondocker system df pour voir la consommation. docker system prune -a --volumes pour tout nettoyer (⚠ irréversible !). En routine : docker image prune -a + docker container prune.
🔴 "permission denied" dans le container
CauseLe container tourne avec un utilisateur non-root (UID 1001) mais le volume monté appartient à root sur l'hôte. Ou les fichiers copiés n'ont pas les bonnes permissions.
SolutionUtiliser COPY --chown=user:group dans le Dockerfile. Pour les volumes : docker run --user $(id -u):$(id -g). Ou dans Compose : user: "1001:1001".
16
Glossaire
Alpine
Distribution Linux ultra-légère (~5 MB) basée sur musl libc. Base idéale pour les images Docker légères (node:20-alpine).
ARG
Variable de build Dockerfile, accessible uniquement pendant docker build, non présente dans l'image finale. Utiliser pour la version, la date de build.
Bind Mount
Montage d'un répertoire de l'hôte dans un container (-v /chemin/hote:/container). Idéal pour le développement avec hot-reload.
BuildKit
Backend de build Docker modernisé (activé par défaut depuis Docker 23). Plus rapide, meilleur cache, support multi-platform, cache SSH.
cgroups
Mécanisme Linux (Control Groups) permettant de limiter les ressources (CPU, RAM, I/O) d'un groupe de processus. Base des limites Docker.
CMD
Instruction Dockerfile définissant la commande par défaut au démarrage du container. Surchargeable à l'exécution avec docker run image commande.
Container
Instance en cours d'exécution d'une image Docker. Isolé via namespaces Linux, éphémère par défaut. Partage le kernel de l'hôte.
Dangling image
Image sans tag (affiché <none>). Résulte d'un rebuild : l'ancien tag est réattribué à la nouvelle image, laissant l'ancienne orpheline.
Distroless
Images Google sans shell ni package manager, contenant uniquement les librairies runtime. Surface d'attaque minimale pour la production.
Docker Compose
Outil de définition et gestion de stacks multi-containers via un fichier YAML. docker compose up lance toute la stack.
Docker Desktop
Application GUI pour Mac/Windows incluant Docker Engine, Compose, Docker Scout, Kubernetes local et un dashboard visuel.
Dockerfile
Fichier texte contenant les instructions pour construire une image Docker, de la base jusqu'à la commande de démarrage.
ENTRYPOINT
Instruction Dockerfile définissant la commande fixe du container. CMD lui sert d'arguments. Moins facilement surchargeable que CMD seul.
ENV
Instruction Dockerfile définissant une variable d'environnement persistée dans l'image et accessible au runtime dans le container.
Healthcheck
Vérification périodique de l'état d'un container. Statuts : starting, healthy, unhealthy. Utilisé par Compose pour les depends_on.
Image
Template immuable en lecture seule composé de layers superposés. Construite depuis un Dockerfile ou tirée d'un registry.
Layer
Couche du système de fichiers produite par chaque instruction Dockerfile (RUN, COPY, ADD). Mise en cache pour accélérer les rebuilds.
Multi-stage build
Technique Dockerfile utilisant plusieurs FROM pour produire une image finale légère ne contenant que les artefacts de build.
Namespace
Mécanisme Linux d'isolation (PID, réseau, montages, utilisateurs). Chaque container a ses propres namespaces = isolation sans VM.
Network
Réseau virtuel Docker permettant la communication entre containers. Bridge personnalisé = DNS automatique par nom de service.
Registry
Serveur de stockage et distribution d'images Docker. Docker Hub est le registry public officiel. ECR, GCR, Harbor sont des alternatives.
Secret
Mécanisme sécurisé pour passer des données sensibles aux containers. Monté en tmpfs dans /run/secrets/, non visible dans docker inspect.
Tag
Étiquette d'une image (ex: nginx:1.25-alpine). latest par défaut mais non recommandé en production (non déterministe).
tmpfs
Montage en mémoire RAM, non persisté sur disque. Utilisé pour les fichiers temporaires sensibles ou les caches haute performance.
Union FS
Système de fichiers par union permettant de superposer les layers d'une image. Implementations : overlay2 (défaut), devicemapper, btrfs.
Volume
Stockage persistant géré par Docker, indépendant du cycle de vie du container. Survit à docker rm, partageable entre containers.
WORKDIR
Instruction Dockerfile définissant le répertoire courant pour les instructions suivantes (COPY, RUN, CMD). Crée le dossier si inexistant.