Horizontal Pod Autoscaler (HPA) jest mechanizmem w Kubernetes, który automatycznie dostosowuje liczbę replik Podów (np. w ramach Deploymentu lub StatefulSetu) do bieżącego obciążenia aplikacji. Innymi słowy, HPA realizuje skalowanie horyzontalne – przy rosnącym obciążeniu uruchamiane są dodatkowe Pody, co zwiększa moc przetwarzania poprzez równoległość. Jest to przeciwieństwo skalowania wertykalnego, gdzie zwiększa się zasoby (CPU, RAM) istniejących już Podów, zamiast dodawać nowe. Gdy zapotrzebowanie spada, a liczba podów przekracza zdefiniowane minimum, HPA automatycznie zmniejszy liczbę replik, zwalniając zasoby klastra. HPA nie obsługuje obiektów, których nie da się skalować (np. DaemonSet), skupiając się na obciążeniach skalowalnych przez zmianę liczby podów.
HPA jest zaimplementowany jako zasób API (HorizontalPodAutoscaler) oraz odpowiadający mu kontroler działający w planie kontrolnym Kubernetes. Użytkownik definiuje obiekt HPA (np. w pliku YAML), wskazując docelowy workload do skalowania (np. Deployment), minimalną i maksymalną liczbę replik oraz metryki wraz z ich progami. Na tej podstawie kontroler HPA co pewien czas analizuje aktualne metryki systemowe aplikacji i podejmuje decyzje o skalowaniu.
Jak działa HPA
HPA działa w formie pętli kontrolnej (tzw. control loop), która okresowo (domyślnie co 15 sekund) sprawdza zadane metryki i skaluje aplikację w razie potrzeby. Nie jest to proces ciągły w czasie rzeczywistym, lecz cykliczny – co każde X sekund kontroler pobiera bieżące wartości metryk, porównuje je z wartościami docelowymi zdefiniowanymi w obiekcie HPA i ewentualnie koryguje liczbę podów.
W każdym cyklu działania, kontroler HPA wykonuje następujące kroki:
Pobranie metryk – kontroler odczytuje bieżące metryki dla wskazanych podów. Źródłem metryk może być Metrics API Kubernetes (dla metryk zasobów jak CPU/RAM) lub API metryk niestandardowych/zewnętrznych (o tym w dalszych sekcjach).
Porównanie z celem – odczytane wartości (np. średnie zużycie CPU) są porównywane z zadanymi progami/targetami zdefiniowanymi w specyfikacji HPA.
Obliczenie pożądanej liczby replik – na podstawie proporcji aktualnego wykorzystania do celu, HPA wylicza ile podów powinno działać, aby osiągnąć docelowy poziom metryki. Dla przykładu, jeśli średnie użycie CPU wynosi 200 mCPU na pod przy limicie 1000 mCPU, a celem jest 50% wykorzystania, to HPA stwierdzi, że należy uruchomić więcej podów. W przypadku wielu metryk, HPA oblicza zapotrzebowanie dla każdej z osobna i wybiera największą wymaganą liczbę replik (tj. metrykę “najbardziej wymagającą”).
Skalowanie – jeżeli wyliczona pożądana liczba replik różni się od obecnej liczby podów, kontroler modyfikuje skalę obiektu (np. .spec.replicas Deploymentu) do tej wartości, z zastrzeżeniem limitów minReplicas i maxReplicas.
Warto podkreślić, że HPA w swoich decyzjach kieruje się średnimi metrykami na pod (np. średnim zużyciem CPU na jeden pod) lub sumarycznymi wartościami (dla metryk zewnętrznych/obiektowych), co pozwala mu skalować w sposób proporcjonalny. Domyślnie kontroler HPA synchronizuje się co 15 sekund, ale parametr ten można zmienić (flaga –horizontal-pod-autoscaler-sync-period w kube-controller-manager). Kubernetes ogranicza też zbyt częste zmiany – decyzje skalujące (zwłaszcza skalowanie w dół) nie będą podejmowane częściej niż co ok. 5 minut, aby zapobiec tzw. flapping (ciągłym oscylacjom góra-dół). Mechanizm ten nazywa się oknem stabilizacji i pozwala odczekać, czy spadek obciążenia jest trwały zanim zredukuje się liczbę podów.
Metryki i komponenty HPA
HPA może korzystać z różnych źródeł metryk do podejmowania decyzji skalujących. Kubernetes obsługuje trzy kategorie metryk dla HPA:
Metryki zasobów (Resource metrics) – dotyczą standardowych zasobów kontenerów, jak zużycie CPU czy pamięci RAM. Dostarczane są przez Metrics Server i udostępniane poprzez API metrics.k8s.io.
Metryki niestandardowe (Custom metrics) – dowolne metryki aplikacyjne wewnątrz klastra (np. liczba żądań HTTP/s na pod). Wymagają zewnętrznego adaptera implementującego API custom.metrics.k8s.io (np. Prometheus Adapter).
Metryki zewnętrzne (External metrics) – metryki spoza klastra, np. zewnętrzne usługi w chmurze lub kolejki wiadomości (np. długość kolejki RabbitMQ, liczba zapytań w load balancerze). Wymagają adaptera obsługującego API external.metrics.k8s.io i zazwyczaj integracji z systemem monitoringu zewnętrznego.
Metrics Server
Metrics Server jest lekkim komponentem Kubernetes, który agreguje podstawowe metryki zużycia zasobów (CPU, RAM) z poszczególnych węzłów i podów. Działa on jako źródło danych dla wbudowanego Metrics API Kubernetes. HPA wykorzystuje te dane do autoskalowania na podstawie wykorzystania CPU/memory. Według dokumentacji, Metrics Server “zbiera metryki zasobów z Kubeletów i udostępnia je poprzez API Metrics (metrics.k8s.io) do wykorzystania przez Horizontal Pod Autoscaler i Vertical Pod Autoscaler”. Innymi słowy, jeśli chcemy korzystać z HPA opierającego się na zużyciu CPU lub pamięci, w klastrze musi być zainstalowany Metrics Server i poprawnie skonfigurowany.
Metrics Server nie wymaga instalacji w przypadku klastrów zarządzanych chmurowo (wiele z nich ma go preinstalowanego), ale w klastrach on-premise lub lokalnych (minikube, kubeadm) trzeba go doinstalować. Standardowa instalacja polega na zastosowaniu manifestu YAML lub Helm Chart dostarczanego przez projekt Metrics Server (przykładowo: kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml). Po instalacji możemy zweryfikować działanie poprzez komendę kubectl top pods – pojawienie się danych CPU/Memory potwierdza, że Metrics Server działa poprawnie i HPA będzie miał dostęp do metryk.
Uwaga: Metrics Server został zaprojektowany tylko na potrzeby autoskalowania i wglądu w bieżące zużycie zasobów. Nie przechowuje historycznych metryk i nie zastąpi pełnoprawnego monitoringu – do długoterminowego monitoringu i metryk aplikacyjnych należy użyć narzędzi typu Prometheus. Metrics Server odświeża dane co ok. 15 sekund i jest zoptymalizowany pod kątem wydajności (zużywa ~1 miliCPU i 2 MB RAM na węzeł), dzięki czemu skaluje się do klastrów rzędu kilku tysięcy węzłów.
Prometheus Adapter i metryki niestandardowe
Jeśli chcemy skalować aplikacje na podstawie metryk innych niż podstawowe (CPU/RAM), np. liczby obsłużonych żądań na sekundę, głębokości kolejki zadań czy niestandardowych metryk biznesowych, potrzebny będzie mechanizm dostarczenia tych danych do HPA. Kubernetes udostępnia tzw. Custom Metrics API (custom.metrics.k8s.io) oraz External Metrics API (external.metrics.k8s.io), ale domyślnie nie ma komponentu zbierającego te metryki – musimy zainstalować odpowiedni adapter.
Najpopularniejszym rozwiązaniem jest Prometheus Adapter dla Kubernetes. Jest to projekt integrujący Prometheusa (powszechny system monitoringu) z Kubernetesowym API metryk niestandardowych. Adapter ten implementuje wymagane interfejsy API i umożliwia HPA pobieranie metryk zgromadzonych w Prometheusie. Repozytorium Prometheus Adapter podaje, że “adapter jest implementacją Kubernetes Custom Metrics API (oraz Resource i External Metrics API), odpowiednią do użycia z Horizontal Pod Autoscaler (autoscaling/v2)”. Oznacza to, że po zainstalowaniu adaptera i odpowiedniej konfiguracji, możemy definiować w HPA metryki typu Pods, Object lub External, które będą mapowane na zapytania do Prometheusa. Prometheus Adapter domyślnie dostarcza pewien zestaw reguł metrów (np. agregacje CPU/RAM, czy standardowe metryki nginx), ale w praktyce często wymaga dostosowania konfiguracji (poprzez ConfigMap) do konkretnych nazw metryk aplikacyjnych w danym klastrze.
W kontekście HPA wyróżniamy następujące rodzaje metryk niestandardowych, obsługiwane od wersji API autoscaling/v2:
Pods metrics (metryki Pods) – metryki odnoszące się do każdego poda z osobna, raportowane i agregowane dla grupy podów. HPA oblicza średnią wartość na pod i porównuje do zadanego celu (tylko typ celu AverageValue). Przykład: liczba żądań HTTP na sekundę obsługiwanych przez pod. W definicji HPA wygląda to np. tak: type: Pods, metryka o nazwie X, target.averageValue: Y (średnio Y na pod).
Object metrics (metryki Object) – metryki związane z konkretnym obiektem Kubernetes innym niż pod, np. Service, Ingress, czy nawet obiekt spoza cluster (w przypadku External). HPA odczytuje wartość metryki dla wskazanego obiektu i może ją porównać bezpośrednio (Value) lub podzielić przez liczbę podów (AverageValue). Przykład: throughput (requests per second) mierzony na obiekcie Ingress (całościowo dla wszystkich podów za nim).
External metrics (metryki External) – metryki pochodzące spoza Kubernetes, niemające powiązania z konkretnym obiektem w klastrze. Pozwalają skalować na podstawie zewnętrznych danych (np. kolejka wiadomości, metryki z chmury publicznej). Konfiguracja jest podobna do Object, ale jako metric.name podajemy nazwę dowolnej metryki ujawnianej przez adapter, a zamiast describedObject używamy opcjonalnie selektora etykiet. Np. możemy skalować worker-Deployment w oparciu o długość kolejki zadań w systemie kolejkowym. Załóżmy, że Prometheus zbiera metrykę queue_messages_ready{queue=“worker_tasks”} – wtedy HPA z metryką External może zostać zdefiniowany tak, że na każdych 30 niewykonanych zadań przypada 1 pod.
Przed skorzystaniem z metryk niestandardowych należy:
Zainstalować i skonfigurować odpowiedni adapter metryk (np. Prometheus Adapter). Dostępne są też adaptery dla innych źródeł, np. adapter Datadog, Stackdriver dla GCP itp.
Upewnić się, że metryki są eksponowane w systemie monitoringu i prawidłowo mapowane przez adapter do API Kubernetes (często wymaga to napisania reguł w ConfigMap adaptera, określających jak np. metryka Prometheus o danej nazwie ma być udostępniona jako metryka custom/external).
Zweryfikować dostępność metryk komendą kubectl get –raw “/apis/custom.metrics.k8s.io/v1beta2/” (dla custom metrics) lub analogiczną dla external, aby upewnić się, że adapter zwraca jakieś dane.
Metrics Server vs Prometheus Adapter: Warto zauważyć, że Prometheus Adapter może opcjonalnie zastąpić Metrics Server, jeśli już używamy Prometheusa – potrafi on wystawiać również metryki CPU/RAM (Resource) poprzez API metrics.k8s.io. Jednak konfiguracja takiego trybu bywa złożona i w praktyce wiele instalacji korzysta z obu komponentów: Metrics Server dla prostoty (CPU/RAM) oraz adaptera Prometheus dla metryk aplikacyjnych.
Konfiguracja HPA – przykłady YAML
HPA można utworzyć w sposób deklaratywny, definiując manifest YAML rodzaju HorizontalPodAutoscaler. Poniżej przedstawiono dwa przykłady konfiguracji:
Przykład 1: Autoskalowanie na podstawie CPU – HPA skalujący Deployment na podstawie średniego wykorzystania CPU podów. Minimalna liczba replik to 1, maksymalna 10, a celem jest 50% wykorzystania przydzielonego CPU (średnio) na pod:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: php-apache
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: php-apache
minReplicas: 1
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
W powyższym przykładzie HPA będzie starał się utrzymywać średnie użycie procesora na poziomie 50%. Gdy obciążenie przekroczy ten próg (np. średnio 70% CPU), kontroler zwiększy liczbę podów, natomiast gdy spadnie poniżej 50% i są więcej niż 1 pod, nastąpi skalowanie w dół. Zauważ, że używamy pola averageUtilization: 50, które odnosi się do procentu requestu CPU zdefiniowanego dla kontenerów – aby to miało sens, każdy pod powinien mieć ustawiony resources.requests.cpu. Alternatywnie moglibyśmy użyć type: AverageValue i podać absolutną wartość CPU (np. 500m), co oznacza docelowe średnie użycie 0.5 vCPU na pod.
Przykład 2: Autoskalowanie na podstawie metryki zewnętrznej – HPA skalujący liczbę podów workerów w zależności od zewnętrznej metryki (np. długości kolejki zadań). Załóżmy, że zewnętrzny system publikuje metrykę queue_messages_ready z etykietą queue="worker_tasks", a adapter udostępnia ją poprzez external.metrics.k8s.io. Chcemy utrzymać średnio 30 oczekujących wiadomości na jednego poda:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: queue-worker-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: queue-worker
minReplicas: 1
maxReplicas: 5
metrics:
- type: External
external:
metric:
name: queue_messages_ready
selector:
matchLabels:
queue: "worker_tasks"
target:
type: AverageValue
averageValue: 30
W tym przykładzie HPA odpyta adapter metryk zewnętrznych o wartość metryki queue_messages_ready z etykietą queue=worker_tasks. Jeśli, na przykład, aktualnie jest 120 zadań w kolejce, a działa 1 pod, to średnio na pod przypada 120 zadań – HPA zwiększy repliki do 4 (120/30 = 4). Jeżeli zadań będzie mniej (np. 15 przy 1 podzie), to średnia 15/1 jest poniżej progu 30, więc HPA może zmniejszyć liczbę podów (nie poniżej minReplicas). Dzięki użyciu AverageValue HPA dynamicznie reaguje na sumaryczną wartość metryki dzieloną na liczbę podów.
Uwaga do konfiguracji: W polu .spec.metrics możemy zdefiniować wiele metryk jednocześnie (lista). HPA obliczy wymaganą liczbę replik osobno dla każdej metryki i zastosuje największą z wartości jako desiredReplicas. Zapobiega to sytuacji, w której HPA spełnia jeden warunek kosztem innego. Przykładowo, jeśli mamy dwa cele: 50% CPU i 1000 req/s na pod, to przy wzroście obu metryk HPA skalując wybierze tyle podów, aby oba cele zostały spełnione, przy czym decydujący będzie ten wymagający większej liczby podów.
Dobre praktyki
Wdrożenie HPA wiąże się z odpowiednią konfiguracją zarówno samego autoskalera, jak i aplikacji oraz zasobów klastra. Oto zalecane dobre praktyki przy korzystaniu z Horizontal Pod Autoscaler:
Zapewnij źródło metryk: Upewnij się, że w klastrze działa Metrics Server (dla CPU/memory) oraz ewentualnie adapter metryk niestandardowych (np. Prometheus Adapter) zanim utworzysz HPA korzystające z tych metryk. Brak dostępnych metryk to najczęstsza przyczyna nieskalowania się aplikacji przez HPA.
Ustaw
requestsdla zasobów: Każdy kontener powinien mieć zdefiniowaneresources.requests(przynajmniej dla CPU, a najlepiej i RAM). HPA oparty o procentowe wykorzystanie CPU lub pamięci bazuje na wartościach requestów do obliczania % użycia. Brak zdefiniowanych requestów utrudnia lub wręcz uniemożliwia działanie HPA w trybieUtilization(np. CPU utilization).Stosuj HPA do Deploymentów lub StatefulSetów: Podpinaj autoskaler do Deployment, StatefulSet zamiast bezpośrednio do ReplicaSet czy pojedynczych podów. Deployment zapewnia wyższy poziom abstrakcji i automatycznie zarządza ReplicaSetami podczas rolloutów, co upraszcza operacje skalowania i aktualizacji. HPA obsługuje również StatefulSet (skalowanie stateful), natomiast nie działa z DaemonSet (który z założenia ma stałą replikę na węzeł).
Unikaj ręcznego skalowania tych samych obiektów: Jeśli HPA zarządza skalą danego Deploymentu, nie modyfikuj ręcznie liczby replik tego Deploymentu (np. przez
kubectl scale). Może to wprowadzić konflikt – HPA będzie dążyć do swojej kalkulowanej wartości. Pozwól, aby to HPA automatycznie zarządzał wielkością repliki.Wybierz odpowiednie metryki i progi: Dobierz metrykę, która faktycznie odzwierciedla obciążenie usługi. Najczęściej startuje się od CPU (bo koreluje z obciążeniem procesora przez ruch) lub pamięci, ale w wielu przypadkach lepszym wskaźnikiem może być metryka aplikacyjna (np. liczba zapytań, wielkość kolejki). Ustal próg skalowania ostrożnie – zbyt niski próg spowoduje częste skalowanie (nadwrażliwość, możliwe przepłacanie za zasoby), za wysoki próg może skutkować opóźnioną reakcją na wzrost ruchu. Często zaleca się zaczynać konserwatywnie i ewentualnie dostroić wartości po obserwacji.
Monitoruj działanie HPA: Miej oko na to, jak HPA się zachowuje w praktyce. Użyj
kubectl describe hpa <nazwa>aby sprawdzić status HPA – zwłaszcza sekcję Conditions i Events. WarunekScalingActive=True/Falsepowie Ci czy HPA widzi poprawnie metryki (False oznacza problem, np. brak danych metryk). Z koleiScalingLimited=Truewskazuje, że osiągnięto limit min/max i HPA nie może skalować dalej.Wykorzystaj okna stabilizacji (stabilization window): Skonfiguruj w razie potrzeby parametry opóźnień skalowania, zwłaszcza dla skalowania w dół. Domyślnie Kubernetes posiada ~5 minutowy globalny bufor na skalowanie w dół, ale od wersji autoscaling/v2 można to dostroić w specyfikacji HPA (pola behavior, scaleDown, stabilizationWindowSeconds). Ustawienie okna stabilizacji zapobiega gwałtownym oscylacjom przy chwilowych spadkach metryki.
Nie łącz pochopnie HPA z VPA: Unikaj jednoczesnego stosowania Horizontal Pod Autoscaler i Vertical Pod Autoscaler na tej samej aplikacji (zwłaszcza jeśli oba miałyby reagować na CPU/memory). HPA skaluje poziomo dodając pody przy rosnącym wykorzystaniu, a VPA skaluje zasoby w pionie zmieniając requesty/limity. Działając razem mogą sobie przeszkadzać – np. VPA zwiększając request CPU może sprawić, że % użycia spadnie i HPA przestanie skalować, lub odwrotnie. Jeśli musisz użyć obu, zaleca się aby HPA bazował na custom metrykach, a nie CPU/memory wprost. W większości przypadków jednak lepiej zdecydować się na jedno podejście skalowania automatycznego, w zależności od charakterystyki aplikacji.
Integruj autoskalery klastrów: Zapewnij, by HPA działał w parze z mechanizmem autoskalowania węzłów (Cluster Autoscaler) na platformach on-demand. Więcej o tym w kolejnym rozdziale – generalnie jest to ważne, aby mieć możliwość dodania nowych węzłów, gdy HPA zwiększy liczbę podów ponad bieżącą pojemność klastra.
Typowe problemy i pułapki
Mimo poprawnej konfiguracji, z HPA można napotkać pewne częste problemy. Poniżej lista typowych zagadnień i wskazówki, jak je rozwiązać:
HPA nie skaluje – brak metryk: Jeśli po wdrożeniu HPA nie obserwujesz skalowania w górę mimo obciążenia, najpierw sprawdź, czy dostępne są metryki. Komenda kubectl get hpa pokazująca TARGETS jako unknown albo 0%/50% wskazuje, że HPA nie widzi danych (np. Metrics Server nie działa, adapter nie zwraca metryk). Upewnij się, że kubectl top pods działa (dla CPU/memory) oraz że adapter custom metrics zwraca metryki (dla niestandardowych). Brak metryk to najczęstsza przyczyna braku reakcji HPA.
Nieprawidłowe wartości TARGETS: Przy autoskalowaniu CPU często w kubectl get hpa widnieje np. TARGETS: 250%/50% co oznacza, że obciążenie znacznie przekracza próg, a HPA skaluje. Jeśli jednak zawsze widzisz 0%/50% (0 wykorzystania), nawet przy obciążeniu – możliwe, że kontenery nie mają ustawionych requestów CPU. Wtedy % jest liczony względem domyślnego request (który wynosi 0, co daje 0% użycia) lub metryka jest interpretowana jako 0. Rozwiązanie: ustawić sensowne resources.requests dla kontenerów, aby HPA miał punkt odniesienia.
Oscylacje liczby podów (flapping): Jeśli zauważasz, że HPA często dodaje po czym usuwa pody w krótkim czasie, może to oznaczać zbyt agresywne progi lub brak stabilizacji. Sprawdź, czy nie masz bardzo niskiej wartości stabilizationWindowSeconds albo czy metryka nie jest zbyt “szumowa”. Można zastosować także parametr –horizontal-pod-autoscaler-downscale-stabilization (globalnie) lub odpowiednie behavior w HPA, aby wydłużyć czas między skalowaniami w dół. Dla skalowania w górę istnieje też możliwość ograniczenia tempa (np. maksymalna liczba podów dodanych na minutę) poprzez pola behavior.scaleUp.limit itp.
Osiągnięto limit maxReplicas, a obciążenie rośnie: HPA przestaje skalować powyżej ustawionego spec.maxReplicas. Jeśli widzisz w opisach HPA warunek ScalingLimited = True z powodem DesiredWithinRange, oznacza to, że kalkulowana pożądana liczba podów przekroczyłaby maksymalną dozwoloną. Rozwiązaniem może być podniesienie maxReplicas (jeśli zasoby na to pozwalają) lub optymalizacja aplikacji, by radziła sobie z mniejszą liczbą podów. Podobnie, minReplicas ustawia dolne ograniczenie – HPA nie zredukuje podów poniżej tej wartości nawet przy zerowym ruchu.
Pod nie mieści się na węźle – brak zasobów: Zdarza się, że HPA zwiększy liczbę replik, ale nowe Pody pozostają w stanie Pending, bo klaster nie ma wolnych zasobów (CPU/RAM) na żadnym węźle. Sam HPA nie doda nowych maszyn – tutaj powinien wkroczyć Cluster Autoscaler (jeśli jest skonfigurowany). Jeśli nie używasz autoskalowania węzłów, osiągniesz fizyczny limit klastra. W logach HPA może nie być to bezpośrednio widoczne, ale zobaczysz Pending Pods. Rozwiązanie: wdrożyć Cluster Autoscaler lub ręcznie dodać węzły, ewentualnie ograniczyć maxReplicas do tego, co klaster udźwignie.
Niestabilna metryka niestandardowa: Przy korzystaniu z custom metrics, upewnij się że metryka istnieje i jest emitowana w miarę stabilnie. HPA zakłada, że co cykl otrzyma aktualne dane. Jeśli adapter nie zwróci metryki (np. Prometheus nie ma danych w ostatnim scrapie), HPA może to zinterpretować jako 0 i nie skalować. Przykładowy błąd: “unable to get metric … no metrics returned from custom metrics API”. Należy wtedy sprawdzić konfigurację Prometheus Adapter (czy metryka jest uwzględniona w regułach) i czy Prometheus ma aktualne dane. Czasem dodanie –metrics-relist-interval lub zmiana metricsMaxAge w adapterze pomaga, by metryki nie “znikały”.
HPA nie reaguje na obciążenie I/O, sieci etc.: Domyślnie HPA patrzy tylko na te metryki, które mu wskażemy. Jeśli używamy tylko CPU, a aplikacja np. dławi się na przepustowości sieci lub dysku, HPA tego nie wykryje – będzie uważał, że CPU jest ok i nic nie zrobi, mimo że realnie wydajność spada przez inne wąskie gardło. To ograniczenie – HPA nie monitoruje np. IOPS, czy bandwidth (chyba że skonfigurujemy custom metric, o ile taka jest). Dlatego do pełnego obrazu skalowania czasem trzeba wziąć pod uwagę więcej niż jeden wymiar metryk albo połączyć HPA z innymi mechanizmami (np. KEDA dla zdarzeń, jak długość kolejki, czy nawet ręczne interwencje gdy saturacja zasobów niewidocznych dla HPA nastąpi).
Współpraca z Cluster Autoscaler
Cluster Autoscaler (CA) to odrębny komponent Kubernetes odpowiadający za automatyczne dodawanie lub usuwanie węzłów (maszyn/instancji) w klastrze w zależności od zapotrzebowania. HPA i CA działają niezależnie, ale komplementarnie. HPA dba o skalowanie wewnątrz klastra (liczba podów), a Cluster Autoscaler o skalowanie samego klastra (liczba node’ów).
W praktyce, dla uzyskania autoskalowania w pełni elastycznego, zaleca się używać obu mechanizmów łącznie . Scenariusz jest następujący:
Gdy HPA zwiększa liczbę podów i brakuje miejsca na istniejących węzłach, nowe Pody pozostają w stanie Pending. Cluster Autoscaler wykrywa, że są nieschedulowalne Pody (co sprawdza co ~10 sekund) i automatycznie podejmuje próbę dodania nowego węzła do klastra, aby te Pody mogły zostać uruchomione. Po utworzeniu nowego node’a, Pody zostaną na nim rozplanowane i zaczną działać.
Jeśli obciążenie spada, HPA redukuje liczbę podów. Może się okazać, że niektóre węzły staną się puste (nie będą już mieć żadnych podów poza systemowymi). Wówczas Cluster Autoscaler po pewnym czasie może usunąć niepotrzebne węzły, zwalniając zasoby (np. wyłączając maszyny w chmurze). Dzięki temu oszczędzamy koszty, a klaster wraca do mniejszych rozmiarów.
Ważne jest, że HPA i CA nie komunikują się bezpośrednio ze sobą – każdy działa na innym poziomie. HPA obserwuje metryki podów i skaluje Deploymenty/StatefulSety, nie wiedząc nic o fizycznych maszynach. Z kolei Cluster Autoscaler obserwuje schedulowanie podów: jeśli widzi pod, który nie może zostać przypisany do żadnego węzła z powodu braku zasobów, to skaluje klaster w górę. Analogicznie, jeśli widzi węzeł od dłuższego czasu prawie pusty, usuwa go. Cytując odpowiedź na pytanie na Stack Overflow: “Cluster Autoscaler automatycznie dodaje lub usuwa węzły bazując na żądaniach zasobów od podów. W odróżnieniu od HPA, CA nie patrzy na wykorzystanie CPU czy pamięci, tylko reaguje na zdarzenia – sprawdza co 10s, czy istnieją nieschedulowalne pody”. Oznacza to, że jeśli nie użyjemy HPA (a tylko CA), to sam wzrost ruchu nie spowoduje dodania podów – cluster autoscaler zareaguje dopiero, gdy jakiś pod nie będzie miał gdzie się uruchomić. Dlatego HPA jest potrzebne, by zwiększyć liczbę podów przy rosnącym obciążeniu, a CA by zapewnić miejsce dla tych podów na nowych node’ach. W odwrotnej sytuacji, bez CA, HPA skaluje tylko do granic bieżących zasobów – jeśli klaster jest pełny, kolejne repliki pozostaną Pending i nie obsłużą ruchu, co mija się z celem autoskalowania.
Podsumowując, najlepsze efekty daje połączenie HPA + Cluster Autoscaler. HPA dba o to, aby aplikacja miała odpowiednią liczbę instancji do obsługi ruchu, a Cluster Autoscaler dba o to, żeby w klastrze było wystarczająco maszyn do uruchomienia tych instancji. Razem zapewniają automatyczne skalowanie na dwóch poziomach – aplikacyjnym (pody) i infrastrukturze (node’y) – co przekłada się na wysoką dostępność i efektywność kosztową środowiska. W kontekście chmury oznacza to, że podczas peaków automatycznie dostaniemy więcej maszyn i podów do obsługi użytkowników, a podczas ciszy obciążeniowej zbędne zasoby zostaną odłączone. Przy konfiguracji autoskalera klastra warto ustawić odpowiednie limity minimalnej i maksymalnej liczby węzłów, aby kontrolować koszty i zapewnić pewną bazową pojemność systemu.
Uwaga: Należy pamiętać, że usuwanie węzłów przez CA podlega ograniczeniom typu Pod Disruption Budget oraz pewnym regułom (np. nie usuwa węzłów z krytycznymi podami systemowymi). Warto zaplanować PDB dla aplikacji, aby autoskalowanie (zarówno HPA jak i CA) nie powodowało niedostępności usługi przez nagłe ubicie zbyt wielu podów naraz. Jednak to już temat na osobną dokumentację.