Probes: liveness, readiness, startup

↑ Этап 5 · Kubernetes

Желательно~6 мин чтенияУровень: middle

Зачем это на собесе

Неправильные probes — частая причина каскадных перезапусков и потери трафика; спрашивают различия трёх типов.

Три вида проб

ProbeВопросПри провале
startupProbeприложение уже запустилось?пока не пройдена, liveness/readiness не выполняются; после failureThreshold — контейнер убивается
livenessProbeприложение живо (не зависло)?kubelet перезапускает контейнер
readinessProbeготово принимать трафик?под исключается из Endpoints Service (трафик не идёт), контейнер не перезапускается

Способы: httpGet (код 200–399), tcpSocket (порт открыт), exec (команда, код 0), grpc (стандартный gRPC Health Checking).

containers:
  - name: app
    image: registry.example.com/clinic/api:1.4.2
    ports: [{ name: http, containerPort: 8080 }]
    startupProbe:
      httpGet: { path: /health/startup, port: http }
      periodSeconds: 5
      failureThreshold: 30            # до 150 с на старт
    livenessProbe:
      httpGet: { path: /health/live, port: http }
      periodSeconds: 10
      timeoutSeconds: 2
      failureThreshold: 3
    readinessProbe:
      httpGet: { path: /health/ready, port: http }
      periodSeconds: 5
      timeoutSeconds: 2
      failureThreshold: 3
      successThreshold: 1

Параметры: initialDelaySeconds, periodSeconds, timeoutSeconds, successThreshold, failureThreshold, terminationGracePeriodSeconds (для probe).

Что проверять

Liveness: «процесс жив и способен отвечать» — лёгкая проверка без внешних зависимостей (не БД, не другие сервисы!). Цель — выявить «зависание» (deadlock, исчерпан пул потоков). Если liveness зависит от БД, то при сбое БД все поды начнут перезапускаться: каскадный отказ и усугубление инцидента.

Readiness: «можно ли сейчас направлять запросы»: инициализация завершена, прогрев кэша, соединения с критичными зависимостями установлены; может учитывать БД/кэш (тогда при сбое зависимости под выводится из балансировки, но не убивается). Временная перегрузка: readiness может возвращать 503, чтобы сбросить нагрузку.

Startup: для медленных приложений (.NET с прогревом, JVM): защищает от преждевременного liveness; даёт большое окно запуска без увеличения initialDelaySeconds.

ASP.NET Core Health Checks

builder.Services.AddHealthChecks()
    .AddCheck("self", () => HealthCheckResult.Healthy(), tags: new[] { "live" })
    .AddNpgSql(connectionString, tags: new[] { "ready" })
    .AddRedis(redisConnection, tags: new[] { "ready" });
 
app.MapHealthChecks("/health/live",  new HealthCheckOptions { Predicate = r => r.Tags.Contains("live") });
app.MapHealthChecks("/health/ready", new HealthCheckOptions { Predicate = r => r.Tags.Contains("ready") });

Типичные ошибки

ОшибкаПоследствие
Нет readinessтрафик идёт на под до готовности → 5xx при деплое
Liveness проверяет БД/зависимостикаскадные перезапуски при сбое зависимости
Слишком агрессивные пороги (timeoutSeconds: 1, failureThreshold: 1)ложные перезапуски под нагрузкой (GC-паузы, CPU throttling)
Одинаковые liveness и readinessнельзя отделить «не готов» от «завис»
Нет startupProbe у медленного приложенияперезапуски в цикле во время старта (CrashLoopBackOff)
Probe на тяжёлый эндпоинтсоздаёт нагрузку, ложные отказы
Probe проходит через Ingress/аутентификациюпробы — напрямую на под, без авторизации
Прослушивание 127.0.0.1kubelet обращается к IP пода: probe не проходит
Не учтён graceful shutdownпри остановке readiness должна стать «не готов» до закрытия

Probes и rolling update

Поток трафика на новый под начинается после readiness (и minReadySeconds); пока нет — Deployment не считает под доступным; неудачный rollout останавливается (progressDeadlineSeconds). При остановке пода: readiness → «не готов», удаляется из Endpoints (есть задержка распространения → preStop sleep), SIGTERM, graceful shutdown.

Graceful shutdown

lifecycle:
  preStop: { exec: { command: ["sh", "-c", "sleep 10"] } }     # даём время убраться из Endpoints/LB
terminationGracePeriodSeconds: 45                              # > preStop + время завершения запросов

В приложении: обработка SIGTERM, переключение readiness на «не готов», завершение запросов (ShutdownTimeout .NET < terminationGracePeriodSeconds).

Диагностика

kubectl describe pod api-xxx          # Events: Liveness probe failed: HTTP probe failed with statuscode: 503 / Readiness probe failed / Startup probe failed
kubectl get pod api-xxx -o jsonpath='{.status.containerStatuses[0].restartCount}'
kubectl logs api-xxx --previous
kubectl get endpoints api             # список готовых адресов
kubectl exec -it api-xxx -- wget -qO- localhost:8080/health/ready

Причины провала: медленный старт, нехватка CPU (throttling) → таймауты, миграции при старте, зависимость недоступна, неверный путь/порт, аутентификация на health-эндпоинте, перегрузка пула потоков.

Практики

  • три пробы по назначению, отдельные эндпоинты; лёгкие и быстрые (< 100 мс);
  • liveness — без внешних зависимостей; readiness — с критичными;
  • разумные пороги (failureThreshold ≥ 3, timeoutSeconds 2–5);
  • startupProbe для медленного старта;
  • метрики: число перезапусков, готовность подов, время до Ready; алерты;
  • на health-эндпоинтах не использовать аутентификацию и не логировать на каждый запрос (шум);
  • нагрузочно проверять поведение при сбое зависимости.

Вопросы с ответами