Probe handlers: exec, httpGet, tcpSocket, grpc
В каждом probe (liveness / readiness / startup) указывается handler — конкретный механизм, как kubelet будет проверять контейнер. Доступно четыре handlers: exec, httpGet, tcpSocket, grpc. Внутри одного probe можно указать ровно один handler — иначе validation error. Каждый handler — это своя семантика «healthy», и подбор handler-а критично влияет на корректность.
Почему TCP сложный: что он гарантирует
exec: команда внутри контейнера
exec запускает команду внутри namespace контейнера. Exit code 0 означает success, любой ненулевой — failure. Это самый гибкий handler — позволяет проверить что угодно, что можно выразить shell-командой или утилитой.
livenessProbe:
exec:
command: ["cat", "/tmp/healthy"]
periodSeconds: 10
В этом примере cat /tmp/healthy возвращает 0, если файл существует. Если приложение создаёт файл-флаг при готовности и удаляет при критической ошибке — это idiomatic exec probe для batch-воркеров без HTTP-эндпоинтов.
command — это array of strings, не одна string. Если написать command: "cat /tmp/healthy" — kubectl покажет validation error, но в command: ["cat /tmp/healthy"] ошибки не будет: kubelet попробует выполнить файл с именем “cat /tmp/healthy” (с пробелом!) и получит executable file not found. Probe всегда failed, контейнер крашится.
Шелл-конструкции (pipe, redirect, &&) требуют явного запуска shell:
# ПЛОХО — нет shell в этой строке, pipe не работает
exec:
command: ["ps", "aux", "|", "grep", "myapp"]
# ХОРОШО — shell интерпретирует
exec:
command: ["sh", "-c", "ps aux | grep -v grep | grep myapp"]
Также: exec probe довольно дорогой — каждый запуск forks процесс в контейнере. Для high-frequency probes (periodSeconds: 1-2) предпочитайте httpGet, если есть HTTP endpoint.
httpGet: HTTP GET на путь
httpGet отправляет HTTP GET-запрос. Статус 200-399 — success, всё остальное (включая connection refused) — failure.
readinessProbe:
httpGet:
path: /healthz
port: 8080
scheme: HTTP
httpHeaders:
- name: X-Health-Probe
value: kubelet
periodSeconds: 5
Поля:
- path: URL path. Должен возвращать быстро и легко (никакого DB-запроса).
- port: integer или именованный port (если в
containers.portsестьname: http, можноport: http). - scheme: HTTP или HTTPS. По умолчанию HTTP. Для HTTPS — kubelet принимает любой сертификат (TLS verify отключён).
- host: hostname. Default — Pod IP. Меняйте только при странных edge cases (multi-homed Pod).
- httpHeaders: список дополнительных заголовков. Часто нужен
Host:для virtual host routing или auth-токен (если probe endpoint требует header-based auth).
tcpSocket: TCP connect
tcpSocket пытается открыть TCP-соединение на указанный порт. Установка соединения = healthy, отказ — failure. Никаких данных kubelet не отправляет.
livenessProbe:
tcpSocket:
port: 5432
periodSeconds: 10
Use case: сервисы без HTTP — PostgreSQL, Redis (хотя у Redis есть redis-cli ping, exec лучше), legacy TCP-протоколы. Полезен также как дешёвый readiness — порт открыт, значит, listener стартовал.
TCP-открытый порт не означает, что HTTP/protocol-уровень работает. Веб-сервер может accept TCP, но захлёбываться на TLS handshake или возвращать 500 на любой path. На HTTP сервис используйте httpGet, не tcpSocket — это даёт намного больше информации (status code, timeout на response, headers).
grpc: native gRPC health check (GA с v1.27)
grpc — это native поддержка gRPC Health Checking Protocol. kubelet вызывает RPC grpc.health.v1.Health/Check и интерпретирует ответ. Без extra-контейнеров, без grpc_health_probe бинаря в image — kubelet сам умеет говорить gRPC.
readinessProbe:
grpc:
port: 9090
service: my-service
periodSeconds: 5
- port: gRPC порт.
- service: имя сервиса для health check. Optional, default — empty string (overall health of the server). gRPC server может реализовать множественные health services (для разных subsystems) — это поле выбирает один.
Условие success — RPC отвечает SERVING. NOT_SERVING, UNKNOWN, или ошибка RPC — failure.
Приложение должно сам implement gRPC Health Checking Protocol (зарегистрировать grpc.health.v1.Health service). В большинстве gRPC библиотек есть готовая реализация: grpc-health-checking в Go, grpc.health.v1.HealthServicer в Python. Просто HTTP / 2 на порту — не подойдёт.
До v1.27 (когда grpc стал GA) приходилось использовать exec с бинарём grpc-health-probe, вкомпилированным в image. Это до сих пор work, и для multi-arch / shim cases может быть нужно — но в новых кластерах native grpc handler чище.
Killer момент: exec command — это array
На CKAD типовая опечатка — command: "sh -c 'cat /tmp/x'" (строка вместо массива). Probe формально валиден (или валидна сериализация — зависит от конкретной версии), но семантика искажена: kubelet попробует exec один файл с длинным именем, а не shell с аргументами.
# ПЛОХО — это не array, kubectl может проявиться по-разному
exec:
command: sh -c "cat /tmp/x"
# ПЛОХО — array из одной длинной строки
exec:
command: ["sh -c cat /tmp/x"]
# → kubelet exec файл "sh -c cat /tmp/x" → not found → fail
# ХОРОШО — три элемента в array
exec:
command: ["sh", "-c", "cat /tmp/x"]
Проверка после kubectl apply:
kubectl get pod <name> -o jsonpath='{.spec.containers[0].livenessProbe.exec.command}'
Должен вернуть JSON array из трёх элементов. Если возвращает одну длинную строку — exec не работает как задумано.