Dockerfile

Un Dockerfile est un fichier texte contenant une suite d’instructions permettant d’automatiser la construction d’une image Docker.
C’est la “recette” qui décrit pas à pas comment obtenir une image personnalisée, réutilisable et portable.

Chaque ligne du Dockerfile est interprétée par le moteur Docker (dockerd) lors d’un docker build.
Chaque instruction produit une couche (layer) qui s’empile sur l’image de base.


Structure générale

Un Dockerfile est lu de haut en bas.
Les instructions principales sont :

  • FROM : définit l’image de base (ex. FROM ubuntu:24.04).

  • RUN : exécute une commande lors de la construction (ex. installation de paquets).

  • COPY ou ADD : copie des fichiers du contexte de build dans l’image.

  • WORKDIR : définit le répertoire de travail par défaut.

  • CMD : définit la commande par défaut exécutée au démarrage du conteneur.

  • ENTRYPOINT : définit le programme principal du conteneur (arguments ajoutés à l’exécution).


Exemple minimal

FROM ubuntu:24.04
RUN apt-get update && apt-get install -y curl
CMD ["bash"]

Cette image est basée sur Ubuntu 24.04, inclut curl, et lance bash par défaut.


CMD vs ENTRYPOINT

CMD

  • Définit une commande par défaut.

  • Peut être remplacée par des arguments donnés à docker run.

Exemple :

CMD ["echo", "Hello World"]
docker run monimage echo "Autre commande"

Ici, echo "Autre commande" remplace le CMD.

ENTRYPOINT

  • Définit un programme fixe.

  • Les arguments passés en ligne de commande sont ajoutés.

Exemple :

ENTRYPOINT ["echo"]
docker run monimage "Hello"

Résultat : echo Hello

Combinaison

Il est courant de combiner les deux :

ENTRYPOINT ["ping"]
CMD ["127.0.0.1"]
  • docker run monimageping 127.0.0.1

  • docker run monimage google.comping google.com


Couches et cache

  • Chaque instruction (RUN, COPY, etc.) crée une nouvelle couche immuable.

  • Docker conserve un cache pour accélérer les builds.

  • Si une étape n’a pas changé, Docker réutilise la couche précédente.

  • ⚠️ Conséquence : l’ordre des instructions est important.

Exemple :

RUN apt-get update
RUN apt-get install -y curl

crée deux couches.

En regroupant :

RUN apt-get update && apt-get install -y curl

une seule couche, plus efficace.


Contexte de build

Lors d’un docker build ., Docker envoie le contenu du répertoire courant (.) au démon.
Ce répertoire est appelé le contexte de build.

  • Le Dockerfile et les fichiers copiés avec COPY doivent être dans ce contexte.

  • Éviter d’envoyer des fichiers inutiles (logs, binaires, node_modules…).

  • On peut utiliser un fichier .dockerignore pour exclure certains fichiers.

Astuce : utiliser l’option -f avec docker build

Par défaut, Docker cherche un fichier nommé Dockerfile à la racine du contexte de build (.).
Si ton fichier s’appelle autrement ou se trouve ailleurs, il faut utiliser l’option -f.

# Exemple : Dockerfile situé dans le répertoire build/
docker build -f build/Dockerfile -t monimage:1.0 .

-f build/Dockerfile : indique où se trouve le Dockerfile.

  • . : reste le contexte (fichiers copiés via COPY/ADD).


⚠️ Attention

  • Le chemin du Dockerfile (-f) et le contexte (.) sont deux notions indépendantes.

  • Si le Dockerfile fait un COPY ./fichier.txt /app/, ce fichier doit exister dans le contexte, pas forcément à côté du Dockerfile.


Exemple pratique

Avoir deux Dockerfiles (Dockerfile.dev, Dockerfile.prod) pour construire des images différentes :

docker build -f Dockerfile.dev -t monapp:dev .
docker build -f Dockerfile.prod -t monapp:prod .

Bonnes pratiques

  • Utiliser des images officielles fiables (Docker Hub).

  • Choisir des images minimales (alpine, debian-slim).

  • Grouper les commandes RUN pour réduire le nombre de couches.

  • Nettoyer les caches d’installation (ex. apt-get clean).

  • Éviter d’utiliser latest en production, préférer des tags de version stables.

  • Ajouter un .dockerignore pour réduire la taille du contexte.

  • Séparer construction et exécution avec les multi-stage builds.


Multi-stage builds

Les multi-stage builds permettent de produire des images finales beaucoup plus légères.
On utilise plusieurs FROM dans un même Dockerfile.

Exemple :

# Étape 1 : construction de l’app
FROM node:22-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build    # produit le dossier /app/dist

# Étape 2 : image finale, minimaliste
FROM alpine:3.19
RUN apk add --no-cache nodejs
WORKDIR /app

# Cette ligne est essentielle et copie l'applicatif depuis le conteneur de construction.
COPY --from=builder /app/dist ./dist  
CMD ["node", "dist/index.js"]

L’image finale ne contient que l’exécutable ./dist, pas le compilateur ni les sources


Résumé

  • Le Dockerfile est la recette pour créer une image Docker.

  • Chaque instruction crée une couche, réutilisable grâce au cache.

  • CMD et ENTRYPOINT définissent le comportement par défaut d’un conteneur.

  • Le contexte de build doit être maîtrisé (.dockerignore recommandé).

  • Les bonnes pratiques et les multi-stage builds permettent des images plus légères, sécurisées et maintenables.