Прим. прев.: Главният инженер на компанията 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 секунди, timeout: 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-а. Още съм почитател на самостоятелни приложения, т.е. такива, в които контейнерът на приложението знае без външна координация как да настрои базата данни в необходимото състояние.
- най-простият начин да постигнете това е да се свързвате с HTTP сървъра само след завършване на инициализацията (например, миграция на БД с и т.н.); тоест вместо да променяте статуса на проверката за здравословно състояние, просто не стартирайте уеб сървъра до завършването на миграцията на БД*.
- Използвайте
httpGetза проверки на readiness чрез типични endpoint-и на health check-ове (например,/health). - Разберете параметрите на проверките, зададени по подразбиране (
интервал: 10s,таймаут: 1s,успехов праг: 1,праг на неуспех: 3):- параметрите по подразбиране означават, че pod-ът ще стане not-ready приблизително след 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), например, да присвоява статус not-ready след 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
