Bonnes pratiques
Images légères — Alpine et slim
La taille d'une image Docker impacte le temps de pull, l'espace disque et la surface d'attaque. Utilise des images de base légères dès que possible.
node:20-alpine(~136 Mo) plutôt quenode:20(~1 Go)python:3.12-slimplutôt quepython:3.12nginx:alpineplutôt quenginx
Multi-stage builds
Un multi-stage build utilise plusieurs FROM dans un Dockerfile.
Le premier stage compile/build. Le second stage ne contient que le résultat final —
pas les outils de build. Résultat : image finale beaucoup plus petite.
# Stage 1 : build
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Stage 2 : image de production (sans node_modules de dev)
FROM node:20-alpine AS production
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
USER node
EXPOSE 3000
CMD ["node", "dist/server.js"]
Ne pas tourner en root
Par défaut, les processus dans un conteneur tournent en root.
C'est un risque : si un attaquant compromet le processus, il a les droits root dans le conteneur.
Utilise l'instruction USER pour basculer sur un utilisateur non-privilégié.
FROM node:20-alpine
WORKDIR /app
COPY --chown=node:node . .
RUN npm ci --production
# Basculer sur l'user "node" (fourni par l'image node officielle)
USER node
CMD ["node", "server.js"]
Gestion des secrets
Ne mets jamais de secrets (mots de passe, API keys) dans le Dockerfile ou l'image. Ils seraient visibles dans l'historique de layers.
- Passe les secrets via des variables d'environnement au lancement (
-eouenv_file) - Utilise Docker Secrets en mode Swarm pour les infras avancées
- En CI/CD : stocke dans les secrets du pipeline (GitHub Actions Secrets, GitLab CI Variables)
Un RUN echo "my-password" > /etc/secret dans un Dockerfile est visible dans les layers
même si tu supprimes le fichier ensuite. Les layers sont immuables.
Utilise --mount=type=secret (BuildKit) pour passer des secrets pendant le build sans les stocker.
Health checks
Un health check permet à Docker (et Kubernetes) de savoir si ton service est opérationnel.
# Vérifie que l'app répond toutes les 30 secondes
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1
Un processus par conteneur
Un conteneur = un seul processus principal. Ne mets pas nginx + node + cron dans le même conteneur. Utilise Docker Compose pour orchestrer plusieurs conteneurs spécialisés. Cela facilite le scaling, les logs et le débogage.
Scanne régulièrement tes images pour des vulnérabilités connues :
docker scout quickview (intégré Docker Desktop) ou trivy image mon-app:latest.
Les images de base reçoivent des mises à jour de sécurité — rebuild régulièrement.
- Utilise des images de base légères : alpine ou slim.
- Multi-stage builds = image finale sans outils de build → plus petite et plus sûre.
- Ajoute
USERdans le Dockerfile pour ne pas tourner en root. - Jamais de secrets dans le Dockerfile ou dans les layers — utilise des variables d'environnement.
- Un conteneur = un processus. Utilise Docker Compose pour les architectures multi-services.