Sondy na żywo w Kubernetesie mogą być niebezpieczne

Notatka. przeł.: Główny inżynier z Zalando, Henning Jacobs, wielokrotnie zauważył problemy wśród użytkowników Kubernetesa w zrozumieniu celu sond żywotności (i gotowości) oraz ich prawidłowego użycia. Dlatego zebrał swoje przemyślenia w tej pojemnej notatce, która docelowo stanie się częścią dokumentacji K8.

Sondy na żywo w Kubernetesie mogą być niebezpieczne

Kontrole kondycji, znane w Kubernetesie jako sondy żywotności (tj. dosłownie „testy żywotności” - ok. tłum.), może być dość niebezpieczne. Radzę ich unikać, jeśli to możliwe: jedynymi wyjątkami są sytuacje, gdy są naprawdę konieczne i jesteś w pełni świadomy specyfiki i konsekwencji ich użycia. W tej publikacji omówiono kontrole żywotności i gotowości, a także wyjaśniono, w jakich przypadkach jest i nie powinieneś ich używać.

Mój kolega Sandor niedawno podzielił się na Twitterze najczęstszymi błędami, jakie napotyka, w tym tymi związanymi ze stosowaniem sond gotowości/żywotności:

Sondy na żywo w Kubernetesie mogą być niebezpieczne

Nieprawidłowo skonfigurowany livenessProbe może pogorszyć sytuacje związane z dużym obciążeniem (wyłączenie kuli śnieżnej + potencjalnie długi czas uruchamiania kontenera/aplikacji) i prowadzić do innych negatywnych konsekwencji, takich jak spadek zależności (Zobacz też mój najnowszy artykuł o ograniczeniu ilości żądań w kombinacji K3s+ACME). Jeszcze gorzej jest, gdy sondę żywotności połączymy z kontrolą stanu zdrowia, czyli zewnętrzną bazą danych: pojedyncza awaria bazy danych spowoduje ponowne uruchomienie wszystkich kontenerów!

Wiadomość ogólna „Nie używaj sond żywotności” w tym przypadku niewiele to pomoże, więc przyjrzyjmy się, do czego służą kontrole gotowości i żywotności.

Uwaga: większość poniższego testu została pierwotnie uwzględniona w wewnętrznej dokumentacji programistycznej Zalando.

Kontrole gotowości i żywotności

Kubernetes udostępnia dwa ważne mechanizmy zwane sondy żywotności i sondy gotowości. Okresowo wykonują pewne działania — takie jak wysyłanie żądania HTTP, otwieranie połączenia TCP lub wykonywanie polecenia w kontenerze — aby potwierdzić, że aplikacja działa zgodnie z oczekiwaniami.

Kubernetes używa sondy gotowościaby zrozumieć, kiedy kontener jest gotowy do przyjęcia ruchu. Kapsułę uważa się za gotową do użycia, jeśli wszystkie jej pojemniki są gotowe. Jednym z zastosowań tego mechanizmu jest kontrolowanie, które pody są używane jako backendy dla usług Kubernetes (a zwłaszcza Ingress).

Sondy żywotności pomóż Kubernetesowi zrozumieć, kiedy należy zrestartować kontener. Na przykład takie sprawdzenie pozwala przechwycić zakleszczenie, gdy aplikacja utknie w jednym miejscu. Ponowne uruchomienie kontenera w tym stanie pomaga w uruchomieniu aplikacji pomimo błędów, ale może również prowadzić do kaskadowych błędów (patrz poniżej).

Jeśli spróbujesz wdrożyć aktualizację aplikacji, która nie przejdzie kontroli dostępności/gotowości, jej wdrożenie zostanie wstrzymane, ponieważ Kubernetes będzie czekał na status Ready ze wszystkich strąków.

Przykład

Oto przykład sondy gotowości sprawdzającej ścieżkę /health przez HTTP z ustawieniami domyślnymi (interwał: 10 sekund, Timeout: 1 sekunda, próg sukcesu: 1, próg awarii: 3):

