tetes
Możliwości
Historia
Home App
Warstwy
Mapa homelaba
Blog
Studia przypadków
Współpraca
Kontakt
tetes

Docker homelab. 40+ serwisów. 0 subskrypcji chmurowych.

mariuszbinczyk.com

Nawigacja

  • Możliwości
  • Historia
  • Home App
  • Warstwy
  • Współpraca
  • Kontakt

Kontakt

  • GitHub
  • Email
  • PL / EN / DE

© 2026 tetes.pl — Wszelkie prawa zastrzeżone

0d98bb6
O projekciePrywatność
>|
Język:ENPLDE
Monitoring·8 lipca 2026·9 min czytania·Aktualizacja: 9 lipca 2026

Alerty Prometheusa: lekcje z sześciu miesięcy fałszywych alarmów

Warsztat pisania reguł, które budzą tylko wtedy, gdy trzeba: weryfikacja metryk przed regułą, predict_linear zamiast progów, pułapki alertów z logów i dwustopniowy pipeline AI, który zamienia JSON na zdanie po polsku.

#prometheus#monitoring#alerting#loki#observability
Alerty Prometheusa: lekcje z sześciu miesięcy fałszywych alarmów

Trzecia w nocy, telefon wibruje, nic się nie pali

Pierwsza wersja moich reguł alertów budziła mnie regularnie. Nie dlatego, że serwer padał — dlatego, że reguły były naiwne. Pik użycia pamięci przy nocnym skanie biblioteki mediów wyglądał dla nich jak wyciek. Licznik restartów, który raz drgnął, alarmował już na zawsze. A metryka, której zaufałem, liczyła coś innego, niż myślałem.

Dziś na serwerze działa ponad siedemdziesiąt reguł i przez większość tygodni żadna nie odzywa się bez powodu. Ten wpis to warsztat: co konkretnie zmieniło się między wersją, która budziła, a wersją, która budzi tylko naprawdę. Fałszywy alarm nie jest niewinny — każdy uczy ignorowania powiadomień, a monitoring, którego nikt nie czyta, nie istnieje.

Zanim napiszesz regułę, obejrzyj metrykę

Najdroższa lekcja z całych sześciu miesięcy: metryka nie zawsze mierzy to, co sugeruje nazwa. Zanim napiszesz próg, wpisz metrykę w konsolę i sprawdź trzy rzeczy: czy w ogóle istnieje pod tą nazwą, jakie ma etykiety i czy jej wartości zgadzają się z rzeczywistością, którą znasz skądinąd.

Klasyk tej pułapki: container_memory_usage_bytes zawiera cache systemu plików, więc zawyża „zużycie” pamięci o kilkadziesiąt procent — kontener wyglądał na zjadający 433 MB, gdy naprawdę pracował na 326 MB. Właściwa metryka to container_memory_working_set_bytes. Tę historię rozpisałem w case study o stacku monitoringu; tu zostawiam samą regułę warsztatową: próg na metryce, której nie obejrzałeś, to zgadywanie z powagą na twarzy.

for: — alert to stan, nie pik

Druga poprawka o największym efekcie była najprostsza. Alert bez klauzuli for: odpala przy pierwszej próbce spełniającej warunek — czyli przy każdym piku, restarcie scrape'a i chwilowej czkawce sieci.

Rozkład w moich ponad siedemdziesięciu regułach mówi sam za siebie: najwięcej reguł czeka 5 minut, krytyczne dostępnościowe 2 minuty, a powolne trendy godzinę (trzy najczęstsze ustawienia to 25 reguł na pięciu minutach, 14 na dwóch i 9 na godzinie; pozostałe rozkładają się od pół minuty do sześciu godzin). Jest też wyjątek z historią: alert o wysokiej pamięci kontenera czeka pół godziny, bo nocny skan biblioteki mediów potrafi legalnie podbić zużycie powyżej progu na kilkadziesiąt minut — i pierwsza wersja tej reguły alarmowała co noc o tej samej porze.

- alert: ServiceDown
  expr: up == 0
  for: 2m    # restart scrape'a to nie awaria
- alert: ContainerHighMemory
  expr: ...  # working_set > 85% limitu
  for: 30m   # nocny skan biblioteki mediów legalnie podbija pamięć

