Reibungslose Canary-Release mit APISIX Ingress Controller und Flagger

Hengliang Tan

January 19, 2023

Ecosystem

Autor: Hengliang Tan, Engineering Manager bei XPENG

Im Prozess der Projektentwicklung sind Service-Updates oft eine Herausforderung. Um das beste Benutzererlebnis zu bieten, müssen wir das Risiko von Service-Unverfügbarkeit so weit wie möglich vermeiden. So wurde Continuous Delivery geboren, als eine Unternehmenssoftware-Praxis akzeptiert und als natürliche Weiterentwicklung der etablierten Continuous-Integration-Prinzipien. Dennoch ist Continuous Deployment aufgrund der Komplexität des Managements und der Angst, dass Bereitstellungsfehler die Systemverfügbarkeit beeinträchtigen könnten, immer noch sehr selten. Canary Release ist wahrscheinlich das klassischste Szenario im Continuous-Delivery-System. Basierend darauf können wir schnell ungesunde und problematische Dienste erkennen und mühelos auf die vorherige Version zurückrollen.

Canary Release

Canary Release wird auch als Graustufen-Release bezeichnet. Im Allgemeinen wird die neue Version der Anwendung als "Canary" veröffentlicht und bereitgestellt, um die Leistung zu testen. Die alte Version bleibt für den normalen Betrieb in derselben Phase erhalten. Während des Upgrades werden einige Benutzer auf die neue Version umgeleitet, während andere Benutzer weiterhin die alte Version verwenden. Unter der Voraussetzung, dass die Stabilität des Gesamtsystems gewährleistet ist, ermöglicht dies die frühzeitige Erkennung von Fehlern und eine rechtzeitige Anpassung.

Der Canary Release gibt das Update nicht direkt frei. Es leitet langsam einen bestimmten Prozentsatz des Datenverkehrs zu einer kleinen Anzahl von Benutzern. Wenn keine Fehler festgestellt werden, wird es für alle Benutzer freigegeben, und die alte Version wird schrittweise abgelöst. Diese Methode reduziert das Risiko, neue Funktionen in die Produktionsumgebung einzuführen.

Dieser Artikel wird vorstellen, wie man durch Apache APISIX Ingress und Flagger einen reibungslosen Canary Release erreichen, die Release-Effizienz verbessern und die Release-Risiken reduzieren kann.

Über Apache APISIX Ingress

Apache APISIX Ingress wird durch den Kubernetes Ingress Controller realisiert, der Apache APISIX als Datenebenen-Proxy verwendet. Es bietet Hunderte von Funktionen wie Lastenausgleich, dynamisches Upstream, Canary Release, fein abgestimmtes Routing, Ratenbegrenzung, Service-Degradation, Service-Circuit-Breaker, Authentifizierung und Beobachtbarkeit. Es wurde von in- und ausländischen Unternehmen und Organisationen übernommen, darunter Zoom, Tencent Cloud, Jiakaobaodian, Horizon Robotics, European Copernicus Reference System usw.

Über Flagger

Flagger ist ein CNCF-Projekt (Cloud Native Computing Foundation) und Teil der Flux-Familie von GitOps-Tools. Kürzlich hat die CNCF auch die offizielle Graduierung von Flux bekannt gegeben, was ein guter Indikator für den Erfolg und die vielversprechende Zukunft der Cloud-Native-Technologie ist. Als ein progressives Bereitstellungstool automatisiert Flagger den Release-Prozess für Anwendungen, die auf Kubernetes laufen. Es reduziert das Risiko, eine neue Softwareversion in der Produktion einzuführen, indem es den Datenverkehr schrittweise auf die neue Version umleitet, während es Analyse-Metriken misst und Konformitätstests durchführt.

Nach kontinuierlichen Bemühungen der Apache-APISIX- und Flux-Communities hat Flagger kürzlich v1.27.0 veröffentlicht, das automatisierte Canary Releases mit Apache APISIX Ingress und Flagger unterstützt.

featured-<Flagger und Apache APISIX Ingress>.jpg

Lassen Sie uns gemeinsam diesen reibungslosen Canary-Release-Prozess erleben.

Umgebung

Erfordert einen Kubernetes-Cluster der Version 1.19 oder neuer, den Sie über kind installieren können.

Komponenten installieren

Verwenden Sie Helm V3, um Apache APISIX und den Apache APISIX Ingress Controller zu installieren.

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

Installieren Sie die Flagger- und Prometheus-Komponenten im apisix-Namespace.

helm repo add flagger https://flagger.app


