Learning Platform
Глоссарий Troubleshooting
Урок 13.02 · 22 мин
Продвинутый
ProbesexechttpGettcpSocketgrpchealth checking

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-эндпоинтов.

DANGER

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).
httpGet probe: что считается failure
HTTP 200-399Любой код в диапазоне 200-399 — success. Включая 3xx редиректы — kubelet не следует за ними, но 301/302 считаются healthy. Это решение в коде Kubernetes, на CKAD спрашивают про точные диапазоны.
HTTP 4xx / 5xx401, 403, 404, 500, 503 — всё failure. Поэтому /healthz endpoint должен быть без auth. Если probe попадает на authenticated route — 401 → restart, даже если app работает.
connection refusedПроцесс ещё не открыл порт (стартует) или упал. kubelet получает ECONNREFUSED — failure. На старте это нормально, поэтому есть initialDelaySeconds и startupProbe.
timeoutЗапрос не уложился в timeoutSeconds (default 1s). probe FAIL. Если app под нагрузкой — частые timeouts → восприятие, будто app мёртв → рестарт → меньше replicas → больше нагрузка на остальных → cascade.

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 стартовал.

WARNING

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.

NOTE

Приложение должно сам 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 не работает как задумано.


Выбор handler-а: short matrix

Когда какой handler
HTTP servicehttpGet — самый информативный. Status code, timeout на response, headers — всё это даёт kubelet больше сигнала. Endpoint /healthz должен быть без auth, без heavy logic.
gRPC servicegrpc handler с v1.27. Требует, чтобы app implement health checking protocol. До v1.27 — exec с grpc_health_probe бинарём в image.
Legacy TCP / DBtcpSocket для базовой проверки listener-а. Дёшево, но не различает 'TCP open' и 'protocol actually works'. Для PostgreSQL: exec pg_isready информативнее.
Batch / без HTTPexec с file-flag (touch /tmp/ready при готовности) или с CLI-утилитой (redis-cli ping, pg_isready, custom script).

Проверка знанийKnowledge check
В probe указано command: 'sh -c cat /tmp/healthy' (одна строка). Применится ли probe и что произойдёт?
ОтветAnswer
API server вероятно отвергнет — command должен быть array. Если каким-то путём пройдёт сериализация (или указано как array из одной длинной строки 'sh -c cat /tmp/healthy'), kubelet попробует найти и запустить файл с именем 'sh -c cat /tmp/healthy' (с пробелами в имени) — fail, executable not found. Probe всегда failed → restart loop. Правильно: command: ['sh', '-c', 'cat /tmp/healthy'] — три элемента.
Проверка знанийKnowledge check
HTTP service на порту 8080 возвращает 401 на endpoint /api/health (требует auth). Использован httpGet probe на этот endpoint. Что произойдёт?
ОтветAnswer
kubelet получает 401, это не входит в диапазон 200-399, probe FAIL. Если это livenessProbe — контейнер будет рестартован после failureThreshold. Если readinessProbe — Pod вырезан из Endpoints. Решение: использовать unauth endpoint /healthz (или подобный), либо передать токен через httpHeaders в spec probe.
Проверка знанийKnowledge check
Для gRPC сервиса использован tcpSocket probe на порт 9090 (тот же, где gRPC). Зависит ли probe от того, что приложение действительно отвечает по gRPC?
ОтветAnswer
Нет. tcpSocket проверяет только установку TCP-соединения. Если gRPC server открыл порт но завис, или отвечает UNAVAILABLE на все RPC — tcpSocket всё равно PASS, так как listener accept-ит. Это false-positive. Правильно: grpc handler (v1.27+) который вызывает grpc.health.v1.Health/Check и проверяет статус SERVING. До v1.27 — exec с grpc_health_probe.
Проверка знанийKnowledge check
Внутри одного probe можно указать несколько handlers (httpGet и exec одновременно)?
ОтветAnswer
Нет. Probe должен содержать ровно один handler. API server отвергнет манифест с двумя handlers (validation error). Если нужно проверить две вещи одновременно — лучше написать один endpoint, который агрегирует проверки, либо разнести по разным probes (но даже это редко имеет смысл — readiness и liveness служат разным целям).

Проверьте понимание

Результат: 0 из 0
Прикладной
Вопрос 1 из 5. В probe указано command: ['sh -c cat /tmp/healthy'] (один элемент в array). Что произойдёт при выполнении?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 5