Ingress: пускаем трафик снаружи

Рейтинг: 48.7% · 7 голосов
Kubernetes для разработчиков: поды, деплойменты, сервисы, ingress, конфиги и отладка. Уроки по главам с обсуждением.
Ответить
Аватара пользователя
anton_k8s
Сообщения: 55
Зарегистрирован: 12 май 2026, 03:23

Ingress: пускаем трафик снаружи

Сообщение anton_k8s »

Оглавление курса (48)
  1. Зачем нужен Kubernetes и из чего состоит кластер
  2. Поднимаем локальный кластер: minikube и kind
  3. Поды: базовая единица запуска
  4. Deployment и ReplicaSet: управляем репликами
  5. Service: сетевой доступ к подам
  6. ConfigMap и Secret: выносим конфигурацию
  7. Ingress: пускаем трафик снаружи (вы здесь)
  8. Хранилище: Volumes и PersistentVolumeClaim
  9. Namespaces, requests и limits
  10. Health checks: liveness и readiness пробы
  11. Отладка: почему под не стартует
  12. Helm: пакетный менеджер для Kubernetes
  13. Базовая безопасность: RBAC и доступы
  14. Job и CronJob: разовые и периодические задачи
  15. StatefulSet и DaemonSet: stateful-нагрузки и системные агенты
  16. Стратегии обновления и планирование: rollout и rollback, graceful shutdown, nodeSelector, affinity, taints
  17. Автомасштабирование: HPA по метрикам, обзор VPA и Cluster Autoscaler
  18. Наблюдаемость: логи, метрики, events, обзор Prometheus и Grafana
  19. Безопасность глубже: securityContext, Pod Security Standards, NetworkPolicy, шифрование секретов
  20. Архитектура control plane: api-server, etcd, scheduler
  21. Узел кластера: kubelet, kube-proxy и container runtime
  22. Декларативная модель: reconciliation, контроллеры, CRD
  23. kubectl профессионально: get, describe, explain, jsonpath
  24. Под глубже: init, sidecar, lifecycle hooks и QoS
  25. Метки, селекторы и организация ресурсов
  26. Сервисы и kube-proxy глубже: типы, IPVS, EndpointSlices
  27. Ingress, ingress-контроллеры и Gateway API
  28. Секреты в кластере: шифрование, External Secrets, Vault
  29. Хранилище глубже: PV, StorageClass, CSI и StatefulSet
  30. Сеть кластера: CNI, NetworkPolicy и CoreDNS
  31. Планировщик: affinity, taints, topology spread
  32. Ресурсы, QoS и вытеснение: requests, limits, eviction
  33. Helm глубже: шаблоны, хуки, зависимости, OCI
  34. Kustomize и управление конфигурацией без шаблонов
  35. RBAC и аутентификация глубже
  36. Admission и Pod Security: контроль на входе
  37. Policy as code: Kyverno и OPA Gatekeeper
  38. GitOps: Argo CD и Flux
  39. Операторы и CRD: расширяем Kubernetes
  40. Сервис-меш: Istio, Linkerd и когда он нужен
  41. Эксплуатация кластера: апгрейд, узлы, бэкап etcd
  42. Где запускать кластер: managed, self-hosted, k3s, Deckhouse
  43. Траблшутинг кластера: Pending, CrashLoop, узлы NotReady
  44. Стоимость и эффективность кластера: FinOps
  45. CI/CD в Kubernetes: сборка, деплой, прогрессивные релизы
  46. Лучшие практики и антипаттерны Kubernetes
  47. Сквозной проект и путь дальше: от манифеста до прода
  48. Деплой приложений через Argo CD: Application, sync и App-of-Apps
У тебя крутится Deployment с веб-приложением, перед ним Service. Внутри кластера все ходят друг к другу по ClusterIP и DNS-именам - красота. Но приходит реальность: на приложение должен попасть пользователь из браузера, по адресу shop.example.com, по HTTPS, с валидным сертификатом. И таких приложений у тебя не одно, а двадцать, и все они должны висеть на одном внешнем IP, разделяясь по домену и пути. Вот тут и начинается тема, ради которой существует kubernetes ingress.

Если в лоб давать каждому сервису свой внешний адрес через type: LoadBalancer, ты получишь двадцать публичных IP (а у облака каждый балансировщик - это деньги), двадцать раз настроенный TLS и ноль централизованного контроля над маршрутизацией. Ingress решает ровно эту боль: один вход, умные правила, один TLS-терминатор. Разберём, как это реально устроено под капотом, потому что вокруг Ingress больше всего мифов и граблей у новичков.