Dobór for: to zawsze ten sam kompromis: za krótko — budzą cię piki, za długo — dowiadujesz się ostatni. Praktyczna heurystyka: ile czasu problem może trwać, zanim naprawdę coś popsuje? Dla padniętego reverse proxy to minuty. Dla trendu pamięci — godziny.

predict_linear: alarmuj zanim się stanie, nie kiedy drgnie

Sztywny próg na pamięci ma wbudowany dylemat: ustaw nisko — alarmuje przy normalnej pracy, ustaw wysoko — budzi, gdy jest już za późno. Dla wycieków pamięci lepszy jest trend: predict_linear() ekstrapoluje ostatnie godziny i pyta, czy przy obecnym tempie kontener sięgnie limitu.

Moja reguła wykrywania wycieków przeszła trzy wersje i każda poprawka to była lekcja:

- alert: ContainerMemoryLeak
  expr: |
    predict_linear(container_memory_working_set_bytes{...}[6h], 6*3600)
      > container_spec_memory_limit_bytes * 0.95
    and container_memory_working_set_bytes{...}
      / container_spec_memory_limit_bytes > 0.5
    and delta(container_memory_working_set_bytes{...}[1h]) > 50 * 1024 * 1024

Trzy warunki spięte and, bo każdy z osobna kłamie. Sama predykcja na oknie trzygodzinnym reagowała na naturalne oscylacje — kontener falujący między 50 a 65% limitu wyglądał chwilami jak rakieta. Okno rozszerzone do sześciu godzin uspokoiło trend, warunek „już zużywa ponad połowę limitu” odsiał świeżo wystartowane kontenery, a wymóg realnego przyrostu (ponad 50 MB w godzinę) — te, które po prostu stoją wysoko i nic złego nie robią.

✓Wniosek

Reguła alertu to nie jednorazowy zapis, tylko kod, który się stroi. Każdy fałszywy alarm powinien zostawić ślad: komentarz w regule, co poprawiono i dlaczego. Moje najlepsze reguły mają w komentarzach trzy daty poprawek — i właśnie dlatego są najlepsze.

Alerty z logów: trzy pułapki, których nie ma w poradnikach

Metryki nie widzą wszystkiego — proces zabity przez OOM killera zostawia ślad w logach, nie na wykresie. Do tego służą reguły w . I tu czekały na mnie pułapki zupełnie innego rodzaju niż w Prometheusie, bo dopasowywanie wzorców do tekstu ma własne sposoby na złośliwość:

Granice słów. Wzorzec oom dopasowuje też „Room” i „Zoom” — dowolny czat lub nazwa urządzenia w logach potrafi odpalić alert o braku pamięci. Ratunek: \boom\b. Podobnie „killed” jest za szerokie — łapie niewinne zdania w logach aplikacji; trzeba dopasowywać konkretne frazy w rodzaju „OOM-killer” czy „was killed”.

Pętla sprzężenia. Moja reguła szukająca wzorca OOM w logach kontenerów znalazła go… we własnych logach Loki, które przecież przetwarzają te wzorce. Alert odpalał sam siebie w nieskończoność. Od tamtej pory każda reguła logowa ma wykluczenie container_name!="loki".

Poznaj swoje etykiety. Reguła jest tak dobra, jak jej selektor. U mnie job nazywa się containerlogs, a nazwy kontenerów są bez wiodącego ukośnika — ale wystarczy inna konfiguracja promtaila, by te same reguły nie dopasowały niczego i milczały w najlepsze. Zanim zaufasz regule logowej, sprawdź w konsoli, że jej selektor w ogóle coś zwraca. Cisza bywa błędem konfiguracji, nie zdrowiem.

Walidator przepuszcza, semantyka kłamie: co znalazł audyt

Po pół roku strojenia zrobiłem pełny audyt wszystkich reguł — nie dlatego, że coś nie działało, tylko dlatego, że wszystko wyglądało na działające. Znalazły się błędy, których żaden walidator składni nie wyłapie, bo składniowo wszystko grało.

Reguła wyciszania martwa od pierwszego dnia. Alertmanager pozwala wyciszać alerty powiązane: gdy pada cała usługa, nie chcę osobnego alarmu o jej wysokim CPU. Moja reguła używała target_match z wartością 'HighCPUUsage|HighMemoryUsage' — a target_match dopasowuje dokładnie, znak po znaku. Wersja z regexem nazywa się target_match_re. Literal ze znakiem | jest poprawnym stringiem, więc walidator milczał, a reguła przez pół roku nie wyciszyła niczego. Na dokładkę alert, którego miała dotyczyć, nazywał się w rzeczywistości inaczej. Dwa błędy w czterech linijkach konfiguracji, zero ostrzeżeń.

