AKS Platform: load testing¶
Deze pagina beschrijft hoe het platform wordt belast getest en wat de test meet. De test heeft twee doelen: uitzoeken hoeveel verkeer een workload op het niet-productiecluster aankan voordat die breekt, en bewijzen dat de alertketen (Prometheus-regel, Alertmanager, PagerDuty) afgaat en weer sluit wanneer dat hoort.
Referentieontwerp, jouw deployment kan afwijken
De test draait alleen tegen het niet-productiecluster. De doelapplicatie, drempelwaarden en routes zijn die van de referentieopzet. Een uitgebreider ontwerpdocument beschrijft een breder testprogramma met een andere tool. Deze pagina behandelt wat is geïmplementeerd en noemt de rest als gepland.
Hoe een testrun werkt¶
Een handmatig gestarte pipeline maakt een kortlevende job in het cluster, stuurt in drie fasen verkeer, bekijkt de effecten en ruimt alles weer op. Het cluster draagt geen load generator als het niets doet.
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"]
| Onderdeel | Detail |
|---|---|
| Tool | Vegeta, een HTTP-aanvaller met constante snelheid, uitgevoerd als Kubernetes job (één pod, geen retries) |
| Waar | In het cluster in een eigen load-testing namespace, zodat het verkeer via het clusternetwerk en de DNS loopt |
| Trigger | Een handmatige GitHub Actions-workflow met de onderstaande parameters |
| Identity | De gefedereerde identity van de pipeline met de Azure-rol Azure Kubernetes Service RBAC Admin, beperkt tot het cluster |
| Voetafdruk | Een service account met een rol op namespaceniveau, een network policy voor de generator-pods en een config map voor het Grafana-dashboard. De job en de config map met het script worden aan het eind verwijderd (if: always()); de job heeft ook een time-to-live |
| Grootte van de generator | Requests 500m CPU en 1 GiB, limits 2 CPU en 4 GiB. De workerpool is begrensd op 8000 connecties, nodig om 3000 requests per seconde vast te houden als de latency stijgt |
| Pre-flight | Het script wacht maximaal 60 seconden op het health endpoint van het doel voordat het aanvalt |
Fasen en parameters¶
| Fase | Standaardsnelheid | Standaardduur | Doel |
|---|---|---|---|
| 1. Warm-up | 60 requests per seconde | 30 s | Gezonde baseline |
| 2. Sustained | 400 requests per seconde | 1 min | Belasting waarop de autoscaler reageert |
| 3. Overload | 3000 requests per seconde | 5 min | Voorbij de capaciteit van de workload duwen |
Alle zes waarden zijn workflow-inputs. Een zevende input, trigger_failure (standaard aan), automatiseert het storingsverhaal: de
pipeline verhoogt de foutfrequentie van de applicatie aan het begin van fase 2 en zet die in de laatste minuut van fase 3
terug, zodat een foutpiek gegarandeerd is zonder dat je snelheden met de hand hoeft af te stellen. Zonder die input voer je de
twee wijzigingen met de hand uit met kubectl set env.
Wat wordt gemeten¶
De applicatie exporteert haar eigen Prometheus-metrics (de generator zelf exporteert er geen). De run wordt beoordeeld aan de kant van de applicatie en van het cluster.
| Gebied | Signaal | Gebruikt voor |
|---|---|---|
| Requestsnelheid | Requests per seconde per responscode | Aangeboden belasting en behaalde throughput |
| Fouten | Aandeel 5xx-responses over 5 minuten | Beschikbaarheid en de fast-burn-alert |
| Latency | p50, p90, p95, p99 uit het histogram van de requestduur | Latency-doelstelling |
| Autoscaling | Gewenste replicas van de HPA ten opzichte van huidige replicas | Schaalt de workload uit, en hoe snel |
| Capaciteit | Pod-CPU ten opzichte van requests, pending pods, restarts, out-of-memory kills | Waar de workload verzadigd raakt |
| Alerts | Prometheus-alertstatus met het load test-label, Alertmanager-receiver, PagerDuty-incident | Of de keten werkt |
| Clientweergave | Het Vegeta-rapport: totalen per fase en samen, met latencypercentielen en succespercentage | Controle vanaf de clientkant |
Een Grafana-dashboard voor de test wordt ingericht vanuit een config map. Een hulpscript kan na de run een samenvatting uit Prometheus tonen (totaal aantal requests, piekrate, piek van het foutpercentage, piek van p95 en p99, maximaal aantal replicas, restarts, alertstatus).
Geslaagd en mislukt¶
De job slaagt of faalt niet op het succespercentage van Vegeta, omdat fase 3 bedoeld is om de workload te overbelasten. De workflow faalt alleen als de job een fout geeft (bijvoorbeeld als het doel onbereikbaar is) of niet op tijd klaar is. Het echte resultaat is of de alerts afgaan en weer oplossen en of er een incident wordt aangemaakt en gesloten.
Alertvalidatie¶
Drie alertregels voor de load test spiegelen de service level objectives van de referentieopdracht. Ze dragen labels die ze als testalerts markeren:
| Alert | Voorwaarde | Gedurende | Severity |
|---|---|---|---|
AvailabilityErrorBudgetBurnFast |
5xx-aandeel over 5 minuten boven 10 keer het foutbudget van 0,1% | 5 min | page |
AvailabilityErrorBudgetBurnSlow |
5xx-aandeel over 30 minuten boven 2 keer het budget | 12 u | ticket |
LatencySLOViolation |
p95-latency over 5 minuten boven 300 ms | 15 min | page |
Alertmanager routeert alerts met source = load-test naar een eigen receiver. In de geïmplementeerde opzet gebruikt die dezelfde
PagerDuty routing key als productie en wordt hij onderscheiden door een [LOAD-TEST]-prefix en velden in het event. Het
ontwerpdocument stelde hiervoor een aparte PagerDuty-service voor.
Wat je in één run kunt zien: alleen de fast-burn-alert, omdat fase 3 standaard 5 minuten duurt, even lang als de for-periode
van de regel. Laat fase 3 20 minuten of langer duren om de latency-alert te zien afgaan. De slow-burn-alert is niet live te
observeren.
Bewijs om te verzamelen bij een alertvalidatie:
| Controle | Hoe |
|---|---|
Alert bereikt firing |
Prometheus-alertspagina, gefilterd op het testlabel |
| Gerouteerd naar de test-receiver | Alertmanager-alertspagina |
| Incident aangemaakt | PagerDuty, titel met de [LOAD-TEST]-prefix |
| Incident lost zichzelf op | PagerDuty, nadat de foutfrequentie is teruggezet en de metrics herstellen |
| Geen effect op alerting in productie | Geen andere incidenten op dezelfde service in dat tijdvak |
De doelworkload¶
Het doel is een kleine publieke demo-webapplicatie (Flask, met Prometheus-metrics), gedeployd in de namespace <team>-dev met de
gedeelde applicatiechart: autoscaling van 3 tot 10 replicas op een CPU-doel van 70%, een disruption budget, een geharde security
context en een service monitor die het Prometheus-label job zet, zodat regels, dashboard en queries allemaal op één naam
werken. Het work-endpoint simuleert 50 tot 200 ms latency en faalt willekeurig met een instelbare frequentie (standaard 2%). Het
degradeert onder belasting realistisch, zonder kunstmatige stressschakelaar.
Alleen de omgeving dev wordt ondersteund. De namespaces test en accp draaien een placeholder-webserverimage, niet de
demoapplicatie.
Wat de cijfers betekenen
In de gevalideerde run vlakte de throughput af op ongeveer 1.800 tot 2.260 requests per seconde (ongeveer 220 per pod bij tien pods), schaalde de autoscaler van 3 naar 10 pods, ging de fast-burn-alert na ongeveer zes minuten af en loste die kort nadat de foutfrequentie was teruggezet weer op. Deze cijfers beschrijven de demoapplicatie (een ontwikkelserver met één proces), niet de capaciteit van het platform. Een hogere CPU-limit maakte geen verschil. Zie de run als een herhaalbare methode om het getal voor elke service te vinden.
Bekende beperkingen¶
| Beperking | Effect |
|---|---|
| Het latencyhistogram meet alleen het afhandelen van requests, niet de wachttijd in de wachtrij als de server verzadigd is | De latency-alert gaat zelfs bij zware overbelasting zelden af, dus de fast-burn-alert is het betrouwbare signaal |
| Een self-heal van Argo CD draaide de wijziging van de foutfrequentie binnen een seconde terug | Opgelost door de Argo CD-applicatie dat ene veld te laten negeren |
| Roltoewijzingen voor de pipeline en het Graph API-probleem | Gebruik het target cicd-aks-rbac (Deployment) |
| Resultaten van runs worden niet automatisch opgeslagen of vergeleken | Leg de samenvatting van de run en het dashboard zelf vast |
| Lokale runs op een laptop geven ruwe, onbetrouwbare absolute cijfers | Gebruik cijfers uit het cluster |
Gepland testprogramma (alleen ontwerp)¶
Het ontwerpdocument beschrijft verdere soorten tests voor het niet-productiecluster. Ze zijn niet in de pipeline geïmplementeerd.
| Test | Patroon | Doel |
|---|---|---|
| Smoke | 1 tot 5 gebruikers, 1 tot 2 minuten | De testopzet en het doel controleren |
| Baseline | Normale belasting gedurende ongeveer 13 minuten | Referentiewaarden voor releasevergelijking |
| Load | Verwachte piekbelasting gedurende ongeveer 23 minuten | Alle doelstellingen van het platform worden gehaald |
| Stress | Stapsgewijs opvoeren tot degradatie | Het breekpunt vinden, informatief |
| Spike | Plotselinge piek, daarna terug | De autoscaler reageert en het systeem herstelt |
| Soak | Matige belasting gedurende 2 tot 8 uur | Leaks en geleidelijke degradatie |
| Capacity | Opvoeren tot één doelstelling breekt | Maximale houdbare throughput |
| Autoscaling | Belasting boven het doel van de autoscaler, daarna naar nul | Timing van scale-up en scale-down |
| Alerting | Belastingpatronen die bekende alerts triggeren | Keten van regel naar incident |
Het ontwerp noemde ook k6 met zijn Kubernetes-operator als primaire tool en een Azure DevOps-pipeline. De implementatie is overgestapt op Vegeta, aangestuurd vanuit GitHub Actions, omdat de demo-runs met k6 herhaaldelijk niet de verwachte resultaten gaven.