🐳 Розділ 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 секунд! Упродовж цих секунд вхідні пакети від клієнтів усе ще летять у сокет пода.

Архітектурне рішення: тандем 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-команди.

Пов’язані питання