Docker a considérablement évolué depuis ses débuts. En 2025, c’est une plateforme de production sophistiquée qui nécessite des workflows modernes et des bonnes pratiques actualisées. Ce guide complet vous présente les 42 meilleures pratiques essentielles pour sécuriser, optimiser et maintenir vos conteneurs Docker.
Sécurité : Protéger Vos Conteneurs
1. Ne Jamais Exécuter les Conteneurs en Root
Pourquoi c’est critique : Exécuter des conteneurs en tant qu’utilisateur root augmente considérablement les risques d’escalade de privilèges. Si un attaquant compromet votre conteneur, il obtient des droits administratifs.
Solution :
# Créer un utilisateur non-privilégié
RUN addgroup -g 1001 -S appgroup &&
adduser -u 1001 -S appuser -G appgroup
# Basculer vers cet utilisateur
USER appuser
2. Scanner les Images pour les Vulnérabilités
Utilisez des outils comme Trivy ou Docker Scout pour analyser régulièrement vos images. Ces outils détectent les vulnérabilités connues dans vos dépendances et composants système.
# Installation de Trivy
docker run aquasec/trivy image votre-image:tag
# Utilisation de Docker Scout
docker scout cves votre-image:tag
3. Utiliser .dockerignore pour Protéger les Secrets
Le fichier .dockerignore empêche l’inclusion de fichiers sensibles comme .env, credentials.json ou des clés SSH dans vos images.
Exemple de .dockerignore :
.env
.git
.pem
.key
nodemodules
.vscode
secrets/
4. Ne Jamais Embarquer de Secrets dans les Images
Mauvaise pratique :
# ❌ DANGER : Secret en dur
ENV APIKEY="sk-1234567890abcdef"
Bonne pratique :
# ✅ Utiliser Docker Secrets ou des variables d'environnement
# Les secrets sont injectés au runtime
# Avec Docker Swarm
echo "monsecret" | docker secret create apikey -
# Avec docker-compose
docker-compose --env-file .env up
5. Limiter les Capacités des Conteneurs
Restreignez les capacités système (capabilities) aux seules nécessaires pour l’application.
# docker-compose.yml
services:
app:
capdrop:
- ALL
capadd:
- NETBINDSERVICE
6. Définir des Limites de Ressources
Prévenez les attaques par épuisement des ressources en définissant des limites CPU et mémoire.
services:
app:
deploy:
resources:
limits:
cpus: '0.50'
memory: 512M
reservations:
cpus: '0.25'
memory: 256M
Performance : Optimiser la Vitesse et l’Efficacité
7. Utiliser les Builds Multi-Stages
Les builds multi-stages séparent l’environnement de build et l’environnement d’exécution, produisant des images ultra-légères.
# Stage 1 : Build
FROM node:20-alpine AS builder
WORKDIR /app
COPY package.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
# Stage 2 : Production
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/nodemodules ./nodemodules
USER node
CMD ["node", "dist/server.js"]
Avantages :
- Réduction de la taille d’image de 70-90%
- Exclusion des outils de développement
- Surface d’attaque minimale
- Builds parallèles : Étapes indépendantes exécutées simultanément
- Cache intelligent : Meilleure réutilisation des couches
- Montages de cache : Persistance du cache entre builds
8. Activer BuildKit pour des Builds Rapides
BuildKit est le moteur de build moderne de Docker, activé par défaut depuis Docker 23.0. Il offre :
# Activer BuildKit (si version < 23.0)
export DOCKERBUILDKIT=1
# Utiliser les montages de cache
docker build --progress=plain .
Exemple avec cache mount :
# Installer les dépendances avec cache persistant
RUN --mount=type=cache,target=/root/.npm
npm install
9. Optimiser la Mise en Cache des Couches
Docker construit les images en couches. Ordonnez vos instructions du plus stable au plus changeant.
# ✅ Bon ordre : cache efficace
FROM python:3.12-slim
# 1. Dépendances système (changent rarement)
RUN apt-get update && apt-get install -y
gcc
&& rm -rf /var/lib/apt/lists/
# 2. Dépendances Python (changent occasionnellement)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 3. Code applicatif (change fréquemment)
COPY . .
# ❌ Mauvais ordre : cache inefficace
FROM python:3.12-slim
COPY . . # Invalide le cache à chaque modification
RUN pip install -r requirements.txt
10. Nettoyer le Cache APT/YUM
Supprimez les fichiers de cache après installation des paquets pour réduire la taille de l’image.
# Pour Debian/Ubuntu
RUN apt-get update && apt-get install -y
package1 package2
&& apt-get clean
&& rm -rf /var/lib/apt/lists/
# Pour Alpine
RUN apk add --no-cache package1 package2
# Pour RHEL/CentOS
RUN yum install -y package1 package2
&& yum clean all
Optimisation des Images : Taille Minimale
11. Utiliser des Images de Base Minimales
En 2025, les « micro-distros » comme Wolfi et Chainguard Images offrent d’excellentes garanties de sécurité avec une empreinte minimale.
Comparaison des tailles :
ubuntu:latest → 77 MB
python:3.12 → 1.02 GB
python:3.12-slim → 131 MB
python:3.12-alpine → 51 MB
chainguard/python → 45 MB (+ sécurité renforcée)
Recommandations par langage :
# Node.js
FROM node:20-alpine
# Python
FROM python:3.12-slim
# Go (distroless)
FROM gcr.io/distroless/static-debian12
# Rust
FROM rust:1.75-alpine AS builder
FROM gcr.io/distroless/cc-debian12
12. Éviter les Packages Inutiles
N’installez que les dépendances strictement nécessaires.
# ❌ Mauvais : installe des recommandations inutiles
RUN apt-get install -y curl
# ✅ Bon : n'installe que le minimum
RUN apt-get install -y --no-install-recommends curl
13. Combiner les Commandes RUN
Chaque instruction RUN crée une nouvelle couche. Combinez les commandes pour réduire le nombre de couches.
# ❌ Mauvais : 3 couches
RUN apt-get update
RUN apt-get install -y curl
RUN curl https://example.com/install.sh | bash
# ✅ Bon : 1 seule couche
RUN apt-get update &&
apt-get install -y curl &&
curl https://example.com/install.sh | bash &&
apt-get clean &&
rm -rf /var/lib/apt/lists/
Pratiques de Production
14. Implémenter des Health Checks
Les health checks permettent à Docker et aux orchestrateurs (Kubernetes, Swarm) de détecter et redémarrer les conteneurs défaillants.
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3
CMD curl -f http://localhost:3000/health || exit 1
# docker-compose.yml
services:
app:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 3s
retries: 3
startperiod: 5s
15. Utiliser des Tags Sémantiques
Ne vous contentez pas du tag :latest. Utilisez des versions sémantiques et des hash de commit.
# ❌ Mauvais : impossible de tracer la version
docker build -t monapp:latest .
# ✅ Bon : tracabilité complète
docker build -t monapp:1.2.3 .
docker build -t monapp:1.2.3-$(git rev-parse --short HEAD) .
docker build -t monapp:sha-a3b2c1d .
16. Maintenir les Images à Jour
Mettez régulièrement à jour vos images de base et dépendances pour corriger les vulnérabilités.
# Spécifier une version précise (mais pas latest)
FROM node:20.11-alpine3.19
# Planifier des mises à jour régulières (ex: mensuelle)
17. Utiliser des Labels pour la Métadonnée
Les labels documentent vos images et facilitent l’automatisation.
LABEL org.opencontainers.image.title="Mon Application"
LABEL org.opencontainers.image.description="API REST pour la gestion d'utilisateurs"
LABEL org.opencontainers.image.version="1.2.3"
LABEL org.opencontainers.image.authors="dev@monentreprise.com"
LABEL org.opencontainers.image.source="https://github.com/monentreprise/monapp"
LABEL org.opencontainers.image.revision="${GITCOMMIT}"
Nouvelles Fonctionnalités 2025
18. Docker Init pour Démarrer Rapidement
Docker 24.0+ inclut docker init qui génère automatiquement les fichiers Docker pour votre projet.
# Génère Dockerfile, .dockerignore et compose.yaml
docker init
# Supporte : Go, Python, Node.js, Rust, ASP.NET
19. Docker Scout pour la Sécurité
Docker Scout analyse vos images et recommande des corrections.
# Analyser une image
docker scout cves monapp:latest
# Obtenir des recommandations
docker scout recommendations monapp:latest
# Comparer deux versions
docker scout compare monapp:1.0.0 monapp:2.0.0
20. Attestations de Build
Les attestations prouvent la provenance et l’intégrité de vos images.
# Créer une image avec attestation
docker buildx build --sbom=true --provenance=true -t monapp:1.0 .
# Vérifier l'attestation
docker buildx imagetools inspect monapp:1.0 --format "{{json .Provenance}}"
Architecture et Orchestration
21. Un Processus par Conteneur
Respectez le principe « one process per container » pour faciliter la scalabilité.
# ✅ Bon : Services séparés
services:
api:
image: monapp-api:latest
worker:
image: monapp-worker:latest
scheduler:
image: monapp-scheduler:latest
# ❌ Mauvais : Tout dans un conteneur
services:
monolithe:
image: monapp-tout-en-un:latest
# api + worker + scheduler + cron
22. Utiliser des Réseaux Personnalisés
Isolez vos services avec des réseaux Docker dédiés.
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true # Pas d'accès externe
services:
web:
networks:
- frontend
api:
networks:
- frontend
- backend
database:
networks:
- backend # Accessible uniquement par l'API
23. Gérer les Logs Correctement
Dirigez les logs vers STDOUT/STDERR pour que Docker les capture.
# ✅ Bon : Logs vers STDOUT
CMD ["node", "server.js"]
# Configuration du logging
# docker-compose.yml
services:
app:
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
Développement et CI/CD
24. Utiliser Docker Compose pour le Développement Local
Définissez votre stack complète dans compose.yaml.
version: '3.9'
services:
app:
build:
context: .
dockerfile: Dockerfile.dev
volumes:
- .:/app
- /app/nodemodules
environment:
- NODEENV=development
ports:
- "3000:3000"
dependson:
db:
condition: servicehealthy
db:
image: postgres:16-alpine
environment:
POSTGRESDB: myapp
POSTGRESUSER: dev
POSTGRESPASSWORD: devpass
volumes:
- postgresdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pgisready -U dev"]
interval: 5s
volumes:
postgresdata:
25. Builds Reproductibles
Fixez les versions de toutes vos dépendances.
# ✅ Bon : Versions fixes
FROM node:20.11.1-alpine3.19
RUN npm install express@4.18.2
# ❌ Mauvais : Versions flottantes
FROM node:latest
RUN npm install express
26. Automatiser avec GitHub Actions
Intégrez Docker dans votre pipeline CI/CD.
# .github/workflows/docker.yml
name: Docker Build & Push
on:
push:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUBUSERNAME }}
password: ${{ secrets.DOCKERHUBTOKEN }}
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: |
monapp:latest
monapp:${{ github.sha }}
cache-from: type=registry,ref=monapp:buildcache
cache-to: type=registry,ref=monapp:buildcache,mode=max
Conseils Avancés
27. BuildKit Secrets pour les Builds Sécurisés
Passez des secrets aux builds sans les exposer dans les couches.
# Utiliser un secret pendant le build
RUN --mount=type=secret,id=npmtoken
echo "//registry.npmjs.org/:authToken=$(cat /run/secrets/npmtoken)" > .npmrc &&
npm install &&
rm .npmrc
# Build avec secret
docker buildx build --secret id=npmtoken,src=$HOME/.npmrc .
28. Compression des Couches
Minimisez le nombre de fichiers modifiés dans chaque couche.
# ✅ Bon : Suppression dans la même couche
RUN wget https://example.com/large-file.tar.gz &&
tar xzf large-file.tar.gz &&
rm large-file.tar.gz # Fichier non présent dans l'image finale
# ❌ Mauvais : Suppression dans une autre couche
RUN wget https://example.com/large-file.tar.gz
RUN tar xzf large-file.tar.gz
RUN rm large-file.tar.gz # Fichier toujours dans la couche précédente!
29. Utiliser ARG pour la Paramétrisation
Les ARG permettent de paramétrer vos builds.
ARG NODEVERSION=20
ARG APPENV=production
FROM node:${NODEVERSION}-alpine
ENV NODEENV=${APPENV}
# Build avec args personnalisés
# docker build --build-arg NODEVERSION=18 --build-arg APPENV=staging .
30. Rootless Docker pour la Sécurité Maximum
Exécutez le daemon Docker lui-même sans privilèges root.
# Installation de Docker en mode rootless
curl -fsSL https://get.docker.com/rootless | sh
# Configurer les variables d'environnement
export PATH=/home/user/bin:$PATH
export DOCKERHOST=unix:///run/user/1000/docker.sock
Performance de Production
31. Utiliser Healthcheck avec Dépendances
Attendez que les dépendances soient prêtes avant de démarrer.
services:
api:
dependson:
db:
condition: servicehealthy
redis:
condition: servicehealthy
32. Configurer les Restart Policies
Définissez comment Docker doit gérer les redémarrages.
services:
app:
restart: unless-stopped
deploy:
restartpolicy:
condition: on-failure
delay: 5s
maxattempts: 3
33. Optimiser pour les Systèmes de Fichiers
Utilisez des volumes pour les données persistantes et les caches.
services:
app:
volumes:
# Données persistantes
- appdata:/app/data
# Cache de build (performance)
- nodemodules:/app/nodemodules
# Code en développement (bind mount)
- ./src:/app/src:ro # read-only
volumes:
appdata:
driver: local
nodemodules:
34. Utiliser tmpfs pour les Données Temporaires
Les montages tmpfs utilisent la RAM pour des performances maximales.
services:
app:
tmpfs:
- /tmp
- /app/cache:size=100M
Sécurité Avancée
35. Scanner en Continu avec Trivy
Intégrez Trivy dans votre CI pour bloquer les images vulnérables.
# .github/workflows/security.yml
name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: 'monapp:${{ github.sha }}'
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'
exit-code: '1' # Fail le build si vulnérabilités
36. Utiliser AppArmor ou SELinux
Renforcez l’isolement avec des profils de sécurité.
services:
app:
securityopt:
- apparmor:docker-default
- no-new-privileges:true
37. Désactiver l’Accès au Socket Docker
Ne montez JAMAIS /var/run/docker.sock sauf nécessité absolue.
# ❌ TRÈS DANGEREUX
volumes:
- /var/run/docker.sock:/var/run/docker.sock
# Cette configuration donne au conteneur un contrôle TOTAL sur l'hôte
38. Utiliser Read-Only Filesystems
Montez le système de fichiers racine en lecture seule.
services:
app:
readonly: true
tmpfs:
- /tmp
- /var/run
Monitoring et Observabilité
39. Exposer des Métriques
Fournissez un endpoint de métriques pour Prometheus.
EXPOSE 3000 9090
# 3000: Application
# 9090: Métriques Prometheus
// Exemple Node.js avec prom-client
const prometheus = require('prom-client');
const register = new prometheus.Registry();
// Métriques par défaut
prometheus.collectDefaultMetrics({ register });
app.get('/metrics', async (req, res) => {
res.set('Content-Type', register.contentType);
res.end(await register.metrics());
});
40. Configurer les Log Drivers
Envoyez les logs vers un système centralisé.
services:
app:
logging:
driver: "fluentd"
options:
fluentd-address: "fluentd:24224"
tag: "monapp"
41. Utiliser des Tracing Distribués
Intégrez OpenTelemetry pour le tracing.
# Installer l'agent OpenTelemetry
RUN npm install @opentelemetry/sdk-node @opentelemetry/auto-instrumentations-node
Checklist Finale de Production
42. Checklist Avant Déploiement
Avant de déployer en production, vérifiez :
Sécurité :
Performance :
Production :
Observabilité :
Conclusion
Docker en 2025 est une plateforme mature qui exige rigueur et expertise. Les pratiques obsolètes de 2015 n’ont plus leur place : les images doivent être minimales, sécurisées et optimisées pour la production.
Points clés à retenir :
En appliquant ces 42 meilleures pratiques, vous construirez des images Docker robustes, sécurisées et performantes, prêtes pour les environnements de production exigeants.
Sources et Références
Article mis à jour en décembre 2025 avec les dernières pratiques et outils de l’écosystème Docker.