Zum Inhalt

AKS-Plattform: Lasttests

Diese Seite beschreibt, wie die Plattform lastgetestet wird und was der Test misst. Der Test hat zwei Ziele: herausfinden, wie viel Traffic ein workload auf dem Nicht-Produktions-Cluster aushält, bevor er kaputtgeht, und nachweisen, dass die Alerting-Kette (Prometheus- Regel, Alertmanager, PagerDuty) auslöst und sich wieder auflöst, wenn sie es soll.

Referenzdesign, dein Deployment kann abweichen

Der Test läuft nur gegen den Nicht-Produktions-Cluster. Die Ziel-Anwendung, die Schwellenwerte und die Routen stammen aus dem Referenz-Setup. Ein längeres Designdokument beschreibt ein breiteres Testprogramm mit einem anderen Tool. Diese Seite behandelt, was umgesetzt ist, und nennt den Rest als geplant.

So läuft ein Testlauf

Eine manuell gestartete pipeline erstellt im Cluster einen kurzlebigen Job, erzeugt Traffic in drei Stufen, beobachtet die Auswirkungen und entfernt danach alles wieder. Im Leerlauf trägt der Cluster keinen Lastgenerator.

flowchart TB
    start["Pipeline started by hand<br/>(rates, durations, failure trigger)"] --> login["OIDC login to Azure,<br/>cluster credentials"]
    login --> infra["Apply namespace, RBAC,<br/>network policy, dashboard"]
    infra --> mark1["Annotate Grafana: test start"]
    mark1 --> job["Vegeta job in the load-testing namespace"]
    job --> s1["Stage 1: warm-up"]
    s1 --> s2["Stage 2: sustained"]
    s2 --> s3["Stage 3: overload"]
    s3 --> report["Vegeta report in the run summary"]
    report --> mark2["Annotate Grafana: test end"]
    mark2 --> clean["Delete job and config map,<br/>reset the failure rate"]
Teil Detail
Tool Vegeta, ein HTTP-Angreifer mit konstanter Rate, als Kubernetes-Job ausgeführt (ein Pod, keine Retries)
Wo Im Cluster in einem eigenen Namespace load-testing, sodass der Traffic durch das Cluster-Netzwerk und DNS läuft
Trigger Ein manueller GitHub-Actions-Workflow mit den unten genannten Parametern
Identität Die föderierte Identität der pipeline mit der Azure-Rolle Azure Kubernetes Service RBAC Admin, auf den Cluster beschränkt
Footprint Ein Service Account mit einer Rolle im Namespace, eine Network Policy für die Generator-Pods und eine Grafana-Dashboard-ConfigMap. Der Job und die ConfigMap seines Skripts werden am Ende gelöscht (if: always()); der Job hat außerdem eine Time-to-live
Größe des Generators Requests 500m CPU und 1 GiB, Limits 2 CPU und 4 GiB. Der Worker-Pool ist auf 8000 Verbindungen begrenzt, was nötig ist, um 3000 Requests pro Sekunde zu halten, wenn die Latenz steigt
Pre-flight Das Skript wartet bis zu 60 Sekunden auf den Health-Endpunkt des Ziels, bevor es angreift

Stufen und Parameter

Stufe Standardrate Standarddauer Zweck
1. Warm-up 60 Requests pro Sekunde 30 s Gesunde Baseline
2. Sustained 400 Requests pro Sekunde 1 Min. Last, auf die der Autoscaler reagiert
3. Overload 3000 Requests pro Sekunde 5 Min. Über die Kapazität des workloads hinausgehen

Alle sechs Werte sind Eingaben des Workflows. Eine siebte Eingabe, trigger_failure (standardmäßig an), automatisiert die Fehlergeschichte: Die pipeline erhöht die Fehlerrate der Anwendung zu Beginn von Stufe 2 und setzt sie in der letzten Minute von Stufe 3 zurück, sodass ein Fehlerpeak garantiert ist, ohne Raten von Hand abzustimmen. Ohne sie steuerst du die beiden Änderungen von Hand mit kubectl set env.

Was gemessen wird