Jedna awaria, trzy krytyczne powiadomienia. Alertmanager grupuje powiadomienia m.in. po nazwie alertu — każda nazwa to osobny e-mail. Przez pół roku dopisywałem reguły dostępnościowe i nie zauważyłem, że padnięcie jednego eksportera metryk spełnia warunki trzech różnych reguł o trzech różnych nazwach. Jedna awaria, trzy krytyczne powiadomienia o tym samym zdarzeniu. Poprawka ma dwie części: reguły będące duplikatami 1:1 po prostu wyleciały, a tam, gdzie alert dedykowany niesie lepszy opis niż generyczny, dedykowany wycisza generyczny (inhibicja z equal po wspólnej etykiecie joba lub instancji).

Wykluczenie czegoś, co nie istnieje. Generyczna reguła dostępności wykluczała job blackbox-http — który nie istniał; kiedyś został przemianowany, wykluczenie zostało. Martwe wykluczenie jest gorsze niż brak wykluczenia: sugeruje, że przypadek jest obsłużony, więc nikt tam nie zagląda.

Wnioski operacyjne z tej rundy: routing da się testować behawioralnie — amtool config routes test z etykietami przykładowego alertu pokazuje, do których odbiorców trafi. Wyciszenia trzeba sprawdzać osobno: czy nazwy alertów i etykiety z source_match, target_match oraz equal faktycznie występują w regułach, a w środowisku testowym także na parze syntetycznych alertów. I drobiazg wdrożeniowy, który kosztował kwadrans: po edycji pliku zamontowanego w kontenerze jako pojedynczy bind mount kontener dalej widzi starą wersję, bo edytor podmienia inode — pomaga dopiero restart kontenera, nie reload.

✓Wniosek

Walidator sprawdza składnię, nie intencje. Nazwa alertu w regule wyciszania, job w wykluczeniu, etykieta w selektorze — to wszystko stringi, które muszą zgadzać się z resztą konfiguracji, a żadne narzędzie tej zgodności nie pilnuje. Kwartalny audyt semantyki (czy nazwy nadal istnieją, czy wyciszenia naprawdę wyciszają) znajduje błędy, których nie widać, bo objawiają się nadmiarem powiadomień, nie ich brakiem.

Audyt dorzucił też znalezisko spoza samego alertowania: Loki od początku pisał indeks w formacie, który w międzyczasie zdążył zostać oznaczony jako przestarzały (boltdb-shipper). Migracja na następcę (TSDB) okazała się bezpieczniejsza, niż brzmi — nowy wpis w schema_config z datą w przyszłości, stare dane do końca retencji czyta stary silnik, rollback to usunięcie wpisu przed nadejściem tej daty.

Ostatnia mila: z JSON-a do zdania po polsku

Nawet dobrze nastrojony alert dociera na telefon jako wiadomość od robota do robota: etykiety, wartości, identyfikatory. Ostatni odcinek toru obsługują u mnie dwa lokalne modele językowe przez — i podział ról między nimi to osobna lekcja, zmierzona, nie wydumana. Przy czym nie każdy alert w ogóle budzi modele: znane, powtarzalne wzorce mają przypisaną klasę i gotowy komunikat na sztywno, a do AI trafiają tylko te nieoczywiste — na procesorze bez GPU to rozsądna oszczędność.

Plan był prosty: jeden model klasyfikuje priorytet i pisze komunikat. Testy powiedziały co innego. phi4-mini klasyfikował bezbłędnie i szybko, ale jego polszczyzna okazała się kaleka („Zróbmy to w razie pilności”). Bielik — polski model od SpeakLeash — pisał naturalnie, za to klasyfikację spłaszczał: wszystko lądowało w środku skali, z krytycznym dyskiem włącznie. Żaden nie umiał obu rzeczy naraz. Rozwiązanie: pipeline dwustopniowy — phi4-mini klasyfikuje (etap 1), Bielik pisze finalny komunikat po polsku (etap 2).

