Новинка Виртуальный VDS сервер в Финляндии от 390р
Выберите продукт

Kubernetes Ingress: как диагностировать 502/504 между ingress-controller, Service и Pod

502/504 на Kubernetes Ingress чаще всего возникают на стыке ingress-controller → Service → Pod: нет endpoints, Pod не Ready, перепутаны порты, не совпал протокол, сработали таймауты или рвутся keepalive-соединения. Ниже — быстрый чек-лист и типовые фиксы с командами.
Kubernetes Ingress: как диагностировать 502/504 между ingress-controller, Service и Pod

Что означают 502 и 504 на Ingress и почему это почти всегда «стык»

Когда вы видите kubernetes ingress 502 или ingress 504, важно помнить: Ingress не «исполняет приложение», он проксирует запросы дальше. В типичной схеме NGINX Ingress маршрут такой:

Client → LoadBalancer/NodePort → ingress-controller (NGINX) → Service → Endpoints/EndpointSlice → Pod (containerPort)

502 Bad Gateway означает, что NGINX как прокси не смог корректно получить ответ от upstream: не установилось соединение, upstream закрыл его, ответ не похож на ожидаемый протокол (HTTP/TLS), произошёл reset.

504 Gateway Timeout означает, что NGINX дотянулся до upstream, но не дождался ответа в пределах таймаутов. Частый текст в логах: upstream timed out.

В Kubernetes 502/504 чаще всего — симптом того, что Ingress «видит» Service, но фактически не может стабильно дойти до готового Pod по правильному порту и протоколу.

Быстрый чек-лист: где искать причину за 5–10 минут

Если времени мало, идите по порядку: это быстрее всего приводит к конкретному месту поломки.

  1. Понять, кто возвращает 502/504: ingress-controller или внешний прокси/балансировщик перед ним.
  2. Проверить, есть ли у Service реальные endpoints (EndpointSlice/Endpoints).
  3. Проверить, что Pod действительно Ready и readinessProbe не «флапает».
  4. Проверить соответствие портов: Ingress backend port → Service port → targetPort → containerPort.
  5. Посмотреть логи ingress-controller и вытащить точную формулировку: upstream timed out, connect() failed, no live upstreams.
  6. Проверить таймауты NGINX Ingress и реальное время ответа приложения (p95/p99).
  7. Проверить keepalive и закрытие соединений приложением/sidecar.

Если ваш Ingress/контроллер живёт в облегчённом кластере, полезно держать под рукой сравнение вариантов (Traefik/NGINX/HAProxy) и их поведения по таймаутам/балансировке: Ingress-контроллеры в k3s: что выбрать и как отличаются.

FastFox VDS
Облачный VDS-сервер
Виртуальные серверы с быстрым запуском и гибкой конфигурацией от 390₽ / мес
Доступные локации
Россия Нидерланды Финляндия

Шаг 1. Убедиться, что 502/504 отдаёт именно ingress-controller

Надёжный способ — посмотреть логи ingress-controller в момент запроса. Если записи появляются с вашим host/path, проблема почти наверняка на участке ingress-controller → Service/Pod.

kubectl -n ingress-nginx get pods -o wide
kubectl -n ingress-nginx logs deploy/ingress-nginx-controller --tail=200

Если 502/504 приходит, но в логах контроллера «тишина», ошибку может возвращать внешний L7/L4 балансировщик или другой прокси до Ingress.

Шаг 2. Service без endpoints: самая частая причина 502

Ситуация выглядит так: Ingress ссылается на Service, Service существует, но у него нет endpoints. Тогда проксировать просто некуда, и NGINX отдаёт 502 (иногда 503) или пишет, что upstream пустой.

Проверяем Service и соответствие selector’ов:

kubectl -n app get svc my-service -o yaml
kubectl -n app get pods -l app=my-app -o wide

Дальше смотрим Endpoints/EndpointSlice:

kubectl -n app get endpoints my-service -o yaml
kubectl -n app get endpointslices -l kubernetes.io/service-name=my-service -o yaml

Проверка Service, selectors и EndpointSlice при ошибках 502 на Ingress

Почему endpoints могут быть пустыми

  • Неверный selector у Service: метки не совпадают с Pod.
  • Pod не проходит readinessProbe и не попадает в ready endpoints.
  • Service типа ExternalName или нестандартная схема, где Ingress ожидает обычные endpoints.
  • Ошибка с namespace: Ingress и Service в разных namespaces, а ссылка сделана «как будто» в одном.

Классика: Service смотрит на app: backend, а Pod помечен app: back. В манифестах «всё есть», но endpoints пустые, и Ingress закономерно падает в 502.

Шаг 3. Readiness probe и «флапающие» Pods: причина и 502, и 504