helm upgrade -i flagger flagger/flagger \
--namespace apisix \
--set prometheus.install=true \
--set meshProvider=apisix

Hinweis: Wenn Sie Prometheus oder den Prometheus-Operator anpassen müssen, können Sie nach verwandten Artikeln suchen, um Änderungen vorzunehmen.

Anwendungsinitialisierung

Flagger kann auf Kubernetes-Deployments und andere Workloads angewendet werden und kann auch mit HPA kombiniert werden. Es wird eine Reihe von Objekten erstellen: Kubernetes-Deployments, ClusterIP-Services und ApisixRoute. Diese Objekte können Anwendungen für Cluster-externe Dienste verfügbar machen und werden für die Analyse des Canary-Release-Prozesses verwendet.

Erstellen Sie einen neuen Test-Namespace:

kubectl create ns test

Erstellen Sie ein neues Deployment und HPA. Hier extrahieren wir den offiziellen Code-Beispiel von Flagger.

kubectl apply -k https://github.com/fluxcd/flagger//kustomize/podinfo?ref=main

Stellen Sie den Lasttestdienst von Flagger bereit, um während des Canary-Releases Datenverkehr für die Analyse zu generieren.

helm upgrade -i flagger-loadtester flagger/loadtester \ --namespace=test

Erstellen Sie die ApisixRoute von Apache APISIX, und dann wird Flagger die erstellte Ressource referenzieren und die ApisixRoute von Apache APISIX Ingress in der Canary-Version generieren. (Ersetzen Sie app.example.com im folgenden Beispiel durch Ihren tatsächlichen Domainnamen)

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

Speichern Sie es als podinfo-apisixroute.yaml und übermitteln Sie es an den Cluster:

kubectl apply -f ./podinfo-apisixroute.yaml

Erstellen Sie eine Flagger-Custom-Resource Canary. (Ersetzen Sie app.example.com im Beispiel durch Ihren tatsächlichen Domainnamen)

apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
  name: podinfo
  namespace: test
spec:
  provider: apisix
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: podinfo
  # Referenzieren Sie die apisix route
  routeRef:
    apiVersion: apisix.apache.org/v2
    kind: ApisixRoute
    name: podinfo
  progressDeadlineSeconds: 60
  service:
    port: 80
    targetPort: 9898
  analysis:
    interval: 10s
    # Maximale Anzahl von Fehlern für den Rollback
    threshold: 10
    # Maximaler Prozentsatz des Datenverkehrs zur Canary-Version
    # (0-100)
    maxWeight: 50
    # Die Schrittgröße der Canary-Analyse
    # (0-100)
    stepWeight: 10
    # Verwenden Sie Prometheus, um die Verkehrsinformationen von APISIX zu überprüfen
    metrics:
      - name: request-success-rate
        # Die minimale Erfolgsrate (keine 5xx-Antworten)
        # (0-100)
        thresholdRange:
          min: 99
        interval: 1m
      - name: request-duration
        # P99 ist die größte Anforderungsverzögerung(ms)
        thresholdRange:
          max: 500
        interval: 30s
    webhooks:
        # Automatisierter Datenverkehr für die Canary-Analyse, basierend auf dem tatsächlichen Szenario angepasst
      - 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

Speichern Sie es als podinfo-canary.yaml und übermitteln Sie es an den Cluster:

kubectl apply -f ./podinfo-canary.yaml

Flagger wird automatisch verwandte Ressourcen generieren:

# Übermittelt deployment.apps/podinfo horizontalpodautoscaler.autoscaling/podinfo apisixroute/podinfo canary.flagger.app/podinfo

# Automatisch generiert deployment.apps/podinfo-primary horizontalpodautoscaler.autoscaling/podinfo-primary service/podinfo service/podinfo-canary service/podinfo-primary apisixroute/podinfo-podinfo-canary

featured-<version 1>.jpg

An diesem Punkt können Sie die Anwendung über den Domainnamen app.example.com aufrufen (Ersetzen Sie app.example.com im Beispiel durch Ihren tatsächlichen Domainnamen), und Sie werden die aktuelle Version der Anwendung sehen.

Automatisierung des Canary-Releases

Flagger implementiert eine Kontrollschleife, die den Datenverkehr schrittweise auf Canary-Knoten umleitet, während wichtige Leistungsmetriken wie die HTTP-Anfrageerfolgsrate, die durchschnittliche Anforderungsdauer und die Pod-Gesundheit gemessen werden. Basierend auf der Analyse der relevanten Indikatoren wird die Freigabe oder das Stoppen der Canary-Bereitstellung durchgeführt und die Analyseergebnisse an relevante Plattformen wie Slack, MS Teams oder Prometheus Alert Manager usw. veröffentlicht.