Что такое Ingress и чего он сам по себе НЕ делает

Ingress - это объект API, набор правил маршрутизации HTTP и HTTPS трафика внутрь кластера. Ключевое слово - правила. Сам по себе объект Ingress не маршрутизирует ничего. Это как заявка на маршрутизацию, лист бумаги с инструкцией хост такой-то, путь такой-то - отправить на такой-то Service. Кто эту бумагу читает и исполняет - отдельная сущность, Ingress-контроллер.

Это первая и самая частая грабля. Человек создаёт манифест Ingress в голом кластере (например, в свежем kubeadm или minikube без аддонов), делает kubectl get ingress, видит объект - а трафик не идёт, поле ADDRESS пустое. Потому что исполнять правила некому. В управляемых кластерах ситуация разная: в Yandex Managed Service for Kubernetes ALB Ingress Controller ставится как отдельный аддон, в Deckhouse модуль ingress-nginx включается флагом, в k3s из коробки приезжает Traefik. Но базовый Kubernetes контроллер не несёт - его ставишь ты.

Изображение

Ingress-контроллер: кто реально исполняет правила

Контроллер - это под (обычно Deployment или DaemonSet), внутри которого крутится настоящий обратный прокси: nginx, Traefik, Envoy, HAProxy. Он подписан на API-сервер и следит за объектами Ingress. Как только появляется или меняется правило, контроллер на лету пересобирает конфигурацию своего прокси и применяет её. Грубо говоря, ingress nginx контроллер берёт все твои Ingress-объекты и генерирует из них один большой nginx.conf с server-блоками и location-ами.

Сам контроллер должен иметь точку входа снаружи. Обычно это его собственный Service типа LoadBalancer (в облаке) или NodePort/hostNetwork (на bare metal). То есть схема двухслойная: облачный балансировщик гонит весь трафик на под контроллера, а уже контроллер по правилам Ingress раскидывает запросы по сервисам приложений. Один внешний IP - десятки приложений за ним.

Поставим ingress-nginx через Helm и посмотрим, что приехало:

Код: Выделить всё

helm upgrade --install ingress-nginx ingress-nginx \
  --repo https://kubernetes.github.io/ingress-nginx \
  --namespace ingress-nginx --create-namespace

kubectl get svc -n ingress-nginx
Вывод:

Код: Выделить всё

NAME                       TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)
ingress-nginx-controller   LoadBalancer   10.96.142.10    158.160.12.34   80:31480/TCP,443:30900/TCP
Разбор. EXTERNAL-IP 158.160.12.34 - это публичный адрес, выданный облаком, на него ты направишь A-запись своего домена. PORT(S) показывает, что 80 и 443 контроллера наружу проброшены через NodePort 31480 и 30900 - так облачный балансировщик дотягивается до пода. Если EXTERNAL-IP завис в pending - значит облако не смогло выдать балансировщик (нет квоты, нет cloud-controller-manager, или ты на bare metal без MetalLB). Это вторая классическая грабля.

Хосты, пути и IngressClass: как пишется правило

Теперь сам Ingress. Актуальный apiVersion - networking.k8s.io/v1 (стабилен с Kubernetes 1.19, всё, что старше с extensions/v1beta1 - мусор из интернета, не копируй):

Код: Выделить всё

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: shop-ingress
  namespace: shop
spec:
  ingressClassName: nginx
  rules:
  - host: shop.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: shop-frontend
            port:
              number: 80
      - path: /api
        pathType: Prefix
        backend:
          service:
            name: shop-api
            port:
              number: 8080
Что здесь важно по существу. Поле ingressClassName: nginx говорит: это правило исполняет именно nginx-контроллер. В кластере может стоять несколько контроллеров (nginx для одних доменов, ALB для других), и IngressClass их разводит. Без указания класса твой Ingress либо подхватит контроллер по умолчанию, либо его не подхватит никто.

pathType - поле, которое все игнорируют, а зря. Значений три. Prefix матчит по сегментам пути: /api совпадёт с /api и /api/users, но НЕ с /apixyz - граница идёт по слешу, а не по символам. Exact требует точного совпадения строки. ImplementationSpecific отдаёт трактовку на откуп контроллеру (у nginx это включает регулярки). Перепутал Prefix и Exact - и половина роутов внезапно отдаёт 404. Маршруты внутри одного хоста матчатся от самого длинного и специфичного к короткому, поэтому /api перехватит запросы раньше, чем /.

Проверяем, что правило подхвачено:

Код: Выделить всё

kubectl describe ingress shop-ingress -n shop

Код: Выделить всё

