Liveness probes в Kubernetes могат да бъдат опасни

Прим. прев.: Водещият инженер в компанията Zalando — Хенинг Якобс — нееднократно е забелязвал, че потребителите на Kubernetes имат проблеми с разбирането на предназначението на liveness (и readiness) probes и тяхното коректно прилагане. По тази причина той събра мислите си в този кратък запис, който с времето ще стане част от документацията на K8s.

Liveness probes в Kubernetes могат да бъдат опасни

Състоянията, известни в Kubernetes като liveness probes (т.е. „тестове за жизненост“ — бел. прев.), могат да бъдат доста опасни. Препоръчвам да ги избягвате, доколкото е възможно: изключения са само случаите, когато те са наистина необходими и вие напълно осъзнавате спецификата и последиците от тяхното използване. В тази публикация ще разгледам liveness- и readiness-проверките, както и ще обясня в какви случаи е добре и не е добре да бъдат прилагани.

Моят колега Сандор наскоро сподели в Twitter най-честите грешки, с които се сблъсква, включително свързани с употребата на readiness/liveness probes:

Liveness probes в Kubernetes могат да бъдат опасни

Неправилно конфигуриран livenessProbe може да влоши ситуациите с висока натовареност (лавинообразно спиране + потенциално дълго стартиране на контейнера/приложението) и да доведе до други негативни последици, като падане на зависимости (вижте също моята скорошна статия за ограничаване на заявките в комбинация K3s+ACME). Дори по-лошо е, когато liveness probe се комбинира с проверка на здравето на зависимостта (health check), в ролята на която стои външната база данни: единственото сблъскване на БД ще рестартира всички ваши контейнери.!

Общото послание „Не използвайте liveness probes“ в този случай помага малко, затова ще разгледаме какво всъщност представляват проверките readiness и liveness.

Забележка: по-голямата част от предоставения по-долу тест първоначално беше включена в вътрешната документация за разработчици на Zalando.

Проверки Readiness и Liveness

Kubernetes предоставя два важни механизма, наречени liveness probes и readiness probes. Те периодично изпълняват определено действие — например, изпращат HTTP заявка, отварят TCP връзка или изпълняват команда в контейнера, — за да потвърдят, че приложението работи правилно.

Kubernetes използва readiness probes, за да разберете кога контейнерът е готов да приема трафик. Pod се смята за готов за работа, ако всички негови контейнери са готови. Едно от приложенията на този механизъм е да контролира кои pod-ове се използват като бекенди за услугите на Kubernetes (и особено Ingress-а).

Прозорци за живост помагат на Kubernetes да разбере кога е време да рестартира контейнера. Например, такава проверка позволява да се предотврати блокировка, когато приложението 'застане' на едно място. Рестартиране на контейнера в такова състояние помага да се премести приложението от мъртвата точка, въпреки грешките, а също така може да доведе до каскадни неуспехи (вж. по-долу).

Ако опитате да развернете обновление на приложението, което не преминава проверките за живост/готовност, разпространението му ще се блокира, тъй като Kubernetes ще изчака статуса Готово от всички pod-ове.

Пример

Ето пример за проверка на готовността, проверяваща пътя /health чрез HTTP с настройки по подразбиране (интервал: 10 секунди, таймаут: 1 секунда, праг на успех: 1, праг на неуспех: 3):

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

Препоръки

  1. За микросервизи с HTTP крайна точка (REST и др.) винаги определяйте проверка на готовността, която проверява дали приложението (pod) е готово да приема трафик.
  2. Убедете се, че проверката за готовност обхваща готовността на фактическия порт на уеб сървъра:
    • използвайки портове за административни нужди, наричани 'admin' или 'management' (например, 9090), за readinessProbe, уверете се, че крайният точка връща ОК само ако основният HTTP порт (като 8080) е готов да приема трафик*;

      * Зная за поне един случай в Zalando, когато това не се е случило, а именно readinessProbe провери порт 'management', но самият сървър не започна да работи поради проблеми с зареждането на кеша.

    • поставянето на проверка на готовността на отделен порт може да доведе до това, че натоварването на основния порт няма да се отразява в проверката на здравето (тоест, пулът на потоковете на сървъра е запълнен, но проверката на здравето продължава да показва, че всичко е ОК).
  3. Убедете се, че проверка за готовност включва инициализация/миграция на базата данни;
    • най-простият начин да го постигнете е да се обръщате към HTTP сървъра само след завършване на инициализацията (например, миграция на БД с Flyway и т.н.); тоест вместо да променяте статуса на проверката на здравето, просто не стартирайте уеб сървъра до приключване на миграцията на БД*.

      * Можете също така да стартирате миграции на базата данни от init-контейнери извън pod-а. Все още съм почитател на самостоятелните (self-contained) приложения, т.е. такива, при които контейнерът на приложението знае как да доведе базата данни в нужното състояние без външна координация.

  4. Използвайте httpGet за проверки на readiness през типични endpoint-ове на health check-ове (например, /health).
  5. Изучете параметрите за проверки, зададени по подразбиране (интервал: 10s, таймаут: 1s, успешен праг: 1, праг на провал: 3):
    • параметрите по подразбиране означават, че pod-ът ще стане не-готов приблизително след 30 секунди (3 неуспешни проверки на работоспособността).
  6. Използвайте отделен порт за «админ» или «управление», ако технологичният стек (например, Java/Spring) позволява това, за да отделите управлението на «здоровето» и метриките от обикновения трафик:
    • но не забравяйте за точка 2.
  7. При необходимост readiness probe може да се използва за предварително загряване/зареждане на кеша и да върне код на състояние 503, докато контейнерът не се «загрее»:
    • също така ви препоръчвам да се запознаете с новата проверка startupProbe, появила се в версия 1.16 (писали сме за нея на руски тук. — забележка на преводача).

