Три вида проб:
livenessProbe отвечает на вопрос "жив ли процесс". Если проверка проваливается несколько раз подряд, kubelet перезапускает контейнер. readinessProbe отвечает на вопрос "готов ли под принимать трафик". Пока она красная, под исключен из эндпоинтов Service (глава 5), но контейнер никто не трогает. startupProbe придумана для медленно стартующих приложений: пока она не пройдет, две остальные пробы не запускаются вовсе.
Механизм проверки у всех трех общий, на выбор: httpGet (запрос на порт контейнера, успех при ответе 200-399), tcpSocket (достаточно открыть соединение), exec (команда внутри контейнера, успех при коде возврата 0) и grpc для сервисов со стандартным grpc.health.v1.Health (стабильно с Kubernetes 1.27).
Подключаем к Deployment:
Код: Выделить всё
apiVersion: apps/v1
kind: Deployment
metadata:
name: orders-api
spec:
replicas: 3
selector:
matchLabels:
app: orders-api
template:
metadata:
labels:
app: orders-api
spec:
containers:
- name: app
image: orders-api:1.8.2
ports:
- containerPort: 8080
livenessProbe:
httpGet:
path: /healthz
port: 8080
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 3
readinessProbe:
httpGet:
path: /ready
port: 8080
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 2Эндпоинты в примере разные, и это принципиально. /healthz для liveness отвечает только за сам процесс: запрос дошел до обработчика, значит процесс жив. Никаких проверок базы или внешних API там быть не должно. Если liveness ходит в PostgreSQL и база легла, kubelet примется перезапускать все поды по кругу. Базе от этого легче не станет, а у вас вместо одной проблемы будет две. /ready, наоборот, может смотреть глубже: есть ли соединение с базой, прогрет ли кэш, применились ли миграции.
Медленный старт и воркеры без HTTP:
Приложению на JVM или сервису с прогревом кэша за десять секунд не подняться. Для таких случаев startupProbe:
Код: Выделить всё
startupProbe:
httpGet:
path: /healthz
port: 8080
periodSeconds: 5
failureThreshold: 30У фонового воркера может вообще не быть HTTP порта. Выручает exec и прием с heartbeat файлом: процесс периодически обновляет файл, а проба проверяет его свежесть.
Код: Выделить всё
livenessProbe:
exec:
command: ["sh", "-c", "find /tmp/heartbeat -mmin -1 | grep -q ."]
periodSeconds: 30
timeoutSeconds: 5Код: Выделить всё
kubectl describe pod orders-api-6f7c9d4b58-x2m4p
kubectl get pods -l app=orders-api -wТипичные грабли:
Внешние зависимости в liveness, про это уже было выше, но наступают на эти грабли постоянно. Дефолтный timeoutSeconds в 1 секунду: под нагрузкой пауза GC или медленный диск съедают ее целиком, и начинаются рестарты на ровном месте, ставьте 3-5 секунд. Один эндпоинт на обе пробы: работает до первого случая, когда под надо вывести из-под трафика, не убивая его. Readiness, завязанная на общую зависимость, способна уронить сервис целиком: база моргнула на десять секунд, все поды разом выпали из эндпоинтов, и пользователи получили полный отказ вместо ошибок на части запросов. И последнее: проба должна быть дешевой. healthz, который дергает три соседних сервиса и пишет подробные логи, при опросе раз в 5 секунд с каждой реплики сам превращается в источник нагрузки.
Итог:
liveness перезапускает зависшее, readiness управляет трафиком, startup дает время на разгон. Liveness смотрит только на сам процесс, readiness может проверять зависимости, но осознанно. Частые рестарты из-за проваленной liveness выглядят в kubectl get pods как CrashLoopBackOff, и в следующей главе про отладку разберем, как отличить такой случай от пода, который не стартует по другим причинам.