Vue d’ensemble

Le Dockerfile définit comment Docker construit une image. Cet aide-mémoire couvre les 17 instructions primaires, les patterns avancés comme les builds multi-étages et les cache mounts, les bonnes pratiques de sécurité et de performance, et les techniques d’optimisation. Toute la syntaxe est à jour pour Docker 27.

Instructions principales

FROM

Instruction Objectif Exemple
FROM <image>:<tag> Définir l’image de base (doit être la première ligne, sauf commentaires/ARG) FROM ubuntu:24.04
FROM <image>:<tag> AS <stage> Définir une étape nommée dans un build multi-étages FROM golang:1.22 AS builder
FROM scratch Commencer à partir d’une base vide (pour les binaires statiques seulement) FROM scratch

Notes :
– Vous pouvez utiliser plusieurs déclarations FROM pour créer plusieurs étapes de build.
– Chaque FROM réinitialise le système de fichiers ; les couches précédentes sont supprimées à moins d’être explicitement copiées.
– scratch ne contient que ce que vous ajoutez explicitement ; la plus petite image possible.

RUN

Instruction Objectif Exemple
RUN <command> Exécuter une commande pendant le build (forme shell) RUN apt-get update && apt-get install -y curl
RUN ["executable", "param1", "param2"] Exécuter une commande en forme exec (pas de shell) RUN ["python3", "-m", "pip", "install", "django"]

