Health и readiness эндпоинты
Чем liveness отличается от readiness, зачем приложению отдельный /healthz и как это связано с балансировкой и оркестратором.
Откуда оркестратор знает, что приложение живо
Балансировщик и оркестратор не умеют читать мысли приложения. Им нужен
способ спросить «ты в порядке?» по сети. Поэтому приложение отдаёт
специальный HTTP-эндпоинт, который быстро отвечает о своём состоянии.
По соглашению его называют /healthz или /health.
Проверок три, и каждая отвечает на свой вопрос: запустилось ли приложение, живо ли оно и готово ли принимать трафик.
Liveness: приложение живо
Liveness отвечает на вопрос «приложение не зависло?». Если liveness перестаёт отвечать или возвращает ошибку, оркестратор считает копию мёртвой и перезапускает её. Это лечит зависания, из которых процесс сам не выберется (дедлок, утечка, бесконечный цикл).
Liveness делают максимально простым: вернуть 200 OK, если процесс жив.
Он не должен ходить в базу или внешние сервисы, иначе временный сбой базы
вызовет лавину ненужных перезапусков.
$ curl -s -o /dev/null -w "%{http_code}" http://app:8080/healthz
200
Readiness: приложение готово к трафику
Readiness отвечает на другой вопрос: «можно ли уже слать сюда
запросы?». Приложение запустилось, но ещё прогревает кеш, устанавливает
соединение с базой, читает конфиг. В этот момент оно живо, но не готово.
Readiness возвращает не 200, пока приложение не готово, и балансировщик
не шлёт на него трафик.
В отличие от liveness, readiness как раз проверяет зависимости: есть ли соединение с базой, доступна ли очередь. Нет базы, значит не готов обслуживать, и трафик идёт на здоровые копии.
Startup: приложение ещё запускается
Третья проверка решает проблему медленного старта. Пусть приложению нужно две минуты на прогрев: поднять JVM, прочитать большой конфиг, накатить миграции. Liveness с обычным таймаутом за это время решит, что процесс завис, и перезапустит его. Приложение начнёт стартовать заново, опять не успеет — и так по кругу. Классический CrashLoopBackOff на ровном месте.
Раньше это лечили костылём: ставили liveness огромный
initialDelaySeconds или десятки разрешённых провалов. Побочный эффект
неприятный — после прогрева проверка становится вялой, и реальное
зависание ловится не за пять секунд, а за пять минут.
Startup probe разводит эти два режима. Она отвечает на вопрос «стартовало ли приложение» и работает только в начале жизни копии. В Kubernetes она появилась в 1.16 и стала стабильной в 1.20.
Порядок такой. Пока startup не вернула успех, liveness и readiness вообще не запускаются — оркестратор просто ждёт, столько, сколько разрешает бюджет startup-проверки. Как только startup прошла, она больше не выполняется никогда, и включаются liveness с readiness со своими нормальными, короткими таймаутами.
старт копии
│
├── startup probe: опрашивается, пока не ответит 200
│ (liveness и readiness ждут)
│
└── startup прошла → выключается навсегда
│
├── liveness — весь остаток жизни
└── readiness — весь остаток жизни
Бюджет startup считают как «период опроса × число попыток». Тридцать попыток раз в 10 секунд дают пять минут на запуск. Не уложился — копию перезапускают.
Отдельный эндпоинт под startup обычно не заводят: чаще всего она
смотрит на тот же /healthz, только с более щедрым лимитом попыток.
Зачем разделять
Разделение даёт правильное поведение в трёх случаях:
- Долгий запуск. Startup-проверка держит liveness и readiness выключенными, пока приложение поднимается, и не даёт зациклить перезапуски.
- Прогрев после запуска. Приложение уже стартовало, но ещё
наполняет кеш: liveness
200(не перезапускать), readiness ещё нет (не слать трафик). Без readiness балансировщик завалил бы непрогретую копию запросами. - Временный сбой зависимости. База моргнула. Readiness ушёл в
«не готов», трафик перетёк на другие копии, копию не перезапустили. Когда
база вернулась, readiness снова
200.
Если бы liveness ходил в базу, такой сбой устроил бы каскад перезапусков на ровном месте.
Связь с выкатом
Readiness замыкает прошлые уроки. Rolling и canary полагаются на него:
новую копию начинают грузить трафиком, только когда её readiness стал
200. А graceful shutdown наоборот: при SIGTERM приложение переводит
readiness в «не готов», балансировщик убирает его из ротации, и дренаж
проходит без потерянных запросов.
Что важно запомнить
Приложение отдаёт health-эндпоинты, чтобы оркестратор и балансировщик знали его состояние по сети. Liveness отвечает «живо ли» (провал → перезапуск) и делается простым, без зависимостей.
Readiness отвечает «готово ли к трафику» (провал → убрать из ротации) и как раз проверяет базу и очереди. Разделение спасает при старте и временных сбоях зависимостей.
Startup отвечает «запустилось ли» и работает только в начале жизни копии: пока она не прошла, liveness и readiness не выполняются. Так медленный старт не превращается в бесконечный перезапуск, а liveness после прогрева остаётся быстрым.
Выкат грузит копию трафиком по readiness, а graceful shutdown переводит readiness в «не готов» перед дренажом.
В следующем уроке разберём 12-factor конфигурацию: как держать настройки в окружении.
Прошли материал до конца? Отметьте урок пройденным.
Прогресс сохранён в этом браузере
Почистишь историю или откроешь с телефона, и отметки пропадут. Оставь почту, они переедут в аккаунт. Пароль придумывать не нужно.
Готово. теперь в аккаунте: прогресс виден с любого устройства. Мой прогресс