Die Anwendung exportiert ihre eigenen Prometheus-Metriken (der Generator selbst exportiert keine). Der Lauf wird anhand der Anwendung und des Clusters bewertet.

Bereich Signal Verwendet für
Request-Rate Requests pro Sekunde nach Response-Code Angebotene Last und erreichter Durchsatz
Fehler Anteil der 5xx-Antworten über 5 Minuten Verfügbarkeit und den Fast-burn-Alert
Latenz p50, p90, p95, p99 aus dem Histogramm der Request-Dauer Latenzziel
Autoscaling Gewünschte Replicas des HPA gegenüber aktuellen Replicas Skaliert der workload aus, und wie schnell
Kapazität Pod-CPU gegenüber Requests, pending Pods, Restarts, Out-of-Memory-Kills Wo der workload saturiert
Alerts Prometheus-Alert-Status mit dem Label für den Lasttest, Alertmanager-Receiver, PagerDuty-Incident Ob die Kette funktioniert
Client-Sicht Der Vegeta-Report: Summen pro Stufe und gesamt, mit Latenz-Perzentilen und Erfolgsquote Gegenprüfung von der Client-Seite

Ein Grafana-Dashboard für den Test wird aus einer ConfigMap bereitgestellt. Ein Hilfsskript kann nach dem Lauf eine Zusammenfassung aus Prometheus ausgeben (Requests gesamt, Spitzenrate, Spitzen-Fehlerrate, Spitzen-p95 und -p99, maximale Replicas, Restarts, Alert-Status).

Bestanden und fehlgeschlagen

Der Job besteht oder scheitert nicht an der Erfolgsquote von Vegeta, weil Stufe 3 den workload überlasten soll. Der Workflow schlägt nur fehl, wenn der Job einen Fehler hat (zum Beispiel ist das Ziel nicht erreichbar) oder nicht rechtzeitig fertig wird. Das eigentliche Ergebnis ist, ob die Alerts auslösen und sich auflösen und ob ein Incident erstellt und wieder geschlossen wird.

Alert-Validierung

Drei Alert-Regeln für den Lasttest spiegeln die Service Level Objectives der Referenzaufgabe. Sie tragen Labels, die sie als Test-Alerts kennzeichnen:

Alert Bedingung For Severity
AvailabilityErrorBudgetBurnFast 5xx-Anteil über 5 Minuten über dem 10-Fachen des Error Budgets von 0,1 % 5 Min. page
AvailabilityErrorBudgetBurnSlow 5xx-Anteil über 30 Minuten über dem 2-Fachen des Budgets 12 h ticket
LatencySLOViolation p95-Latenz über 5 Minuten über 300 ms 15 Min. page

Alertmanager leitet Alerts mit source = load-test an einen eigenen Receiver weiter. Im umgesetzten Setup nutzt er denselben PagerDuty-Routing-Key wie die Produktion und ist an einem Präfix [LOAD-TEST] und an Feldern im Event zu erkennen. Das Designdokument schlug dafür einen separaten PagerDuty-Service vor.

Was du in einem Lauf beobachten kannst: nur den Fast-burn-Alert, weil Stufe 3 standardmäßig 5 Minuten dauert, so lange wie die for-Periode der Regel. Lass Stufe 3 20 Minuten oder länger laufen, um den Latenz-Alert auslösen zu sehen. Den Slow-burn-Alert kannst du nicht live beobachten.

Nachweise, die du für eine Alert-Validierung sammelst:

Prüfung Wie
Der Alert erreicht firing Prometheus-Alerts-Seite, nach dem Test-Label gefiltert
An den Test-Receiver geleitet Alertmanager-Alerts-Seite
Incident erstellt PagerDuty, Titel mit dem Präfix [LOAD-TEST]
Incident löst sich selbst auf PagerDuty, nachdem die Fehlerrate zurückgesetzt wurde und sich die Metriken erholen
Keine Auswirkung auf das Produktions-Alerting Keine weiteren Incidents auf demselben Service im Zeitfenster

Der Ziel-workload