# часть общего описания deployment'а/стека
podTemplate:
  spec:
    containers:
    - name: my-container
      # ...
      readinessProbe:
        httpGet:
          path: /health
          port: 8080

zalecenia

  1. W przypadku mikrousług z punktem końcowym HTTP (REST itp.) zawsze definiuj sondę gotowości, który sprawdza, czy aplikacja (pod) jest gotowa na przyjęcie ruchu.
  2. Upewnij się, że sonda gotowości obejmuje dostępność rzeczywistego portu serwera WWW:
    • używanie portów do celów administracyjnych, zwanych „adminem” lub „zarządzaniem” (na przykład 9090), na przykład readinessProbe, upewnij się, że punkt końcowy zwraca OK tylko wtedy, gdy podstawowy port HTTP (np. 8080) jest gotowy do akceptowania ruchu*;

      *Znam co najmniej jeden przypadek w Zalando, w którym tak się nie stało, tj. readinessProbe Sprawdziłem port „zarządzania”, ale sam serwer nie zaczął działać z powodu problemów z ładowaniem pamięci podręcznej.

    • podłączenie sondy gotowości do osobnego portu może spowodować, że przeciążenie na porcie głównym nie zostanie odzwierciedlone w kontroli stanu (czyli pula wątków na serwerze jest pełna, ale kontrola stanu nadal pokazuje, że wszystko jest OK ).
  3. Upewnij się, że sonda gotowości umożliwia inicjalizację/migrację bazy danych;
    • Najłatwiej to osiągnąć, kontaktując się z serwerem HTTP dopiero po zakończeniu inicjalizacji (na przykład podczas migracji bazy danych z Droga przelotowa i tak dalej.); oznacza to, że zamiast zmieniać status kontroli stanu, po prostu nie uruchamiaj serwera WWW, dopóki migracja bazy danych nie zostanie zakończona*.

      * Możesz także uruchamiać migracje baz danych z kontenerów inicjujących poza zasobnikiem. Nadal jestem zwolennikiem aplikacji samodzielnych, czyli takich, w których kontener aplikacji wie, jak doprowadzić bazę danych do pożądanego stanu bez zewnętrznej koordynacji.

  4. Stosowanie httpGet w przypadku kontroli gotowości poprzez typowe punkty końcowe kontroli stanu (na przykład /health).
  5. Zapoznaj się z domyślnymi parametrami sprawdzania (interval: 10s, timeout: 1s, successThreshold: 1, failureThreshold: 3):
    • domyślne opcje oznaczają, że kapsuła stanie się nie gotowy po około 30 sekundach (3 nieudane testy poprawności).
  6. Użyj osobnego portu dla „administratora” lub „zarządzania”, jeśli pozwala na to stos technologii (np. Java/Spring), aby oddzielić zarządzanie stanem i wskaźnikami od zwykłego ruchu:
    • ale nie zapomnij o punkcie 2.
  7. W razie potrzeby można użyć sondy gotowości do rozgrzania/załadowania pamięci podręcznej i zwrócenia kodu stanu 503 do czasu nagrzania kontenera:

