Kubernetes Autoscaling: HPA en VPA in de Praktijk
Horizontal en Vertical Pod Autoscaling instellen zonder dat je cluster explodeert. Resource requests, metrics en de valkuilen bij schalen.
Jean-Pierre Broeders
Freelance DevOps Engineer
Kubernetes Autoscaling: HPA en VPA in de Praktijk
Handmatig replica's opschalen bij piekverkeer. Het werkt, tot je een keer te laat bent of vergeet om weer terug te schalen. Kubernetes heeft twee mechanismen om dit te automatiseren: de Horizontal Pod Autoscaler (HPA) en de Vertical Pod Autoscaler (VPA). Beide hebben hun plek, maar ze werken fundamenteel anders.
HPA: meer pods bij meer load
De HPA is het bekendste mechanisme. Simpel concept: als de CPU of het geheugen boven een drempel komt, worden er pods bijgemaakt. Zakt de load, dan verdwijnen ze weer.
Een basis-HPA ziet er zo uit:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: api-hpa
namespace: production
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: api-server
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
behavior:
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Pods
value: 1
periodSeconds: 60
scaleUp:
stabilizationWindowSeconds: 30
policies:
- type: Pods
value: 2
periodSeconds: 60
Dat behavior blok is cruciaal. Zonder die configuratie schiet de HPA alle kanten op. De standaard scaleDown is agressief — binnen een minuut kan de helft van je pods weg zijn. Met een stabilization window van 300 seconden voorkom je dat een korte dip in traffic meteen een golf van shutdowns triggert.
Resource requests: de basis moet kloppen
Een HPA die schaalt op CPU utilization kijkt naar het percentage ten opzichte van de resource request. Geen requests? Dan werkt de HPA gewoon niet. Dit is veruit de meest gemaakte fout.
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
cpu: 500m
memory: 512Mi
Die requests moeten realistisch zijn. Te laag en de HPA schaalt te snel op. Te hoog en er wordt nooit geschaald, terwijl er wel CPU-druk is. Een goede aanpak: draai de applicatie een week met kubectl top pods en bekijk het daadwerkelijke verbruik. Stel de request in op het P50 verbruik, de limit op het P95.
Custom metrics: voorbij CPU
CPU is een grove maat. Voor een API-server is het aantal requests per seconde een veel betere metric. Met de Prometheus adapter kan de HPA schalen op custom metrics:
metrics:
- type: Pods
pods:
metric:
name: http_requests_per_second
target:
type: AverageValue
averageValue: 100
Dit vereist dat de applicatie metrics exporteert en dat de Prometheus adapter draait. Meer werk om op te zetten, maar het verschil in schaalprecisie is enorm. CPU-gebaseerde scaling reageert traag — de CPU stijgt pas nadat de requests al binnenkomen. Request-gebaseerde scaling anticipeert veel beter.
VPA: grotere pods in plaats van meer pods
Niet elke workload schaalt horizontaal. Denk aan een database, een cache layer, of een monolith die niet stateless is. Daar komt de Vertical Pod Autoscaler om de hoek kijken. In plaats van meer pods, maakt de VPA bestaande pods groter.
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: worker-vpa
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: background-worker
updatePolicy:
updateMode: "Auto"
resourcePolicy:
containerPolicies:
- containerName: worker
minAllowed:
cpu: 100m
memory: 128Mi
maxAllowed:
cpu: 2
memory: 4Gi
Belangrijk detail: VPA in Auto mode herstart pods om de nieuwe resource limits toe te passen. Dat betekent korte downtime, tenzij er meerdere replica's draaien. In veel gevallen is updateMode: "Off" een veiligere keuze — dan geeft de VPA alleen aanbevelingen die handmatig toegepast kunnen worden.
De aanbevelingen opvragen:
kubectl describe vpa worker-vpa
Dat toont lower bound, target en upper bound voor CPU en memory. Bruikbaar als startpunt voor het finetunen van resource requests.
HPA en VPA combineren: kan dat?
Kort antwoord: ja, maar niet op dezelfde metric. Als de HPA schaalt op CPU en de VPA ook CPU aanpast, ontstaat er een feedbackloop die nergens toe leidt. De oplossing:
- HPA schaalt op custom metrics (requests per seconde, queue depth)
- VPA beheert CPU en memory requests
Of gebruik de Multidimensional Pod Autoscaler (MPA) als die beschikbaar is in je cluster. Die combineert beide strategieën zonder conflicten.
Veelgemaakte fouten
| Fout | Gevolg | Oplossing |
|---|---|---|
| Geen resource requests | HPA werkt niet | Altijd requests instellen, gebaseerd op werkelijk verbruik |
| minReplicas op 1 | Single point of failure bij lage load | Minimaal 2 voor productie |
| Geen scaleDown stabilization | Flapping: pods gaan constant aan en uit | stabilizationWindowSeconds van 300+ |
| VPA op Auto zonder replica's | Downtime bij elke aanpassing | Gebruik "Off" mode of zorg voor meerdere replica's |
| Limits veel hoger dan requests | Node overcommitment, OOM kills | Houd limits dicht bij requests (max 2x) |
Monitoring van je autoscaler
Zonder monitoring is autoscaling een zwarte doos. Een paar essentiële checks:
# Huidige status van alle HPA's
kubectl get hpa -A
# Details met events
kubectl describe hpa api-hpa -n production
# Resource verbruik per pod
kubectl top pods -n production --sort-by=cpu
Stel alerts in voor situaties waar de HPA op maxReplicas zit. Dat betekent dat de applicatie meer nodig heeft dan het cluster kan bieden — tijd om maxReplicas te verhogen of de applicatie te optimaliseren.
Wanneer autoscaling overkill is
Niet alles hoeft te schalen. Een interne tool met vijf gebruikers? Gewoon twee vaste replica's. Een cronjob die één keer per uur draait? Vaste resources. Autoscaling voegt complexiteit toe. Gebruik het waar het verschil maakt: publieke API's, event-driven workloads, en alles wat onvoorspelbare pieken kent.
De sweet spot: begin met vaste replica's en goed ingestelde resource requests. Meet het daadwerkelijke verbruik over een paar weken. Pas dan autoscaling toe, met de meetdata als basis voor je thresholds.
