Cours NestJS · Module 12: Conteneurs et CI/CD
Dockerfile pour NestJS - Construire le camp
Dans cette leçon5
Légionnaire, il est temps d'apprendre à rédiger les instructions de construction du camp - c'est-à-dire un Dockerfile ! Un Dockerfile est un fichier texte contenant une suite de commandes que Docker exécute pour construire une image. Chaque commande crée une nouvelle couche (strate) dans l'image.
Instructions de base d'un Dockerfile
Un Dockerfile est composé d'instructions, chacune remplissant un rôle précis :
FROM - Fondation du camp
L'instruction FROM sélectionne l'image de base sur laquelle nous construisons. Pour les applications NestJS, nous utilisons l'image Node.js :
1# Nous utilisons l'image officielle Node.js en version Alpine (légère !)
2FROM node:20-alpineAlpine Linux est une distribution minimaliste - elle pèse ~5 Mo au lieu de ~900 Mo pour un Ubuntu complet. C'est comme un camp de campagne léger au lieu d'une forteresse complète - rapide à monter et à déplacer.
WORKDIR - Désigner le chantier
L'instruction WORKDIR définit le répertoire de travail à l'intérieur du conteneur :
1# Définir le répertoire de travail
2WORKDIR /appCOPY - Transporter les matériaux
COPY copie des fichiers depuis notre ordinateur vers le conteneur :
1# Copier les fichiers package.json et yarn.lock
2COPY package.json yarn.lock ./
3
4# Copier le reste du code source
5COPY . .RUN - Exécuter les travaux de construction
RUN exécute des commandes pendant la construction de l'image :
1# Installer les dépendances
2RUN yarn install --frozen-lockfile
3
4# Construire l'application
5RUN yarn buildCMD - L'ordre de démarrage
CMD définit la commande à exécuter au démarrage du conteneur :
1# Lancer l'application
2CMD ["node", "dist/main"]Dockerfile simple pour NestJS
1FROM node:20-alpine
2
3WORKDIR /app
4
5COPY package.json yarn.lock ./
6RUN yarn install --frozen-lockfile
7
8COPY . .
9RUN yarn build
10
11EXPOSE 4000
12
13CMD ["node", "dist/main"]Build multi-stage - Stratégie de build avancée
Un Dockerfile simple a un problème - l'image finale contient les outils de développement, les fichiers source TypeScript et les devDependencies. C'est comme laisser les échafaudages après l'achèvement de la forteresse.
Le build multi-stage permet d'utiliser plusieurs étapes de construction, où l'image finale ne contient que ce qui est nécessaire à l'exécution :
1# =========================
2# ÉTAPE 1 : Builder (ingénieurs de la légion)
3# =========================
4FROM node:20-alpine AS builder
5
6WORKDIR /app
7
8# Copier les fichiers de dépendances
9COPY package.json yarn.lock ./
10RUN yarn install --frozen-lockfile
11
12# Copier le code source et construire
13COPY . .
14RUN yarn build
15
16# Installer uniquement les dépendances de production
17RUN yarn install --frozen-lockfile --production
18
19# =========================
20# ÉTAPE 2 : Production (camp prêt)
21# =========================
22FROM node:20-alpine AS production
23
24WORKDIR /app
25
26# Copier UNIQUEMENT le code construit et les dépendances de production
27COPY /app/dist ./dist
28COPY /app/node_modules ./node_modules
29COPY /app/package.json ./package.json
30
31# Créer un utilisateur non-root
32RUN addgroup -g 1001 -S nodejs && \
33 adduser -S nestjs -u 1001
34
35USER nestjs
36
37EXPOSE 4000
38
39CMD ["node", "dist/main"]Comparaison des tailles
1const comparison = {
2 singleStage: {
3 size: '~800 MB',
4 contains: ['node_modules (dev + prod)', 'src/', 'test/', '.git'],
5 security: 'utilisateur root'
6 },
7 multiStage: {
8 size: '~200 MB',
9 contains: ['dist/', 'node_modules (prod uniquement)', 'package.json'],
10 security: 'utilisateur non-root (nestjs)'
11 }
12};Le fichier .dockerignore
Tout comme .gitignore empêche l'ajout de fichiers au dépôt, .dockerignore empêche la copie de fichiers inutiles dans l'image :
1node_modules
2dist
3.git
4.gitignore
5*.md
6.env
7.env.*
8test
9coverage
10.vscode
11.ideaGrâce à .dockerignore, la commande COPY . . ne copiera pas ces fichiers, ce qui accélère la construction et réduit la taille de l'image.
Construire et exécuter
1# Construire l'image
2docker build -t roman-imperium-api:1.0 .
3
4# Exécuter le conteneur
5docker run -d -p 4000:4000 --name imperium-api roman-imperium-api:1.0
6
7# Vérifier les logs
8docker logs imperium-api
9
10# Vérifier que ça fonctionne
11curl http://localhost:4000/healthSouviens-toi, légionnaire - le build multi-stage est la meilleure pratique pour la production. On construit lourd, mais on déploie léger !
Code de cette leçon : src/dockerfile-example.ts
1// Dockerfile - Instructions de construction du camp de légionnaires
2console.log("=== DOCKERFILE POUR NestJS ===\n");
3
4// Instructions Dockerfile
5interface DockerInstruction {
6 command: string;
7 purpose: string;
8 example: string;
9}
10
11const instructions: DockerInstruction[] = [
12 {
13 command: 'FROM',
14 purpose: 'Image de base (fondation du camp)',
15 example: 'FROM node:20-alpine',
16 },
17 {
18 command: 'WORKDIR',
19 purpose: 'Répertoire de travail (chantier)',
20 example: 'WORKDIR /app',
21 },
22 {
23 command: 'COPY',
24 purpose: 'Copie de fichiers (transport des matériaux)',
25 example: 'COPY package.json yarn.lock ./',
26 },
27 {
28 command: 'RUN',
29 purpose: 'Exécution d\'une commande (travaux de construction)',
30 example: 'RUN yarn install --frozen-lockfile',
31 },
32 {
33 command: 'EXPOSE',
34 purpose: 'Déclaration du port (porte du camp)',
35 example: 'EXPOSE 4000',
36 },
37 {
38 command: 'CMD',
39 purpose: 'Commande de démarrage (ordre de départ)',
40 example: 'CMD ["node", "dist/main"]',
41 },
42];
43
44console.log("Instructions Dockerfile :\n");
45instructions.forEach(i => {
46 console.log(`${i.command} : ${i.purpose}`);
47 console.log(` Exemple : ${i.example}\n`);
48});
49
50// Comparaison du build multi-stage
51console.log("=== BUILD MULTI-STAGE ===\n");
52console.log("Single-stage : ~800 MB (dépendances dev + prod)");
53console.log("Multi-stage : ~200 MB (production uniquement)\n");
54
55console.log("Étape 1 (builder) : install, build, compilation");
56console.log("Étape 2 (production) : COPY --from=builder uniquement dist/");
57console.log("\nAvantage : image plus petite, pas de dev-dependencies, utilisateur non-root");
58Tu as repéré une erreur dans cette leçon ?
Teste tes connaissances
Réponds aux questions de cette leçon. Choisis une réponse pour voir tout de suite si elle est correcte.
1. Que définit l'instruction FROM dans un Dockerfile ?
2. Quel est le principal avantage du build multi-stage dans Docker ?
Voici 2 des 3 questions de cette leçon. Réponds aux autres dans le jeu.
Tâches pratiques dans le jeu
- Éditeur de code
Définissez deux étapes de Dockerfile : builder (construction) et production (exécution)
- Clique dans l'ordre
Ordonnez les instructions du Dockerfile dans le bon ordre :
- Éditeur de code
Choisissez quels fichiers/dossiers doivent être ignorés par Docker (node_modules, dist, .git, .env, src, test, package.json, coverage)
- Tri horizontal
Ordonnez les éléments de la commande de build d'une image Docker dans le bon ordre :