Ostrzeżenia

  1. Nie polegaj na zależnościach zewnętrznych (takich jak hurtownie danych) podczas uruchamiania testów gotowości/żywotności — może to prowadzić do kaskadowych błędów:
    • Jako przykład weźmy stanową usługę REST z 10 podami w zależności od jednej bazy danych Postgres: gdy sprawdzenie zależy od działającego połączenia z bazą danych, wszystkie 10 podów może nie działać, jeśli występuje opóźnienie po stronie sieci/bazy danych - zwykle tak jest wszystko kończy się gorzej niż mogłoby;
    • Pamiętaj, że Spring Data domyślnie sprawdza połączenie z bazą danych*;

      * Jest to domyślne zachowanie Spring Data Redis (przynajmniej tak było ostatnim razem, gdy sprawdzałem), co doprowadziło do „katastrofalnej” awarii: gdy Redis był przez krótki czas niedostępny, wszystkie pody „awariowały”.

    • „zewnętrzny” w tym sensie może również oznaczać inne pody tej samej aplikacji, co oznacza, że ​​w idealnym przypadku sprawdzenie nie powinno zależeć od stanu innych podów w tym samym klastrze, aby zapobiec kaskadowym awariom:
      • wyniki mogą się różnić w przypadku aplikacji o stanie rozproszonym (na przykład buforowanie w pamięci w zasobnikach).
  2. Nie używaj sondy na żywo dla strąków (wyjątkiem są przypadki, gdy są one naprawdę potrzebne i masz pełną świadomość specyfiki i konsekwencji ich stosowania):
    • Sonda na żywo może pomóc w odzyskaniu zawieszonych kontenerów, ale ponieważ masz pełną kontrolę nad aplikacją, w idealnym przypadku takie sytuacje jak zawieszanie procesów i zakleszczenia nie powinny mieć miejsca: najlepszą alternatywą jest celowe zawieszenie aplikacji i przywrócenie jej do poprzedniego, stabilnego stanu;
    • nieudana sonda żywotności spowoduje ponowne uruchomienie kontenera, co potencjalnie zaostrzy konsekwencje błędów związanych z ładowaniem: ponowne uruchomienie kontenera spowoduje przestój (przynajmniej na czas uruchamiania aplikacji, powiedzmy 30 nieparzystych sekund), powodując nowe błędy , zwiększenie obciążenia innych kontenerów i zwiększenie prawdopodobieństwa ich awarii itp.;
    • sprawdzanie żywotności w połączeniu z zależnością zewnętrzną to najgorsza możliwa kombinacja, grożąca kaskadowymi awariami: niewielkie opóźnienie po stronie bazy danych doprowadzi do ponownego uruchomienia wszystkich kontenerów!
  3. Parametry kontroli żywotności i gotowości musi być inny:
    • możesz użyć sondy na żywo z tą samą kontrolą stanu, ale z wyższym progiem odpowiedzi (failureThreshold), na przykład przypisz status nie gotowy po 3 próbach i weź pod uwagę, że sonda żywotności nie powiodła się po 10 próbach;
  4. Nie używaj kontroli exec, ponieważ są one związane ze znanymi problemami, które prowadzą do pojawienia się procesów zombie:

Streszczenie

  • Użyj sond gotowości, aby określić, kiedy moduł jest gotowy do odbierania ruchu.
  • Używaj sond żywotności tylko wtedy, gdy są naprawdę potrzebne.
  • Niewłaściwe użycie sond gotowości/żywotności może prowadzić do zmniejszenia dostępności i kaskadowych awarii.

Sondy na żywo w Kubernetesie mogą być niebezpieczne

Dodatkowe materiały na ten temat

Aktualizacja nr 1 z dnia 2019

Informacje o kontenerach inicjujących migrację bazy danych: Dodano przypis.

EJ przypomniał mi o PDB: jednym z problemów związanych z sprawdzaniem żywotności jest brak koordynacji pomiędzy zasobnikami. Kubernetes ma Budżety na zakłócenia podów (PDB) aby ograniczyć liczbę jednoczesnych błędów, jakie może wystąpić aplikacja, ale kontrole nie uwzględniają WPB. Idealnie byłoby, gdybyśmy mogli powiedzieć K8, aby „Uruchom ponownie jeden moduł, jeśli jego test się nie powiedzie, ale nie uruchamiaj ponownie wszystkich, aby uniknąć pogorszenia sytuacji”.

Bryan ujął to doskonale: „Wykorzystuj badanie żywotności, jeśli wiesz dokładnie, co najlepiej jest zabić aplikację„(ponownie, nie daj się ponieść emocjom).

Sondy na żywo w Kubernetesie mogą być niebezpieczne

Aktualizacja nr 2 z dnia 2019

Jeśli chodzi o zapoznanie się z dokumentacją przed użyciem: Utworzyłem odpowiednie żądanie (żądanie funkcji), aby dodać dokumentację dotyczącą sond żywotności.

PS od tłumacza

Przeczytaj także na naszym blogu:

Źródło: www.habr.com

Dodaj komentarz