Как стать автором
Обновить
582.47
OTUS
Цифровые навыки от ведущих экспертов

Как livenessProbe может убить ваш Pod

Время на прочтение6 мин
Количество просмотров2.7K

Привет, Хабр!

Если вы хоть раз дебажили под, который вроде работает, но Kubernetes его всё равно убивает — добро пожаловать. Сегодня разложим по косточкам, как livenessProbe может угробить ваш сервис в самый беззащитный момент — и как не дать этому случиться.

Сценарий проблемы

Рассмотрим типичный кейс. Есть микросервис, например на Spring Boot или.NET, который при запуске выполняет стандартный набор операций:

  • применяет миграции схемы базы данных (Flyway, Liquibase);

  • загружает конфигурации из внешнего Vault или Consul;

  • устанавливает соединения с Redis, Kafka, S3;

  • прогревает кеш, создаёт фоновые воркеры;

  • и только после этого начинает слушать HTTP‑порт и отдавать /healthz.

Инициализация может занимать от 30 до 60 секунд — особенно на загруженном CI/CD‑кластере, с прогретыми томами и сетевой задержкой к БД.

Теперь посмотрим на фрагмент манифеста:

livenessProbe:
  httpGet:
    path: /healthz
    port: 8080
  initialDelaySeconds: 10
  periodSeconds: 5
  failureThreshold: 2

Что делает kubelet:

  1. Через 10 секунд после старта контейнера запускается первая проверка на /healthz.

  2. Приложение ещё не завершило старт: порт 8080 может не слушаться, эндпоинт /healthz ещё не отвечает.

  3. Первая проверка возвращает connection refused или timeout — это считается ошибкой.

  4. Через 5 секунд — вторая попытка. Ситуация та же: приложение не готово.

  5. Второй фейл подряд. Достигнут failureThreshold = 2 → kubelet считает контейнер «неживым».

  6. Контейнер убивается и перезапускается с нуля.

  7. Цикл повторяется бесконечно.

Суть проблемы: livenessProbe срабатывает до того, как приложение технически готово пройти проверку, и Kubernetes ошибочно считает, что контейнер «завис». Но пофакту контейнер не завис, он просто ещё не успел инициализироваться.

livenessProbe не ждёт, пока приложение будет готово. Она начинает проверки строго по initialDelaySeconds. И если приложение в этот момент ещё не подняло HTTP‑сервер — оно будет считаться «мертвым».

Что ещё усугубляет ситуацию:

  • Эндпоинт /healthz зависит от внешней инфраструктуры: если при старте сервис не может достучаться до БД или Redis, он будет возвращать 500 или 503, даже если сам процесс жив и находится в стабильной инициализации.

  • Параметры пробы подобраны без учёта real‑world‑таймингов: значения вроде initialDelaySeconds: 10 и failureThreshold: 2 подходят для лёгких сервисов, но не для сложных backend‑приложений с цепочкой инициализаций.

  • В CI/CD pipeline нет возможности протестировать пробу под высокой нагрузкой — на слабых узлах с подогретым volume startup может быть заметно медленнее.

Как правильно настраивать пробы

readinessProbe — контроль трафика, а не здоровья

Это первая проба, которую стоит включить в продакшен. Её задача — сообщить Kubernetes, что контейнер ещё не готов обрабатывать запросы, даже если он запущен.

readinessProbe:
  httpGet:
    path: /ready
    port: 8080
  initialDelaySeconds: 15
  periodSeconds: 10
  failureThreshold: 5

Что происходит при отказе: контейнер не будет включён в список endpoints, и сервис не станет направлять на него трафик. Но контейнер останется жив — он не будет перезапущен. Это нужно, если:

  • приложение стартует, но ещё инициализирует зависимости (DB, кеш, внешние API);

  • сервис может пережить временные ошибки, не прерывая работу (например, перегрузка, пауза GC);

  • вы хотите, чтобы временно недоступные поды просто «выпали из балансировки».

use‑case: сервис стартует за 20–30 секунд, но обрабатывать запросы может начать только после 40-й. readinessProbe не даст нагружать его раньше времени.

startupProbe — защита от преждевременного рестарта

Если приложение имеет тяжёлую инициализацию — обязательно добавляйте startupProbe.

startupProbe:
  httpGet:
    path: /healthz
    port: 8080
  periodSeconds: 10
  failureThreshold: 30

Эта конфигурация позволяет приложению стартовать в течение до 5 минут (30 попыток по 10 секунд), прежде чем Kubernetes начнёт применять livenessProbe и readinessProbe.

Пока startupProbe не пройдена, Kubernetes не выполняет другие пробы.

livenessProbe — только после стабилизации поведения

