🐳 Раздел 14 · Вопрос #18

Что такое readiness probe

В отличие от Liveness Probe, Readiness Probe НИКОГДА не убивает и не перезапускает контейнер:


🟢 Junior Level

30-секундный ответ

Readiness Probe (Проба готовности) — это диагностический механизм Kubernetes, с помощью которого агент kubelet непрерывно проверяет, готово ли приложение внутри пода принимать и обрабатывать входящий сетевой трафик от пользователей.

В отличие от Liveness Probe, Readiness Probe НИКОГДА не убивает и не перезапускает контейнер:

  • Если проба готовности провалилась, Kubernetes делает только одно действие: временно исключает IP-адрес этого пода из балансировки сервиса (Endpoints / EndpointSlice).
  • Пользовательский трафик перестаёт поступать на проблемный под и перенаправляется на соседние здоровые реплики.
  • Как только приложение прогреется или освободит внутренние очереди, проба снова станет успешной, и Kubernetes автоматически вернёт под обратно в балансировку.

Наглядная аналогия из жизни

Readiness Probe — это табличка «ПЕРЕРЫВ 10 МИНУТ» на кассе супермаркета:

  • Кассир жив, здоров и не уволен (контейнер не перезапускается).
  • Но прямо сейчас кассир меняет кассовую ленту или пересчитывает наличные (прогрев кэша, подключение к БД).
  • Очередь покупателей направляется к соседним работающим кассам (трафик уходит на другие поды).
  • Как только кассир готов, табличка убирается, и касса снова принимает покупателей.

Базовый манифест для Spring Boot 3

apiVersion: v1
kind: Pod
metadata:
  name: order-service
spec:
  containers:
  - name: order-app
    image: order-service:1.0
    readinessProbe:
      httpGet:
        path: /actuator/health/readiness # Эндпоинт готовности Spring Boot Actuator
        port: 8080
      initialDelaySeconds: 15 # Пауза перед первой проверкой
      periodSeconds: 5        # Проверять каждые 5 секунд
      failureThreshold: 2     # Исключить из трафика после 2 неудач подряд
      successThreshold: 1     # Вернуть в трафик после 1 первого успеха

В выводе kubectl get pods статус готовности виден в столбце READY:

  • 1/1 Running — под готов и принимает трафик.
  • 0/1 Running — процесс запущен, но трафик на него НЕ идёт (провал readiness probe).

🟡 Middle Level

Роль Readiness Probe в Rolling Update (Zero Downtime)

Без настройки Readiness Probe обеспечить развёртывание без простоя (Zero Downtime Deployment) невозможно:

  1. Вы раскатываете новую версию v2.
  2. Контейнер запустился в Linux, процесс Java получил PID, и Kubernetes видит статус Running.
  3. Если пробы готовности нет, Kubernetes с первой же секунды начинает слать запросы пользователей на новый под, хотя JVM ещё даже не загрузила Spring ApplicationContext!
  4. Пользователи получают поток ошибок 502 Bad Gateway и Connection Refused.
  5. С Readiness Probe: Kubernetes ждёт, пока под вернёт HTTP 200 на /actuator/health/readiness, и только после этого плавно переключает трафик со старой версии на новую.

Фундаментальные отличия: Liveness vs Readiness

                       +─────────────────────────────────+
                       |           ПРОБА УПАЛА           |
                       +────────────────┬────────────────+
                                        │
             ┌──────────────────────────┴──────────────────────────┐
             ▼                                                     ▼
     [ Liveness Probe ]                                    [ Readiness Probe ]
     - Жёсткое действие                                    - Мягкое действие
     - 🔴 ПЕРЕЗАПУСК КОНТЕЙНЕРА                           - 🟡 ОТКЛЮЧЕНИЕ СЕТЕВОГО ТРАФИКА
     - Для снятия дедлоков и зависаний                     - Для прогрева и защиты от перегрузки
Характеристика Liveness Probe Readiness Probe
Реакция на ошибку Принудительный перезапуск контейнера (kill) Удаление IP из Endpoints (изоляция от трафика)
Жизненный цикл пода Контейнер рестартится, память очищается Под продолжает работать и выполнять фоновые задачи
Что проверять Внутренний жизненный цикл процесса (Deadlock) Готовность пулов соединений, кэшей, очередей
Влияние на деплой Не влияет на переключение версий Блокирует Rolling Update до полной готовности

Spring Boot 3 ReadinessState в коде

Spring Boot 3 автоматически управляет компонентом ReadinessState:

  • ReadinessState.ACCEPTING_TRAFFIC: контекст поднят, все бины инициализированы, ликвидность пулов подтверждена. Actuator возвращает HTTP 200 OK.
  • ReadinessState.REFUSING_TRAFFIC: сервис временно не готов. Actuator возвращает HTTP 503 Service Unavailable.

