Chapitre 430 min2 exercices
Écrire un Dockerfile
Un Dockerfile est une recette : une instruction par ligne, exécutées de haut en bas. Le résultat est une image.
Les instructions utiles
Il en existe une vingtaine. Ces neuf couvrent presque tout.
| Instruction | Rôle |
|---|---|
FROM | L'image de départ. Toujours la première ligne. |
WORKDIR | Le dossier courant pour la suite (le crée s'il n'existe pas). |
COPY | Copie des fichiers de ton projet vers l'image. |
RUN | Exécute une commande pendant la construction (installer un paquet...). |
ENV | Définit une variable d'environnement. |
ARG | Une variable disponible uniquement pendant la construction. |
EXPOSE | Indique le port écouté. C'est de la documentation, ça ne publie rien. |
USER | L'utilisateur qui exécute la suite. Évite de tourner en root. |
CMD | La commande lancée au démarrage du conteneur. Une seule par image. |
Ton premier Dockerfile
Une mini-API Node avec Express. Crée un dossier avec ces trois fichiers.
{
"name": "mini-api",
"private": true,
"dependencies": { "express": "^5.1.0" }
}const express = require("express");
const app = express();
app.get("/", (req, res) => res.json({ message: "Bonjour depuis un conteneur" }));
app.listen(3000, () => console.log("API prête sur le port 3000"));# 1. Image de départ : Node 24, variante légère
FROM node:24-slim
# 2. Dossier de travail dans le conteneur
WORKDIR /app
# 3. D'abord les dépendances (change rarement)
COPY package*.json ./
RUN npm ci
# 4. Ensuite le code (change tout le temps)
COPY . .
# 5. Documente le port et lance l'application
EXPOSE 3000
CMD ["node", "server.js"]Il manque le fichier package-lock.json attendu par npm ci. Génère-le sans installer Node, grâce à un conteneur jetable, puis construis et lance l'image :
# --user évite que le fichier créé appartienne à root
docker run --rm --user "$(id -u):$(id -g)" -e npm_config_cache=/tmp/npm \
-v "$PWD":/app -w /app node:24-slim npm install --package-lock-only
docker build -t mini-api:1.0 .
docker run --rm -p 3000:3000 mini-api:1.0Le point final de docker build est important : c'est le contexte, le dossier envoyé à Docker. -t donne un nom et un tag à l'image.
Les couches et le cache
Chaque instruction produit une couche. Au build suivant, Docker réutilise les couches inchangées. Mais dès qu'une couche change, toutes celles du dessus sont reconstruites. L'ordre des lignes décide donc de la vitesse de tes builds.
.dockerignore
COPY . . copie tout le dossier, y compris ce qui n'a rien à faire dans l'image. Un fichier .dockerignore à côté du Dockerfile l'exclut. Le build est plus rapide et tes secrets restent dehors.
node_modules
vendor
.git
.env
.next
storage/logsLe build multi-étapes
Un Dockerfile peut contenir plusieurs FROM. Les premières étapes compilent, la dernière ne garde que le résultat. L'image finale ne contient ni les outils de build ni le code source inutile. Tu en écriras un pour Next.js au chapitre 8.
FROM node:24-slim AS build
WORKDIR /app
COPY . .
RUN npm ci && npm run build
FROM node:24-slim
COPY --from=build /app/dist ./dist
CMD ["node", "dist/server.js"]Construis et versionne ton image
- Crée les trois fichiers de la section précédente, construis
mini-api:1.0et lance-la en arrière-plan. - Vérifie la réponse avec
curl localhost:3000ou ton navigateur. - Change le message, construis
mini-api:1.1et remplace le conteneur par cette nouvelle version.
Ce que tu dois obtenir
curl localhost:3000 renvoie {"message":"Bonjour depuis un conteneur"}. docker images mini-api liste deux tags, 1.0 et 1.1, avec des tailles proches.
Un indice
Modifie le message dans server.js, puis relance docker build avec un nouveau tag. Une image ne se modifie jamais : on en construit une nouvelle.
Voir la solution
docker build -t mini-api:1.0 .
docker run -d --name api -p 3000:3000 mini-api:1.0
curl localhost:3000
# Modifie le message dans server.js, puis :
docker build -t mini-api:1.1 .
docker rm -f api
docker run -d --name api -p 3000:3000 mini-api:1.1
curl localhost:3000
docker images mini-apiMesure l'effet du cache
- Modifie une ligne de
server.js, relance le build avec--progress=plainet repère les étapes marquéesCACHED. - Déplace
COPY . .juste aprèsWORKDIR, supprimeCOPY package*.json ./, et recommence. - Compare. Remets ensuite le bon ordre.
Ce que tu dois obtenir
Avec le bon ordre, la ligne RUN npm ci affiche CACHED après une modification de server.js. Avec COPY . . en premier, npm ci est relancé à chaque fois.
Voir la solution
Dockerfile volontairement mal ordonné :
FROM node:24-slim
WORKDIR /app
COPY . .
RUN npm ci
CMD ["node", "server.js"]docker build --progress=plain -t mini-api:test .