Flagger Control Loop

Lösen Sie einen Canary-Release aus, indem Sie die Container-Image-Version aktualisieren.

kubectl -n test set image deployment/podinfo \ podinfod=stefanprodan/podinfo:6.0.1

Flagger erkennt, dass es eine neue Version des Deployments gibt, und wird einen Testlauf der Canary-Analysefreigabe starten.

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

Während des Canary-Release-Prozesses erhalten Sie unterschiedliche Antworten, wenn Sie die Anwendung über den Domainnamen app.example.com aufrufen (Ersetzen Sie app.example.com durch Ihren tatsächlichen Domainnamen).

featured-<version 2>.jpg

Durch das Anzeigen der ApisixRoute-Ressource podinfo-podinfo-canary von Apache APISIX, die automatisch von Flagger erstellt wurde, werden Sie feststellen, dass die Gewichtungen des Dienstes podinfo-primary und des Dienstes podinfo-canary sich mit dem Veröffentlichungsprozess ändern.

spec:
  http:
    - backends:
        - serviceName: podinfo-primary
          servicePort: 80
          # Automatisch von Flagger angepasst
          weight: 80
        - serviceName: podinfo-canary
          servicePort: 80
          # Automatisch von Flagger angepasst
          weight: 20

Sie werden die neueste stabile Version sehen, wenn der endgültige Release abgeschlossen ist.

featured-<version 3>.jpg

Hinweis: Flagger wird die Canary-Analyse erneut ausführen, wenn Sie das Deployment während des Canary-Releases erneut ändern.

Sie können alle Canary-Releases mit diesem Befehl beobachten:

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

Rollback

Während der Canary-Release-Analyse können Sie Flagger testen, um den Canary-Release zu unterbrechen und auf die alte Version zurückzurollen, indem Sie einen HTTP 500 Bad Request generieren.

Lösen Sie einen weiteren Canary-Release aus:

kubectl -n test set image deployment/podinfo \ podinfod=stefanprodan/podinfo:6.0.2

Geben Sie den Lasttest-Container ein.

kubectl -n test exec -it deploy/flagger-loadtester bash

Generieren Sie einen HTTP 500-Fehler:

hey -z 1m -c 5 -q 5 -host app.example.com http://apisix-gateway.apisix/status/500

Simulieren Sie eine Serververzögerung:

watch -n 1 curl -H \"host: app.example.com\" http://apisix-gateway.apisix/delay/1

Wenn die Anzahl der erkannten Fehler den Schwellenwert der Canary-Analyse erreicht, wird der Datenverkehr automatisch zurück zum Master-Knoten geleitet, der Canary-Knoten wird auf Null herunterskaliert, und der Canary-Release-Prozess wird als fehlgeschlagen markiert.

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"

Anpassen von Metriken für die Canary-Analyse

Die Canary-Analyse kann durch das Abfragen von Prometheus-Metriken erweitert werden. Wir passen basierend auf den tatsächlichen Geschäftsszenarien an. Erstellen Sie eine Metrikvorlage und übermitteln Sie sie an den 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
# Ändern Sie die Analyse im Canary-Release und fügen Sie die oben erstellte Indikatorvorlage hinzu.
  analysis:
    metrics:
      - name: "404s percentage"
        templateRef:
          name: not-found-percentage
        thresholdRange:
          max: 5
        interval: 1m

Die obige Konfiguration validiert den Canary, indem sie überprüft, ob die QPS (Queries per second) von HTTP 404-Anfragen höher als 5 % des gesamten Datenverkehrs ist. Der Canary-Rollout schlägt fehl, wenn die HTTP 404-Anfragen den 5 %-Schwellenwert überschreiten.

Zusammenfassung

Der obige Prozess kann mit weiteren benutzerdefinierten Metrikprüfungen, Webhooks, manuellen Genehmigungen und Benachrichtigungen über Slack oder MS Teams erweitert werden.

Ein sehr reibungsloser Canary-Release wird durch die Integration von Apache APISIX und Flagger erreicht, was die Release-Effizienz verbessert und die Release-Risiken reduziert. In Zukunft werden die beiden Communities enger zusammenarbeiten, um weitere Veröffentlichungsfunktionen wie Blue/Green Mirroring und A/B Testing zu realisieren.

Tags: