Po co monitorować wydajność w Kubernetes i kiedy to się opłaca
Typowe problemy wydajnościowe w klastrach Kubernetes
Środowisko Kubernetes potrafi ukryć problemy wydajnościowe pod warstwą automatyzacji. Aplikacja „działa”, pody się restartują, HPA coś tam skaluje, ale użytkownicy widzą coraz większe opóźnienia lub błędy. Bez sensownego monitoringu łatwo przepalić zasoby i czas na zgadywanie.
Najczęściej spotykane problemy wydajnościowe w klastrach Kubernetes to:
- CPU throttling – kontener ma ustawiony za niski CPU limit, scheduler przydziela go na node, ale kubelet i cgroup duszą procesy. Metryki pokazują niskie zużycie CPU, a aplikacja reaguje wolno, bo jest dławiona.
- Out-Of-Memory (OOMKill) – brak monitoringu pamięci na poziomie poda kończy się nagłymi ubiciami procesów przez kernel. Użytkownik widzi 500, a ty w logach tylko restart kontenera.
- Przeciążone nody – node ma „na papierze” wolne CPU, ale storage lub sieć są na granicy. Pody migrują, restartują się lub w ogóle nie mogą się zschedule’ować.
- Problemy sieciowe – interfejsy CNI, kube-proxy, błędna konfiguracja polityk sieciowych, limit na connection tracking. Aplikacja wydaje się ciężka, a problem leży w sieci.
- Wolny lub niestabilny storage – wolumeny z wysokim opóźnieniem, niskim IOPS lub sporadycznymi time-outami. Dla API wygląda to jak „czasami muli”, a bez metryk storage ciężko to udowodnić.
Monitoring wydajności w Kubernetes jest tak naprawdę sposobem na wczesne wykrywanie tych problemów i szybkie znalezienie winowajcy, bez przekopywania się przez logi z kilku usług naraz.
Koszt braku monitoringu vs koszt narzędzi
Sprzęt, instancje chmurowe i narzędzia monitoringowe kosztują, ale brak monitoringu bywa dużo droższy. Trzy punkty, które mocno czuć w portfelu:
- Przewymiarowane klastry – bez metryk zespoły „dla bezpieczeństwa” dodają nody i podnoszą limity. Nagle rachunek za chmurę rośnie kilkukrotnie, a realna potrzebna moc była o połowę mniejsza.
- Dłuższe awarie i SLA – gdy coś padnie, zespół bez metryk skacze po logach, podejrzewa DNS, bazę, GC, wszystko naraz. Każda godzina dłuższej awarii to realna strata: zwroty, reklamacje, utrata reputacji.
- Chaos w decyzjach technicznych – bez twardych danych trudno podjąć decyzję: optymalizować kod, zmieniać bazę, podnieść zasoby czy przenieść usługę. Zwykle kończy się drogim refactoringiem „na wszelki wypadek”.
Monitoring, nawet w budżetowej wersji, umożliwia policzenie opłacalności zmian. Zamiast „kupmy większe nody”, można powiedzieć „zwiększmy requesty CPU o 20% i dodajmy HPA na konkretnej metryce, bo wykresy pokazują saturację CPU w godzinach szczytu”.
Kiedy wystarczy kubectl top, a kiedy potrzebny jest pełny stack observability
Nie każde środowisko wymaga od razu Prometheusa, Grafany i całego zestawu exporterów. Im prostszy system, tym bardziej można polegać na narzędziach wbudowanych:
- kubectl top – szybki podgląd zużycia CPU i pamięci na nodach i podach. Wystarczy, gdy:
- masz mały klaster dev/test,
- liczba podów jest ograniczona,
- nie potrzebujesz historycznych danych, tylko „tu i teraz”.
- kubectl describe i kubectl logs – podstawowe narzędzia do diagnozy pojedynczych incydentów: OOM, crash loop, problemy z readiness/liveness.
Pełniejszy stack observability (Prometheus, Grafana, alerty) zaczyna się opłacać, gdy:
- usług jest kilka–kilkanaście i przestajesz ogarniać obserwację „na żywo”,
- masz wymagania SLA/uptime dla klientów,
- koszt godziny awarii jest większy niż koszt utrzymania prostego systemu metryk,
- chcesz realnie optymalizować zużycie zasobów i koszty klastra.
Prosty test: jeśli kiedykolwiek ktoś zadał pytanie „co działo się z klastrem godzinę temu, jak było to spowolnienie?” i nie miałeś odpowiedzi, to znaczy, że sam kubectl top to za mało.
Mały klaster dev vs produkcja z SLA
Przykładowe dwa scenariusze:
Mały klaster dev/stage:
- parę usług, brak wymagań SLA, budżet ściśnięty,
- wystarcza metrics-server, kubectl top, proste dashboardy (np. Lens lub narzędzie z GUI),
- czasem lekki Prometheus z krótkim retention (np. 1–3 dni), bez zaawansowanych alertów.
Produkcja z SLA:
- kilkanaście+ usług, klienci płacą za dostępność,
- potrzeba historii metryk (co najmniej 7–30 dni) i korelacji z deployami,
- minimalny zestaw: Prometheus, Grafana, kube-state-metrics, node-exporter, alerty na metrykach CPU/memory, availability.
W produkcji bardziej kosztowne jest zgadywanie bez danych niż utrzymanie sensownego monitoringu, nawet w wersji „budżetowej” z krótkim retention i gotowymi dashboardami.
Kluczowe wymiary wydajności w Kubernetes: klaster, node, pod, aplikacja
Warstwy obserwacji: od infrastruktury po kod
Monitoring w Kubernetes trzeba układać warstwowo. Inaczej łatwo leczyć objawy zamiast przyczyny. Sensowne rozbicie to:
- Infrastruktura – nody (VM/metal), sieć, storage. Tu pojawiają się problemy z CPU hosta, pamięcią, dyskami, I/O, interfejsami sieciowymi.
- Platforma Kubernetes – control plane (API server, scheduler, controller-manager), kubelet, kube-proxy, CNI, CSI. Gdy te komponenty są przeciążone lub w złym stanie, cierpi cały klaster.
- Workloady – Deploymenty, StatefulSety, DaemonSety, CronJoby. Na tym poziomie patrzysz na liczbę replik, restarty, status condition, problemy z rolloutem.
- Aplikacja – logika biznesowa, frameworki, bazy, cache, wewnętrzne kolejki. Tu monitorujesz metryki typu QPS, latency, błędy, GC, pool’e połączeń.
Dopiero łącząc metryki z tych warstw, można powiedzieć, czy problem to „za mały node”, „zły limit CPU na podzie”, czy np. „błąd logiki w aplikacji i memory leak”. Sam poziom podów rzadko wystarcza.
Najczęstsze wąskie gardła: CPU, pamięć, IO, sieć, limity/requesty
W Kubernetes wąskie gardła zwykle kręcą się wokół kilku rodzajów zasobów:
- CPU – zbyt niskie requests powodują, że HPA nie skaluje, zbyt niskie limits powodują throttling. Bez metryk trudno zdecydować, czy zwiększać replikę, czy zmienić limity.
- Pamięć – aplikacje bez limitów potrafią wysycić node. Z kolei za ciasne limity kończą się OOMKill. Monitorowanie realnego zużycia i trendów to podstawa przy ustawianiu requests i limits.
- IO / storage – opóźnienia w bazie, wolne PV-ki, problem z IOPS. Z perspektywy aplikacji wygląda to na „CPU high, requesty wolne”, ale to storage nie wyrabia.
- Sieć – saturacja interfejsu, drops, wysokie opóźnienia na ścieżkach między usługami. Bez prostych metryk sieciowych diagnoza trwa godzinami.
- Limity i requesty – nieprawidłowe dobranie requests/limits jest jednym z głównych powodów złej wydajności i przepalonych kosztów. Monitoring pokazuje, które pody są notorycznie niedoszacowane lub przewymiarowane.
Na początku wystarczy patrzeć na te zasoby globalnie. Potem zawęża się obraz do problematycznych namespace’ów, usług, wreszcie konkretnych podów.
Dlaczego nie da się diagnozować tylko z poziomu podów
Patrzenie wyłącznie na metryki podów prowadzi do mylnych wniosków. Przykład z praktyki: pody serwisu API mają „normalne” użycie CPU i pamięci, a czas odpowiedzi rośnie wieczorami. Na poziomie podów wszystko wygląda stabilnie.
Po spojrzeniu na metryki nodów okazuje się, że:
- na tych samych nodach są inne pody intensywnie korzystające z dysku,
- storage ma wysokie opóźnienia,
- kolejka I/O rośnie, a aplikacja czeka na odczyt/zapis.
Bez metryk infrastruktury doszłoby się do wniosku, że „API trzeba skalować w poziomie” albo „optimizować kod”. Tańsze i skuteczniejsze rozwiązanie może polegać na zmianie typu dysku lub rozłożeniu podów między nody z innym storage.
Z drugiej strony, patrząc tylko na nody, da się przegapić memory leak w konkretnej usłudze – node ma jeszcze RAM, ale jeden pod w namespace „prod-payments” rośnie w pamięci liniowo.
Które poziomy monitorować w małym i dużym klastrze
Żeby nie przedobrzyć, warto etapować zakres monitoringu:
Mały klaster (dev / mała produkcja):
- poziom node: CPU, pamięć, dysk, sieć (prosty node-exporter),
- poziom pod: CPU usage, memory, restarty, limity vs użycie (kube-state-metrics + metryki z kubelet),
- poziom aplikacja: podstawowe metryki RED (requests, errors, latency) dla kluczowych usług.
Większy klaster (produkcyjny, wiele zespołów):
- dokładniejsze metryki infra (np. storage: latency, IOPS; sieć: packet drops, opóźnienia między usługami),
- metryki komponentów control plane (API server, scheduler, etcd),
- metryki aplikacyjne rozszerzone (percentyle latency, liczniki biznesowe),
- ewentualnie dodatkowe narzędzia: tracing, profilowanie CPU/pamięci w krytycznych usługach.
Rozszerzanie zakresu metryk trzeba robić świadomie, bo każda kolejna sonda i exporter to dodatkowy koszt CPU, pamięci i storage metryk. Dla wielu zespołów sensowny jest model „najpierw prosty monitoring całego klastra, później pogłębianie dla kilku krytycznych usług”.

Podstawowe metryki klastra, nodów i podów – co faktycznie śledzić
Metryki klastra: ogólny stan i pojemność
Na poziomie klastra celem jest odpowiedź na pytania: „Czy mamy jeszcze zapas mocy?” oraz „Czy control plane działa stabilnie?”. Przydatne są zwłaszcza:
- Zagregowane zużycie CPU i pamięci – sumaryczne usage vs capacity. Wykres pokazujący, czy zbliżasz się do limitów nodów i kiedy pojawiają się szczyty.
- Liczba podów – ogólnie i per node/namespace. Daje pojęcie, czy scheduler ma wolne miejsce oraz czy nie ma runaway jobów.
- Allocatable vs używane zasoby – ile CPU/memory klaster może realnie przydzielić podom (po odliczeniu systemowych daemonów) i ile jest już wykorzystane.
- Stan komponentów control plane – API server (czas odpowiedzi, liczbę requestów, błędy), scheduler (opóźnienia schedule’owania), etcd (latencja, rozmiar bazy).
Klaster bez obserwacji tych metryk wygląda na „zielony” aż do momentu, gdy scheduler przestaje znajdować miejsce na nowe pody, a API server zaczyna odrzucać requesty. Historia zużycia pozwala zaplanować skalowanie klastra zanim zrobi to za ciebie awaria.
Metryki nodów: CPU, pamięć, pressure i dyski
Na node warto patrzeć jak na ograniczony kubelem zasobów serwer. Podstawowy zestaw:
- CPU
- użycie CPU (user/system) – pozwala rozpoznać, czy node jest realnie zajęty,
- load average – ogólne obciążenie wątki/zadania vs liczba rdzeni.
- Pamięć
- użyta pamięć vs total/allocatable,
- memory pressure (node_condition),
- page cache vs RSS – gdy storage jest wolny, system buforuje, co wpływa na pamięć.
- Pressure (CPU/memory)
- Node CPU pressure – sygnał, że scheduler ma problemy z przydzielaniem podów,
- Node memory pressure – zbliżają się OOM-y na node’ach.
IO i storage na nodzie: sygnały zbliżającej się katastrofy
Storage zabija wydajność po cichu, a objawy pojawiają się dopiero na poziomie aplikacji. Zanim requesty zaczną się ślimaczyć, metryki nodów zwykle już krzyczą:
- IOPS i throughput – liczba operacji I/O oraz MB/s dla dysków/PV. Spadek IOPS przy rosnącym latency to klasyczny znak, że wolumen jest na granicy.
- Latency dysku – opóźnienia odczytu/zapisu. Kilkukrotny wzrost względem „normalnego” poziomu powinien włączać lampkę ostrzegawczą.
- Queue depth – długość kolejki I/O. Rosnąca kolejka przy stałym IOPS oznacza, że host nie nadąża z obsługą operacji.
- Wolne miejsce – dysk na nodzie oraz PV-ki. Gdy fs zaczyna się zapełniać, rośnie fragmentacja, a backupy i logrotate potrafią dodatkowo zamulić system.
Tani trik: nawet prosty node-exporter + gotowy dashboard „Node Exporter Full” w Grafanie daje wystarczający wgląd w dysk. Nie ma sensu od razu budować skomplikowanego storage monitoringu – najpierw złap podstawowe opóźnienia i zajętość.
Metryki podów: usage, limity i realne zachowanie
Na poziomie podów interesuje, czy kontenery działają „w granicach kontraktu” określonego przez requests i limits oraz jak często Kubernetes musi interweniować. Podstawowy zbiór:
- CPU usage vs requests/limits
- średnie i piki zużycia CPU,
- czas spędzany w throttlingu (np.
container_cpu_cfs_throttled_seconds_total).
- Memory usage vs requests/limits
- zużycie pamięci RSS per kontener,
- przyrost pamięci w czasie – wykrywanie memory leaków,
- liczba OOMKill (
kube_pod_container_status_last_terminated_reason= OOMKilled).
- Restarty kontenerów – skokowy wzrost restartów w krótkim czasie to często sygnał problemu z zależnością (baza, kolejka) lub regresją w nowej wersji.
- Stan podów – Pending, CrashLoopBackOff, ImagePullBackOff, Unschedulable. Te wartości same w sobie są alertem na poziomie SRE/DevOps.
Prosty, tani w utrzymaniu schemat: dla każdego krytycznego deploymentu skonfigurować dwa alerty – „pody nie w stanie Ready > X minut” i „restarty kontenerów > Y w ciągu Z minut”. Resztę dogląda się w dashboardach, gdy coś zaczyna się dziać.
Metryki sieciowe: natężenie, błędy, podziały per namespace
Sieć często jest wspólnym mianownikiem „dziwnych” problemów: raz jest wolno, raz szybko, część requestów time-outuje, ale CPU i pamięć wyglądają dobrze. Kilka kluczowych metryk:
- Przepływ (throughput) – liczba bajtów wysłanych/odebranych per node/pod/namespace. Ujawnia, które usługi zasysają najwięcej pasma.
- Pakiety i błędy – dropped, retransmissions. Nagły wzrost błędów bywa skorelowany z aktualizacją CNI lub zmianą security group.
- Połączenia – liczba aktywnych połączeń TCP (per pod lub per node), zwłaszcza dla bramek ingress, serwisów API i baz danych.
Na początek wystarczy widok „sieć per node + top namespaces”. Dopiero gdy pojawią się realne problemy, jest sens rozbijać to na poszczególne pody czy serwisy sidecar.
Zdrowie workloadów: Deploymenty, StatefulSety i Joby
Sam CPU i RAM nie pokażą, czy roll-outy przechodzą poprawnie, a zadania batchowe domykają się na czas. Metryki z kube-state-metrics pozwalają reagować wcześniej niż klienci:
- Deploymenty
- liczba replik desired vs available,
- czas trwania rolloutów (różnica między updateRevision a readyReplicas),
- częstotliwość zmian (czy nie ma „flappingu” spowodowanego autoscalerem).
- StatefulSety
- gotowość wszystkich replik (ważne przy bazach i kolejkach),
- czas konwergencji po restarcie noda.
- Joby / CronJoby
- liczba udanych vs nieudanych wykonań,
- czas wykonania (czy window czasowy nadal wystarcza),
- czy joby nie kumulują się przy wolniejszym storage.
To nadal względnie tanie metryki, a pozwalają szybko zdiagnozować problemy z rolloutem albo przesuwanie się okien przetwarzania wsadowego.
Minimalny, budżetowy stack monitoringu w Kubernetes – co wystarczy na start
Cel: sensowne metryki bez osobnego zespołu SRE
Da się mieć działający monitoring klastra i aplikacji bez kosztownego, rozbudowanego stosu i bez poświęcania tygodni na rzeźbienie konfiguracji. Minimalny, ale praktyczny zestaw:
- Prometheus – zbieranie metryk z klastra i aplikacji, krótki retention (np. 7–15 dni),
- Grafana – wizualizacja i pierwsze alerty,
- node-exporter – metryki nodów,
- kube-state-metrics – stan obiektów Kubernetes,
- metrics-server – wystarcza dla HPA i prostych odczytów usage.
To daje ogólny obraz zdrowia klastra, bazowe alerty i możliwość korelacji deployów z zachowaniem podów. Koszt: kilka niedużych podów w systemowym namespace, trochę storage na metryki i odrobina czasu na pierwsze dashboardy.
Instalacja Prometheusa i Grafany: Helm zamiast własnych YAML-i
Ręczne pisanie manifestów dla Prometheusa szybko zamienia się w utrapienie. Szybsza droga:
- użyć kube-prometheus-stack (dawniej prometheus-operator) jako podstawy,
- na początek zostawić większość wartości domyślnych, modyfikując głównie:
- czas retencji (np.
7d), - limit pamięci Prometheusa (żeby nie ubił noda),
- storage (np. mały PVC klasy standard).
- czas retencji (np.
Dla mniejszych środowisk sensownie jest zacząć od jednego Prometheusa z lokalnym storage. Gdy pojawią się problemy z pojemnością lub HA, dopiero wtedy jest powód, żeby myśleć o federacji lub zewnętrznej bazie metryk.
Krótka retencja metryk: kiedy to „wystarczająco dobrze”
Wielu zespołom wystarczy historia 7–14 dni. To pozwala:
- porównać ruch i obciążenie między tygodniami,
- zobaczyć skutki ostatnich kilku deployów,
- analizować ostatnie incydenty bez inwestowania w duże dyski.
Jeżeli w organizacji nikt realnie nie wraca do metryk sprzed miesiąca, dokupienie storage pod rok historii to wyrzucanie pieniędzy. Lepiej włożyć je w sensowny alerting i kilka dobrych dashboardów.
Gotowe dashboardy zamiast ręcznego klikania
Grafana ma cały ekosystem gotowych dashboardów. Na start wystarczy:
- kube-prometheus-stack / Kubernetes / Compute Resources – użycie CPU i pamięci na poziomie podów/nodów,
- Node Exporter Full – szczegóły nodów: CPU, RAM, dysk, sieć,
- Kubernetes / Networking – podstawowe metryki sieciowe.
Zamiast projektować „idealny dashboard” przez kilka dni, lepiej wziąć gotowy i dopasować go do własnych potrzeb. Realny zysk przychodzi z alertów i świadomości, gdzie szukać problemu, a nie z perfekcyjnej estetyki wykresów.
Minimalny alerting: kilka reguł, które robią różnicę
Alerting łatwo przegiąć – kilkadziesiąt reguł i po tygodniu nikt nie reaguje. Rozsądny, minimalny zestaw:
- API server niedostępny lub wysokie latency – bez tego nie działa nic,
- Node NotReady / cordoned bez planu – sygnał, że pojemność klastra się kurczy,
- CPU i pamięć na node > 90% przez X minut – ostrzeżenie przed realnym brakiem zasobów,
- Pody w CrashLoopBackOff > 0 w kluczowych namespace’ach,
- Restarty kontenerów w kluczowych deploymentach > N w krótkim czasie.
Dopiero gdy ten zestaw działa bez generowania „szumu”, można dodawać kolejne, bardziej szczegółowe reguły – np. osobne alerty dla storage czy konkretnych usług.

Prometheus w Kubernetes – praktyczne wzorce wdrożenia i konfiguracji
Model „pull” i ServiceMonitor: nie łatać endpointów ręcznie
Prometheus najlepiej współpracuje z Kubernetes przez prometheus-operator i CRD typu ServiceMonitor oraz PodMonitor. Zamiast ręcznie dopisywać endpointy w configu Prometheusa:
- tworzy się serwis z odpowiednimi labelami,
- definiuje
ServiceMonitor, który mówi „zbieraj metryki z usług o labelu X w port Y”, - operator sam aktualizuje konfigurację Prometheusa.
To oszczędza czas przy każdym nowym komponencie. Zespół aplikacyjny dodaje eksporter/metryki i odpowiedni serwis, a resztą zajmuje się mechanizm discovery.
Relabeling i filtrowanie: mniej śmieci, tańszy storage
Domyślna konfiguracja Prometheusa z kube-prometheus-stack-em zbiera masę metryk, z których spora część nigdy nie będzie użyta. Kilka praktycznych trików:
- wyłączenie niepotrzebnych jobów scrape (np. eksperymentalnych exporterów),
- filtrowanie metryk po nazwie (drop całych rodzin, których się nie używa),
- usuwanie bardzo szczegółowych labeli, które eksplodują krotność serii (np. pełne ścieżki URL zamiast sensownie zgrupowanych patternów).
To bezpośrednio zmniejsza zużycie pamięci przez Prometheusa i ilość danych na dysku. Różnica między „zbieramy wszystko” a „zbieramy to, czego realnie używamy” jest zwykle kilkukrotna.
Sharding i federacja: kiedy jeden Prometheus to za mało
Dla większości małych i średnich klastrów jeden Prometheus z lokalnym PVC wystarcza. Sygnały, że zbliża się granica:
- Prometheus zużywa absurdalne ilości RAM (dziesiątki GB),
- czas odpowiedzi na zapytania w Grafanie znacząco rośnie,
- restart Prometheusa trwa długo przez odtwarzanie indeksów.
Wtedy można rozważyć:
- shardowanie Prometheusa (np. rozdzielenie scrape’owania na kilka instancji),
- federację – jeden Prometheus „agregujący” dane w wyższym poziomie (sumy, zagregowane metryki) z kilku klastrów.
To jednak kolejny skok złożoności. Z perspektywy budżetu lepiej najpierw ograniczyć liczbę serii (filtrowanie metryk) i skrócić retencję, zanim wchodzi się w architektury z kilkoma poziomami Prometheusa.
Bezpieczeństwo: kto może czytać i eksponować metryki
Metryki potrafią zdradzić dane wrażliwe: nazwy baz, identyfikatory tenantów, fragmenty URL. Minimalny zestaw praktyk:
- ograniczenie dostępu do UI Prometheusa i Grafany (np. tylko przez VPN lub wewnętrzny SSO),
- segregacja dashboardów per zespół/namespace,
- przegląd metryk aplikacyjnych pod kątem wylewania danych osobowych w labelach.
To kosztuje niewiele – zwykle kilka reguł Ingress/NetworkPolicy i rozsądne role w Grafanie – a oszczędza stres przy audytach bezpieczeństwa.
Grafana i praktyczne dashboardy: od ogólnego zdrowia klastra po detale podów
Dashboard „zdrowie klastra”: 30 sekund, żeby stwierdzić, czy jest pożar
Jedno miejsce, w którym widać, czy klaster jest przytomny, to ogromna oszczędność czasu przy incydentach. Taki dashboard zwykle zawiera:
- liczbę nodów Ready/NotReady,
- zagregowane CPU i RAM usage vs capacity,
- liczbę podów Pending/CrashLoopBackOff,
- podstawowe metryki API servera (latency, błędy),
- liczbę alertów aktywnych wg poziomu (warning/critical).
Gdy coś się dzieje, ten widok jest pierwszym krokiem. Dopiero potem przechodzi się do detalicznych dashboardów per node/namespace/usługa.
Dashboard per namespace i per usługa
Przykładowy dashboard dla pojedynczego namespace
Dobry widok „per namespace” pozwala szybko zobaczyć, czy konkretny kawałek systemu ma problem z pojemnością albo stabilnością. Taki dashboard może zawierać:
- sumaryczne użycie CPU i RAM dla namespace vs zdefiniowane limity,
- liczbę podów według stanu (Running, Pending, CrashLoopBackOff),
- najbardziej „gorące” deploymenty (CPU, RAM, restarty),
- liczbę requestów HTTP i błędów 5xx/4xx z usług w namespace (jeśli są metryki aplikacyjne),
- historię rolloutów (np. na podstawie labeli
versionlubgit_sha).
Filtr po namespace na górze dashboardu rozwiązuje pół problemu. Drugą połowę stanowi sensowne grupowanie wykresów: najpierw agregaty, potem drill-down. Dzięki temu w ciągu minuty da się stwierdzić, czy problem wynika z braku zasobów, z błędu aplikacji, czy z instabilnego storage.
Dashboard per usługę: tylko to, co faktycznie pomaga w debugowaniu
Widok per usługę nie musi być piękny. Ma odpowiadać na proste pytanie: „czy ten serwis zachowuje się normalnie?”. W praktyce wystarcza:
- przepływ requestów (RPS/QPS) + błędy 5xx / 4xx,
- latencja (p50/p90/p99) dla głównych endpointów lub zgrupowanych pathów,
- CPU i RAM podów tego serwisu + ewentualne limity,
- liczba replik vs
HPA desired(jeśli jest autoscaling), - restarty kontenerów w czasie.
Przykład z życia: incydent „wieczorne lagi” w jednej usłudze. Dashboard per usługę pokazuje, że latencja rośnie wraz z RPS, ale CPU na podach jest daleko od 100%, za to widać dropy połączeń do bazy. Zamiast kręcić gałkami HPA, właściciel usługi od razu idzie w kierunku połączeń DB i indeksów.
Szablony i foldery w Grafanie: porządek zamiast jednego mega-dashboardu
Szybko robi się chaos: dashboard dla klastra, dla nodów, dla każdego serwisu. Zamiast klikać wszystko ręcznie:
- trzymać dashboardy w Git (JSON-y w repo) i wdrażać je automatycznie (prosty
ConfigMaplub provisioning Grafany), - utworzyć foldery: Platforma (klaster, nody, sieć), Aplikacje (per namespace/serwis), Eksperymentalne,
- zrobić 1–2 szablony per kategoria aplikacji (np. API HTTP, worker kolejki) zamiast osobnego dashboardu dla każdej usługi.
To pozwala nowym usługom „podpiąć się” pod gotowe widoki za pomocą samych labeli i zmiennych w Grafanie. Efekt: mniej klikania, bardziej przewidywalne ścieżki diagnozy.

Metryki aplikacyjne (RED/USE) i integracja z Kubernetes
RED i USE – prosty filtr na „przydatne vs zbędne” metryki
Zamiast generować dziesiątki losowych metryk aplikacyjnych, da się podeprzeć dwoma sprawdzonymi modelami:
- RED (Rate, Errors, Duration) dla usług sieciowych:
- Rate – liczba requestów na sekundę,
- Errors – odsetek lub liczba błędów (zwykle 5xx),
- Duration – czas odpowiedzi (p95/p99).
- USE (Utilization, Saturation, Errors) dla zasobów:
- Utilization – procent użycia (np. CPU, dysk),
- Saturation – kolejki, backlog (np. długość kolejki w workerze),
- Errors – porażki operacji (np. nieudane joby).
Ten prosty filtr od razu zabija pomysł „mierzmy wszystko na wszelki wypadek”. Skupiając się na kilku kluczowych wskaźnikach, ogranicza się liczbę serii w Prometheusie, a jednocześnie ma się materiał do sensownych alertów.
Jak eksponować metryki aplikacyjne w Kubernetes bez wymyślania koła
Najprostsza droga do metryk aplikacyjnych w klastrze:
- Użyć gotowej biblioteki klienta Prometheusa dla danego języka (Go, Java, Python, .NET itd.).
- Wystawić endpoint
/metricsw serwisie HTTP (albo dedykowany port). - Dodać do
Serviceodpowiednie labele (np.prometheus.io/scrape: "true"lub te wymagane przezServiceMonitor). - Stworzyć
ServiceMonitorw namespace aplikacji, w którym zdefiniowany jest job scrape.
Po tej konfiguracji metryki aplikacyjne pojawiają się w Prometheusie tak samo, jak te klastra. Dalsza praca odbywa się w Grafanie i regułach alertingowych.
Standaryzacja metryk HTTP: mniej labeli, mniej bólu
Metryki HTTP potrafią szybko rozsadzić liczbę serii, jeśli wrzuca się pełne ścieżki i identyfikatory w labelach. Kilka prostych zasad:
- zamiast
path="/user/12345/orders/6789"używać zgrubnych patternów, np.path="/user/{id}/orders/{orderId}", - nie wsadzać do labeli informacji o tenantach, ID użytkowników, numerach biletów – jeśli już, to do body logów, nie do metryk,
- ograniczyć liczbę labeli do kilku, które naprawdę są używane w zapytaniach (np.
path,method,status).
Prosta normalizacja ścieżek często zmniejsza liczbę serii razy kilka. To bezpośrednia oszczędność RAM i dysku po stronie Prometheusa.
Alerty na metrykach RED: proste, ale skuteczne
Na metrykach RED da się zbudować podstawowe alerty SLO bez finezyjnych systemów typu SLO-as-a-service. Minimalne reguły:
- „zwiększa się odsetek 5xx” – np. procent 5xx > określony próg przez kilka minut,
- „latencja p95 wyższa niż X ms” – dla kluczowych endpointów lub całego serwisu,
- „brak ruchu” – gdy RPS spada do zera w godzinach, w których ruch normalnie jest.
Na początek wystarczy, że alert informuje „ten serwis zachowuje się inaczej niż zwykle”. Z czasem można dorzucić bardziej wyrafinowane wzory czy integrację z SLO, ale to już wyższy poziom dojrzałości.
Integracja z HPA: metryki aplikacyjne zamiast samego CPU
Horizontal Pod Autoscaler domyślnie reaguje na CPU/Memory. Często bardziej opłaca się skalować po metrykach biznesowych lub RED:
- RPS na pod – utrzymanie mniej więcej stałego obciążenia pojedynczego poda,
- długość kolejki zadań (np. w Kafka/Redis/RabbitMQ),
- czas obsługi (np. średnia latencja jednego joba).
W praktyce wygląda to tak:
- Eksport metryki aplikacyjnej do Prometheusa (np.
http_requests_totalalboqueue_length). - Definicja dodatkowej metryki dla HPA przez Prometheus Adapter (API
custom.metrics.k8s.iolubexternal.metrics.k8s.io). - Skonfigurowanie HPA, który używa tej metryki jako targetu.
To krok, który wymaga trochę więcej pracy niż standardowy HPA, ale za to skraca okresy przeciążenia i pozwala lepiej dopasować zasoby do realnego ruchu.
Profilowanie podów i usług: CPU, pamięć, latency – techniki niskim kosztem
Od metryk do profilowania: kiedy zwykłe „CPU high” nie wystarcza
Metryki mówią „co” się dzieje, ale nie „dlaczego”. Gdy pod zużywa dwa razy więcej CPU niż miesiąc temu, a requesty działają wolniej, przychodzi czas na profilowanie. W Kubernetes można to zrobić bez specjalnych platform obserwowalności – wystarczą proste techniki:
- tymczasowe włączenie profilera w aplikacji (jeśli język to wspiera),
- użycie narzędzi z zewnątrz (np.
kubectl exec+ narzędzia systemowe), - przepięcie części ruchu na specjalnie profilowany pod.
Celem nie jest stałe, ciągłe profilowanie wszystkiego, tylko krótkie, celowane sesje na czas analizy problemu.
Profilowanie CPU w Go, Java, .NET – podejście „on demand”
W wielu językach produkcyjne profilowanie CPU jest dość tanie, o ile nie włącza się go na stałe. Przykładowo:
- Go – standardowy
net/http/pproflub wbudowany w framework, wystawiony na osobnym porcie lub za feature flagą, - Java –
async-profiler, Java Flight Recorder, ewentualnie lekkie samplingowe profilery dostępne z zewnątrz (bez modyfikacji kodu), - .NET –
dotnet-trace,dotnet-counterslub podobne narzędzia CLI, uruchamiane przezkubectl exec.
Prosty workflow:
- Zreprodukować problem (albo poczekać na jego wystąpienie w godzinach szczytu).
- Odblokować endpoint/port profilerowy w jednym podzie (np. przez
kubectl port-forward). - Włączyć krótką sesję profilowania (kilkadziesiąt sekund – parę minut) i ściągnąć profil lokalnie.
- Przeanalizować flamegrapha lub raport i wyciągnąć wnioski (np. gorące funkcje, locki, intensywne alokacje).
Taki tryb „on demand” nie zwiększa trwale kosztów, a daje realne odpowiedzi na pytania w stylu „który fragment kodu je 50% CPU?”.
Profilowanie pamięci: uniknięcie OOM zanim pody zaczną się restartować
Gdy pody zabija OOM killer lub widać stały dryf użycia pamięci po deployu, samo patrzenie na wykres „RAM podów” nic nie da. Z pomocą przychodzą:
- heap profile w Go/Java/.NET – podobnie jak CPU, często dostępne z tych samych bibliotek,
- proste narzędzia systemowe:
top,htop,ps,smem, jeśli podejrzany jest konkretny proces lub wątek, - obserwacja GC (time spent in GC, częstotliwość) – np. przez metryki Javy lub .NET.
Częsty, tani w naprawie przypadek: leak w cache lub brak limitu rozmiaru wewnętrznej kolejki. Profil pamięci jasno pokaże obiekt, który zjada większość RAM-u. Naprawa to kilka linijek kodu, a bez profilowania często miesiące zgadywania.
Latency na poziomie podów i call tree usług
Gdy rośnie czas odpowiedzi, problem może siedzieć zarówno w kodzie, jak i poza nim (sieć, baza, inne zależności). Niedrogi sposób podejścia do tematu:
- metryki histogramowe dla czasu odpowiedzi HTTP lub operacji (Prometheus
Histogram/Summary), - prosty tracing samplingowy (np. OpenTelemetry z bardzo niskim sampling rate),
- korelacja latencji z metrykami zasobów (CPU, IO, połączenia do bazy).
Tracing w trybie „tani, samplingowy” daje poglądowy call tree między usługami przy niewielkim koszcie. Nie musi to być od razu pełna platforma APM z ceną jak z katalogu luksusowego SaaS – wystarczy backend oparty na Jaegerze lub Tempo i kilka prostych dashboardów.
Profilowanie „z zewnątrz”: narzędzia wstrzykiwane do poda
Gdy aplikacja nie ma wbudowanego profilera albo dodanie go wymagałoby ingerencji w kod, można podejść od drugiej strony:
- użyć ephemeral containers w Kubernetes do wstrzyknięcia narzędzi diagnostycznych do już działającego poda,
- podłączyć się przez
kubectl execi używać standardowych narzędzi systemowych (strace, perf, iostat), - korzystać z eBPF-owych narzędzi (np. BCC, bpftrace) na nodzie, jeśli ma się dostęp i nie boi się odrobiny złożoności.
To wymaga więcej wiedzy systemowej, ale nie generuje stałych kosztów. Nadaje się szczególnie dla produkcyjnych incydentów, gdy nie ma czasu na przebudowę obrazów aplikacji.
Izolowanie problemów do pojedynczych podów
Profilowanie najlepiej robić na jednym, wybranym podzie, a nie na całym deploymentcie. W praktyce:
- sklonowanie deploymentu do osobnej instancji (np.
my-service-profiler) z tym samym obrazem, ale mniejszą liczbą replik, - przepięcie kawałka ruchu (np. 1% przez Ingress/Service mesh) na profilowany deployment,
- masz kilka usług bez twardych wymagań SLA,
- interesuje Cię głównie „tu i teraz”,
- problemy wydajnościowe nie oznaczają realnej straty pieniędzy.
- CPU throttling – za niskie limity CPU, kontener jest dławiony i reaguje wolno, mimo że metryki „użycia CPU” wyglądają niewinnie.
- OOMKill – procesy ubijane przez kernel z powodu zbyt ciasnych limitów pamięci lub wycieków w aplikacji.
- Przeciążone nody – formalnie wolne CPU, ale zawalony storage lub sieć, przez co pody migrują i restartują się.
- Problemy sieciowe – CNI, kube-proxy, limity connection tracking, błędne NetworkPolicy, które robią z aplikacji „mulącego potwora”.
- Wolny lub niestabilny storage – wysokie opóźnienia, niskie IOPS, sporadyczne timeouty na wolumenach.
- CPU – wykorzystanie i throttling na poziomie nodów i podów (czy limity nie duszą aplikacji, czy requests są sensownie ustawione).
- Pamięć – zużycie RAM, OOMKill, trendy wzrostu (czy limit jest zbyt niski, czy aplikacja ma memory leak).
- IO / storage – opóźnienia dysku, IOPS, kolejki I/O (zwłaszcza dla baz danych i usług intensywnie zapisujących/odczytujących).
- Sieć – throughput, opóźnienia, dropy pakietów, błędy na interfejsach.
- Requests/limits – jak bardzo rzeczywiste zużycie odbiega od zadanych wartości.
- metrics-server + kubectl top do podglądu CPU i RAM „na żywo”,
- kubectl describe i kubectl logs do pojedynczych incydentów (OOM, crash loop),
- lekkie GUI typu Lens lub wbudowane dashboardy cloud providera, jeśli są w pakiecie.
Najczęściej zadawane pytania (FAQ)
Po co w ogóle monitorować wydajność w Kubernetes, skoro aplikacja „działa”?
Bez metryk Kubernetes potrafi długo udawać, że wszystko jest w porządku: pody się restartują, HPA skaluje repliki, a użytkownik widzi coraz większe opóźnienia i błędy. Monitoring skraca drogę od „coś jest wolno” do „dokładnie ten pod na tym node ma problem z CPU, pamięcią albo storage”.
Druga sprawa to koszty. Bez danych zespoły zwykle „dokręcają” zasoby na ślepo – większe nody, wyższe limity, więcej replik. Monitoring pokazuje, gdzie naprawdę brakuje mocy, a gdzie klastry są przewymiarowane i można spokojnie ciąć rachunki.
Kiedy wystarczy kubectl top, a kiedy trzeba wdrożyć Prometheus + Grafana?
kubectl top i metrics-server wystarczą w małym klastrze dev/test, gdzie:
To tani i szybki sposób na sprawdzenie, czy coś nie zjada całego CPU albo pamięci.
Prometheus, Grafana i alerty zaczynają mieć sens, gdy usług jest kilkanaście lub więcej, pojawiają się wymagania SLA, a ktoś w firmie zadaje pytanie „co się działo z klastrem godzinę temu?”. Wtedy potrzeba historii metryk, korelacji z deployami i automatycznych powiadomień – koszt utrzymania takiego stacka jest zwykle niższy niż jedna dłuższa awaria w produkcji.
Jakie są najczęstsze problemy wydajnościowe w klastrach Kubernetes?
W praktyce najczęściej wracają te same tematy:
Bez monitoringu łatwo zgadywać i poprawiać nie ten element, który faktycznie blokuje wydajność.
Jakie metryki wydajności w Kubernetes są kluczowe na start?
Na początek dobrze skupić się na podstawowych wąskich gardłach:
Te metryki już pozwalają zobaczyć, gdzie klaster jest niedoszacowany, a gdzie przepalasz budżet na przewymiarowane pody.
Czy mogę diagnozować problemy wydajności tylko na podstawie metryk podów?
Diagnoza wyłącznie z poziomu podów zazwyczaj prowadzi do złych wniosków. Pod może mieć „normalne” zużycie CPU i pamięci, a i tak będzie działał wolno, bo node, na którym siedzi, ma np. zawalony storage albo sieć. Z perspektywy samego poda tego nie widać.
Dlatego monitorowanie powinno obejmować kilka warstw naraz: infrastrukturę (nody, sieć, dyski), samą platformę Kubernetes (control plane, kubelet, CNI/CSI), workloady (Deploymenty, StatefulSety) oraz metryki aplikacyjne (QPS, latency, błędy). Dopiero zestawienie tych danych pokazuje, czy trzeba zmienić limity na podzie, powiększyć node, czy jednak naprawić kod.
Jak tanio zacząć monitoring wydajności w małym klastrze Kubernetes?
Dla małego środowiska dev/stage sensowny, „budżetowy” zestaw to:
Jeśli brakuje historii metryk, można dorzucić małego Prometheusa z krótkim retention (1–3 dni) i gotowymi dashboardami – to nadal tanie w utrzymaniu, a już pozwala odpowiedzieć na pytanie „co się działo godzinę temu, gdy wszystko zwolniło”.
Najważniejsze punkty
- Bez sensownego monitoringu Kubernetes łatwo maskuje problemy wydajnościowe (CPU throttling, OOMKill, przeciążona sieć lub storage), więc aplikacja „jakoś działa”, ale użytkownicy dostają timeouty i błędy.
- Brak metryk kosztuje więcej niż narzędzia: prowadzi do przewymiarowanych klastrów, dłuższych awarii i chaotycznych decyzji technicznych, bo zespół zgaduje zamiast podejmować decyzje na podstawie danych.
- kubectl top, describe i logs wystarczą w małym, deweloperskim klastrze bez SLA i historii zdarzeń, ale przestają mieć sens, gdy potrzebujesz wiedzieć, co działo się godzinę lub dzień temu.
- Pełniejszy stack observability (Prometheus, Grafana, podstawowe alerty) opłaca się, gdy usług jest już kilka–kilkanaście, masz SLA i każda godzina awarii lub nadpłaty za chmurę realnie boli budżet.
- Dla małych środowisk wystarczy „budżetowy” zestaw: metrics-server, kubectl top, proste GUI lub lekki Prometheus z krótkim retention; w produkcji z SLA minimalnym standardem staje się Prometheus + Grafana + kube-state-metrics + node-exporter + alerty.
- Monitoring trzeba układać warstwowo (infrastruktura → platforma Kubernetes → workloady → aplikacja), bo tylko korelacja metryk z tych poziomów pozwala odróżnić za mały node od złego limitu CPU czy błędu w samej aplikacji.
- Metryki wydajności pozwalają podejmować precyzyjne, tanie decyzje optymalizacyjne: zamiast „kupmy większe nody” można świadomie podnieść requesty CPU, dodać HPA na konkretnej metryce i zmniejszyć rachunek za chmurę bez ryzyka utraty wydajności.






