1. Comprendre les images Docker

Une image Docker est un template read-only contenant tout ce dont une application a besoin : code, runtime, librairies, variables d'env et config. Les images sont composées de layers (couches) immuables empilées.

docker pull node:18-alpine    # Télécharger
docker image ls                  # Lister
docker image inspect node:18-alpine  # Détails JSON
docker image history node:18-alpine  # Voir les layers
docker image rm     node:18-alpine  # Supprimer

Naming convention

registry/namespace/name:tag

nginx                     # = docker.io/library/nginx:latest
nginx:alpine              # Image nginx avec tag alpine
monuser/monapp:1.0.0      # Image personnelle sur Docker Hub
ghcr.io/org/app:v2        # GitHub Container Registry

2. Layers & Cache

Chaque instruction dans un Dockerfile crĂ©e un layer. Les layers sont partagĂ©s entre images — ce qui Ă©conomise du stockage et accĂ©lĂšre les builds.

# docker image history node:18-alpine (exemple simplifié)
IMAGE       CREATED   SIZE    CREATED BY
a8b3c4d5e6  2 days    0B      CMD ["node"]
f7g8h9i0j1  2 days    2.1MB   ENV NODE_VERSION=18.x.x
k2l3m4n5o6  5 days    5.2MB   RUN apk add --no-cache npm
p7q8r9s0t1  5 days    7.1MB   RUN apk add --no-cache nodejs
u2v3w4x5y6  12 days   7.3MB   /bin/sh -c #(nop) ADD alpine

Cache invalidation

Docker utilise le cache dÚs que possible. Si une instruction (et tout ce qui précÚde) n'a pas changé, la couche est réutilisée :

# BAD — COPY . invalide le cache tît → tout est reconstruit
FROM node:18-alpine
COPY . .
RUN npm install

# GOOD — package.json copiĂ© en premier → cache npm stable
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .

3. Structure d'un Dockerfile

# Dockerfile pour une app Node.js

# 1. Image de base
FROM node:18-alpine

# 2. Métadonnées
LABEL maintainer="dev@example.com"
LABEL version="1.0"

# 3. Répertoire de travail
WORKDIR /app

# 4. Variables d'environnement
ENV NODE_ENV=production \
    PORT=3000

# 5. Copier les dépendances en premier (cache)
COPY package*.json ./
RUN npm ci --only=production

# 6. Copier le reste du code
COPY . .

# 7. Port exposé (documentation)
EXPOSE 3000

# 8. Commande de démarrage
CMD ["node", "server.js"]

4. Instructions Dockerfile clés

FROM

FROM ubuntu:22.04             # Image de base obligatoire
FROM scratch                  # Image vide (binaires statiques)
FROM node:18 AS builder       # Alias pour multi-stage

RUN

# Forme shell (s'exécute dans /bin/sh -c)
RUN apt-get update && apt-get install -y curl

# Forme exec (recommandĂ©e — pas de shell)
RUN ["apt-get", "update"]

# Combiner pour réduire les layers
RUN apt-get update \
    && apt-get install -y --no-install-recommends \
       curl git \
    && rm -rf /var/lib/apt/lists/*

COPY vs ADD

COPY src/ /app/src/           # Copie simple (préférer COPY)
COPY --chown=node:node . .    # Avec propriétaire
ADD  archive.tar.gz /app/    # ADD décompresse les archives
ADD  https://url/file /app/  # ADD tĂ©lĂ©charge (dĂ©conseillĂ© → RUN curl)

CMD vs ENTRYPOINT

# CMD — commande par dĂ©faut, remplaçable avec docker run <cmd>
CMD ["npm", "start"]

# ENTRYPOINT — binaire fixe, les args s'ajoutent aprùs
ENTRYPOINT ["node"]
CMD ["server.js"]
# → docker run myapp app.js   exĂ©cute: node app.js

# ENTRYPOINT + CMD ensemble (pattern recommandé)
ENTRYPOINT ["docker-entrypoint.sh"]
CMD        ["node", "server.js"]

ARG vs ENV

# ARG — disponible seulement pendant le BUILD
ARG BUILD_VERSION=1.0
RUN echo "Building $BUILD_VERSION"

# ENV — disponible à BUILD et RUNTIME
ENV PORT=3000
ENV DATABASE_URL=""     # valeur vide, Ă  surcharger au run

# Passer ARG au build
docker build --build-arg BUILD_VERSION=2.1 -t myapp .

5. docker build

# Build basique depuis le dossier courant
docker build -t monapp:1.0 .

# Spécifier un Dockerfile alternatif
docker build -f Dockerfile.prod -t monapp:prod .

# Forcer la reconstruction sans cache
docker build --no-cache -t monapp .

# Passer des build args
docker build --build-arg VERSION=2.0 -t monapp:2.0 .

# Voir les étapes du build
docker build --progress=plain -t monapp .

# Tags multiples
docker build -t monapp:latest -t monapp:1.0.0 .

.dockerignore

# .dockerignore — exclut des fichiers du contexte de build
node_modules/
.git/
.env
*.log
dist/
coverage/
README.md
.DS_Store

6. Bonnes pratiques

  • Toujours utiliser des images de base versionnĂ©es (node:18-alpine, pas node:latest)
  • PrĂ©fĂ©rer les variantes alpine ou slim pour rĂ©duire la taille
  • Regrouper les RUN liĂ©s pour minimiser les layers
  • Nettoyer les caches apt/apk dans le mĂȘme RUN
  • Copier package*.json avant COPY . . pour optimiser le cache
  • Utiliser .dockerignore pour exclure node_modules/, .git/
  • Ne pas stocker de secrets dans les layers (utiliser les secrets Docker ou les variables d'env au runtime)
Taille des images : Utiliser docker image ls pour comparer. node:18 ≈ 950 MB vs node:18-alpine ≈ 115 MB vs node:18-slim ≈ 240 MB.