Разработчик может временно снять под с балансировки на время фоновой операции (например, прогрева локального кэша Caffeine):

@Service
public class CacheWarmupService {

    private final ApplicationEventPublisher eventPublisher;

    public CacheWarmupService(ApplicationEventPublisher eventPublisher) {
        this.eventPublisher = eventPublisher;
    }

    public void reloadLargeDictionary() {
        // 1. Временно отключаем трафик от K8s
        AvailabilityChangeEvent.publish(eventPublisher, this, ReadinessState.REFUSING_TRAFFIC);
        
        try {
            // 2. Выполняем тяжелую загрузку данных из БД в память
            loadMillionRecordsIntoCache();
        } finally {
            // 3. Возвращаем под в балансировку
            AvailabilityChangeEvent.publish(eventPublisher, this, ReadinessState.ACCEPTING_TRAFFIC);
        }
    }
}

🔴 Senior Level

Задержка распространения правил и PreStop Hook

Senior-инженер обязан знать, что удаление пода из балансировщика происходит асинхронно:

  1. Kubelet фиксирует провал пробы и шлёт отчет в kube-apiserver (~1 сек).
  2. EndpointSlice Controller обновляет объект EndpointSlice (~1 сек).
  3. Агент kube-proxy на всех нодах кластера пересчитывает правила iptables / IPVS (~1–3 сек).
  4. Суммарный лаг составляет от 2 до 5 секунд! В течение этих 3 секунд входящие пакеты от клиентов всё ещё летят в сокет пода.

Архитектурное решение: тандем Readiness + PreStop Hook

Чтобы при остановке пода не потерять ни одного клиентского запроса:

lifecycle:
  preStop:
    exec:
      command: ["sh", "-c", "sleep 10"] # Пауза в 10 секунд перед отправкой SIGTERM

Во время 10-секундного сна Kubelet успевает гарантированно обновить iptables на всех серверах кластера, трафик перестаёт поступать, и лишь затем Spring Boot получает сигнал SIGTERM и начинает graceful shutdown.


Readiness Gates (Внешние шлюзы готовности)

В современных облачных средах (AWS EKS с ALB Ingress Controller или Google Cloud GKE) стандартной проверки Kubelet недостаточно:

  • Kubelet проверил локальный порт пода и считает его готовым (PodReady=True).
  • Однако внешний балансировщик AWS ALB ещё не успел зарегистрировать IP пода в своей целевой группе (Target Group) и провести собственную проверку здоровья.
  • Трафик, приходящий через Ingress, обрывается.

Для решения этой проблемы используются Readiness Gates:

spec:
  readinessGates:
  - conditionType: "target-health.elbv2.k8s.aws/v2" # Внешний флаг готовности

Под не перейдёт в статус Ready до тех пор, пока облачный контроллер AWS ALB не подтвердит, что под успешно зарегистрирован во внешнем балансировщике нагрузки!


Опасность проверки БД в Readiness (Каскадный отказ)

Классическая ловушка на Highload-проектах:

  • Если 200 подов проверяют доступность PostgreSQL в Readiness Probe, то при кратковременной деградации БД (например, блокировка таблицы) все 200 подов одновременно вернут HTTP 503.
  • Kubernetes моментально очистит Endpoints сервиса до нуля.
  • Вся система моментально ляжет с ошибкой 503 Service Temporarily Unavailable для 100% пользователей. Best Practice: В Readiness Probe проверяются только локальные критические ресурсы (свободная память, состояние пула потоков Tomcat). Для баз данных используется Circuit Breaker (Resilience4j): если база тормозит, под остаётся в балансировке и отдаёт пользователю кэшированные данные или понятный Fallback.

4 Tricky Questions

1. Почему для обеспечения 100% Zero-Downtime при Rolling Update одного readinessProbe недостаточно, и обязательно требуется preStop hook с командой sleep?

Ответ: События удаления пода и обновления сетевых правил происходят в Kubernetes параллельно и независимо:

  1. При удалении пода Kubelet немедленно отправляет процессору контейнера сигнал SIGTERM, и Spring Boot начинает останавливать контекст и закрывать сокеты.
  2. Одновременно с этим kube-apiserver отправляет событие об удалении пода контроллеру EndpointSlice, который передаёт команду агентам kube-proxy на десятках нод переписать правила iptables.
  3. Обновление сетевых таблиц iptables занимает от 1 до 4 секунд.
  4. В этот промежуток времени клиенты продолжают отправлять запросы на умирающий под, чьи порты уже закрыты процессом Spring Boot, в результате чего пользователи получают ошибки Connection Refused.
  5. Добавление preStop: exec: command: ["sh", "-c", "sleep 10"] искусственно задерживает отправку SIGTERM на 10 секунд, гарантируя, что правила iptables успеют обновиться на всех нодах и трафик прекратится ДО того, как процесс начнёт завершаться.

