Контейнер в состоянии Running не означает, что приложение работает корректно: процесс может зависнуть, не завершить инициализацию или потерять соединение с БД. Probes дают kubelet сигнал о реальном состоянии приложения.
[source: kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes]
Три типа проб
livenessProbe
Проверяет, жив ли процесс. Если проверка проваливается — kubelet перезапускает контейнер. Применяется, когда приложение может зависнуть (deadlock, бесконечный цикл), но процесс продолжает работать.
spec:
containers:
- name: app
image: myapp:1.0
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 10
periodSeconds: 15
timeoutSeconds: 3
failureThreshold: 3
readinessProbe
Проверяет, готово ли приложение принимать трафик. При провале Pod убирается из EndpointSlice Service (трафик перестаёт поступать), контейнер не перезапускается. Применяется при загрузке кеша, прогреве соединений, инициализации данных.
spec:
containers:
- name: app
image: myapp:1.0
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 2
failureThreshold: 3
successThreshold: 1
startupProbe
Проверяет, завершился ли запуск. Пока startupProbe не пройдёт — livenessProbe и readinessProbe не запускаются. Для приложений с долгой инициализацией: загрузка ML-моделей, прогрев кеша, миграции при старте.
spec:
containers:
- name: app
image: myapp:1.0
startupProbe:
httpGet:
path: /healthz
port: 8080
periodSeconds: 10
failureThreshold: 30 # 30 × 10 = 300 секунд максимум на запуск
livenessProbe:
httpGet:
path: /healthz
port: 8080
periodSeconds: 15
timeoutSeconds: 3
failureThreshold: 3
Без startupProbe для медленного приложения приходится ставить большой initialDelaySeconds у livenessProbe — это маскирует реальные зависания после старта.
Методы проверки
httpGet
HTTP GET запрос. Успех — код ответа 200–399.
livenessProbe:
httpGet:
path: /healthz
port: 8080
httpHeaders:
- name: X-Custom-Header
value: healthcheck
tcpSocket
Проверка TCP-соединения. Успех — порт открыт и принимает соединения.
livenessProbe:
tcpSocket:
port: 3306
Подходит для сервисов без HTTP-эндпоинта: базы данных, кеши.
exec
Выполнение команды внутри контейнера. Успех — exit code 0.
livenessProbe:
exec:
command:
- cat
- /tmp/healthy
grpc
Проверка через gRPC Health Checking Protocol (K8s 1.24+, GA в 1.27):
livenessProbe:
grpc:
port: 50051
service: "grpc.health.v1.Health"
[source: kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#define-a-grpc-liveness-probe]
Параметры проб
Полный пример со всеми пробами
apiVersion: v1
kind: Pod
metadata:
name: robust-app
spec:
containers:
- name: app
image: myapp:1.0
ports:
- containerPort: 8080
startupProbe:
httpGet:
path: /healthz
port: 8080
periodSeconds: 5
failureThreshold: 60 # до 5 минут на запуск
livenessProbe:
httpGet:
path: /healthz
port: 8080
periodSeconds: 15
timeoutSeconds: 3
failureThreshold: 3
readinessProbe:
httpGet:
path: /ready
port: 8080
periodSeconds: 10
timeoutSeconds: 2
failureThreshold: 3
successThreshold: 1
Сводка: три пробы
Когда использовать
livenessProbe — для приложений, которые могут зависнуть без падения процесса.
readinessProbe — для любого приложения, принимающего трафик. Без неё Pod попадает в EndpointSlice сразу после старта контейнера — пользователи получают 502/503.
startupProbe — для приложений с initialDelaySeconds у livenessProbe > 30 секунд. Заменяет костыль с большим initial delay на явную проверку старта.
/healthz для liveness должен проверять только внутреннее состояние (deadlock, corrupted state). /ready для readiness может проверять внешние зависимости (соединение с БД, наполненность кеша).
Типичные ошибки
livenessProbe проверяет внешние зависимости. Если liveness проверяет подключение к БД — при её недоступности все Pod начнут перезапускаться, усугубляя ситуацию. liveness должна проверять только внутреннее состояние процесса.
failureThreshold = 1 у livenessProbe. Один сетевой сбой или GC-пауза — и контейнер перезапускается. Минимум failureThreshold: 3.
readinessProbe не настроена. Pod сразу получает трафик — пользователи видят ошибки пока приложение инициализируется.
Нет startupProbe у медленного приложения. При initialDelaySeconds: 120 liveness потом проверяет каждые 10-15 секунд — зависание обнаруживается с задержкой.
timeoutSeconds слишком мал. По умолчанию 1 секунда. Если эндпоинт иногда отвечает за 1.5 секунды под нагрузкой — probe ложно фейлит. Ставь 2-3 секунды.
Один эндпоинт для liveness и readiness. Смешивать — значит либо рестартовать при проблемах с БД, либо не убирать из ротации неготовый Pod.
Альтернативы
Readiness на основе метрик Prometheus (lag очереди, error rate) вместо HTTP 200. Требует кастомной логики в приложении.
Lifecycle hooks (postStart, preStop) — дополняют probes: preStop даёт приложению время завершить обработку запросов перед остановкой контейнера.
lifecycle:
preStop:
exec:
command: ["sh", "-c", "sleep 5"] # дать время на drain соединений