Rules:
  Host              Path  Backends
  ----              ----  --------
  shop.example.com  /     shop-frontend:80   (10.112.1.5:80,10.112.1.6:80)
                    /api  shop-api:8080      (10.112.2.9:8080)
Events:
  Type    Reason  Age   From                      Message
  Normal  Sync    12s   nginx-ingress-controller  Scheduled for sync
В скобках после имени сервиса - реальные IP подов (эндпойнты). Если там пусто - значит селектор Service ни на кого не указывает, и трафик пойдёт в никуда. Событие Sync от nginx-ingress-controller - подтверждение, что контроллер увидел правило и применил. Нет события Sync - контроллер либо не стоит, либо не твой класс.

TLS, cert-manager и Let's Encrypt: HTTPS без боли

Голый HTTP в проде - моветон. Ingress терминирует TLS на стороне контроллера: браузер устанавливает HTTPS с nginx, а внутрь кластера к приложению идёт уже расшифрованный HTTP. Сертификат и ключ контроллер берёт из Secret типа kubernetes.io/tls.

Руками генерить и продлевать сертификаты - каторга. Стандарт индустрии - cert-manager: оператор, который сам получает сертификаты от Let's Encrypt по протоколу ACME и автоматически продлевает их за две недели до истечения. Ставишь cert-manager, описываешь ClusterIssuer (кто выдаёт), вешаешь аннотацию на Ingress - дальше магия.

Код: Выделить всё

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: admin@example.com
    privateKeySecretRef:
      name: letsencrypt-prod-key
    solvers:
    - http01:
        ingress:
          ingressClassName: nginx
Теперь добавляем в Ingress аннотацию и блок tls:

Код: Выделить всё

metadata:
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  tls:
  - hosts:
    - shop.example.com
    secretName: shop-tls
Что происходит дальше. cert-manager видит аннотацию, создаёт ресурс Certificate, тот - запрос на выдачу. Через http01-solver Let's Encrypt проверяет, что домен реально твой: кладёт временный токен по пути /.well-known/acme-challenge/, и cert-manager на лету добавляет в твой Ingress правило, чтобы этот путь отвечал нужным токеном. Прошла проверка - сертификат лёг в Secret shop-tls, nginx его подхватил. Здесь важная предпосылка: A-запись домена уже должна указывать на твой EXTERNAL-IP, иначе Let's Encrypt не достучится до challenge и выдача зависнет. Это третья частая грабля - запросили сертификат раньше, чем настроили DNS.

Смотрим статус:

Код: Выделить всё

kubectl get certificate -n shop

Код: Выделить всё

NAME       READY   SECRET     AGE
shop-tls   True    shop-tls   90s
READY True - сертификат получен. Если False, смотри kubectl describe certificate и события cert-manager: чаще всего там DNS не резолвится или rate limit Let's Encrypt (у него лимит пять сертификатов на домен в неделю, не дёргай его в цикле, для тестов есть staging-сервер).

Аннотации: где спрятана половина функциональности

Базовый спек Ingress умеет немного: хост, путь, бэкенд, TLS. Всё остальное - таймауты, размер тела запроса, rewrite пути, rate limiting, sticky sessions, проксирование gRPC - живёт в аннотациях, и они специфичны для конкретного контроллера. Пример для ingress-nginx:

Код: Выделить всё

metadata:
  annotations:
    nginx.ingress.kubernetes.io/proxy-body-size: "50m"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/rewrite-target: /$2
И вот здесь системная проблема Ingress как API. Аннотация nginx.ingress.kubernetes.io/rewrite-target не работает в Traefik. Аннотации Traefik не понимает ALB Ingress Controller от Yandex Cloud. То есть твой манифест прибит гвоздями к конкретному контроллеру - перенос на другой требует переписывания всех аннотаций. Спецификация Ingress намеренно минималистична, и весь продвинутый функционал вендоры реализовали кто во что горазд через нестандартные аннотации. Это архитектурный тупик, и именно из него растёт следующая тема.

Gateway API: преемник Ingress в 2026

Сообщество признало, что Ingress исчерпан, и сделало замену - gateway api. Это не косметика, а новая модель управления входящим трафиком, и в 2026 она уже не эксперимент: ресурсы Gateway, GatewayClass и HTTPRoute стабильны (apiVersion gateway.networking.k8s.io/v1), а в феврале 2026 вышла версия 1.5, где в стабильный канал переехали ещё несколько фич. Дополнительный толчок к миграции - проект ingress-nginx объявлен end-of-life с марта 2026, так что планировать переход на gateway api придётся всем, кто на нём сидит.