2. Что произойдёт с сетевым трафиком и состоянием пода, если readinessProbe возвращает ошибку (HTTP 500), а livenessProbe в этот же момент возвращает успех (HTTP 200)?

Ответ:

  1. Состояние контейнера: контейнер НЕ будет перезапущен, он продолжит спокойно работать в памяти. В выводе kubectl get pods статус останется Running, но счетчик готовности изменится на 0/1 READY.
  2. Сетевой трафик: контроллер Kubernetes исключит IP-адрес этого пода из списков Endpoints и EndpointSlice всех ассоциированных сервисов.
  3. Результат: ни один внешний запрос через ClusterIP, NodePort или Ingress больше не поступит на этот контейнер. Однако сам контейнер сохранит возможность отправлять исходящие запросы во внешние системы и продолжать обработку внутренних фоновых очередей.

3. Для чего используется параметр successThreshold в конфигурации readinessProbe, и почему по умолчанию он равен 1?

Ответ:

  • successThreshold определяет количество последовательных успешных проверок подряд, которые должно вернуть приложение, прежде чем Kubernetes сочтёт под готовым и вернёт его IP-адрес в балансировку трафика.
  • Значение по умолчанию равно 1, чтобы минимизировать задержку ввода нового прогретого пода в эксплуатацию.
  • Однако при нестабильных нагрузках или волнообразном прогреве (когда сервис кратковременно отвечает успехом, а затем снова проседает) увеличение successThreshold: 2 или 3 защищает сервис от преждевременной подачи пользовательского трафика на ещё не до конца стабилизировавшийся инстанс.

4. Влияет ли провал readinessProbe на работу механизма Headless Service (clusterIP: None)?

Ответ: Да, напрямую влияет. Для Headless Service DNS-сервер CoreDNS формирует A-записи на основе списка адресов в объекте Endpoints. Если под проваливает readinessProbe:

  • Его IP-адрес удаляется из секции subsets.addresses и перемещается в секцию subsets.notReadyAddresses.
  • CoreDNS перестаёт возвращать IP-адрес этого пода в стандартных DNS-запросах.
  • Однако если в спецификации Headless Service явно активирован флаг publishNotReadyAddresses: true, CoreDNS продолжит отдавать IP-адрес не готового пода (это используется специализированными кластерными системами, например, для репликации логов в кластере Elasticsearch или etcd до того, как нода станет готова обслуживать клиентские запросы).

🎯 Шпаргалка для интервью

Главное о Readiness Probe

  • Назначение: проверка готовности принимать сетевой трафик пользователей.
  • Действие при сбое: удаление IP из Endpoints / EndpointSlice; контейнер НЕ перезапускается!
  • Zero Downtime: блокирует переключение трафика во время Rolling Update до полной готовности новой версии.
  • Связка с PreStop: связка readinessProbe + preStop: sleep 10 предотвращает потерю запросов из-за лага обновления iptables (2–4 сек).
  • Spring Boot 3 Actuator: стандартный эндпоинт /actuator/health/readiness (ReadinessState).
  • Readiness Gates: ожидание проверки готовности внешними облачными балансировщиками (AWS ALB Target Group).
  • Anti-Pattern: проверка общей БД всеми подами разом (грозит отключением 100% подов при сбое БД).

Сводная таблица поведения проверок

| Проверка | Действие при отказе | Влияет на статус READY? | Влияет на работу процесса? | | :— | :— | :—: | :—: | | livenessProbe | Принудительный перезапуск | ❌ Нет | 🔴 Процесс убивается (SIGKILL) | | readinessProbe| Отключение от сервиса | 🟢 Да (0/1 READY) | 🟢 Процесс продолжает работать | | startupProbe | Принудительный перезапуск | 🟢 Да (0/1 READY) | 🔴 Процесс убивается при превышении таймаута |

Красные флаги на собеседовании (Чего говорить нельзя)

  • ❌ «Если readinessProbe падает 3 раза подряд, Kubernetes перезапускает под» — грубая ошибка, перезапуском занимается только Liveness/Startup.
  • ❌ «Если под перешёл в статус Running, значит он уже может принимать трафик без readinessProbe» — статус Running означает лишь то, что контейнер создан в Linux, Java может грузиться ещё 60 секунд.
  • ❌ «ReadinessProbe проверяет только внешние сетевые порты» — проба может выполнять HTTP GET, TCP socket, gRPC или exec-команды.

Связанные вопросы