Bonnes pratiques :
– Utilisez la forme exec quand possible pour éviter les problèmes d’interprétation shell.
– Chaînez les commandes avec && pour garder les couches petites : RUN apt-get update && apt-get install && apt-get clean
– Nettoyez les caches du gestionnaire de paquets : rm -rf /var/lib/apt/lists/* (apt), apk del .build-deps (apk)
– Utilisez les flags --no-cache dans les gestionnaires de paquets pour réduire la taille de la couche.

COPY

Instruction Objectif Exemple
COPY <source> <dest> Copier les fichiers/répertoires du contexte de build vers l’image COPY app.py /app/app.py
COPY --chown=<user>:<group> <source> <dest> Copier et définir la propriété COPY --chown=appuser:appuser . /app/
COPY --chmod=<mode> <source> <dest> Copier et définir les permissions des fichiers COPY --chmod=755 script.sh /app/script.sh

Bonnes pratiques :
– COPY est préféré à ADD pour la copie simple de fichiers.
– Utilisez .dockerignore pour exclure les artefacts de build, les tests, .git.
– Copiez seulement ce dont vous avez besoin ; divisez en plusieurs lignes COPY pour l’efficacité du cache.

ADD

Instruction Objectif Exemple
ADD <source> <dest> Copier les fichiers/répertoires, avec des fonctionnalités supplémentaires (extraction tar, récupération d’URL) ADD archive.tar.gz /app/
ADD --chown=<user>:<group> <source> <dest> Ajouter avec la propriété ADD --chown=appuser:appuser file.txt /app/
ADD --chmod=<mode> <source> <dest> Ajouter avec les permissions des fichiers ADD --chmod=644 config.txt /etc/config.txt

Notes :
– Si la source est une archive tar/zip/gzip, elle est extraite automatiquement.
– Si la source est une URL, elle est téléchargée (pas d’extraction).
– COPY est généralement plus clair ; utilisez ADD seulement pour l’extraction tar ou la récupération d’URL.

WORKDIR

Instruction Objectif Exemple
WORKDIR <path> Définir le répertoire de travail pour toutes les commandes ultérieures (RUN, CMD, ENTRYPOINT, COPY, ADD) WORKDIR /app

Notes :
– Si le répertoire n’existe pas, il est créé.
– Utilisez des chemins absolus pour éviter la confusion.
– Les instructions WORKDIR multiples sont cumulatives : WORKDIR /app puis WORKDIR src résulte en /app/src.

ENV

Instruction Objectif Exemple
ENV <key>=<value> Définir une variable d’environnement (disponible dans le conteneur en cours d’exécution) ENV NODE_ENV=production
ENV <key> <value> Syntaxe alternative (dépréciée, à éviter) ENV DEBUG true

Notes :
– Persiste dans les conteneurs ; défini une fois pendant le build, disponible au runtime.
– Utilisez pour la configuration au niveau de l’application (URLs de base de données, clés API pour le test).
– N’utilisez pas ENV pour les secrets ; utilisez les secrets Docker ou passez au runtime.

ARG

Instruction Objectif Exemple
ARG <name>=<default> Définir une variable de build (disponible seulement pendant le build, pas dans le conteneur en cours d’exécution) ARG PYTHON_VERSION=3.12
ARG <name> Définir une variable sans défaut (doit être fournie avec --build-arg) ARG BUILD_NUMBER

Usage dans le build :

docker build --build-arg PYTHON_VERSION=3.11 -t myapp:1.0 .

Notes :
– Les variables ARG sont utilisées seulement pendant le build ; elles n’apparaissent pas dans l’image finale.
– Pour passer une valeur ARG au conteneur en cours d’exécution, réassignez-la avec ENV : ENV PYTHON_VERSION=$PYTHON_VERSION

EXPOSE

Instruction Objectif Exemple
EXPOSE <port> Documenter qu’un conteneur écoute sur un port (ne publie pas) EXPOSE 8080
EXPOSE <port>/udp Documenter un port UDP EXPOSE 53/udp
EXPOSE <port1> <port2> Documenter plusieurs ports EXPOSE 8080 8443

Notes :
– EXPOSE est seulement des métadonnées ; ne publie pas réellement le port.
– Pour publier, utilisez docker run -p <host>:<container> ou Docker Compose ports:.
– Utile pour la documentation et pour docker run -P (ports aléatoires de haut niveau).

USER

Instruction Objectif Exemple
USER <user> Définir l’utilisateur (ou UID) pour les commandes ultérieures (RUN, CMD, ENTRYPOINT, COPY, ADD) USER appuser
USER <uid>:<gid> Utiliser directement UID et GID USER 1000:1000

Bonne pratique de sécurité :

RUN groupadd -r appgroup && useradd -r -g appgroup appuser
USER appuser

Notes :
– Exécuter en tant que root dans un conteneur est un risque de sécurité.
– Utilisez un utilisateur non-root dédié pour limiter le rayon d’explosion en cas d’échappement du conteneur.
– Doit être créé avant l’instruction USER (utilisez RUN).

HEALTHCHECK

Instruction Objectif Exemple
HEALTHCHECK --interval=<seconds> --timeout=<seconds> --start-period=<seconds> --retries=<count> CMD <command> Définir une commande de vérification de santé HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 CMD curl -f http://localhost:8000/health \|\| exit 1
HEALTHCHECK NONE Désactiver une vérification de santé héritée de l’image de base HEALTHCHECK NONE

Options :
– --interval : Fréquence d’exécution (par défaut : 30s)
– --timeout : Temps d’attente (par défaut : 30s)
– --start-period : Période de grâce avant la première vérification (par défaut : 0s)
– --retries : Échecs consécutifs avant de marquer unhealthy (par défaut : 3)

Notes :
– Code de sortie 0 = healthy, 1 = unhealthy, 2 = réservé.
– Docker Compose et les orchestrateurs utilisent le statut de santé pour redémarrer/remplacer les conteneurs.

ENTRYPOINT

Instruction Objectif Exemple
ENTRYPOINT ["executable", "param1"] Définir le processus principal du conteneur (forme exec, préférée) ENTRYPOINT ["python3", "-u", "app.py"]
ENTRYPOINT command param1 Définir le processus principal (forme shell, à éviter) ENTRYPOINT python3 -u app.py

Forme exec vs. forme shell :
– Forme exec : Exécute le fichier exécutable directement ; les signaux (SIGTERM) sont délivrés correctement ; pas d’interprétation shell.
– Forme shell : Enveloppe la commande dans /bin/sh -c ; le shell traite les signaux, pas votre app ; peut causer des processus zombies.

Avec CMD :

ENTRYPOINT ["python3"]
CMD ["app.py"]
# docker run image arg → python3 app.py arg

Notes :
– ENTRYPOINT définit ce qui ne peut pas être facilement remplacé.
– Utilisez toujours la forme exec pour ENTRYPOINT.

CMD

Instruction Objectif Exemple
CMD ["executable", "param1", "param2"] Fournir les arguments ou la commande par défaut (forme exec, préférée) CMD ["python3", "app.py"]
CMD command param1 Fournir les arguments par défaut (forme shell, à éviter) CMD python3 app.py
CMD ["param1", "param2"] Fournir les arguments par défaut à ENTRYPOINT CMD ["production"]

Notes :
– Si aucun ENTRYPOINT n’est défini, CMD est la commande.
– Si ENTRYPOINT est défini, CMD fournit les arguments à celui-ci.
– Utilisez toujours la forme exec pour CMD.

VOLUME

Instruction Objectif Exemple
VOLUME <path> Marquer un répertoire comme point de montage de volume VOLUME /data
VOLUME ["<path1>", "<path2>"] Marquer plusieurs points de montage VOLUME ["/var/log", "/data"]

Notes :
– VOLUME est déclaratif ; elle documente qu’un répertoire devrait être persisté ou monté.
– Ne crée pas réellement un volume ; le volume est créé au runtime.
– Au runtime : docker run -v myvolume:/data image ou docker run -v /host/path:/data image

LABEL

Instruction Objectif Exemple
LABEL <key>=<value> Ajouter des métadonnées à une image LABEL maintainer="team@example.com"
LABEL <key1>=<value1> <key2>=<value2> Ajouter plusieurs labels LABEL version="1.0" description="My app"

Notes :
– Les labels sont recherchables : docker images --filter "label=version=1.0"
– Labels communs : maintainer, version, description, org.opencontainers.image.*

STOPSIGNAL

Instruction Objectif Exemple
STOPSIGNAL SIGTERM Signal à envoyer lors de l’arrêt du conteneur (par défaut : SIGTERM) STOPSIGNAL SIGTERM
STOPSIGNAL SIGKILL Signal de forçage (rarement nécessaire) STOPSIGNAL SIGKILL

Notes :
– La plupart des apps gèrent SIGTERM (15) pour un arrêt gracieux.
– Utilisez SIGKILL (9) seulement si votre app ne gère pas SIGTERM.

SHELL

Instruction Objectif Exemple
SHELL ["<executable>", "<param>"] Remplacer le shell par défaut (par défaut : ["/bin/sh", "-c"] sur Linux) SHELL ["/bin/bash", "-c"]

Cas d’usage :

FROM mcr.microsoft.com/windows/servercore:ltsc2022
SHELL ["powershell", "-Command", "-ErrorActionPreference", "Stop"]
RUN Get-ChildItem

ONBUILD

Instruction Objectif Exemple
ONBUILD <instruction> Déclencher une instruction dans les images enfants (rarement utilisé) ONBUILD RUN npm install

Notes :
– Quand une image enfant utilise FROM <parent>, les instructions ONBUILD du parent sont exécutées.
– Utile pour les images de base qui orchestrent les builds ; à éviter dans les Dockerfiles d’application.

Builds multi-étages

Les builds multi-étages réduisent la taille de l’image finale en utilisant des étapes intermédiaires pour construire et une étape finale avec seulement les dépendances runtime.

Pattern : Builder + Runtime

# Étape 1 : Build
FROM golang:1.22 AS builder
WORKDIR /src
COPY . .
RUN go build -o app .

# Étape 2 : Runtime (minimal)
FROM alpine:3.20
COPY --from=builder /src/app /app
ENTRYPOINT ["/app"]

Avantages clés :
– Les dépendances de build (compilateurs, outils dev) ne sont pas dans l’image finale.
– L’image finale contient seulement le binaire compilé.
– Peut réduire la taille de l’image de 500MB à 10MB ou moins.

Avancé : étapes nommées, builds conditionnels

FROM golang:1.22 AS builder
ARG BUILD_TARGET=linux
WORKDIR /src
COPY . .
RUN GOOS=linux GOARCH=amd64 go build -o app .

FROM alpine:3.20 AS runtime
COPY --from=builder /src/app /app
USER nobody
ENTRYPOINT ["/app"]

# Utiliser : docker build --target runtime -t myapp:latest .

Cache mounts (Docker 19.03+)

Les cache mounts préservent les fichiers entre les builds, permettant des installations de paquets plus rapides et la mise en cache des dépendances.

FROM python:3.12-alpine
WORKDIR /app

# Monter le cache pour les paquets pip
RUN --mount=type=cache,target=/root/.cache/pip \
    pip install -r requirements.txt

# Utiliser : docker build --build-context . -t myapp:1.0 .

Cas d’usage :
– Caches du gestionnaire de paquets (pip, npm, cargo, etc.)
– Caches d’artefacts de build (cache Go, cible Rust, Maven .m2)

Commande de build :

docker build -t myapp:1.0 --build-context .

.dockerignore

Utilisez .dockerignore pour exclure les fichiers du contexte de build, réduisant la taille de la couche et le temps de build.

# .dockerignore
.git
.gitignore
.env
.env.local
*.pyc
__pycache__
.pytest_cache
node_modules
dist
build
*.log
README.md
.vscode
.idea
.DS_Store

Notes :
– Les patterns fonctionnent comme .gitignore.
– Réduit la taille du contexte envoyée au daemon Docker.
– Peut accélérer significativement les builds sur les grands projets.

Bonnes pratiques de sécurité

Exécuter en tant que non-root

FROM alpine:3.20
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
COPY --chown=appuser:appgroup . /app
USER appuser
ENTRYPOINT ["./app"]

Supprimer les capacités inutiles

RUN setcap -r /bin/app  # Supprimer toutes les capacités du fichier exécutable
# Ou au runtime : docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE image

Utiliser un système de fichiers en lecture seule

# Au runtime : docker run --read-only --tmpfs /tmp image

Images de base minimales

  • alpine:3.20 (~7 MB) — Recommandé pour la plupart des cas
  • distroless/python3-nonroot (~50 MB) — Pré-renforcé, pas de gestionnaire de paquets
  • scratch (~0 MB) — Pour les binaires statiques seulement

Bonnes pratiques de taille

Nettoyer les caches du gestionnaire de paquets

# Alpine
RUN apk add --no-cache python3 py3-pip

# Debian/Ubuntu
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*

# pip
RUN pip install --no-cache-dir django

Combiner les commandes RUN

# Mauvais (3 couches)
RUN apt-get update
RUN apt-get install -y curl
RUN rm -rf /var/lib/apt/lists/*

# Bon (1 couche)
RUN apt-get update && \
    apt-get install -y curl && \
    rm -rf /var/lib/apt/lists/*

Utiliser COPY stratégiquement

# Copier seulement ce dont vous avez besoin, en ordre de fréquence de changement
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY src ./src
# Changer src n'invalide pas la couche pip

Patterns à réutiliser

# Image de base avec ARG pour la version
FROM python:${PYTHON_VERSION:-3.12}-alpine AS base

# Multi-étages avec arguments de build
FROM node:20-alpine AS builder
ARG NODE_ENV=production
RUN npm ci --only=production

# Vérification de santé avec curl
HEALTHCHECK --interval=30s --timeout=5s \
  CMD curl -f http://localhost:3000/health || exit 1

# Utilisateur non-root avec UID statique pour la reproductibilité
RUN adduser -D -u 1000 appuser

# Copier avec propriété pour non-root
COPY --chown=appuser:appuser . /app

# Utiliser le cache de build pour les gestionnaires de paquets
RUN --mount=type=cache,target=/root/.cache/pip pip install -r requirements.txt

# Forme exec ENTRYPOINT + CMD
ENTRYPOINT ["python3", "-u"]
CMD ["app.py"]

FAQ

Quelle est la différence entre COPY et ADD ?

COPY est plus simple et préféré pour les fichiers locaux. ADD peut extraire les archives tar et récupérer les URLs, mais ces fonctionnalités peuvent causer un comportement inattendu. Utilisez COPY à moins que vous n’ayez spécifiquement besoin d’extraction tar ou de récupération d’URL.

Dois-je utiliser ENV ou ARG ?

ARG est pour les variables de build (disponibles seulement pendant le build, pas dans le conteneur en cours d’exécution). ENV est pour les variables runtime (disponibles dans le conteneur en cours d’exécution). Utilisez ARG pour la configuration de build et ENV pour la configuration d’application.

Quelle est la différence entre ENTRYPOINT et CMD ?

ENTRYPOINT définit le processus principal du conteneur et ne peut généralement pas être remplacé. CMD fournit les arguments par défaut à ENTRYPOINT, ou est la commande si aucun ENTRYPOINT n’est défini. Utilisez la forme exec pour les deux.

Comment écrire un Dockerfile qui construise une petite image ?

Utilisez une image de base comme alpine:latest ou scratch. Utilisez les builds multi-étages pour copier seulement les artefacts compilés. Supprimez les dépendances de build. Nettoyez les caches du gestionnaire de paquets (rm -rf /var/lib/apt/lists/*). Évitez d’inclure des fichiers inutiles (utilisez .dockerignore).

Pourquoi dois-je exécuter en tant qu’utilisateur non-root ?

Exécuter en tant que root dans un conteneur signifie qu’une brèche ou une fuite pourrait donner à un attaquant l’accès root à l’hôte. Créez un utilisateur dédié et supprimez les capacités pour réduire le risque. Ajoutez USER <uid> avant la commande finale.

Comment ce guide a été vérifié

Rédigé à la main à partir de la documentation officielle, chaque commande revérifiée, puis relu une seconde fois avant publication. Dernière relecture le .

Sources officielles consultées pour cet article

Share.

Les commentaires sont fermés.