Retour au cours

infra / docker

Dockerfile : les bases

Leçon 31 exercice

Explication

Ce que vous allez apprendre

  • Écrire un Dockerfile minimal en comprenant le rôle de chaque instruction (FROM, WORKDIR, COPY, RUN, CMD)
  • Comprendre le principe des couches et pourquoi il influence la taille et la vitesse de build
  • Distinguer clairement ENTRYPOINT (binaire fixe) de CMD (arguments par défaut remplaçables)
  • Construire une image avec docker build -t et la lancer avec les bons ports
  • Protéger une image avec un .dockerignore pour éviter d'y embarquer des fichiers sensibles ou inutiles

Dans quel contexte ?

Une développeuse doit packager pour la première fois son API FastAPI, jusque-là seulement lancée en local avec uvicorn. Elle doit décrire, dans un Dockerfile, l'image de base Python à utiliser, où copier son code, comment installer les dépendances, et quelle commande lancer au démarrage — pour qu'un collègue, ou un serveur de production, puisse reproduire exactement le même environnement sans jamais avoir eu à l'installer manuellement.

De l'image toute faite à sa propre image

Jusqu'ici, on a téléchargé et lancé des images déjà construites par d'autres (nginx, ubuntu...). Mais pour faire tourner sa propre application, il faut pouvoir construire sa propre image. C'est exactement à ça que sert un Dockerfile : un fichier texte qui décrit, étape par étape, comment fabriquer une image — un peu comme une recette de cuisine décrit comment obtenir un plat à partir d'ingrédients.

InstructionRôle
FROMImage de base sur laquelle construire
WORKDIRRépertoire de travail dans l'image
COPYCopie des fichiers du projet vers l'image
RUNExécute une commande au moment du build
CMDCommande lancée par défaut au démarrage du conteneur

Prérequis

Cette leçon suppose que tu es à l'aise avec les commandes de base (docker run, docker ps) vues dans les deux premières leçons.

Le principe des couches

Chaque instruction d'un Dockerfile (FROM, COPY, RUN...) crée une nouvelle couche (layer) empilée sur les précédentes. C'est une idée centrale à bien comprendre dès maintenant, car elle influence tout le reste : la vitesse de construction, la taille finale de l'image, et l'usage du cache (approfondi dans une leçon ultérieure). Chaque couche est en pratique un ensemble de différences par rapport à la couche du dessous, un peu comme des calques superposés dans un logiciel de dessin.

Ce que fait chaque instruction, en clair

  • FROM choisit le point de départ : on ne repart jamais de zéro, mais d'une image existante (ici une version minimale de Python).
  • WORKDIR fixe le dossier de travail à l'intérieur de l'image, pour éviter de répéter des chemins absolus partout.
  • COPY fait entrer des fichiers du projet dans l'image.
  • RUN exécute une commande pendant la construction (par exemple installer des dépendances) — le résultat est figé dans l'image.
  • CMD ne s'exécute pas au moment du build : c'est la commande lancée par défaut quand un conteneur démarre.

ENTRYPOINT vs CMD, le piège classique

Beaucoup de débutants confondent les deux. Retenir l'image du "binaire fixe" : ENTRYPOINT définit le programme qui sera toujours exécuté, CMD fournit ses arguments par défaut, que l'on peut librement remplacer au lancement sans toucher au Dockerfile.

Ne pas oublier .dockerignore

Sans lui, COPY . . embarque aussi les fichiers .git, les dépendances déjà installées ou même des secrets locaux dans l'image.

Piège fréquent

Oublier un .dockerignore est une erreur de sécurité fréquente : un fichier .env contenant des mots de passe, copié par mégarde via COPY . ., se retrouve gravé dans l'image et reste consultable par quiconque y a accès, même après l'avoir supprimé du code source.

Commandes & code

Dockerfile : les bases

dockerfile
# Dockerfile minimal pour une API Python/FastAPI
FROM python:3.12-slim
# FROM définit l'image de base : toujours choisir la plus légère qui couvre le besoin

WORKDIR /app
# WORKDIR crée (si besoin) et fixe le répertoire de travail pour toutes les instructions suivantes

COPY requirements.txt .
# COPY copie des fichiers depuis le contexte de build vers l'image

RUN pip install --no-cache-dir -r requirements.txt
# RUN exécute une commande AU MOMENT DU BUILD, crée une nouvelle couche (layer)

COPY . .
# Copie le reste du code APRÈS l'installation des dépendances (voir leçon cache pour le pourquoi)

ENV PORT=8000
# ENV définit une variable d'environnement disponible au build ET à l'exécution

EXPOSE 8000
# EXPOSE documente le port utilisé (n'ouvre rien tout seul, -p reste nécessaire au run)

CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
# CMD définit la commande par défaut au démarrage du conteneur (forme exec, recommandée)
bash
docker build -t mon-api:1.0 .              # construit l'image, "." = contexte de build (dossier courant)
docker build -t mon-api:1.0 -f Dockerfile.prod .   # utilise un Dockerfile au nom custom
docker run -d -p 8000:8000 mon-api:1.0       # lance l'image construite
dockerfile
# CMD vs ENTRYPOINT
# CMD seul       : commande par défaut, ENTIÈREMENT remplaçable par un argument de "docker run"
# ENTRYPOINT seul: commande fixe, les arguments de "docker run" lui sont ajoutés en argument
# Les deux combinés : ENTRYPOINT = binaire fixe, CMD = arguments par défaut (remplaçables)
ENTRYPOINT ["uvicorn", "app.main:app"]
CMD ["--host", "0.0.0.0", "--port", "8000"]
# docker run mon-api --port 9000    -> remplace uniquement CMD, garde uvicorn app.main:app
text
# .dockerignore : évite de copier des fichiers inutiles/sensibles dans le contexte de build
.git
__pycache__/
*.pyc
.env
node_modules/
tests/

Résumé

  • FROM, WORKDIR, COPY, RUN, ENV, EXPOSE, CMD forment le socle d'un Dockerfile.
  • ENTRYPOINT fixe le binaire exécuté, CMD fournit ses arguments par défaut — remplaçables au docker run.
  • .dockerignore évite de copier .git, node_modules, secrets et fichiers de test dans l'image finale.

Exercices pratiques

1 disponible
1

Mission : corriger une image qui fuit des secrets et un port mal exposé

Objectif : Corriger un Dockerfile bâclé pour éviter une fuite de secrets et bien distinguer ENTRYPOINT de CMD.

Contexte

Un stagiaire a écrit un Dockerfile FastAPI sans .dockerignore : COPY . . a embarqué le fichier .env contenant un mot de passe, visible dans l'image publiée. Il a aussi mélangé ENTRYPOINT et CMD, rendant impossible de changer le port sans modifier le Dockerfile. Tu dois corriger les deux problèmes.

Résoudre l’exercice →