Das Ziel ist eine kleine öffentliche Demo-Webanwendung (Flask, mit Prometheus-Metriken), deployt im Namespace <team>-dev mit dem gemeinsamen Application Chart: Autoscaling von 3 bis 10 Replicas bei einem CPU-Ziel von 70 %, ein Disruption Budget, ein gehärteter Security Context und ein Service Monitor, der das Prometheus-Label job setzt, sodass Regeln, Dashboard und Abfragen alle auf einen Namen zeigen. Der Work-Endpunkt simuliert 50 bis 200 ms Latenz und schlägt zufällig mit einer konfigurierbaren Rate fehl (Standard 2 %). Er verschlechtert sich unter Last realistisch, ohne einen künstlichen Stress-Schalter.

Nur die Umgebung dev wird unterstützt. Die Namespaces test und accp laufen mit einem Platzhalter-Webserver-Image, nicht mit der Demo- Anwendung.

Was die Zahlen bedeuten

Im validierten Lauf flachte der Durchsatz bei etwa 1.800 bis 2.260 Requests pro Sekunde ab (etwa 220 pro Pod bei zehn Pods), der Autoscaler ging von 3 auf 10 Pods, der Fast-burn-Alert löste etwa sechs Minuten nach Beginn des Laufs aus und löste sich kurz nach dem Zurücksetzen der Fehlerrate auf. Diese Zahlen beschreiben die Demo-Anwendung (einen Entwicklungsserver mit einem Prozess), nicht die Kapazität der Plattform. Ein höheres CPU-Limit machte keinen Unterschied. Betrachte den Lauf als wiederholbare Methode, um die Zahl für jeden Service zu finden.

Bekannte Einschränkungen

Einschränkung Auswirkung
Das Latenz-Histogramm misst nur die Verarbeitung der Requests, nicht die Zeit in der Warteschlange, wenn der Server saturiert ist Der Latenz-Alert löst selbst bei schwerer Überlast selten aus, deshalb ist der Fast-burn-Alert das verlässliche Signal
Ein Self-heal von Argo CD machte die Änderung der Fehlerrate innerhalb einer Sekunde rückgängig Behoben, indem die Argo-CD-Anwendung angewiesen wurde, dieses eine Feld zu ignorieren
Rollenzuweisungen für die pipeline und das Graph-API-Problem Nutze das Target cicd-aks-rbac (Deployment)
Ergebnisse der Läufe werden nicht automatisch gespeichert oder verglichen Sichere die Zusammenfassung des Laufs und das Dashboard selbst
Lokale Läufe auf einem Laptop liefern verrauschte absolute Zahlen Nutze die Zahlen aus dem Cluster

Geplantes Testprogramm (nur Design)

Das Designdokument beschreibt weitere Testarten für den Nicht-Produktions-Cluster. Sie sind in der pipeline nicht umgesetzt.

Test Muster Zweck
Smoke 1 bis 5 User, 1 bis 2 Minuten Test-Setup und Ziel prüfen
Baseline Normale Last für etwa 13 Minuten Referenzwerte für den Release-Vergleich
Load Erwartete Spitzenlast für etwa 23 Minuten Alle Plattformziele werden eingehalten
Stress Schrittweise Steigerung bis zur Degradation Den Bruchpunkt finden, informativ
Spike Plötzlicher Burst, dann zurück Der Autoscaler reagiert und das System erholt sich
Soak Moderate Last über 2 bis 8 Stunden Leaks und schleichende Verschlechterung
Capacity Steigerung, bis ein Ziel bricht Maximal nachhaltiger Durchsatz
Autoscaling Last über dem Autoscaler-Ziel, dann auf null Timing von Scale-up und Scale-down
Alerting Lastmuster, die bekannte Alerts auslösen Kette von der Regel zum Incident

Das Design nannte außerdem k6 mit seinem Kubernetes-Operator als primäres Tool und eine Azure-DevOps-pipeline. Die Umsetzung wechselte zu Vegeta, gesteuert über GitHub Actions, weil die k6-basierten Demo-Läufe wiederholt nicht die erwarteten Ergebnisse lieferten.