Главная идея - разделение ответственности по ролям, чего в Ingress не было вообще. Раньше один объект Ingress мешал в кучу инфраструктуру (TLS, внешний адрес) и прикладную маршрутизацию (пути приложения). В Gateway API три уровня:
  • GatewayClass - описание реализации (какой контроллер), ставит провайдер кластера. Аналог IngressClass, но богаче.
  • Gateway - сама точка входа: какие порты, протоколы, домены и TLS-сертификаты слушаем. Этим владеет платформенная команда или SRE.
  • HTTPRoute (а также TLSRoute, GRPCRoute) - правила маршрутизации конкретного приложения. Этим владеет команда разработки, в своём namespace.
Минимальный комплект выглядит так. Gateway от инфраструктурщиков:

Код: Выделить всё

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: main-gateway
  namespace: infra
spec:
  gatewayClassName: nginx
  listeners:
  - name: https
    protocol: HTTPS
    port: 443
    hostname: "*.example.com"
    tls:
      mode: Terminate
      certificateRefs:
      - name: wildcard-tls
HTTPRoute от разработчиков приложения:

Код: Выделить всё

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: shop-route
  namespace: shop
spec:
  parentRefs:
  - name: main-gateway
    namespace: infra
  hostnames:
  - shop.example.com
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /api
    backendRefs:
    - name: shop-api
      port: 8080
Почувствуй разницу. То, что в Ingress было вендорной аннотацией rewrite-target, здесь - типизированное поле в спеке (filters с urlRewrite). Разделение трафика по весам для канареечного релиза, заголовки, зеркалирование - всё это первоклассные поля API, а не строки в аннотациях. parentRefs из другого namespace позволяет разработчику цепляться к общему Gateway, не трогая инфраструктуру, а владелец Gateway через allowedRoutes решает, кого пускать. Это и есть та гибкость и переносимость, ради которой затевался gateway api.

Про миграцию практически. Не надо переписывать всё за ночь. Gateway API и Ingress спокойно работают параллельно на одном кластере: ставишь Gateway-контроллер (NGINX Gateway Fabric, Envoy Gateway, Cilium, Istio - список реализаций большой), поднимаешь Gateway, и по одному переводишь приложения с Ingress на HTTPRoute, переключая DNS. cert-manager уже умеет работать с Gateway API, выпуская сертификаты на Gateway. Нюанс: в модели Gateway сертификаты привязаны к Gateway (владение инфраструктурой), а не к каждому приложению, как было удобно с Ingress-аннотацией - это меняет процесс выдачи, учитывай при планировании.

LoadBalancer против Ingress: когда что

Частый вопрос новичка: зачем Ingress, если есть Service type: LoadBalancer? Разница принципиальная по слою. LoadBalancer работает на L4 (TCP/UDP) - он просто прокидывает порт наружу, не зная, что внутри. Один балансировщик - один сервис, никакого разбора по доменам и путям, никакой TLS-терминации на уровне HTTP. Ingress и Gateway работают на L7 - понимают HTTP, читают Host-заголовок и URL, терминируют TLS, могут роутить десятки приложений за одним IP.

Практический вывод. Нужен голый TCP (база данных, кастомный бинарный протокол, игровой сервер) - бери LoadBalancer. Публикуешь веб и API по доменам с HTTPS - бери Ingress или, на новых проектах в 2026, сразу Gateway API. И помни: сам Ingress-контроллер наружу почти всегда торчит как раз через один Service type: LoadBalancer - это не конкуренты, а слои одной системы, где kubernetes трафик снаружи сначала бьёт в L4-балансировщик, а тонкую L7-маршрутизацию делает контроллер.

Типичные грабли и антипаттерны
  • Нет контроллера. Ingress создан, ADDRESS пустой, трафика нет. Сначала ставь контроллер, потом правила.
  • Забыл ingressClassName. Правило висит бесхозным, ни один контроллер его не берёт.
  • Перепутал pathType. Exact там, где нужен Prefix - и подпути отдают 404.
  • Сертификат до DNS. Запросил Let's Encrypt раньше, чем A-запись указала на EXTERNAL-IP - challenge не проходит, Certificate висит False.
  • Слепое копирование аннотаций. Скопировал nginx-аннотации в кластер с Traefik или ALB - они молча игнорируются.
  • Один гигантский Ingress на всё. Сложно дебажить, конфликты путей, размытое владение. Дроби по приложениям и namespace.
  • TLS-терминация без понимания. Помни, что внутрь кластера от контроллера к поду идёт расшифрованный HTTP - если нужен сквозной TLS, это отдельная настройка (re-encrypt или passthrough).