livenessProbe — самая опасная из всех трёх. Её задача — обнаруживать зависшие процессы. Но если она настроена неправильно, она же может и убить живой под.

livenessProbe:
  httpGet:
    path: /healthz
    port: 8080
  initialDelaySeconds: 60
  periodSeconds: 20
  failureThreshold: 3

Параметры initialDelaySeconds: 60, periodSeconds: 20 и failureThreshold: 3 означают, что первая проверка начнётся через минуту после запуска, затем будут попытки каждые 20 секунд, и только три подряд неудачи приведут к перезапуску контейнера.

Если под уходит в рестарты, необходимо понять — какая именно проба срабатывает. Делается это с помощью kubectl describe.

kubectl describe pod <pod-name>

В выводе ищите секции вроде:

Liveness probe failed: HTTP probe failed with statuscode: 500

или

Readiness probe failed: Get http://10.0.1.5:8080/ready: connection refused

Также полезна команда:

kubectl get events --sort-by=.lastTimestamp

Она покажет хронологию всех событий по поду: когда сработала проба, когда был рестарт, какие статусы возвращались.

Пример комбинированной конфигурации

startupProbe:
  httpGet:
    path: /healthz
    port: 8080
  periodSeconds: 10
  failureThreshold: 30

readinessProbe:
  httpGet:
    path: /ready
    port: 8080
  initialDelaySeconds: 5
  periodSeconds: 10
  failureThreshold: 3

livenessProbe:
  httpGet:
    path: /healthz
    port: 8080
  initialDelaySeconds: 60
  periodSeconds: 20
  failureThreshold: 3

Такой шаблон подходит для большинства веб‑приложений, которые:

  • стартуют от 30 до 90 секунд;

  • имеют временные зависимости;

  • должны переживать кратковременные сбои без рестарта.

Ошибки, которых стоит избегать

Неиспользование startupProbe при медленном старте

Если приложение запускается дольше 10–15 секунд — обязательно нужно использовать startupProbe. Без неё Kubernetes может начать выполнять livenessProbe слишком рано, когда сервис ещё инициализируется. В результате — ложные фейлы и перезапуски.

Что происходит:

  • livenessProbe срабатывает до завершения инициализации.

  • Приложение не отвечает вовремя на /healthz.

  • kubelet считает его умершим и перезапускает.

Для этого нужно добавить startupProbe, которая даст приложению больше времени на запуск. Например:

startupProbe:
  httpGet:
    path: /healthz
    port: 8080
  failureThreshold: 30
  periodSeconds: 10

Это даёт до 5 минут на старт (30 × 10 секунд), без риска быть «убитым» раньше времени.

Зависимость /healthz от внешних сервисов

Бывает, что в /healthz вы проверяете всё: базу данных, Redis, очередь сообщений, и даже внешний API. Кажется логичным: пусть он скажет, что «всё работает».

Проблема в другом: эти сервисы могут временно недоступны, а это не означает, что сам ваш сервис «умер». Например, если Redis отвалился на 5 секунд — зачем перезапускать весь контейнер?

Поэтому в livenessProbe проверяйте, работает ли сам процесс: есть ли доступ к памяти, нет ли deadlock»ов, не «завис» ли event loop. А так же проверку внешних зависимостей лучше делать в readinessProbe — чтобы временно выключать под из балансировки, не убивая его.

Пример безопасного liveness‑эндпоинта:

func Healthz(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(http.StatusOK)
}

Возврат 200 OK в /healthz в любом случае

Самая распространённая ошибка — всегда возвращать 200, независимо от состояния сервиса. Да, это удобно на старте, чтобы pod не падал. Но по факту такое поведение лишает смысла все проверки.

Что происходит:

  • /healthz всегда отвечает 200, даже если сервис завис.

  • Kubernetes считает, что всё в порядке.

  • Балансировщик продолжает направлять трафик на нерабочий под.

/healthz должен возвращать 200 только в случае, если сервис действительно работоспособен. При любых сбоях — например, потере соединения с базой, блокировке потоков или внутренней ошибке — следует возвращать 503, чтобы Kubernetes мог адекватно отреагировать.


Если вы работаете с Kubernetes в проде, хорошо знаете его поведение в теории и на практике — возможно, вас заинтересуют открытые уроки, где разберём чуть глубже архитектурные принципы и современные инструменты экосистемы.

Ближайшие темы:

  • 8 апреля — Kubernetes: архитектура и абстракции. Подробнее

  • 17 апреля — Знакомство с Service mesh на примере Istio. Подробнее

Теги:
Хабы:
+6
Комментарии1

Публикации

Информация

Сайт
otus.ru
Дата регистрации
Дата основания
Численность
101–200 человек
Местоположение
Россия
Представитель
OTUS