Publication en douceur avec APISIX Ingress Controller et Flagger
Hengliang Tan
January 19, 2023
Auteur : Hengliang Tan, Responsable Ingénierie chez XPENG
Dans le processus de développement de projet, les mises à jour de services sont souvent un défi. Pour offrir la meilleure expérience utilisateur possible, nous devons éviter autant que possible le risque d'indisponibilité des services. Ainsi, la livraison continue est née, acceptée comme une pratique logicielle d'entreprise, et une évolution naturelle des principes bien établis de l'intégration continue. Cependant, le déploiement continu reste très rare en raison de la complexité de gestion et de la crainte que les échecs de déploiement n'affectent la disponibilité du système. La publication en canary est probablement le scénario le plus classique dans le système de livraison continue. Sur cette base, nous pouvons rapidement détecter les services malsains et problématiques et revenir à la version précédente sans effort.
Publication en Canary
La publication en canary est également connue sous le nom de publication en grayscale. En général, la nouvelle version de l'application est publiée et déployée comme un "canary" pour tester les performances. L'ancienne version reste pour les opérations normales à la même étape. Pendant la mise à niveau, certains utilisateurs seront dirigés vers la nouvelle version, tandis que d'autres continueront à utiliser l'ancienne version. Tout en garantissant la stabilité globale du système, cela permet de détecter rapidement les bugs et d'effectuer des ajustements en temps opportun.
La publication en canary ne libère pas directement la mise à jour. Elle guide lentement un certain pourcentage du trafic vers un petit nombre d'utilisateurs. Si aucune erreur n'est détectée, elle sera promue à tous les utilisateurs, et l'ancienne version sera progressivement supprimée. Cette méthode réduit le risque d'introduction de nouvelles fonctionnalités dans l'environnement de production.
Cet article présentera comment réaliser une publication en canary fluide grâce à Apache APISIX Ingress et Flagger, améliorer l'efficacité de la publication et réduire les risques de publication.
À propos d'Apache APISIX Ingress
Apache APISIX Ingress est réalisé par le Kubernetes Ingress Controller qui utilise Apache APISIX comme proxy de plan de données. Il fournit des centaines de fonctionnalités, telles que l'équilibrage de charge, l'amont dynamique, la publication en canary, le routage fin, la limitation de débit, la dégradation de service, la coupure de service, l'authentification et l'observabilité. Il a été adopté par des entreprises et organisations nationales et internationales, notamment Zoom, Tencent Cloud, Jiakaobaodian, Horizon Robotics, le système de référence Copernicus européen, etc.
À propos de Flagger
Flagger est un projet CNCF (Cloud Native Computing Foundation) et fait partie de la famille d'outils GitOps Flux. Récemment, la CNCF a également annoncé la graduation officielle de Flux, ce qui est un bon indicateur du succès et de l'avenir prometteur de la technologie cloud-native. En tant qu'outil de livraison progressive, Flagger automatise le processus de publication pour les applications exécutées sur Kubernetes. Il réduit le risque d'introduction d'une nouvelle version de logiciel en production en déplaçant progressivement le trafic vers la nouvelle version tout en mesurant les métriques analytiques et en exécutant des tests de conformité.
Après les efforts continus des communautés Apache APISIX et Flux, Flagger a récemment publié la version v1.27.0, qui prend en charge les publications en canary automatisées utilisant Apache APISIX Ingress et Flagger.
Vivons ensemble ce processus fluide de publication en canary.
Environnement
Nécessite un cluster Kubernetes v1.19 ou plus récent, que vous pouvez installer via kind.
Installation des composants
Utilisez Helm V3 pour installer Apache APISIX et Apache APISIX Ingress Controller
helm repo add apisix https://charts.apiseven.com
kubectl create ns apisix
helm upgrade -i apisix apisix/apisix --version=0.11.3 \
--namespace apisix \
--set apisix.podAnnotations."prometheus\.io/scrape"=true \
--set apisix.podAnnotations."prometheus\.io/port"=9091 \
--set apisix.podAnnotations."prometheus\.io/path"=/apisix/prometheus/metrics \
--set pluginAttrs.prometheus.export_addr.ip=0.0.0.0 \
--set pluginAttrs.prometheus.export_addr.port=9091 \
--set pluginAttrs.prometheus.export_uri=/apisix/prometheus/metrics \
--set pluginAttrs.prometheus.metric_prefix=apisix_ \
--set ingress-controller.enabled=true \
--set ingress-controller.config.apisix.serviceNamespace=apisix
Installez les composants Flagger et Prometheus dans l'espace de noms apisix.
helm repo add flagger https://flagger.app
helm upgrade -i flagger flagger/flagger \
--namespace apisix \
--set prometheus.install=true \
--set meshProvider=apisix
Note : si vous avez besoin de personnaliser Prometheus ou Prometheus Operator, vous pouvez rechercher des articles connexes pour les modifications.
Initialisation de l'application
Flagger peut être appliqué à Kubernetes deployment et à d'autres charges de travail, et peut également être combiné avec HPA. Il créera une série d'objets : Kubernetes deployments, services ClusterIP et ApisixRoute. Ces objets peuvent exposer les applications à l'extérieur des clusters pour fournir des services et sont utilisés pour l'analyse du processus de publication en canary.
Créez un nouvel espace de noms de test :
kubectl create ns test
Créez un nouveau deployment et HPA. Ici, nous extrayons l'exemple de code officiel de Flagger.
kubectl apply -k https://github.com/fluxcd/flagger//kustomize/podinfo?ref=main
Déployez le service de test de charge de Flagger pour générer du trafic pendant la publication en canary pour l'analyse.
helm upgrade -i flagger-loadtester flagger/loadtester \ --namespace=test
Créez l'ApisixRoute
d'Apache APISIX, puis Flagger référencera la ressource créée et générera l'ApisixRoute
d'Apache APISIX Ingress dans la version canary. (Remplacez app.example.com
dans l'exemple ci-dessous par votre nom de domaine réel)
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
name: podinfo
namespace: test
spec:
http:
- backends:
- serviceName: podinfo
servicePort: 80
match:
hosts:
- app.example.com
methods:
- GET
paths:
- /*
name: method
plugins:
- name: prometheus
enable: true
config:
disable: false
prefer_name: true
Enregistrez-le sous podinfo-apisixroute.yaml
et soumettez-le au cluster :
kubectl apply -f ./podinfo-apisixroute.yaml
Créez une ressource personnalisée Canary de Flagger. (Remplacez app.example.com
dans l'exemple par votre nom de domaine réel)
apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
name: podinfo
namespace: test
spec:
provider: apisix
targetRef:
apiVersion: apps/v1
kind: Deployment
name: podinfo
# Référence à la route apisix
routeRef:
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
name: podinfo
progressDeadlineSeconds: 60
service:
port: 80
targetPort: 9898
analysis:
interval: 10s
# nombre maximum d'échecs pour le retour en arrière
threshold: 10
# pourcentage maximum de trafic vers la version canary
# (0-100)
maxWeight: 50
# taille de l'étape de l'analyse canary
# (0-100)
stepWeight: 10
# utilise Prometheus pour vérifier les informations de trafic d'APISIX
metrics:
- name: request-success-rate
# taux de succès minimum (aucune réponse 5xx)
# (0-100)
thresholdRange:
min: 99
interval: 1m
- name: request-duration
# P99 est le délai de requête le plus long (ms)
thresholdRange:
max: 500
interval: 30s
webhooks:
# trafic automatisé pour l'analyse canary, modifié en fonction du scénario réel
- name: load-test
url: http://flagger-loadtester.test/
timeout: 5s
type: rollout
metadata:
cmd: |-
hey -z 1m -q 10 -c 2 -h2 -host app.example.com http://apisix-gateway.apisix/api/info
Enregistrez-le sous podinfo-canary.yaml
et soumettez-le au cluster :
kubectl apply -f ./podinfo-canary.yaml
Flagger générera automatiquement les ressources associées :
# Soumis deployment.apps/podinfo horizontalpodautoscaler.autoscaling/podinfo apisixroute/podinfo canary.flagger.app/podinfo
# Généré automatiquement deployment.apps/podinfo-primary horizontalpodautoscaler.autoscaling/podinfo-primary service/podinfo service/podinfo-canary service/podinfo-primary apisixroute/podinfo-podinfo-canary
À ce stade, vous pouvez accéder à l'application via le nom de domaine app.example.com (Remplacez app.example.com
dans l'exemple par votre nom de domaine réel), et vous verrez la version actuelle de l'application.
Automatisation de la publication en Canary
Flagger implémente une boucle de contrôle qui déplace progressivement le trafic vers les nœuds canary tout en mesurant les métriques de performance clés telles que le taux de succès des requêtes HTTP, la durée moyenne des requêtes et la santé des pods. Selon l'analyse des indicateurs pertinents, publiez ou arrêtez le déploiement canary et publiez les résultats d'analyse sur des plateformes pertinentes telles que Slack, MS Teams ou Prometheus Alert Manager, etc.
Déclenchez une publication en canary en mettant à jour la version de l'image du conteneur
kubectl -n test set image deployment/podinfo \ podinfod=stefanprodan/podinfo:6.0.1
Flagger détecte qu'il y a une nouvelle version du déploiement et commencera une exécution d'essai de l'analyse de publication en canary.
kubectl -n test describe canary/podinfo
Status:
Canary Weight: 0
Conditions:
Message: Canary analysis completed successfully, promotion finished.
Reason: Succeeded
Status: True
Type: Promoted
Failed Checks: 1
Iterations: 0
Phase: Succeeded
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning Synced 2m59s flagger podinfo-primary.test not ready: waiting for rollout to finish: observed deployment generation less than desired generation
Warning Synced 2m50s flagger podinfo-primary.test not ready: waiting for rollout to finish: 0 of 1 (readyThreshold 100%) updated replicas are available
Normal Synced 2m40s (x3 over 2m59s) flagger all the metrics providers are available!
Normal Synced 2m39s flagger Initialization done! podinfo.test
Normal Synced 2m20s flagger New revision detected! Scaling up podinfo.test
Warning Synced 2m (x2 over 2m10s) flagger canary deployment podinfo.test not ready: waiting for rollout to finish: 0 of 1 (readyThreshold 100%) updated replicas are available
Normal Synced 110s flagger Starting canary analysis for podinfo.test
Normal Synced 109s flagger Advance podinfo.test canary weight 10
Warning Synced 100s flagger Halt advancement no values found for apisix metric request-success-rate probably podinfo.test is not receiving traffic: running query failed: no values found
Normal Synced 90s flagger Advance podinfo.test canary weight 20
Normal Synced 80s flagger Advance podinfo.test canary weight 30
Normal Synced 69s flagger Advance podinfo.test canary weight 40
Normal Synced 59s flagger Advance podinfo.test canary weight 50
Warning Synced 30s (x2 over 40s) flagger podinfo-primary.test not ready: waiting for rollout to finish: 1 old replicas are pending termination
Normal Synced 9s (x3 over 50s) flagger (combined from similar events): Promotion completed! Scaling down podinfo.test
Pendant le processus de publication en canary, vous recevrez différentes réponses lorsque vous accéderez à l'application via le nom de domaine app.example.com (Remplacez app.example.com
par votre nom de domaine réel).
En visualisant la ressource ApisixRoute
podinfo-podinfo-canary
d'Apache APISIX créée automatiquement par Flagger, vous constaterez que les poids des services podinfo-primary
et podinfo-canary
changent avec le processus de publication.
spec:
http:
- backends:
- serviceName: podinfo-primary
servicePort: 80
# Ajusté automatiquement par Flagger
weight: 80
- serviceName: podinfo-canary
servicePort: 80
# Ajusté automatiquement par Flagger
weight: 20
Vous verrez la dernière version stable lorsque la publication finale sera terminée.
Note : Flagger relancera l'analyse canary si vous modifiez à nouveau le déploiement pendant la publication en canary.
Vous pouvez observer toutes les publications en canary avec cette commande :
watch kubectl get canaries --all-namespaces
NAMESPACE NAME STATUS WEIGHT LASTTRANSITIONTIME
test podinfo-2 Progressing 10 2022-11-23T05:00:54Z
test podinfo Succeeded 0 2022-11-23T06:00:54Z
Retour en arrière
Pendant l'analyse de la publication en canary, vous pouvez tester Flagger pour suspendre la publication en canary et revenir à l'ancienne version en générant une requête HTTP 500 Bad Request.
Déclenchez une autre publication en canary :
kubectl -n test set image deployment/podinfo \ podinfod=stefanprodan/podinfo:6.0.2
Entrez dans le conteneur de test de charge
kubectl -n test exec -it deploy/flagger-loadtester bash
Générez une erreur HTTP 500 :
hey -z 1m -c 5 -q 5 -host app.example.com http://apisix-gateway.apisix/status/500
Simulez un délai serveur :
watch -n 1 curl -H \"host: app.example.com\" http://apisix-gateway.apisix/delay/1
Lorsque le nombre d'échecs détectés atteint le seuil de l'analyse canary, le trafic est automatiquement redirigé vers le nœud principal, le nœud canary est réduit à zéro, et le processus de publication en canary est marqué comme échoué.
kubectl -n apisix logs deploy/flagger -f | jq .msg
"New revision detected! Scaling up podinfo.test"
"canary deployment podinfo.test not ready: waiting for rollout to finish: 0 of 1 (readyThreshold 100%) updated replicas are available"
"Starting canary analysis for podinfo.test"
"Advance podinfo.test canary weight 10"
"Halt podinfo.test advancement success rate 0.00% < 99%"
"Halt podinfo.test advancement success rate 26.76% < 99%"
"Halt podinfo.test advancement success rate 34.19% < 99%"
"Halt podinfo.test advancement success rate 37.32% < 99%"
"Halt podinfo.test advancement success rate 39.04% < 99%"
"Halt podinfo.test advancement success rate 40.13% < 99%"
"Halt podinfo.test advancement success rate 48.28% < 99%"
"Halt podinfo.test advancement success rate 50.35% < 99%"
"Halt podinfo.test advancement success rate 56.92% < 99%"
"Halt podinfo.test advancement success rate 67.70% < 99%"
"Rolling back podinfo.test failed checks threshold reached 10"
"Canary failed! Scaling down podinfo.test"
Personnalisation des métriques pour l'analyse Canary
L'analyse canary peut être étendue en interrogeant les métriques Prometheus. Nous personnalisons en fonction des scénarios métier réels. Créez un modèle de métrique et soumettez-le au cluster.
apiVersion: flagger.app/v1beta1
kind: MetricTemplate
metadata:
name: not-found-percentage
namespace: test
spec:
provider:
type: prometheus
address: http://flagger-prometheus.apisix:9090
query: |
sum(
rate(
apisix_http_status{
route=~"{{ namespace }}_{{ route }}-{{ target }}-canary_.+",
code!~"4.."
}[{{ interval }}]
)
)
/
sum(
rate(
apisix_http_status{
route=~"{{ namespace }}_{{ route }}-{{ target }}-canary_.+"
}[{{ interval }}]
)
) * 100
# Modifiez l'analyse dans la publication en canary et ajoutez le modèle d'indicateur créé ci-dessus.
analysis:
metrics:
- name: "404s percentage"
templateRef:
name: not-found-percentage
thresholdRange:
max: 5
interval: 1m
La configuration ci-dessus valide le canary en vérifiant si le QPS (Queries per second) des requêtes HTTP 404 est supérieur à 5 % du trafic total. La publication en canary échoue si les requêtes HTTP 404 dépassent le seuil de 5 %.
Résumé
Le processus ci-dessus peut être étendu avec plus de vérifications de métriques personnalisées, Webhook, approbations manuelles et notifications Slack ou MS Teams.
Une publication en canary très fluide est réalisée grâce à l'intégration d'Apache APISIX et Flagger, ce qui améliore l'efficacité de la publication et réduit les risques de publication. À l'avenir, les deux communautés coopéreront plus étroitement pour réaliser davantage de capacités de publication telles que le Blue/Green Mirroring et les tests A/B.