Wdrożenie dorzuciło własne pułapki. Bielik przez surowy endpoint generowania potrafił odbić prompt echem zamiast odpowiedzieć — pomogły dopiero wywołania czatowe z przykładami odpowiedzi w prompcie systemowym (few-shot); bez nich niezawodność była loterią, z nimi wszystkie testy przeszły. Jeden przykład z kolei kotwiczył styl — model kopiował jego zakończenie do każdego komunikatu; dwa przykłady o różnych zakończeniach załatwiły sprawę. I zasada nadrzędna całego etapu: fail-open. Gdy Bielik zawiedzie albo odpowie echem (łapie to prosty guard na treści), alert wychodzi z komunikatem zapasowym. Ładny język jest opcjonalny — doręczenie nie.

⇄Kompromis

AI stoi na końcu toru nie bez powodu: tłumaczy dobre alerty na ludzki język, ale złych reguł nie naprawi. Kolejność inwestycji jest jednoznaczna — najpierw metryki i reguły, potem doręczanie, na końcu kosmetyka językowa. W odwrotnej kolejności dostajesz pięknie napisane fałszywe alarmy.

Sam tor doręczania — kto dostaje powiadomienie, którym kanałem, co się dzieje w godzinach ciszy — opisałem we wpisie o wzorcach n8n, a dobór modeli pod CPU bez GPU we wpisie o lokalnym LLM.

Checklist przed wdrożeniem reguły

  • Obejrzyj metrykę w konsoli — istnieje, ma te etykiety, mierzy to, co myślisz.
  • Licznik? Porównuj przyrost (increase(...[5m]) > 0), nigdy surową wartość — inaczej alert nie zgaśnie nigdy.
  • Dodaj for: dopasowane do pytania „ile ten problem może trwać, zanim zaboli”.
  • Trend zamiast progu tam, gdzie problem narasta powoli — predict_linear z warunkami odcinającymi oscylacje.
  • Reguły logowe: granice słów we wzorcach, wykluczenie własnych logów systemu logowania, sprawdzony selektor.
  • Opis reguły = pierwsza czynność diagnostyczna, nie powtórzenie nazwy. O trzeciej w nocy podziękujesz sobie za gotową komendę.
  • Każdy fałszywy alarm koryguje regułę i zostawia komentarz z datą. Wyciszenie to nie poprawka.
  • Raz na kwartał audyt semantyki — czy nazwy alertów w regułach wyciszania i joby w wykluczeniach nadal istnieją; routing sprawdzaj amtool config routes test na próbce etykiet.

Sześć miesięcy później monitoring budzi mnie kilka razy na kwartał — i za każdym razem słusznie. To jest właściwa miara: nie liczba reguł ani dashboardów, tylko zaufanie do wibracji telefonu w środku nocy.

Najczęstsze pytania

Od czego zacząć z alertami w homelabie?

Od trzech reguł, które łapią realne awarie: usługa nie odpowiada, kończy się miejsce na dysku, kontener restartuje się w pętli. Każda z rozsądnym opóźnieniem (for: 2-5 minut) i opisem, co zrobić. Dopiero gdy te trzy przestaną generować fałszywe alarmy, warto dokładać kolejne.

Dlaczego mój alert nie gaśnie, choć problem minął?

Najczęściej dlatego, że reguła patrzy na licznik, a nie na jego przyrost. Liczniki w Prometheusie tylko rosną — warunek typu restarty > 0 będzie prawdziwy już zawsze. Porównuj przyrost w oknie czasowym (increase w ostatnich 5 minutach), a alert zgaśnie razem z problemem.

Jak ograniczyć fałszywe alarmy bez wyciszania wszystkiego?

Trzy dźwignie: for (alert to stan trwały, nie pik), właściwa metryka (sprawdź, co naprawdę mierzy, zanim napiszesz próg) i przewidywanie trendu zamiast sztywnego progu tam, gdzie problem narasta powoli. Wyciszanie to ostatnia deska ratunku — reguła, którą regularnie wyciszasz, jest po prostu źle napisana.

Czy AI w torze alertów ma sens bez GPU?

Tak, bo to zadanie w tle — nikt nie czeka na odpowiedź interaktywnie. Mały model klasyfikuje priorytet w kilkanaście sekund, drugi pisze zrozumiały komunikat. Ale AI stoi na końcu toru: tłumaczy dobre alerty na ludzki język, złych reguł nie naprawi.

Tagi

#prometheus#monitoring#alerting#loki#observability
← Powrót do bloga

Następny →

n8n w homelabie: wzorce automatyzacji, które przetrwały rok produkcji