Flagger – Déploiements Canary sur Kubernetes
Fabian Piau | mardi 19 mai 2020 - 19:5617 Octobre 2020 : Utilisation de versions plus récentes (Helm 3, Kube 18, Istio 1.7, Flagger 1.2).
Cet article est le deuxième de la série consacrée à Flagger. En bref, Flagger est un outil de livraison progressive qui automatise le processus de livraison des applications s’exécutant sur Kubernetes. Il réduit le risque d’introduire une nouvelle version logicielle en production en augmentant progressivement le trafic vers la nouvelle version tout en mesurant les métriques et en exécutant des tests de conformité.
Assurez-vous d’avoir un cluster Kubernetes avec le service mesh Istio qui tourne sur votre machine en local. Sinon, lisez le premier article: Flagger – Premiers pas avec Istio et Kubernetes.
Dans ce deuxième tutoriel, nous nous concentrerons sur l’installation de Flagger et lancerons plusieurs déploiements canary de l’application Mirror HTTP Server (MHS). N’oubliez pas que cette application très simple peut simuler des réponses valides ou invalides en fonction de la requête en entrée. C’est exactement ce dont nous avons besoin pour tester les capacités de Flagger. Nous couvrirons à la fois les scénarios type « happy path » (rollout) et « unhappy path » (rollback).
Ce guide est un « hands-on » et peut être suivi pas à pas par les utilisateurs sous MacOS. Il nécessitera quelques ajustements si vous utilisez un PC sous Windows ou Linux. Il est important de signaler que cet article ne s’attardera pas sur les concepts et technologies en détail donc si vous n’êtes pas familier avec Docker, Kubernetes, Helm ou Istio, je vous conseille fortement de vous documenter avant de poursuivre votre lecture.
Installation de Flagger
Installons Flagger en exécutant ces commandes.
Nous installons Flagger dans son propre namespace flagger-system
.
kubectl apply -f https://raw.githubusercontent.com/weaveworks/flagger/master/artifacts/flagger/crd.yaml
helm upgrade -i flagger flagger/flagger \
--namespace=flagger-system \
--set crd.create=false \
--set meshProvider=istio \
--set metricsServer=http://prometheus.istio-system:9090
Référence: Installation de Flagger sur Kubernetes
Flagger dépend des métriques fournies par Istio et de Prometheus (dans notre cas, nous supposons qu’Istio est installé dans le namespaceistio-system
).
Tous les paramètres d’installation sont disponibles dans le fichier readme de Flagger sur GitHub.
Nous ne spécifions pas le numéro de version, ce qui signifie que l’on utilisera la dernière version disponible dans le repository (1.2.0
lorsque j’écris cet article).
Après quelques secondes, vous devriez recevoir un message confirmant que Flagger a été installé. Depuis le Kube dashboard, vérifiez qu’un nouveau namespace flagger-system
a bien été créé et que le pod Flagger est en cours d’exécution.
Expérience 0 – Initialisation avec le déploiement canary de MHS v1.1.1
Mirror HTTP Server est disponible en plusieurs versions. Pour tester la fonctionnalité de déploiement canary de Flagger, nous basculerons entre la version 1.1.1
, 1.1.2
et 1.1.3
de MHS (la dernière version lorsque j’écris cet article).
Avant de déployer MHS, créons un nouveau namespace application
, nous ne voulons pas utiliser celui par défaut à la racine du cluster (c’est une bonne pratique). Le nom est un peu trop générique, mais suffisant pour ce tutoriel, en général vous utiliserez le nom de l’équipe ou le nom d’un regroupement de fonctionnalités.
N’oublions pas d’activer Istio sur ce nouveau namespace:
Pour déployer MHS via Flagger, j’ai créé un Helm chart.
Ce chart de « type canary » a été créé en se basant sur le chart précédent sans Flagger qui lui-même avait été créé avec la commande helm create mhs-chart
, puis adapté. Dans ce chart de « type canary », j’ai fait quelques ajustements supplémentaires pour utiliser 2 répliquas au lieu de 1 pour rendre le déploiement plus réaliste et utiliser la version 1.1.1
, j’ai également ajouté la ressource canary où la magie opère.
Clonez le repo contenant le chart:
Et installez MHS:
helm install --name mhs --namespace application ./mhs
Après quelques instants, si vous regardez le tableau de bord, vous devriez voir 2 répliquas de MHS dans le namespace application
.
Il est important de noter qu’aucune analyse canary n’a été effectuée et que la version a été automatiquement promue. Ce n’était pas un « vrai » déploiement canary.
Pourquoi? Parce que Flagger a besoin de s’initialiser la première fois que nous faisons un déploiement canary de l’application. Assurez-vous donc que la version que vous déployez avec Flagger la première fois est entièrement testée et fonctionne bien!
Vous pouvez également penser que cette promotion automatique s’est produite, car il n’y avait pas de version initiale de l’application dans le cluster. Bien que ce soit évidemment une bonne raison, il est important de noter que, même si nous avions une version précédente auparavant (par exemple1.1.0
), la version canary1.1.1
aurait aussi été automatiquement promue sans analyse.
Vous pouvez quand même consulter les événements canary avec:
Vous devriez avoir une sortie similaire sans analyse canary:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning Synced 2m29s flagger mhs-primary.application not ready: waiting for rollout to finish: observed deployment generation less then desired generation
Normal Synced 92s (x2 over 2m30s) flagger all the metrics providers are available!
Normal Synced 92s flagger Initialization done! mhs.application
Ou vous pouvez également consulter directement les logs de Flagger:
kubectl -n flagger-system logs $FLAGGER_POD_NAME
Si vous regardez de plus près le tableau de bord Kube, vous devriez voir plusieurs ressources mhs
et mhs-primary
:
mhs-primary
sont les instances principales (c.-à-d. non canary). Flagger ajoute automatiquement le suffixe-primary
pour les différencier des instances canary.mhs
sont les instances canary. Elles n’existent que pendant le déploiement et disparaîtront une fois le déploiement canary terminé. C’est pourquoi, dans la capture d’écran ci-dessus, vous ne voyez pas de podmhs
canary (c.-à-d. 0/0 pod).
Pourquoi cette convention de nommage? J’ai demandé directement à l’équipe de Flagger et il y a une contrainte technique.
Flagger est maintenant correctement initialisé et MHS est déployé sur votre cluster. Vous pouvez utiliser le terminal pour confirmer que MHS est accessible (grâce à la Passerelle Istio):
Vous devriez recevoir une réponse HTTP 200 OK:
x-powered-by: Express
date: Sun, 17 May 2020 16:47:33 GMT
x-envoy-upstream-service-time: 10
server: istio-envoy
transfer-encoding: chunked
Et:
devrait retourner une réponse HTTP 500:
x-powered-by: Express
date: Sun, 17 May 2020 16:48:09 GMT
x-envoy-upstream-service-time: 12
server: istio-envoy
transfer-encoding: chunked
Expérience 1 – Déploiement canary de MHS v1.1.2
Nous allons installer une version plus récente 1.1.2
. Vous devez éditer manuellement le fichier mhs-canary-chart/mhs/values.yaml
et remplacer tag: 1.1.1
par tag: 1.1.2
(cette ligne).
Ensuite:
helm upgrade mhs --namespace application ./mhs
Alors que le déploiement canary est en cours, il est très important de générer du trafic vers MHS. Sans trafic, Flagger considérera que quelque chose s’est mal passé avec la nouvelle version et fera un rollback automatique pour retourner à la précédente version. Evidemment, vous n’aurez pas besoin de cette étape supplémentaire dans un environnement de production qui reçoit en permanence du trafic réel.
Exécutez cette commande dans un autre terminal pour générer ce trafic artificiel:
Vérifiez le Kube dashboard, vous devriez voir le pod canary avec la nouvelle version 1.1.2
à un moment donné:
Vérifiez les événements canary avec la même commande que précédemment:
Après un certain temps (environ 6 minutes), vous devriez avoir une sortie d’événements similaire:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning Synced 30m flagger mhs-primary.application not ready: waiting for rollout to finish: observed deployment generation less then desired generation
Normal Synced 29m (x2 over 30m) flagger all the metrics providers are available!
Normal Synced 29m flagger Initialization done! mhs.application
Normal Synced 10m flagger New revision detected! Scaling up mhs.application
Normal Synced 9m16s flagger Starting canary analysis for mhs.application
Normal Synced 9m16s flagger Advance mhs.application canary weight 10
Normal Synced 8m16s flagger Advance mhs.application canary weight 20
Normal Synced 7m16s flagger Advance mhs.application canary weight 30
Normal Synced 6m16s flagger Advance mhs.application canary weight 40
Normal Synced 5m16s flagger Advance mhs.application canary weight 50
Normal Synced 4m16s flagger Copying mhs.application template spec to mhs-primary.application
Normal Synced 3m16s flagger Routing all traffic to primary
Normal Synced 2m16s flagger (combined from similar events): Promotion completed! Scaling down mhs.application
La livraison canary s’est déroulée avec succès. Vous avez maintenant la version 1.1.2
installée sur tous les pods primary et le pod canary a été supprimé.
Pourquoi ce déploiement a-t-il duré environ 6 minutes? Parce qu’il inclut une analyse canary de 5 minutes. Au cours de cette analyse, le trafic a été augmenté de manière progressive vers le pod canary. Le trafic canary a augmenté de 10% toutes les 1 minute jusqu’à atteindre 50% du trafic global. L’analyse est configurable et définie dans le fichier canary.yaml qui a été ajouté au chart.
Voici la configuration de l’analyse:
analysis: # intervalle entre chaque incrémentation de trafic et prises des mesures interval: 1m # pourcentage de trafic max routé vers le canary - pourcentage (0-100) maxWeight: 50 # pas d'incrément canary - pourcentage (0-100) stepWeight: 10 # nombre maximum d'échecs de vérification des métriques avant un rollback (global pour toutes les prises de mesures) threshold: 5 metrics: - name: request-success-rate # pourcentage avant que le taux de réussite soit considéré comme ayant échoué (0-100) thresholdRange: min: 99 # intervalle entre chaque prise de mesure de la métrique taux de réussite interval: 30s - name: request-duration # durée maximale P99 en millisecondes avant que le temps de réponse soit considéré comme ayant échoué thresholdRange: max: 500 # intervalle entre chaque prise de mesure de la métrique temps de réponse interval: 30s
Notre analyse canary utilise les 2 métriques de base fournies par Istio / Prometheus (taux de réussite + temps de réponse). Il est possible de définir vos propres métriques personnalisées. Dans ce cas, elles devront être fournies par votre application. Votre application devra exposer un endpoint Prometheus qui inclura vos métriques personnalisées. Et vous pourrez mettre à jour la configuration de l’analyse de Flagger pour les utiliser avec votre propre requête PromQL. Notez que cela va au-delà de ce guide qui utilise uniquement les métriques de base.
Expérience 2 – Déploiement canary de MHS version v1.1.3
Encore une fois, vous devez éditer manuellement le fichier mhs-canary-chart/mhs/values.yaml
et remplacer la ligne tag: 1.1.2
par tag: 1.1.3
.
Ensuite:
helm upgrade mhs --namespace application ./mhs
Nous générons du trafic artificiel:
Cette fois, nous générons également du trafic non valide pour nous assurer que le taux de réussite des requêtes diminue!
Vérifiez les événements canary avec la même commande que précédemment:
Après un certain temps (environ 6 minutes), vous devriez avoir une sortie d’événements similaire:
Normal Synced 7m23s (x2 over 19m) flagger Advance mhs.application canary weight 10
Normal Synced 7m23s (x2 over 19m) flagger Starting canary analysis for mhs.application
Warning Synced 6m23s flagger Halt mhs.application advancement success rate 57.14% < 99%
Warning Synced 5m24s flagger Halt mhs.application advancement success rate 0.00% < 99%
Warning Synced 3m24s flagger Halt mhs.application advancement success rate 71.43% < 99%
Warning Synced 2m24s flagger Halt mhs.application advancement success rate 50.00% < 99%
Warning Synced 84s flagger Halt mhs.application advancement success rate 63.64% < 99%
Warning Synced 24s flagger Rolling back mhs.application failed checks threshold reached 5
Warning Synced 24s flagger Canary failed! Scaling down mhs.application
Et vous êtes toujours sur la version 1.1.2
.
Flagger a décidé de stopper et ne pas propager la version
1.1.3
car il n’a pas pu effectuer une analyse canary réussie et le seuil d’erreur a était atteint, 5 fois (en effet, à chaque fois, environ 50% des requêtes se sont terminées par une réponse HTTP 500). Flagger a simplement redirigé tout le trafic vers les instances primary et supprimé le pod canary.
Félicitations, vous êtes arrivé à la fin de ce deuxième tutoriel!
Observations
Avant de faire du nettoyage dans notre cluster, terminons par une liste d’observations:
- La suppression d’un déploiement supprimera tous les pods (canary / primary). Et nous ne nous retrouvons pas avec des ressources orphelines.
- Prometheus est un prérequis. Sans lui, l’analyse canary ne fonctionnera pas.
- Il n’est pas possible de relancer un déploiement canary sur la même version s’il vient d’échouer. Cela vous oblige à changer et incrémenter la version (même s’il s’agissait d’un problème de configuration et non d’un problème de code).
- Le processus de désactivation de Flagger n’est pas aussi simple que de supprimer la ressource canary du chart et de déployer une nouvelle version. Si vous supprimez la ressource canary, Flagger ne déclenchera pas le processus canary, il changera la version dans
mhs
et supprimeramhs-primary
mais,mhs
a 0 pod, ce qui rendra votre service indisponible! Vous devez être prudent et adopter un processus de désactivation manuelle approprié. Récement, l’équipe Flagger a ajouté une propriétérevertOnDeletion
que vous pouvez activer pour pallier à ce problème. Vous pouvez vous référer à la doc pour plus de détail sur ce canary finalizer. - Après plusieurs déploiements, il semble que certains événements peuvent manquer, la commande Kubernetes
describe
les accumule (x<int> over <int>m
) et parfois, l’ordre n’est pas conservé et/ou certains événements ne s’affichent pas. Vous pouvez consulter le statut Flagger concernant la phase du canary (les états finis sontInitialized
,Succeeded
ouFailed
). Le mieux est de regarder directement les logs sur le pod Flagger, car elles sont toujours plus précises et complètes. - L’analyse canary doit être configurée pour s’exécuter sur une courte période (c.-à-d. pas plus de 30 minutes) pour tirer profit d’un véritable déploiement continu et éviter de publier une nouvelle version alors qu’un déploiement canary pour la précédente est toujours en cours. Dans le cas où vous souhaitez tester une version canary sur plusieurs heures ou même jours, vous devriez peut-être repenser votre cas d’utilisation et Flagger pourrait ne pas être le meilleur choix.
- Nous l’avons déjà mentionné, mais c’est important: la première fois que vous déployez avec Flagger (comme avec l’expérience 0), l’outil doit s’initialiser (statut
Initialized
) et n’effectuera aucune analyse.
Nettoyage des ressources
Vous pouvez supprimer l’application MHS et son namespace.
kubectl delete namespaces application
Nous vous recommandons de laisser Flagger et Istio en place pour gagner du temps dans le prochain tutoriel. Si toutefois vous souhaitez tout supprimer maintenant, vous pouvez exécuter les commandes suivantes.
Supprimer Flagger:
kubectl delete namespaces flagger-system
Supprimer Istio et Prometheus:
istioctl manifest generate --set profile=demo | kubectl delete -f -
kubectl delete namespaces istio-system
Et après?
Le prochain article se concentrera sur le Tableau de bord Grafana fourni prêt à l’emploi par Flagger qui est un ajout intéressant. Il vous fera gagner du temps, car vous n’aurez pas besoin d’exécuter manuellement des commandes kuberctl
pour vérifier le résultat de vos déploiements canary. Stay tuned! En attendant, vous pouvez arrêter le cluster Kubernetes en décochant la case et redémarrant Docker Desktop. Votre ordinateur peut prendre une pause bien méritée.
Commentaires récents