Skalierung tut nicht, was du erwartest
Ein HPA skaliert nicht
kubectl get hpa
kubectl describe hpa <name>Die Spalte TARGETS ist die Diagnose. <unknown>/70% heißt, der HPA kann keine Metrik lesen und wird gar nichts tun.
Der Container hat keinen CPU-Request. Das ist die übliche Ursache. averageUtilization ist ein Prozentwert vom Request. Ohne Request gibt es keine Bezugsgröße, von der man Prozent nehmen könnte.
Beachte: Ein Container ohne Ressourcenangaben bekommt einen Namespace-Standard. Der Request existiert also, ist aber klein, und die Auslastung liest sich deutlich höher, als du erwartest. So oder so lautet die Antwort, den Request bewusst zu setzen, siehe Abrechnung und Kontingente.
Es sind noch keine Metriken da. Direkt nach einem Deployment gibt es nichts zu mitteln. Gib ihm eine Minute, bevor du Schlüsse ziehst.
Er skaliert, nur nicht so schnell, wie du willst. Der HPA dämpft Änderungen bewusst, damit er nicht flattert. Beobachte ihn über ein paar Minuten statt über Sekunden.
Er ist bei maxReplicas. describe sagt das deutlich, und die Lösung ist ein höheres Maximum oder ein Kontingent, das eins zulässt.
Ein schlafender Workload wacht nie auf oder schläft nie ein
Scale-to-Zero-Probleme melden sich an der Route, nicht am Workload. Schau also zuerst dort:
kubectl describe httproute <name>Er schläft nie ein. Fast immer hält ihn ein zweiter Autoscaler wach. Ein HPA mit minReplicas: 1 oder mehr hält dauerhaft mindestens eine Replica am Laufen, der Workload geht also nie auf null und du zahlst weiter. Dich hindert nichts daran, einen anzulegen, aber die Route sagt es:
Warning ScaleToZeroHPAConflict HorizontalPodAutoscaler myapp also targets
Deployment/myapp ...Lösch den HPA, oder nimm die Scale-to-Zero-Annotation weg, wenn du ihn behalten willst. Ein Autoscaler pro Workload.
Wurde die Anmeldung direkt abgelehnt, bestand der Konflikt schon, als du die Annotation gesetzt hast:
Warning ScaleToZeroError the workload 'myapp' of type 'apps/v1.Deployment'
is already managed by the hpa 'myapp'Er schläft nie ein, und es gibt keinen zweiten Autoscaler. Dann ruft ihn noch etwas auf. Health-Checks, Uptime-Monitore und Crawler zählen als Traffic. Das Idle-Fenster beträgt mindestens 300 Sekunden, ein Monitor im Minutentakt hält ihn also dauerhaft wach.
Er schläft, aber die erste Anfrage scheitert. Aufwachen dauert normalerweise ein paar Sekunden, und der Aufrufer wartet einfach. Muss der Cluster erst einen Node dazunehmen, dauert es länger, als die Verbindung gehalten wird, und der Aufrufer bekommt eine Fehlerseite. Das ist selten, und ein erneuter Versuch gelingt.
Aufwachen dauert länger als nötig. Deine Readiness-Probe ist der größte Hebel. Es wird kein Traffic geschickt, bevor sie durchläuft. initialDelaySeconds: 5, periodSeconds: 10 heißt also frühestens fünf Sekunden, nächste Chance nach fünfzehn. Nimm initialDelaySeconds: 0 und periodSeconds: 1, wenn dir die Aufwachzeit wichtig ist.
Er skaliert auf mehr oder weniger Replicas als erwartet. Das einzige Signal sind gleichzeitig laufende Anfragen. Der Standardwert von 100 pro Replica ist für die meisten Anwendungen viel zu hoch, deshalb wird der Workload unter Last langsamer, statt zu skalieren. Setz den Zielwert auf ungefähr das, was eine Replica bequem bedient:
itsh.dev/scale-to-zero-target-concurrency: "10"Ist deine Last nicht proportional zu gleichzeitigen HTTP-Anfragen, ist Scale-to-Zero das falsche Werkzeug. Nimm einen HPA oder ein KEDA-ScaledObject.
Wie es weitergeht
- Autoscaling, wie die einzelnen Scaler arbeiten
- Scale-to-Zero für alle Annotationen