Мини-лаба: повтори руками
  • Подними локальный кластер (kind или minikube) и поставь ingress-nginx через Helm, как показано выше.
  • Задеплой два простых приложения (например, два разных Deployment с echo-сервером) и заведи на каждый Service.
  • Опиши один Ingress с ingressClassName: nginx, хостом demo.local и двумя путями Prefix - / на первое приложение, /api на второе.
  • Пропиши demo.local в /etc/hosts на EXTERNAL-IP (или 127.0.0.1 для kind) и проверь curl-ом, что разные пути попадают на разные приложения.
  • Сделай kubectl describe ingress и найди в выводе блок Rules с эндпойнтами и событие Sync.
  • Со звёздочкой: разверни тот же роутинг через Gateway API - поставь NGINX Gateway Fabric, опиши Gateway и HTTPRoute, сравни структуру с Ingress.
Контрольные вопросы
  • Почему созданный объект Ingress без установленного контроллера не пропускает трафик и что физически исполняет правила?
  • Чем отличаются pathType Prefix и Exact, и к каким багам приводит их путаница?
  • Как cert-manager получает сертификат от Let's Encrypt через http01 и почему до этого обязательно настроить DNS?
  • Какую архитектурную проблему Ingress решает Gateway API и как в нём разделена ответственность между ролями?
Итог

Ingress - это декларативные правила L7-маршрутизации, но исполняет их отдельно поставленный контроллер (nginx, Traefik), который терминирует TLS и раскидывает kubernetes трафик по сервисам за одним внешним IP. HTTPS закрывается связкой cert-manager плюс Let's Encrypt в три строки. Главный архитектурный недостаток Ingress - вендорные аннотации и смешение ролей - снят в Gateway API, который в 2026 уже стабилен и становится стандартом, тем более что ingress-nginx уходит на покой. На существующих проектах оставайся на Ingress, но новое лучше строить сразу на gateway api, а миграцию вести постепенно и параллельно.
👍5 ❤️1 🔥1 😄 🤔
✔ Лучший ответ сформирован автоматически — tornerd
anton_k8s писал(а):Ingress сам по себе ничего не делает а если поставить два контроллера сразу, nginx и traefik? они подерутся за объекты или каждый возьмет свое по ingressClassName? у нас в проде traefik, хочу локально повторить ту же схему
Перейти к ответу →
Аватара пользователя
tornerd
Сообщения: 1
Зарегистрирован: 21 май 2026, 11:40

Re: Ingress: пускаем трафик снаружи

Сообщение tornerd »

✔ Лучший ответ — сформирован автоматически
anton_k8s писал(а):Ingress сам по себе ничего не делает
а если поставить два контроллера сразу, nginx и traefik? они подерутся за объекты или каждый возьмет свое по ingressClassName? у нас в проде traefik, хочу локально повторить ту же схему
👍1 ❤️2 🔥1 😄 🤔
Аватара пользователя
muttdogg
Сообщения: 2
Зарегистрирован: 12 май 2026, 18:08

Re: Ingress: пускаем трафик снаружи

Сообщение muttdogg »

спасибо за абзац про мак, я на m2 с docker драйвером полчаса не мог понять почему curl висит. minikube tunnel реально надо держать открытым в отдельной вкладке, закрыл терминал и все отвалилось
👍2 ❤️1 🔥 😄 🤔
Аватара пользователя
ksanders
Сообщения: 1
Зарегистрирован: 11 май 2026, 18:55

Re: Ingress: пускаем трафик снаружи

Сообщение ksanders »

маленькое дополнение: аддон minikube помечает класс nginx как дефолтный (аннотация ingressclass.kubernetes.io/is-default-class), поэтому у меня все заработало даже без ingressClassName. но в манифестах все равно пишу явно, в облачном кластере дефолта может и не быть
👍 ❤️ 🔥 😄 🤔
Аватара пользователя
snell99
Сообщения: 2
Зарегистрирован: 11 май 2026, 02:58

Re: Ingress: пускаем трафик снаружи

Сообщение snell99 »

а если домена нет и хочется ходить просто по ip кластера, можно правило вообще без host? или без записи в /etc/hosts никак
👍 ❤️1 🔥 😄 🤔1
Ответить
← Предыдущая глава
ConfigMap и Secret: выносим конфигурацию
Следующая глава →
Хранилище: Volumes и PersistentVolumeClaim

Все главы курса «Kubernetes: оркестрация контейнеров от основ до продакшена»

Поделиться темой: ✈ Telegram VK
Похожие запросы: ingress nginx как пустить трафик в kubernetes снаружи

Вернуться в «Kubernetes на практике»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость