Что означают 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 минут
Если времени мало, идите по порядку: это быстрее всего приводит к конкретному месту поломки.
- Понять, кто возвращает 502/504: ingress-controller или внешний прокси/балансировщик перед ним.
- Проверить, есть ли у Service реальные endpoints (EndpointSlice/Endpoints).
- Проверить, что Pod действительно Ready и
readinessProbeне «флапает». - Проверить соответствие портов:
Ingress backend port → Service port → targetPort → containerPort. - Посмотреть логи ingress-controller и вытащить точную формулировку:
upstream timed out,connect() failed,no live upstreams. - Проверить таймауты NGINX Ingress и реальное время ответа приложения (p95/p99).
- Проверить keepalive и закрытие соединений приложением/sidecar.
Если ваш Ingress/контроллер живёт в облегчённом кластере, полезно держать под рукой сравнение вариантов (Traefik/NGINX/HAProxy) и их поведения по таймаутам/балансировке: Ingress-контроллеры в k3s: что выбрать и как отличаются.
Шаг 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

Почему 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) обеспечить периодические данные, иначе соединение может считаться «молчаливым» и будет разрываться.
Шаг 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

Типовые сообщения в логах 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: типичные грабли.
Короткий рецепт поиска причины: от симптома к фиксу
- Есть kubernetes ingress 502 → смотрим логи ingress-controller → ищем
no live upstreamsилиconnect() failed→ проверяем endpoints и порты. - Есть ingress 504 → ищем
upstream timed out→ измеряем реальное время ответа → настраиваем таймауты и/или ускоряем обработчик. - Ошибки «плавают» → проверяем
readinessProbe, стабильность endpoints, затем keepalive и рестарты Pod.
Главная идея: не лечите 502/504 только настройками Ingress. В большинстве случаев это несогласованность между Service/Endpoints/Pod readiness или реальная производительность приложения под нагрузкой.
Если вы выносите такие сервисы на отдельные ресурсы (выделенные ноды, отдельные ingress-контроллеры, тестовые стенды), удобнее держать инфраструктуру на VDS: проще масштабировать, воспроизводить инциденты и изолировать шумных соседей.


