Introduction : Pourquoi avez-vous encore peur d'appuyer sur "Deploy" ?
\n\nVous avez écrit le code. Vous l'avez testé sur votre machine locale. Les tests sont passés. Tout est parfait. Vous appuyez sur le fameux bouton Deploy... et 5 minutes plus tard, vous voyez une erreur 500 tomber, tandis que les utilisateurs paniqués écrivent au support. Cela vous dit quelque chose ?
\n\nLes stratégies de déploiement traditionnelles (blue-green, rolling update) sont bonnes, mais elles ont un inconvénient : elles incluent soit tout le nouveau code d'un coup, soit pas du tout. Et si vous pouviez envoyer une nouvelle fonctionnalité à seulement 1 % des utilisateurs, observer les métriques, et ensuite seulement, après avoir vérifié la stabilité, la déployer à 100 % ?
\n\nC'est exactement ainsi que fonctionnent les déploiements canary (mises en production canari). Le nom vient d'une ancienne pratique des mineurs : emmener un canari dans la mine pour détecter à temps une fuite de gaz. Si l'oiseau se taisait, les mineurs savaient qu'il était temps de remonter. Dans le monde de l'informatique, le "canari" est un petit groupe d'utilisateurs sur lequel le nouveau code est testé. Si tout va bien, la mise en production se poursuit. Sinon, vous revenez en arrière plus vite que vous ne pouvez dire "hotfix".
\n\nDans cet article, nous allons écrire en TypeScript un système complet de déploiement canary. Vous apprendrez à configurer l'équilibrage du trafic, à automatiser le processus via CI/CD, et à surveiller la "santé" de votre canari. C'est parti !
\n\nQu'est-ce qu'un déploiement Canary et pourquoi en avez-vous besoin ?
\n\nLe déploiement canary est une stratégie de déploiement de nouveau code dans laquelle la version mise à jour de l'application est d'abord envoyée à un petit pourcentage d'utilisateurs (généralement 1 à 10 %). Les autres continuent de travailler sur l'ancienne version stable. Si la nouvelle version ne pose pas de problèmes (erreurs, baisse de performance, augmentation de la latence), vous augmentez progressivement le pourcentage de trafic qui lui est destiné, jusqu'à ce qu'elle remplace complètement l'ancienne.
\n\nAvantages clés :
\n- \n
- Minimisation des risques — les bogues n'affectent qu'une petite partie de l'audience. \n
- Retour en arrière rapide — il suffit de rediriger le trafic vers la version stable. \n
- Tests A/B en conditions réelles — vous pouvez comparer les métriques des anciennes et nouvelles versions. \n
- Déploiement progressif — vous ne submergez pas le serveur par une augmentation soudaine de la charge. \n
Passons maintenant de la théorie à la pratique. Nous allons construire un système composé de trois parties :
\n- \n
- Backend en TypeScript (Express.js). \n
- Équilibreur de trafic avec Nginx. \n
- Automatisation via GitHub Actions. \n
Étape 1. Écrire l'application en TypeScript avec prise en charge du versionnage
\n\nPour commencer, créons une simple application Express capable de fonctionner dans deux modes : stable et canary. La différence résidera uniquement dans la réponse au point de terminaison racine, mais dans un projet réel, il pourrait s'agir de n'importe quelle nouvelle fonctionnalité.
\n\n// src/app.ts\nimport express, { Request, Response } from 'express';\nimport dotenv from 'dotenv';\n\ndotenv.config();\n\nconst app = express();\nconst PORT = process.env.PORT || 3000;\nconst VERSION = process.env.VERSION || 'stable'; // 'stable' ou 'canary'\n\napp.get('/', (req: Request, res: Response) => {\n res.json({\n message: 'Bonjour depuis l\\'API !',\n version: VERSION,\n timestamp: new Date().toISOString(),\n });\n});\n\n// Point de terminaison pour le health check\napp.get('/health', (req: Request, res: Response) => {\n res.status(200).send('OK');\n});\n\napp.listen(PORT, () => {\n console.log(`Serveur en cours d'exécution sur le port ${PORT} en mode ${VERSION}`);\n});\n\n\nCréons maintenant un Dockerfile pour empaqueter l'application dans un conteneur. Cela simplifiera le déploiement et l'équilibrage.
\n\n# Dockerfile\nFROM node:18-alpine AS builder\nWORKDIR /app\nCOPY package*.json ./\nRUN npm ci\nCOPY . .\nRUN npm run build\n\nFROM node:18-alpine AS runner\nWORK