Demandez à deux ingénieurs ce que veut dire « déploiement canary », et vous obtenez souvent deux réponses différentes : l’un décrit un pourcentage de trafic, l’autre décrit une décision. Les deux ont raison, et l’écart entre les deux est exactement là où vit le déploiement progressif. Un canary n’est pas seulement « envoyer 5 % du trafic vers la nouvelle version ». C’est un rollout couplé à un jugement automatisé : continuer à livrer, ou reculer, en fonction de ce que disent réellement les métriques de la nouvelle version. Sans ce jugement câblé dedans, vous avez un rollout lent avec un surnom, pas du déploiement progressif.
Le déploiement n’est pas la release
La distinction qui rend le reste cohérent : le déploiement, c’est du code qui tourne quelque part en production ; la release, c’est ce code devenant ce que les utilisateurs vivent réellement. Un pod canary peut tourner en production, entièrement déployé, servant zéro utilisateur réel, uniquement pour générer des métriques en vue d’une décision. Un feature flag peut basculer une release en direct vers 100 % des utilisateurs sans qu’un seul nouveau déploiement n’ait lieu, parce que le code était déjà déployé, dormant derrière le flag, des jours plus tôt. Confondre les deux explique pourquoi « rollback » signifie si souvent un redéploiement complet alors qu’un simple basculement de flag aurait annulé le comportement en quelques secondes.
Un canary jugé par la CI, pas par une personne devant un dashboard
Argo Rollouts (un contrôleur Kubernetes, remplaçant direct de l’objet Deployment) et Flagger sont les deux implémentations de référence de l’analyse canary automatisée. La mécanique est la même chez les deux : basculer un petit pourcentage du trafic vers la nouvelle version, interroger des métriques réelles sur une fenêtre de temps, et promouvoir ou annuler selon un seuil défini à l’avance, pas selon une personne qui fixe un graphique pendant le rollout.
# Argo Rollouts : étapes canary qui se mettent en pause pour une analyse automatisée
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: payments-api
spec:
strategy:
canary:
steps:
- setWeight: 10
- pause: {} # attend ici la fin de l'AnalysisRun ci-dessous
- analysis:
templates:
- templateName: success-rate
- setWeight: 50
- pause: { duration: 5m }
- setWeight: 100
# AnalysisTemplate : le jugement lui-même, interrogé directement depuis Prometheus
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
name: success-rate
spec:
metrics:
- name: error-rate
interval: 1m
successCondition: result[0] < 0.01
failureLimit: 3
provider:
prometheus:
address: http://prometheus.monitoring:9090
query: |
sum(rate(http_requests_total{app="payments-api",status=~"5.."}[1m]))
/
sum(rate(http_requests_total{app="payments-api"}[1m]))
Si la requête dépasse le seuil trois fois, le contrôleur annule automatiquement le rollout, sans qu’aucune étape de pipeline ni astreinte n’ait à prendre cette décision. C’est ce détail qui transforme un canary d’une procédure manuelle et sous surveillance en quelque chose qu’un pipeline peut déclencher sans supervision, à 2 heures du matin, sur un déploiement à faible trafic, exactement quand personne n’a envie de fixer un dashboard.
Ce que l’analyse doit réellement couvrir pour valoir quelque chose
Une analyse qui ne vérifie que le taux d’erreur rate le mode de défaillance où le canary répond 200 avec des réponses fausses ou lentes. Un AnalysisTemplate sérieux vérifie les percentiles de latence en plus du taux d’erreur, et donne à la fenêtre assez de durée pour attraper une fuite lente, pas seulement un crash instantané : une fenêtre de cinq minutes sur un service avec un TTL de cache de deux minutes laissera passer un canary dont le problème n’apparaît qu’une fois le cache vidé. L’analyse ne vaut que ce que valent les métriques derrière elle, ce qui explique pourquoi les rollouts canary et l’instrumentation d’une application avec les golden signals arrivent souvent ensemble dans un pipeline qui mûrit : on n’automatise pas un jugement sur des données qu’on ne collecte pas.
Feature flags : découpler les deux axes délibérément
Là où un canary automatise une décision sur du code déjà en cours d’exécution, un feature flag retire la décision du pipeline de déploiement tout entier. Le code part dans le noir, derrière un flag évalué au moment de la requête, et quelqu’un bascule la release indépendamment de tout déploiement :
if (flags.isEnabled('new-checkout-flow', { userId })) {
return renderNewCheckout();
}
return renderLegacyCheckout();
Ça achète deux choses qu’un canary seul n’apporte pas. D’abord, la release peut être scopée par attribut (10 % des utilisateurs, un palier de compte donné, une cohorte interne) plutôt que seulement par pourcentage brut de trafic. Ensuite, le « rollback » d’une mauvaise release devient un basculement de flag, quelques secondes, pas un redéploiement, ce qui est un geste sensiblement plus rapide et plus sûr que kubectl rollout undo une fois qu’on tient compte du rolling update normal qu’il faut de toute façon laisser tourner. Le coût est bien réel aussi : des flags laissés dans le code longtemps après que la décision a été prise sont une dette qui s’accumule aussi silencieusement que du code mort, et une base de code avec deux ans de flags jamais retirés devient sa propre forme d’inmaintenabilité.
Choisir entre les deux
Ce ne sont pas des options concurrentes, elles répondent à des questions différentes. Utilisez l’analyse canary quand le risque est dans le code lui-même et qu’il vous faut du trafic réel et de vraies métriques pour savoir si c’est sûr (un nouveau driver de base de données, un chemin critique réécrit). Utilisez un feature flag quand le code est sûr mais que le vrai enjeu est le moment ou l’audience de la release (une refonte du parcours d’achat, un changement de tarification). La plupart des pipelines matures finissent par faire tourner les deux : un canary valide qu’un déploiement n’est pas cassé, et un flag gouverne quand la fonctionnalité qui en résulte devient réellement visible. Cette approche par couches pour réduire le risque de déploiement fait partie de ce que j’apporte dans une mission d’industrialisation CI/CD, calée sur le trafic et les métriques que votre architecture peut réellement soutenir aujourd’hui.