Ingress возвращает 502: проверяем путь от контроллера до приложения

В браузере открывается 502, хотя Pod приложения выглядит Running. Этот код часто возвращает прокси, который не получил корректный ответ upstream, но точный смысл и журнал зависят от реализации контроллера. Сначала установим, какой компонент сформировал ответ, затем пройдём путь до процесса приложения. Изменение аннотаций другого контроллера только добавит шума.

Находим Ingress и его исполнителя

kubectl -n demo get ingress api -o yaml
kubectl get ingressclass
kubectl -n demo describe ingress api

Сопоставьте ingressClassName с controller у IngressClass и установленным компонентом. Kubernetes Ingress описывает маршруты, но сам не принимает HTTP-трафик. Перед ним может находиться внешний балансировщик или CDN, тоже способный вернуть 502. Сохраните время запроса, host, path и доступный request ID; по ним найдите запись в журнале фактического прокси.

Проверьте совпадение Host и path с правилом. Запрос к IP без нужного Host может попасть в default backend и проверять совсем другой маршрут. Для HTTPS важен также SNI, поэтому простая подстановка IP в URL не воспроизводит исходное обращение. Если внешний адрес известен, curl --resolve позволяет сохранить имя URL и выбрать IP.

curl --resolve api.example.com:443:203.0.113.10 --max-time 5 https://api.example.com/readyz

Домен и адрес здесь — заполнители. Не отключайте проверку TLS ради получения любого HTTP-кода: иначе вы поменяете условия проверки. Сначала убедитесь, что запрос доходит до ожидаемого контроллера и что его журнал содержит именно этот host и путь.

Проверяем связь правила с Service

В Ingress backend service.port относится к порту Service, а не напрямую к containerPort приложения. Следующая пара показывает согласованное направление 80 → 8080:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: api
  namespace: demo
spec:
  ingressClassName: example-controller
  rules:
    - host: api.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: api
                port:
                  number: 80
---
apiVersion: v1
kind: Service
metadata:
  name: api
  namespace: demo
spec:
  selector: {app: api}
  ports:
    - port: 80
      targetPort: 8080

example-controller нужно заменить существующим классом. Обычный backend Service находится в namespace самого Ingress. Посмотрите EndpointSlice Service: появились ли адреса ожидаемых Pod, верен ли порт и готовы ли цели. Отсутствие целей может давать разные HTTP-коды у разных контроллеров, поэтому нельзя считать 502 точным доказательством пустого списка.

kubectl -n demo get service api -o yaml
kubectl -n demo get endpointslice -l kubernetes.io/service-name=api -o yaml
kubectl -n demo get pods -l app=api -o wide

Проверяем тот же сетевой источник

Если цели корректны, попробуйте запрос к Pod IP и Service из разрешённого диагностического контейнера в сетевом контексте контроллера. Запрос из рабочего namespace приложения может проходить, а ingress-контроллер из другого namespace — блокироваться NetworkPolicy. Если в самом контейнере контроллера нет shell или curl, используйте согласованный диагностический способ; не устанавливайте пакеты в него на месте.

Connection refused обычно направляет к сокету и порту приложения, timeout — к сети, блокировкам или зависшему обработчику, ошибка TLS upstream — к согласованию протокола. Эти признаки нужно читать в журнале контроллера. Проверьте, действительно ли backend слушает HTTP на 8080: некоторые конфигурации ожидают HTTPS и требуют специфической настройки контроллера. Аннотации разных реализаций не взаимозаменяемы.

Возвращаемся к обычному запросу

Проверьте адрес прослушивания приложения: сервер только на 127.0.0.1 внутри Pod недоступен по Pod IP. Также посмотрите завершение старых Pod во время rollout: прокси мог попытаться использовать уже закрытый сокет. Увеличение тайм-аута не исправит неверный targetPort или протокол. Меняйте тот участок, который подтвердили прямой проверкой.

После исправления повторите исходный HTTPS-запрос с теми же host и path и проверьте журнал backend. Успешный /readyz ещё не гарантирует работу тяжёлого API-метода, поэтому отдельно повторите исходную операцию. Итоговая запись должна называть компонент, вернувший 502, фактическую цель и причину отказа соединения; правило backend Ingress помогает связать эти наблюдения в один маршрут.

Ещё по теме

Продолжить изучение

Хотите увереннее разворачивать приложения и разбирать сбои в кластере? Сети, конфигурация, хранилища и обновления входят в программу «Kubernetes с нуля до PRO».

Продолжить на практике

  • Kubernetes с нуля до PRO ↗

    Разворачивайте и сопровождайте приложения в Kubernetes: от первого Pod до релизов, сетей, хранилищ, масштабирования и диагностики. Итоговый проект — сервис с базой данных, мониторингом и проверенным откатом.