Écrire un Dockerfile
Un Dockerfile est la recette qui décrit comment construire votre image Docker. Chaque instruction crée un nouveau layer.
Instructions essentielles
# Image de base (point de départ)
FROM python:3.11-slim
# Variables d'environnement
ENV PYTHONUNBUFFERED=1
ENV APP_PORT=8000
# Répertoire de travail dans le conteneur
WORKDIR /app
# Copier les fichiers de dépendances EN PREMIER (optimisation du cache)
COPY requirements.txt .
# Exécuter une commande pendant le build
RUN pip install --no-cache-dir -r requirements.txt
# Copier le reste du code
COPY . .
# Exposer le port (documentation, pas une règle de pare-feu)
EXPOSE 8000
# Commande de démarrage du conteneur
CMD ["python", "-m", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
Construire et exécuter
# Construire l'image (. = contexte = répertoire courant)
docker build -t mon-app:v1.0 .
# Voir la progression et les layers
docker build -t mon-app:v1.0 . --progress=plain
# Lancer le conteneur basé sur l'image
docker run -d -p 8080:8000 --name mon-app mon-app:v1.0
# Accéder à l'app
curl http://localhost:8080
Optimiser le cache Docker
Docker met en cache chaque layer. Si un layer n'a pas changé depuis le dernier build, il est réutilisé. L'ordre des instructions est critique :
# ❌ Mauvais : COPY . . en premier invalide le cache à chaque changement de code
FROM python:3.11-slim
COPY . .
RUN pip install -r requirements.txt
# ✅ Bon : dépendances d'abord (changent rarement), code ensuite (change souvent)
FROM python:3.11-slim
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
Le fichier .dockerignore
# .dockerignore : exclut du contexte de build
__pycache__/
*.pyc
.git/
.env
node_modules/
*.log
Sans .dockerignore, COPY . . envoie TOUT le répertoire au daemon Docker, y compris .git et node_modules.
Cas concret : Dockerfile multi-stage
# Stage 1 : build (image complète avec outils de compilation)
FROM node:20 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Stage 2 : production (image minimale, sans node_modules de dev)
FROM nginx:alpine AS production
COPY --from=builder /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
Résultat : image de production de ~30 Mo au lieu de ~1 Go avec tous les outils de build.
Erreurs fréquentes
RUNmultiple au lieu de chaîner avec&&: chaqueRUNcrée un layer. Chaîner (RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*) réduit la taille.- Oublier
.dockerignore: envoyer.gitounode_modulesau daemon ralentit le build et grossit le contexte. - Lancer en root : par défaut les conteneurs tournent en root. Ajouter
USER appuseraprès avoir créé l'utilisateur.
À retenir
FROM→ base.COPY→ fichiers.RUN→ commandes build.CMD→ démarrage.- Mettre les dépendances AVANT le code source pour maximiser le cache.
.dockerignore= obligatoire pour un build propre.- Multi-stage builds → images de production minimales.