Предупреждения

  1. Не разчитайте на външни зависимости (като хранилища на данни) при провеждане на тестове за readiness/liveness — това може да доведе до каскадни провали:
    • например, вземете stateful-сервиз REST с 10 pod-а, зависещи от една база данни Postgres: когато проверката зависи от работеща връзка с БД, всичките 10 pod-а могат да паднат, ако се появи забавяне в мрежата/на страната на БД — обикновено всичко това приключва по-лошо, отколкото би могло;
    • обърнете внимание, че Spring Data по подразбиране проверява връзката с БД*;

      * Такова е поведението по подразбиране на Spring Data Redis (поне така беше, когато проверявах последния път), което доведе до «катастрофичен» провал: когато за кратко време Redis стана недостъпен, всички pod-ове «паднаха».

    • «външен» в този смисъл също може да означава други pod-ове от същото приложение, тоест в идеалния случай проверката не трябва да зависи от състоянието на другите pod-ове от същия клъстер, за да се предотвратят каскадни падения:
      • резултатите могат да варират за приложения с разпределено състояние (например, in-memory кеширане в pod-ове).
  2. Не използвайте liveness probe за pod-ове (изключения са случаите, когато наистина са необходими и вие напълно осъзнавате спецификата и последиците от тяхното приложение):
    • liveness probe може да помогне за възстановяване на "замръзнали" контейнери, но тъй като имате пълен контрол над приложението си, подобни неща като "замръзнали" процеси и deadlock-и идеално не трябва да се случват: най-добрата алтернатива е целенасоченото падение на приложението и връщането му в предишно стабилно състояние;
    • неуспешният liveness probe ще доведе до рестартиране на контейнера, което потенциално може да влоши последствията от проблемите, свързани с товара: рестартирането на контейнера ще предизвика престой (поне за времето на стартиране на приложението, да кажем, за повече от 30 секунди), което води до нови грешки, увеличава натоварването на другите контейнери и повишава вероятността за техния провал и т.н.;
    • liveness проверките в съчетание с външна зависимост са най-лошата възможна комбинация, която заплашва каскадни провали: незначителна забавяне от страна на базата данни ще доведе до рестартиране на всичките ви контейнери!
  3. Параметрите на liveness и readiness проверките трябва да бъдат различни:
    • може да се използва liveness probe със същата health check, но с по-висок праг на задействие (failureThreshold), например, да се присвоява статус не-готов след 3 опита и да се счита, че liveness probe е провалил след 10 опита;
  4. Не използвайте exec проверки, тъй като с тях са свързани известни проблеми, водещи до появата на зомби процеси:

Резюме

  • Използвайте readiness probes, за да определите кога pod е готов за приемане на трафик.
  • Използвайте liveness probes само когато те са наистина необходими.
  • Неправилната употреба на readiness/liveness probes може да доведе до намаляване на наличността и каскадни провали.

Liveness probes в Kubernetes могат да бъдат опасни

Допълнителни материали по темата

Актуализация №1 от 2019-09-29

За init контейнери за миграция на бази данни: добавена бележка.

EJ ми напомни за PDB: едно от нещата, свързани с liveness проверките, е липсата на координация между pod-овете. В Kubernetes има Pod Disruption Budgets (PDB) за ограничаване на броя на паралелните провали, които приложение може да изпитва, но проверките не вземат предвид PDB. В идеалния случай можем да наредим на K8s: "Рестартирай един pod, ако проверката му е неуспешна, но не рестартирайте всички, за да не направите нещата още по-лоши".

Bryan се е изразил отлично: «Използвайте liveness зондове, когато сте абсолютно сигурни, че най-доброто, което можете да направите, е да „убиете“ приложението» (отново, не прекалявайте).

Liveness probes в Kubernetes могат да бъдат опасни

Актуализация №2 от 2019-09-29

По отношение на четенето на документацията преди употреба: създадох съответната заявка (функционална заявка) за допълване на документацията относно liveness probes.

P.S. от преводача

Прочетете също в нашия блог:

Източник: habr.com

Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри 🔥 Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри | ProHoster