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

Състоянията, известни в Kubernetes като liveness probes (т.е. „тестове за жизненост“ — бел. прев.), могат да бъдат доста опасни. Препоръчвам да ги избягвате, доколкото е възможно: изключения са само случаите, когато те са наистина необходими и вие напълно осъзнавате спецификата и последиците от тяхното използване. В тази публикация ще разгледам liveness- и readiness-проверките, както и ще обясня в какви случаи е добре и не е добре да бъдат прилагани.
Моят колега Сандор наскоро сподели в Twitter най-честите грешки, с които се сблъсква, включително свързани с употребата на readiness/liveness probes:
Неправилно конфигуриран livenessProbe може да влоши ситуациите с висока натовареност (лавинообразно спиране + потенциално дълго стартиране на контейнера/приложението) и да доведе до други негативни последици, като падане на зависимости (вижте също за ограничаване на заявките в комбинация K3s+ACME). Дори по-лошо е, когато liveness probe се комбинира с проверка на здравето на зависимостта (health check), в ролята на която стои външната база данни: единственото сблъскване на БД ще рестартира всички ваши контейнери.!
Общото послание „Не използвайте liveness probes“ в този случай помага малко, затова ще разгледаме какво всъщност представляват проверките readiness и liveness.
Забележка: по-голямата част от предоставения по-долу тест първоначално беше включена в вътрешната документация за разработчици на Zalando.
Проверки Readiness и Liveness
Kubernetes предоставя два важни механизма, наречени . Те периодично изпълняват определено действие — например, изпращат 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Препоръки
- За микросервизи с HTTP крайна точка (REST и др.) винаги определяйте проверка на готовността, която проверява дали приложението (pod) е готово да приема трафик.
- Убедете се, че проверката за готовност обхваща готовността на фактическия порт на уеб сървъра:
- използвайки портове за административни нужди, наричани 'admin' или 'management' (например, 9090), за
readinessProbe, уверете се, че крайният точка връща ОК само ако основният HTTP порт (като 8080) е готов да приема трафик*;* Зная за поне един случай в Zalando, когато това не се е случило, а именно
readinessProbeпровери порт 'management', но самият сървър не започна да работи поради проблеми с зареждането на кеша. - поставянето на проверка на готовността на отделен порт може да доведе до това, че натоварването на основния порт няма да се отразява в проверката на здравето (тоест, пулът на потоковете на сървъра е запълнен, но проверката на здравето продължава да показва, че всичко е ОК).
- използвайки портове за административни нужди, наричани 'admin' или 'management' (например, 9090), за
- Убедете се, че проверка за готовност включва инициализация/миграция на базата данни;
- най-простият начин да го постигнете е да се обръщате към HTTP сървъра само след завършване на инициализацията (например, миграция на БД с и т.н.); тоест вместо да променяте статуса на проверката на здравето, просто не стартирайте уеб сървъра до приключване на миграцията на БД*.
* Можете също така да стартирате миграции на базата данни от init-контейнери извън pod-а. Все още съм почитател на самостоятелните (self-contained) приложения, т.е. такива, при които контейнерът на приложението знае как да доведе базата данни в нужното състояние без външна координация.
- най-простият начин да го постигнете е да се обръщате към HTTP сървъра само след завършване на инициализацията (например, миграция на БД с и т.н.); тоест вместо да променяте статуса на проверката на здравето, просто не стартирайте уеб сървъра до приключване на миграцията на БД*.
- Използвайте
httpGetза проверки на readiness през типични endpoint-ове на health check-ове (например,/health). - Изучете параметрите за проверки, зададени по подразбиране (
интервал: 10s,таймаут: 1s,успешен праг: 1,праг на провал: 3):- параметрите по подразбиране означават, че pod-ът ще стане не-готов приблизително след 30 секунди (3 неуспешни проверки на работоспособността).
- Използвайте отделен порт за «админ» или «управление», ако технологичният стек (например, Java/Spring) позволява това, за да отделите управлението на «здоровето» и метриките от обикновения трафик:
- но не забравяйте за точка 2.
- При необходимост readiness probe може да се използва за предварително загряване/зареждане на кеша и да върне код на състояние 503, докато контейнерът не се «загрее»:
- също така ви препоръчвам да се запознаете с новата проверка
startupProbe, (писали сме за нея на руски — забележка на преводача).
- също така ви препоръчвам да се запознаете с новата проверка
Предупреждения
- Не разчитайте на външни зависимости (като хранилища на данни) при провеждане на тестове за readiness/liveness — това може да доведе до каскадни провали:
- например, вземете stateful-сервиз REST с 10 pod-а, зависещи от една база данни Postgres: когато проверката зависи от работеща връзка с БД, всичките 10 pod-а могат да паднат, ако се появи забавяне в мрежата/на страната на БД — обикновено всичко това приключва по-лошо, отколкото би могло;
- обърнете внимание, че Spring Data по подразбиране проверява връзката с БД*;
* Такова е поведението по подразбиране на Spring Data Redis (поне така беше, когато проверявах последния път), което доведе до «катастрофичен» провал: когато за кратко време Redis стана недостъпен, всички pod-ове «паднаха».
- «външен» в този смисъл също може да означава други pod-ове от същото приложение, тоест в идеалния случай проверката не трябва да зависи от състоянието на другите pod-ове от същия клъстер, за да се предотвратят каскадни падения:
- резултатите могат да варират за приложения с разпределено състояние (например, in-memory кеширане в pod-ове).
- Не използвайте liveness probe за pod-ове (изключения са случаите, когато наистина са необходими и вие напълно осъзнавате спецификата и последиците от тяхното приложение):
- liveness probe може да помогне за възстановяване на "замръзнали" контейнери, но тъй като имате пълен контрол над приложението си, подобни неща като "замръзнали" процеси и deadlock-и идеално не трябва да се случват: най-добрата алтернатива е целенасоченото падение на приложението и връщането му в предишно стабилно състояние;
- неуспешният liveness probe ще доведе до рестартиране на контейнера, което потенциално може да влоши последствията от проблемите, свързани с товара: рестартирането на контейнера ще предизвика престой (поне за времето на стартиране на приложението, да кажем, за повече от 30 секунди), което води до нови грешки, увеличава натоварването на другите контейнери и повишава вероятността за техния провал и т.н.;
- liveness проверките в съчетание с външна зависимост са най-лошата възможна комбинация, която заплашва каскадни провали: незначителна забавяне от страна на базата данни ще доведе до рестартиране на всичките ви контейнери!
- Параметрите на liveness и readiness проверките трябва да бъдат различни:
- може да се използва liveness probe със същата health check, но с по-висок праг на задействие (
failureThreshold), например, да се присвоява статус не-готов след 3 опита и да се счита, че liveness probe е провалил след 10 опита;
- може да се използва liveness probe със същата health check, но с по-висок праг на задействие (
- Не използвайте exec проверки, тъй като с тях са свързани известни проблеми, водещи до появата на зомби процеси:
- подробности: вижте .
Резюме
- Използвайте readiness probes, за да определите кога pod е готов за приемане на трафик.
- Използвайте liveness probes само когато те са наистина необходими.
- Неправилната употреба на readiness/liveness probes може да доведе до намаляване на наличността и каскадни провали.
Допълнителни материали по темата
- ;
- ;
- (разказва и за livenessProbe).
Актуализация №1 от 2019-09-29
: добавена бележка.
за PDB: едно от нещата, свързани с liveness проверките, е липсата на координация между pod-овете. В Kubernetes има за ограничаване на броя на паралелните провали, които приложение може да изпитва, но проверките не вземат предвид PDB. В идеалния случай можем да наредим на K8s: "Рестартирай един pod, ако проверката му е неуспешна, но не рестартирайте всички, за да не направите нещата още по-лоши".
: «Използвайте liveness зондове, когато сте абсолютно сигурни, че най-доброто, което можете да направите, е да „убиете“ приложението» (отново, не прекалявайте).
Актуализация №2 от 2019-09-29
: създадох съответната заявка () за допълване на документацията относно liveness probes.
P.S. от преводача
Прочетете също в нашия блог:
- «»;
- «»;
- «».
Източник: habr.com
