Timing параметры probes: tuning
Любой probe (liveness / readiness / startup) — это handler плюс пять параметров timing, которые управляют его поведением во времени. Не зная этих параметров наизусть, нельзя ни настроить production probes, ни решить CKAD-задачу про tuning. Все timing значения — integer-секунды, минимум 1 (где допустимо 0 — указано).
systemctl: управление сервисами в повседневной работе
Пять параметров
| Параметр | Default | Минимум | Что значит |
|---|---|---|---|
initialDelaySeconds | 0 | 0 | Задержка перед первой пробой после старта контейнера |
periodSeconds | 10 | 1 | Интервал между пробами |
timeoutSeconds | 1 | 1 | Таймаут на выполнение одной пробы |
successThreshold | 1 | 1 | Сколько подряд успешных проб для перехода в healthy |
failureThreshold | 3 | 1 | Сколько подряд неуспешных проб для перехода в unhealthy |
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 0
periodSeconds: 10
timeoutSeconds: 1
successThreshold: 1
failureThreshold: 3
Для liveness и startup probes successThreshold ОБЯЗАН быть 1. API server отвергнет другое значение. Логика: liveness/startup управляют lifecycle контейнера, и «один success достаточно, чтобы считать живым» — единственная разумная семантика. Изменять successThreshold имеет смысл только в readiness.
Effective unhealthy time: главная формула
Сколько времени реально пройдёт от момента «что-то сломалось» до действия kubelet? Грубая формула:
Effective unhealthy time = initialDelaySeconds + (failureThreshold × periodSeconds)
С default значениями для liveness: 0 + (3 × 10) = 30 секунд от старта контейнера до возможного первого restart (если probe сразу fail-ит). От момента поломки в healthy контейнере — failureThreshold × periodSeconds = 30 секунд. Точнее, формула — (failureThreshold - 1) × periodSeconds + periodSeconds — есть нюансы по округлению, но 30 — нормальное приближение.
tuning сценариев
Slow-starting app (Java, миграции БД)
Вместо initialDelaySeconds на liveness — startupProbe с большим failureThreshold:
startupProbe:
httpGet:
path: /healthz
port: 8080
failureThreshold: 30
periodSeconds: 10
# max startup time = 30 × 10s = 5 minutes
livenessProbe:
httpGet:
path: /healthz
port: 8080
periodSeconds: 10
failureThreshold: 3
# after startup PASS, default aggressive liveness: 30s to restart
Идея: startupProbe защищает первую фазу (до 5 минут на startup), потом liveness агрессивно следит за зависаниями. Без startup пришлось бы поставить initialDelaySeconds: 300 на liveness — но тогда первые 5 минут зависший контейнер живёт без присмотра.
High-traffic readiness
Для readinessProbe на горячем path хочется быстрее реагировать на degradation:
readinessProbe:
httpGet:
path: /ready
port: 8080
periodSeconds: 3 # чаще проверять
failureThreshold: 2 # быстрее выводить из ротации
successThreshold: 2 # но не флапать обратно
successThreshold: 2 (два подряд PASS, чтобы вернуть в Endpoints) — анти-flapping. Без этого: одна успешная проба возвращает Pod, следующая снова fail-ит, snap из Endpoints — Service постоянно дёргает контроллера Endpoints.
periodSeconds: 1 теоретически возможен, но создаёт реальный overhead: на каждый exec — fork() в контейнере, на каждый httpGet — TCP-соединение и HTTP-парсинг от kubelet. На больших кластерах (тысячи Pods × три probes × 1Hz) это нагрузка на kubelet и на dataplane. Не уходите ниже periodSeconds: 5 без явной причины.
Cascading restart avoidance
В multi-container Pod (или в большом Deployment) все контейнеры с одинаковыми timing просыпаются синхронно — periodic spike нагрузки на app каждые periodSeconds. Сдвиньте periodSeconds на разных контейнерах (или используйте легкий handler), чтобы probes не били app одновременно.
timeoutSeconds: подводный камень
Default timeoutSeconds: 1. Это значит, что если app не отвечает за секунду — probe FAIL.
На loaded app, особенно с GC pauses (Java) или event-loop blocking (Node.js), 1-секундный timeout даёт false-positives. Probe видит app как мёртвого, при том что он просто секунду занят. Restart loop под нагрузкой — типовая авария.
livenessProbe:
httpGet:
path: /healthz
port: 8080
timeoutSeconds: 3 # не 1 — даём app дышать
periodSeconds: 10
failureThreshold: 3
До Kubernetes 1.20 timeoutSeconds для exec probe игнорировался kubelet-ом — probe мог висеть вечно. С 1.20 эта бага исправлена, теперь exec тоже соблюдает timeout. Если у вас старая конфигурация (наследие 1.18-) — проверьте, что timeout adequate для команды.
CKAD: типовое задание про tuning
Формулировка: «Deployment X на slow-starting app зацикливается на restart-ах. Tune probes так, чтобы дать ему 4 минуты на startup, но после этого быстро ловить зависание.»
Канонический ответ:
spec:
containers:
- name: app
image: ...
startupProbe:
httpGet:
path: /healthz
port: 8080
failureThreshold: 24 # 24 × 10s = 4 minutes
periodSeconds: 10
livenessProbe:
httpGet:
path: /healthz
port: 8080
periodSeconds: 10
failureThreshold: 3 # 30s on real hang
timeoutSeconds: 2 # not too aggressive
readinessProbe:
httpGet:
path: /ready
port: 8080
periodSeconds: 5
failureThreshold: 3
Главное: startupProbe даёт запас, livenessProbe агрессивно сторожит после startup, readinessProbe независимо рулит трафиком.