Przyp. tłum.: Inżynier w firmie Zalando — Henning Jacobs — wielokrotnie zauważał problemy użytkowników Kubernetes zrozumieniem celu liveness (i readiness) probes oraz ich właściwym stosowaniem. Dlatego zebrał swoje myśli w tę zwięzłą notatkę, która z czasem stanie się częścią dokumentacji K8s.

Sprawdzenia stanu, znane w Kubernetes jako liveness probes (czyli dosłownie «testy żywotności» — przyp. tłum.), mogą być dość niebezpieczne. Rekomenduję unikanie ich, jeśli to możliwe: wyjątkiem są tylko przypadki, kiedy są one naprawdę niezbędne i w pełni rozumiecie specyfikę oraz konsekwencje ich użycia. W tym artykule mowa będzie o liveness i readiness sprawdzeniach oraz omówimy, kiedy znajduje się i nie należy ich stosować.
Mój kolega Sandor niedawno podzielił się na Twitterze najczęstszymi błędami, które napotyka, w tym związanymi z użyciem readiness/liveness probes:
Niewłaściwie skonfigurowana livenessProbe może pogorszyć sytuację przy dużym obciążeniu (lawinowe wyłączenie + potencjalnie długi czas uruchamiania kontenera/aplikacji) i prowadzić do innych negatywnych skutków, takich jak awarie zależności (zobacz także na temat ograniczenia liczby zapytań w zestawie K3s+ACME). Jeszcze gorzej, gdy liveness probe jest połączony z kontrolą stanu zależności (health check), w roli której występuje zewnętrzna baza danych: jedna awaria Bazy Danych spowoduje ponowne uruchomienie wszystkich twoich kontenerów.!
Ogólny przekaz «Nie używaj liveness probes» w tym przypadku mało pomaga, więc przyjrzyjmy się, do czego służą readiness i liveness sprawdzenia.
Uwaga: większa część poniższego testu została pierwotnie włączona do wewnętrznej dokumentacji dla programistów Zalando.
Sprawdzenia Readiness i Liveness
Kubernetes oferuje dwa ważne mechanizmy, zwane . Regularnie wykonują jakieś działanie — na przykład, wysyłają zapytanie HTTP, otwierają połączenie TCP lub wykonują polecenie w kontenerze — aby potwierdzić, że aplikacja działa prawidłowo.
Kubernetes używa readiness probes, aby zrozumieć, kiedy kontener jest gotowy do przyjmowania ruchu. Pod uznawany jest za gotowy do pracy, jeśli wszystkie jego kontenery są gotowe. Jednym z zastosowań tego mechanizmu jest kontrolowanie, które pod’y są używane jako backendy dla usług Kubernetes (a szczególnie Ingress’a).
Proby żywotności pomagają Kubernetes zrozumieć, kiedy nadszedł czas na ponowne uruchomienie kontenera. Na przykład tego rodzaju weryfikacja pozwala przechwycić deadlock, gdy aplikacja "utknie" w jednym miejscu. Ponowne uruchomienie kontenera w takim stanie pomaga przesunąć aplikację z martwego punktu, mimo błędów, ale może też prowadzić do kaskadowych awarii (zobacz poniżej).
Jeśli spróbujesz wdrożyć aktualizację aplikacji, która nie przechodzi weryfikacji żywotności/readiness, jej wdrożenie zostanie wstrzymane, ponieważ Kubernetes będzie czekał na status Gotowy wszystkich podów.
Przykład
Oto przykład probe readiness, która sprawdza ścieżkę /health przez HTTP z domyślnymi ustawieniami (interval: 10 sekund, timeout: 1 sekunda, success threshold: 1, failure threshold: 3):
# часть общего описания deployment'а/стека
podTemplate:
spec:
containers:
- name: my-container
# ...
readinessProbe:
httpGet:
path: /health
port: 8080Zalecenia
- Dla mikrousług z końcówką HTTP (REST itp.) zawsze definiuj probe readiness, która sprawdza, czy aplikacja (pod) jest gotowa do odbioru ruchu.
- Upewnij się, że probe readiness obejmuje gotowość rzeczywistego portu serwera WWW:
- używając portów dla potrzeb administracyjnych, zwanych „admin” lub „management” (na przykład 9090), dla
readinessProbe, upewnij się, że końcówka zwraca OK tylko wtedy, gdy podstawowy port HTTP (np. 8080) jest gotowy przyjmować ruch*;* Znam co najmniej jeden przypadek w Zalando, w którym tak się nie stało, co oznacza, że
readinessProbesprawdziła port „management”, ale serwer nie rozpoczął działania z powodu problemów z ładowaniem pamięci podręcznej. - przypięcie probe readiness do osobnego portu może spowodować, że obciążenie na głównym porcie nie będzie odzwierciedlane w health checku (to znaczy, że pula wątków na serwerze jest pełna, ale health check wciąż pokazuje, że wszystko jest OK).
- używając portów dla potrzeb administracyjnych, zwanych „admin” lub „management” (na przykład 9090), dla
- Upewnij się, że probe readiness obejmuje inicjalizację/migrację bazy danych;
- najprostszym sposobem, aby to osiągnąć, jest zwrócenie się do serwera HTTP tylko po zakończeniu inicjalizacji (np. migracji DB z itp.); to znaczy, zamiast zmieniać status health checka, po prostu nie uruchamiaj serwera WWW przed zakończeniem migracji DB*.
* Można także uruchamiać migracje DB z kontenerów init poza podem. Wciąż jestem zwolennikiem aplikacji samodzielnych (self-contained), czyli takich, w których kontener aplikacji wie, jak doprowadzić DB do odpowiedniego stanu bez zewnętrznej koordynacji.
- najprostszym sposobem, aby to osiągnąć, jest zwrócenie się do serwera HTTP tylko po zakończeniu inicjalizacji (np. migracji DB z itp.); to znaczy, zamiast zmieniać status health checka, po prostu nie uruchamiaj serwera WWW przed zakończeniem migracji DB*.
- Użyj
httpGetdla weryfikacji readiness przez typowe końcówki health checków (na przykład,/health). - Poznaj parametry weryfikacji ustawione domyślnie (
interval: 10s,timeout: 1s,successThreshold: 1,failureThreshold: 3):- domyślne parametry oznaczają, że pod stanie się niegotowy za około 30 sekund (3 nieudane kontrole dostępności).
- Użyj osobnego portu dla „admin” lub „zarządzania”, jeśli stos technologiczny (na przykład Java/Spring) na to pozwala, aby oddzielić zarządzanie „zdrowiem” i metrykami od zwykłego ruchu:
- ale nie zapomnij o punkcie 2.
- W razie potrzeby probe gotowości można używać do rozgrzewania/ładowania pamięci podręcznej i zwracać kod stanu 503, dopóki kontener się nie „rozgrzeje”:
- zachęcam również do zapoznania się z nową kontrolą
startupProbe, (pisaliśmy o niej po rosyjsku — przyp. tłum.).
- zachęcam również do zapoznania się z nową kontrolą
Ostrzeżenia
- Nie polegaj na zewnętrznych zależnościach (takich jak bazy danych) podczas przeprowadzania testów gotowości/żywotności — może to prowadzić do awarii kaskadowych:
- jako przykład weźmy stateful-service REST z 10 podami, które zależą od jednej bazy danych Postgres: gdy kontrola opiera się na działającym połączeniu z bazą danych, wszystkie 10 podów może się wyłączyć, jeśli wystąpi opóźnienie w sieci/po stronie bazy danych — zazwyczaj kończy się to gorzej, niż mogłoby;
- zauważ, że Spring Data domyślnie sprawdza połączenie z bazą danych*;
* Taki jest domyślny sposób działania Spring Data Redis (przynajmniej tak było, gdy sprawdzałem po raz ostatni), co doprowadziło do „katastrofalnej” awarii: gdy Redis na krótki czas stał się niedostępny, wszystkie pode „wykopy” dosłownie.
- „zewnętrzny” w tym sensie może także oznaczać inne pody tej samej aplikacji, co oznacza, że w idealnym przypadku kontrola nie powinna zależeć od stanu innych podów w tym samym klastrze, aby zapobiec kaskadowym awariom:
- wyniki mogą się różnić dla aplikacji z rozproszonym stanem (na przykład pamięć podręczna w podach).
- Nie używaj liveness probe dla podów (wyjątkiem są przypadki, gdy są one naprawdę potrzebne i jesteś w pełni świadomy specyfiki i konsekwencji ich zastosowania):
- liveness probe może przyczynić się do odzyskiwania „zawieszonych” kontenerów, ale ponieważ masz pełną kontrolę nad swoją aplikacją, takie rzeczy jak „zawieszone” procesy i deadlocki w idealnym przypadku nie powinny się zdarzać: lepszą alternatywą jest celowe wyłączenie aplikacji i jej przywrócenie do poprzedniego stabilnego stanu;
- Nieudana liveness probe spowoduje restart kontenera, co potencjalnie pogorszy skutki błędów związanych z uruchomieniem: restart kontenera prowadzi do przestoju (przynajmniej na czas uruchomienia aplikacji, powiedzmy, ponad 30 sekund), wywołując nowe błędy, zwiększając obciążenie innych kontenerów i zwiększając prawdopodobieństwo ich awarii, itd.;
- Testy liveness w połączeniu z zewnętrzną zależnością to najgorsza możliwa kombinacja, grożąca kaskadowymi awariami: niewielkie opóźnienie po stronie bazy danych spowoduje restart wszystkich twoich kontenerów!
- Parametry testów liveness i readiness powinny być różne:
- można używać liveness probe z tym samym health checkiem, ale z wyższym progiem aktywacji (
failureThreshold), na przykład przypisując status niegotowy po 3 próbach i uznając, że liveness probe nie powiodło się po 10 próbach;
- można używać liveness probe z tym samym health checkiem, ale z wyższym progiem aktywacji (
- Nie używaj testów exec, ponieważ wiążą się z nimi znane problemy, prowadzące do powstawania zombie procesów:
- szczegóły: patrz .
Podsumowanie
- Używaj readiness probes, aby określić, kiedy pod jest gotowy do przyjęcia ruchu.
- Używaj liveness probes tylko wtedy, gdy są naprawdę potrzebne.
- Niewłaściwe użycie readiness/liveness probes może prowadzić do obniżenia dostępności i kaskadowych awarii.
Dodatkowe materiały na ten temat
- ;
- ;
- (opowiada również o livenessProbe).
Aktualizacja nr 1 z 2019-09-29
: dodano przypis.
o PDB: jednym z problemów testów liveness jest brak koordynacji między podami. W Kubernetes istnieją w celu ograniczenia liczby równoległych awarii, które może doświadczyć aplikacja, jednak testy nie uwzględniają PDB. W idealnym przypadku możemy nakazać K8s: „Zrestartuj jeden pod, jeśli jego test nie powiedzie się, ale nie restartuj wszystkich, aby nie pogorszyć sytuacji”.
: „Użyj liveness probing, gdy wiesz, że najlepsze, co można zrobić, to „zabić” aplikację” (znowu, nie przesadzajmy).
Aktualizacja nr 2 z 2019-09-29
: stworzyłem odpowiednie zgłoszenie () dotyczące dodania dokumentacji o liveness probes.
P.S. od tłumacza
Przeczytaj także na naszym blogu:
- «»;
- «»;
- «».
Źródło: habr.com