Если endpoints то появляются, то исчезают, ошибки становятся «плавающими»: часть запросов проходит, часть уходит в 502/504, особенно после релиза или под нагрузкой.

Смотрим события Pod и статусы проб:

kubectl -n app describe pod my-pod-xxxxx
kubectl -n app get pod my-pod-xxxxx -o jsonpath='{.status.containerStatuses[0].ready}'; echo

Проверьте:

  • readiness проверяет правильный порт/путь (часто путают containerPort и порт Service).
  • проба отражает реальную «готовность» (если приложение стартует 40 секунд, а проба начинает падать на 5-й — endpoints будут пустеть).
  • тайминги: initialDelaySeconds, periodSeconds, timeoutSeconds, failureThreshold.

Частый анти-паттерн

Readiness ходит на тяжёлый endpoint (например, / с рендерингом). Под нагрузкой он начинает отвечать медленно, readiness падает, Pod выкидывается из endpoints, Ingress начинает сыпать ошибками, нагрузка перераспределяется на оставшиеся Pod и добивает их. Для readiness лучше иметь лёгкий /healthz без внешних зависимостей или с адекватной деградацией.

Шаг 4. Несовпадение портов Service/Pod: «внутри что-то работает, но Ingress даёт 502»

В Kubernetes легко ошибиться портом в четырёх местах:

  • порт в Ingress backend (ссылка на Service port или named port);
  • spec.ports[].port у Service;
  • spec.ports[].targetPort у Service (число или имя);
  • containerPort у контейнера (и на каком порту реально слушает процесс).

Проверяем связку одним проходом:

kubectl -n app get ingress my-ing -o yaml
kubectl -n app get svc my-service -o yaml
kubectl -n app get pod -l app=my-app -o yaml

Симптомы в логах Ingress

  • connect() failed (111: Connection refused) while connecting to upstream — IP:port доступен, но на порту никто не слушает.
  • no live upstreams — как правило, нет готовых endpoints.

Отдельно проверьте named ports: если Service использует targetPort: http, то в Pod в ports[].name должен существовать порт с именем http.

Шаг 5. Диагностика сети: достучаться до Service «как NGINX»

Чтобы отделить проблему приложения от маршрутизации/политик, проверьте доступность сервиса из кластера.

Проверка DNS и ответа через ClusterIP:

kubectl -n app get svc my-service -o wide
kubectl -n app run tmp-shell --rm -i --tty --image=busybox:1.36 -- sh

Внутри временного Pod:

nslookup my-service
wget -S -O - http://my-service:80/healthz

Если сервис из кластера не отвечает стабильно, Ingress не «исправит» это настройками. Тогда копаем приложение, порты, NetworkPolicy, CNI, kube-proxy/IPVS и ресурсы нод.

Шаг 6. Таймауты NGINX Ingress: когда 504 — это ожидаемо, но нужно настроить

Если обработчик объективно долгий (отчёты, экспорт, тяжёлые запросы к БД), вы получите ingress 504. Типичный лог:

upstream timed out (110: Operation timed out) while reading response header from upstream

Это означает: NGINX ждал заголовки/данные от upstream и не дождался.

Какие таймауты важны

  • proxy_connect_timeout — время на установку соединения до upstream.
  • proxy_read_timeout — сколько ждать данных/ответа от upstream.
  • proxy_send_timeout — сколько ждать, пока NGINX отправляет запрос upstream’у.

В NGINX Ingress это обычно задаётся аннотациями Ingress (конкретные имена зависят от контроллера/версии). Практика простая: если handler реально работает 120 секунд, а read timeout 60 — будет 504 при полностью «живом» приложении.

Рабочий подход:

  • Измерить время ответа приложения (p95/p99), а не «поставить 10 минут на всякий случай».
  • Выставить read timeout немного выше p99 и продумать отмену запроса (cancellation) и идемпотентность.
  • Для стриминга (SSE/stream) обеспечить периодические данные, иначе соединение может считаться «молчаливым» и будет разрываться.
FastFox SSL
Надежные SSL-сертификаты
Мы предлагаем широкий спектр SSL-сертификатов от GlobalSign по самым низким ценам. Поможем с покупкой и установкой SSL бесплатно!

Шаг 7. Keepalive и разрывы соединений: скрытая причина 502

Про keepalive вспоминают, когда ошибка выглядит так: после простоя/релиза первые запросы проходят, а затем периодически появляются 502, особенно при высокой параллельности.

Типовые сценарии:

  • Ingress держит keepalive-соединение к Pod, а приложение/sidecar закрывает его по своему idle timeout. Следующий запрос пытается пойти по «полумёртвому» соединению и ловит 502.
  • HTTP/1.1 keepalive включён, но приложение некорректно обрабатывает повторное использование соединения.
  • Между NGINX и Pod есть ещё один прокси (например, mesh sidecar) — таймауты и лимиты должны совпадать по смыслу.

