Introduction : Pourquoi la conteneurisation avancée de TypeScript est une nécessité
La conteneurisation d'applications TypeScript avec Docker a depuis longtemps cessé d'être une simple tendance – c'est désormais un standard du développement moderne. Cependant, les Dockerfile basiques qui se contentent de copier l'intégralité du projet et d'exécuter npm start sont loin d'être idéaux. À un niveau avancé, nous sommes confrontés à des défis tels que l'optimisation de la taille des images, la garantie de la sécurité, l'organisation d'une architecture de microservices et la configuration de la récupération automatique.
Dans cet article, nous aborderons les techniques qui transformeront votre pipeline Docker pour TypeScript en un standard industriel : constructions multi-étapes (multi-stage builds), minimisation des couches, utilisation de .dockerignore, Docker Compose pour les microservices, healthchecks et gestion des variables d'environnement. Tous les exemples sont écrits en TypeScript et prêts à être intégrés dans des projets réels.
1. Construction multi-étapes : du développement à la production
Le principal problème des Dockerfile basiques est qu'ils incluent tout dans l'image finale : les sources, les node_modules de développement, les outils de construction. Pour TypeScript, c'est critique car tsc et devDependencies ne sont pas nécessaires en production.
La construction multi-étapes (multi-stage build) résout ce problème : la première étape assemble et compile le TypeScript, la seconde crée une image minimale avec uniquement les fichiers nécessaires.
Exemple de Dockerfile en deux étapes
# Étape 1 : Construction TypeScriptFROM node:20-alpine AS builderWORKDIR /appCOPY package*.json ./RUN npm ci --only=productionCOPY tsconfig.json ./COPY src/ ./src/RUN npm run build
# Étape 2 : Image de productionFROM node:20-alpineWORKDIR /appCOPY --from=builder /app/dist ./distCOPY --from=builder /app/node_modules ./node_modulesCOPY package.json ./EXPOSE 3000CMD ["node", "dist/index.js"]Points clés :
- Utilisation de
npm ci– reproduction exacte des dépendances à partir du fichier lock. - Copie uniquement de
dist/etnode_modules– les sources TypeScript ne sont pas incluses dans la production. - Image Alpine – base minimale (environ 5 Mo).
Une telle image pèse 3 à 5 fois moins qu'une construction naïve. Pour un grand projet avec des dizaines de dépendances, la différence peut atteindre des centaines de mégaoctets.
Construction en trois étapes avec dépendances de développement
Parfois, il est nécessaire de séparer les dépendances de développement et de production. Nous ajoutons une troisième étape pour installer uniquement les dépendances de production :
# Étape 1 : Installation de toutes les dépendancesFROM node:20-alpine AS depsWORKDIR /appCOPY package*.json ./RUN npm ci
# Étape 2 : ConstructionFROM node:20-alpine AS builderWORKDIR /appCOPY --from=deps /app/node_modules ./node_modulesCOPY . .RUN npm run build
# Étape 3 : ProductionFROM node:20-alpine AS runnerWORKDIR /appCOPY --from=builder /app/dist ./distCOPY --from=deps /app/node_modules ./node_modulesCOPY package.json ./EXPOSE 3000CMD ["node", "dist/index.js"]2. Optimisation de l'image : .dockerignore, mise en cache et couches
Chaque instruction COPY, RUN et ADD crée une nouvelle couche dans Docker. Moins il y a de couches et plus elles sont mises en cache efficacement, plus la construction est rapide.
.dockerignore – votre premier allié
Créez un fichier .dockerignore à la racine du projet :
node_modulesdist.git.gitignore*.md.env.env.*Dockerfile.dockerignorecoverage.vscode.idea__tests__Cela empêche la copie de fichiers inutiles dans le contexte de construction et accélère le transfert des fichiers au démon Docker.
Ordre correct des instructions
Docker met en cache les couches. Si vous copiez d'abord package.json, puis exécutez npm ci, cette couche sera réutilisée tant que package.json n'est pas modifié. Ensuite, copiez les sources