Readiness, liveness и startup: почему перезапуск мешает приложению запуститься

Приложение загружает справочники и открывает HTTP-порт только через минуту. Контейнер каждые тридцать секунд перезапускается, и до рабочего состояния дело не доходит. В журнале нет необработанного исключения. Такой цикл может создавать Kubernetes: слишком ранняя liveness probe решает, что процесс завис. Добавление реплик повторит проблему на каждом новом экземпляре.

Сначала устанавливаем причину перезапуска

kubectl -n demo describe pod api-7d9b8f-demo
kubectl -n demo logs api-7d9b8f-demo -c api --previous
kubectl -n demo get pod api-7d9b8f-demo -o yaml

В describe сопоставьте Unhealthy и Killing с временем старта контейнера. В YAML посмотрите restartCount и lastState.terminated. Причина OOMKilled требует проверки памяти; сам факт перезапуска ещё не указывает на probe. Ключ --previous запрашивает журнал предыдущего экземпляра контейнера и особенно полезен, когда текущий снова находится в начале прогрева. Данные этого журнала могут уже отсутствовать после дальнейших пересозданий Pod.

Три вопроса вместо одного универсального health

Startup probe отвечает: завершился ли начальный запуск? Пока она не стала успешной, Kubernetes не начинает liveness и readiness проверки этого контейнера. Если старт не уложился в допустимое число неудач, контейнер перезапускается в соответствии с политикой перезапуска. Это позволяет дать долгому прогреву отдельный бюджет, сохранив быструю реакцию на зависание после запуска.

Readiness probe отвечает: можно ли сейчас направить этому экземпляру запрос? Неуспешная проверка делает контейнер неготовым и влияет на готовность Pod. Для обычного Service такой Pod не используется как готовая цель. Контейнер при этом продолжает работать. Liveness probe отвечает на другой вопрос: поможет ли перезапуск устранить состояние процесса? После установленного порога неудач kubelet завершает контейнер и применяет restartPolicy.

Проверка внешней базы в liveness часто создаёт массовые перезапуски при общей аварии PostgreSQL. Процессы теряют соединения и повторно прогреваются, хотя проблема находится вне них. Зависимость может учитываться в readiness, если без неё приложение действительно не обслуживает запросы. Однако выпадение всех реплик тоже нужно продумать: очередь, возврат ошибки и частичная функциональность зависят от устройства сервиса.

Пример настроек для HTTP-приложения

Следующий фрагмент добавляется к контейнеру api в шаблоне Deployment. Приложение должно реализовать три указанных маршрута на порту 8080. /startupz становится успешным после прогрева, /readyz — при возможности обслужить запрос, /livez — когда основной цикл приложения способен продолжать работу. Kubernetes не создаёт эти маршруты за приложение.

ports:
  - name: http
    containerPort: 8080
startupProbe:
  httpGet:
    path: /startupz
    port: http
  periodSeconds: 5
  timeoutSeconds: 2
  failureThreshold: 24
readinessProbe:
  httpGet:
    path: /readyz
    port: http
  periodSeconds: 5
  timeoutSeconds: 2
  failureThreshold: 2
livenessProbe:
  httpGet:
    path: /livez
    port: http
  periodSeconds: 10
  timeoutSeconds: 2
  failureThreshold: 3

У startup задан ориентировочный бюджет 24 × 5 = 120 секунд. Выбирайте его по измеренному медленному запуску с запасом, а не по обычному локальному старту. Это оценка бюджета проверки, а не обещание точного момента перезапуска: есть длительность запросов, планирование проверок и завершение контейнера. Timeout ограничивает отдельный запрос. Readiness с двумя неудачами допускает краткий сбой перед исключением экземпляра; подходящий порог определяется допустимым временем ошибок.

Проверяем поведение, которое хотели получить

На тестовом окружении наблюдайте за новым Pod во время холодного старта. До завершения startup счётчик перезапусков должен оставаться прежним, а приложение ещё не должно получать обычный сервисный трафик. После прогрева Ready меняется на True. Затем проверяйте временную потерю готовности отдельно от зависания процесса: в первом случае ожидается смена готовности без перезапуска, во втором — событие liveness и новый старт контейнера.

kubectl -n demo get pods -w
kubectl -n demo get endpointslice -l kubernetes.io/service-name=api -o yaml

В EndpointSlice смотрите conditions.ready у адресов, соответствующих Pod. Если у Service включён publishNotReadyAddresses, обычные ожидания маршрутизации меняются; это отдельная настройка, которую стоит проверить перед экспериментом. Успешный HTTP-ответ probe тоже должен иметь смысл: статическая страница веб-сервера не доказывает, что рабочий обработчик запросов жив.

HTTP-проверка выполняется kubelet по адресу Pod, поэтому маршрут должен быть доступен снаружи процесса, а не только через localhost внутри контейнера. Проверьте адрес прослушивания и порт. Если боевой вход идёт через reverse proxy, probe к приложению может обходить этот proxy: успешная проверка тогда не подтверждает весь внешний путь. Выберите точку проверки осознанно, чтобы исключение Pod действительно соответствовало его способности обслуживать порученную работу.

Нагрузку от самих probes тоже стоит учитывать. Запрос каждые несколько секунд на каждой реплике не должен запускать тяжёлый запрос ко всем таблицам базы. Лучше возвращать уже известное приложению состояние необходимых компонентов с ограниченным временем ожидания. Для диагностики сохраняйте причину неготовности в журнале и метрике, не отдавая секреты в HTTP-ответе. При отказе это поможет отличить долгий прогрев от потерянного соединения и выбрать действие без немедленного увеличения всех тайм-аутов.

После исправления сохраните длительность холодного старта, выбранный бюджет и признаки обоих отказов. Такой набор объясняет, зачем существуют три маршрута, и помогает следующему разработчику не заменить их одним «удобным» URL.

Ещё по теме

Продолжить изучение

Хотите увереннее разворачивать приложения и разбирать сбои в кластере? Сети, конфигурация, хранилища и обновления входят в программу «Kubernetes с нуля до PRO».

Продолжить на практике

  • Kubernetes с нуля до PRO ↗

    Разворачивайте и сопровождайте приложения в Kubernetes: от первого Pod до релизов, сетей, хранилищ, масштабирования и диагностики. Итоговый проект — сервис с базой данных, мониторингом и проверенным откатом.