Что делать:

  • Сравнить idle timeout на стороне ingress-controller и приложения/sidecar.
  • Проверить, нет ли агрессивного закрытия соединений на уровне приложения или промежуточного прокси.
  • В логах искать: upstream prematurely closed connection, connection reset by peer.

Шаг 8. Когда виноват не Ingress: перегруз нод, DNS, conntrack и политики

Иногда 504 — это не «медленный handler», а деградация инфраструктуры или сетевого контура:

  • Ноды перегружены по CPU: приложение «живое», но ему не дают времени на исполнение, очередь запросов растёт.
  • Проблемы с DNS внутри кластера (CoreDNS): часть компонентов начинает «подвисать» на резолве.
  • Забит conntrack/NAT на нодах: начинаются потери и timeouts.
  • NetworkPolicy режет трафик от ingress-controller до namespace приложения.

Быстрые проверки:

kubectl top nodes
kubectl -n ingress-nginx top pods
kubectl -n kube-system get pods -l k8s-app=kube-dns -o wide
kubectl -n app get networkpolicy

Проверка нагрузки нод, DNS и сетевых политик при ошибках 504 в Kubernetes

Типовые сообщения в логах NGINX Ingress и перевод в действия

upstream timed out

Почти всегда: измерить время ответа, затем увеличивать proxy_read_timeout (разумно), оптимизировать обработчик или выносить долгие операции в async/queue. Для стриминга — убедиться, что соединение не «молчит».

connect() failed (111: Connection refused)

Upstream IP:port есть, но на порту никто не слушает. Проверяйте порты, targetPort, именованные порты, реальный порт процесса в контейнере, а также readiness.

no live upstreams

У Service нет готовых endpoints. Проверяйте EndpointSlice/Endpoints, selectors, readiness и namespace.

upstream prematurely closed connection / connection reset by peer

Upstream сам закрыл соединение: рестарт/краш приложения, лимиты, несогласованный keepalive, перегруз. Смотрите логи приложения и события Pod.

Минимальный набор проверок, который стоит автоматизировать

  • Метрики ingress-controller: доля 5xx по Ingress/host, p95/p99 latency, upstream errors.
  • Алерты на пустые endpoints у критичных Service (EndpointSlice count = 0).
  • Алерты на flapping readiness (частые переходы Ready/NotReady).
  • Дашборд по ресурсам нод и Pod: CPU throttling, memory pressure, рестарты.

Если параллельно упираетесь в особенности кеширования/частичных ответов и поведение прокси, может пригодиться практический разбор: HTTP Range и кеширование в NGINX/Apache: типичные грабли.

Короткий рецепт поиска причины: от симптома к фиксу

  1. Есть kubernetes ingress 502 → смотрим логи ingress-controller → ищем no live upstreams или connect() failed → проверяем endpoints и порты.
  2. Есть ingress 504 → ищем upstream timed out → измеряем реальное время ответа → настраиваем таймауты и/или ускоряем обработчик.
  3. Ошибки «плавают» → проверяем readinessProbe, стабильность endpoints, затем keepalive и рестарты Pod.

Главная идея: не лечите 502/504 только настройками Ingress. В большинстве случаев это несогласованность между Service/Endpoints/Pod readiness или реальная производительность приложения под нагрузкой.

Если вы выносите такие сервисы на отдельные ресурсы (выделенные ноды, отдельные ingress-контроллеры, тестовые стенды), удобнее держать инфраструктуру на VDS: проще масштабировать, воспроизводить инциденты и изолировать шумных соседей.

Поделиться статьей

Вам будет интересно

Как безопасно выполнить bootstrap MariaDB Galera после полного останова

Как безопасно выполнить bootstrap MariaDB Galera после полного останова

После одновременной остановки всех узлов Galera обычного запуска MariaDB недостаточно. Сначала найдите сервер с последней транзакц ...
CoreDNS в Kubernetes: исправляем CrashLoopBackOff, SERVFAIL и DNS-петлю

CoreDNS в Kubernetes: исправляем CrashLoopBackOff, SERVFAIL и DNS-петлю

Разберём, почему CoreDNS перезапускается или отвечает SERVFAIL, как обнаружить замкнутую пересылку DNS-запросов, проверить доступн ...
Apache Kafka KRaft на VDS: отдельные controller и broker

Apache Kafka KRaft на VDS: отдельные controller и broker

Соберём новый Kafka-кластер без ZooKeeper на шести Linux VDS: три узла controller образуют отказоустойчивый metadata quorum, а три ...