Ingress, ingress-контроллеры и Gateway API

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

Ingress, ingress-контроллеры и Gateway API

Сообщение 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
Боль: как пустить внешний трафик внутрь кластера и не утонуть

У тебя в кластере крутится десяток сервисов. Снаружи им нужен один вход: api.example.com, shop.example.com, grafana.example.com - все на 443, с валидным TLS, с маршрутизацией по хосту и пути. Поднимать на каждый сервис по облачному балансировщику - дорого и глупо: пять сервисов это пять внешних IP, пять счетов и зоопарк правок DNS. Городить свой nginx на отдельной VM, который проксирует в NodePort - значит вернуться в 2015 год и руками держать конфиг в актуальном состоянии.

Kubernetes придумал на это два слоя абстракции. Сначала был Ingress - декларативное правило "хост плюс путь -> Service". Потом, когда стало ясно, что Ingress слишком беден и его раздули аннотациями до неузнаваемости, появился Gateway API - его официальный преемник. И тут важная новость 2026 года, которую ты обязан знать: самый популярный контроллер ingress-nginx ретирован (best-effort поддержка закончилась в марте 2026), а его планируемая замена InGate так и не взлетела и тоже свёрнута. Поэтому разговор про kubernetes ingress сегодня - это во многом разговор про то, куда с него мигрировать. Давай по порядку: что такое Ingress под капотом, почему ingress nginx был стандартом, и почему профессиональный выбор на новых кластерах - Gateway API.

Изображение

Механика Ingress: правило и контроллер - это две разные вещи

Главное, что путает новичков: ресурс Ingress сам по себе НЕ принимает трафик. Это просто запись в etcd, набор правил. Чтобы она ожила, в кластере должен крутиться ingress-контроллер - реальный под (обычно Deployment или DaemonSet) с прокси внутри (nginx, Envoy, HAProxy, Traefik), который следит за объектами Ingress через API-сервер и на лету перестраивает свой конфиг. Создал Ingress без контроллера - он просто висит и ничего не делает.

Снаружи на контроллер обычно смотрит Service типа LoadBalancer: облако (Yandex Managed Kubernetes, VK Cloud) выдаёт ему один внешний IP и один сетевой балансировщик L4, а дальше уже под-контроллер раскидывает HTTP по правилам L7. То есть один внешний IP обслуживает все твои домены. Вот минимальный реальный Ingress:

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

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: shop
  namespace: prod
spec:
  ingressClassName: nginx
  rules:
  - host: shop.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: shop-web
            port:
              number: 80
Разберём поля, которые реально решают:
  • ingressClassName - какой контроллер обслуживает это правило. В кластере их может быть несколько (внутренний и внешний, например), и каждый берёт только "свои" Ingress. Раньше класс задавали аннотацией kubernetes.io/ingress.class - это устаревший способ, на новых версиях используй поле.
  • pathType - Prefix (совпадение по префиксу пути с учётом сегментов), Exact (точное совпадение) или ImplementationSpecific (как решит контроллер). Тут классические грабли: Prefix /foo матчит /foo и /foo/bar, но НЕ /foobar - матчинг идёт по сегментам, а не по символам.
  • host - маршрутизация по Host-заголовку. Без host правило ловит любой домен, что почти всегда не то, что тебе нужно.
Проверяем, что контроллер реально подцепил адрес:

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

$ kubectl get ingress -n prod
NAME   CLASS   HOSTS              ADDRESS         PORTS     AGE
shop   nginx   shop.example.com   84.201.xxx.xx   80, 443   12m
Если в колонке ADDRESS пусто дольше пары минут - контроллер не отработал. Смотри kubectl describe ingress shop -n prod (внизу в Events будет Sync), затем логи самого пода-контроллера. Чаще всего причина банальна: не тот ingressClassName, либо Service-бэкенд указывает на несуществующий порт.

TLS и cert-manager: автоматический kubernetes tls без боли

Терминировать HTTPS руками, обновляя сертификаты раз в три месяца через cron - путь к ночному инциденту "сертификат протух". Стандарт индустрии - cert-manager: оператор, который выпускает и продлевает сертификаты автоматически, в том числе бесплатные от Let's Encrypt по протоколу ACME.

Схема такая. Ты ставишь cert-manager, создаёшь объект Issuer или ClusterIssuer (кто и как выдаёт сертификаты), вешаешь на Ingress аннотацию - и cert-manager сам проходит ACME-челлендж, кладёт готовый сертификат в Secret, а потом следит за сроком и перевыпускает за 30 дней до истечения. Никакого cron.

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

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

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

metadata:
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  tls:
  - hosts:
    - shop.example.com
    secretName: shop-tls
Как это работает под капотом при http01-челлендже: cert-manager создаёт временный Ingress (или, в режиме Gateway API, временный HTTPRoute) на путь /.well-known/acme-challenge/..., Let's Encrypt стучится по нему снаружи, убеждается что домен твой, выдаёт сертификат - и временный объект удаляется. Отсюда главная грабля: для http01 домен ОБЯЗАН резолвиться на твой балансировщик из внешнего интернета ещё до выпуска. Нет публичного DNS A-записи - используй dns01-челлендж (cert-manager создаёт TXT-запись через API твоего DNS-провайдера). Проверить статус:

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

$ kubectl get certificate -n prod
NAME       READY   SECRET     AGE
shop-tls   True    shop-tls   3m

$ kubectl get certificaterequest,order,challenge -n prod
Если READY долго False - смотри kubectl describe challenge: там в Reason обычно прямым текстом "Waiting for HTTP-01 challenge propagation" или ошибка DNS. Это экономит часы гадания.

Аннотации: где Ingress начал трещать по швам

Базовый Ingress умеет только host/path. Всё остальное - rate-limit, переписывание путей, canary, таймауты, размер тела запроса - в ingress-nginx навешивалось аннотациями, специфичными для контроллера. Примеры из боевой эксплуатации:

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

metadata:
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$2
    nginx.ingress.kubernetes.io/limit-rps: "20"
    nginx.ingress.kubernetes.io/proxy-body-size: "50m"
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-weight: "10"
Выглядит удобно, но это и есть корень проблемы. Аннотации - это конфиг, спрятанный в строках, без схемы и валидации на уровне API. Контроллер подставляет их значения в шаблон nginx.conf, и именно отсюда росла та цепочка тяжёлых CVE (вспомни IngressNightmare 2025-го), из-за которой проект в итоге и ретировали: внедрение конфигурации nginx через поля Ingress давало путь к выполнению кода в контроллере. Плюс аннотации не переносимы: canary-weight от ingress-nginx ничего не значит для Traefik. Ты прибит гвоздями к одному контроллеру. Gateway API ровно эту болезнь и лечит.

Gateway API: стандартная замена Ingress в 2026

Gateway API - это не "ещё один контроллер", а новый набор ресурсов (CRD), который SIG Network делает официальным преемником Ingress. Ключевые ресурсы GatewayClass, Gateway и HTTPRoute давно стабильны (v1, GA), а версия Gateway API 1.5, вышедшая в начале 2026, перевела в Standard ещё кучу фич. Главная идея - разделение ролей. Раньше один Ingress смешивал заботы платформенной команды (порты, TLS, инфраструктура) и заботы команды приложения (пути, бэкенды). Gateway API режет это на три слоя:
  • GatewayClass - "какой реализацией рулим" (аналог StorageClass для дисков). Ставит вендор/инфра-команда: Envoy Gateway, Cilium, Istio, NGINX Gateway Fabric, облачный.
  • Gateway - конкретная точка входа: слушатели (listeners) на портах, протоколы, TLS-сертификаты. Это зона ответственности платформенной команды.
  • HTTPRoute (а также GRPCRoute, TCPRoute, TLSRoute) - правила маршрутизации, которые пишет команда приложения в своём неймспейсе, ссылаясь на общий Gateway.

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

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: prod-gw
  namespace: gateway-system
spec:
  gatewayClassName: envoy
  listeners:
  - name: https
    protocol: HTTPS
    port: 443
    hostname: "*.example.com"
    tls:
      mode: Terminate
      certificateRefs:
      - name: wildcard-example-tls
    allowedRoutes:
      namespaces:
        from: Selector
        selector:
          matchLabels:
            gateway-access: "true"

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

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: shop
  namespace: prod
spec:
  parentRefs:
  - name: prod-gw
    namespace: gateway-system
  hostnames:
  - shop.example.com
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    - name: shop-web
      port: 80
Что тут принципиально лучше Ingress:
  • Canary и веса - это поле, а не аннотация. Под одним match можно дать несколько backendRefs с weight: 90 и weight: 10 - и это часть стандартной спеки, переносимой между контроллерами. Никаких canary-weight в строках.
  • filters вместо аннотаций: requestHeaderModifier, urlRewrite, requestRedirect, requestMirror - типизированные поля с валидацией на API-сервере.
  • allowedRoutes - платформенная команда явно решает, какие неймспейсы вправе цепляться к Gateway. Multi-tenant из коробки.
  • Не только HTTP: GRPCRoute для gRPC, TCPRoute/TLSRoute для L4 - то, чего в Ingress не было в принципе.
Проверка статуса даёт куда больше сигнала, чем у Ingress:

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

$ kubectl get gateway prod-gw -n gateway-system
NAME      CLASS   ADDRESS         PROGRAMMED   AGE
prod-gw   envoy   84.201.xxx.xx   True         5m

$ kubectl get httproute shop -n prod -o wide
NAME   HOSTNAMES               AGE
shop   ["shop.example.com"]    4m
В Gateway условие PROGRAMMED=True означает "слушатель реально сконфигурирован в дата-плейне". А в status HTTPRoute контроллер пишет condition Accepted и ResolvedRefs - если бэкенд не найден или ты не имеешь права цепляться к Gateway, увидишь это явным False с причиной. У классического Ingress такой обратной связи по сути не было, и отладка шла через логи.

L4 против L7: что где терминируется

Чтобы не путаться. L4-балансировка (транспорт, TCP/UDP) - это про IP и порт, она не знает про HTTP-хосты и пути. Service типа LoadBalancer и облачный сетевой балансировщик - это L4. L7-балансировка (приложение) понимает HTTP: хост, путь, заголовки, может терминировать TLS и раздавать canary. Ingress-контроллер и Gateway с HTTPRoute - это L7.

В типичном кластере они работают в связке: облачный L4-балансировщик ловит трафик на внешнем IP и просто перебрасывает пакеты на поды контроллера, а уже контроллер (L7) разбирает HTTP и маршрутизирует. Знать разницу критично: rate-limit по URL или canary по весу ты сделаешь только на L7; а если нужен голый TCP (база, брокер, кастомный протокол) - тебе хватит L4 Service-а или TCPRoute, и тащить туда HTTP-прокси бессмысленно.

Миграция Ingress -> Gateway API и выбор контроллера

Раз ingress-nginx ретирован, а InGate не состоялся, оставаться на нём после марта 2026 - это сознательно держать незакрываемые уязвимости на главном входе в кластер. Steering Committee прямо предупреждает: drop-in замены нет, мигрировать надо осознанно. Практические варианты:
  • Остаёшься на модели Ingress, но меняешь контроллер: Traefik (богатый, свои CRD), HAProxy Ingress (предсказуемая производительность), NGINX Gateway Fabric от F5 (это уже не ingress-nginx, а отдельный проект на Gateway API). На k3s по умолчанию едет Traefik.
  • Переходишь на Gateway API - стратегически верный путь: Envoy Gateway, Cilium (если уже на eBPF-CNI - Gateway встроен), Istio, облачные реализации в Yandex Managed Kubernetes и VK Cloud.
Миграцию не делают рубильником. Реальный путь: подними Gateway-контроллер рядом со старым, переведи cert-manager на gateway-shim (он умеет вешать ClusterIssuer прямо на Gateway), перенеси маршруты по одному домену через DNS/веса, дай поработать в паре, потом гаси Ingress. Для перевода манифестов есть утилита ingress2gateway - она конвертирует Ingress в Gateway+HTTPRoute, но проверяй результат руками: аннотации ingress-nginx в чистый стандарт переносятся не один-в-один.

Типичные грабли и антипаттерны
  • Несколько контроллеров без ingressClassName/gatewayClassName - правило подхватывают сразу два, конфликт. Всегда указывай класс явно.
  • Терминируешь TLS на Ingress и снова на приложении (двойной HTTPS) без нужды - лишняя задержка и путаница с сертификатами. Решай, где именно граница TLS.
  • http01-челлендж на домене, который не резолвится снаружи - Let's Encrypt не достучится, сертификат вечно Pending. Внутренние домены - только dns01.
  • Prefix-матчинг как подстрока - /api матчит /api/v1, но не /apitest. Не путай с regex.
  • Тяжёлая логика в аннотациях ingress-nginx - именно отсюда росли CVE. На новых кластерах не строй на этом, иди в Gateway API с типизированными filters.
  • rewrite-target без понимания capture-групп - классический источник 404: путь переписался не туда. Тестируй на staging.
Мини-лаба: повторить руками
  • Подними локальный кластер (kind или k3s). На k3s Traefik уже внутри - удобно.
  • Поставь cert-manager: kubectl apply -f с официальным манифестом релиза, дождись Running всех подов в namespace cert-manager.
  • Разверни простой Deployment с echo-сервером и Service на порт 80.
  • Вариант A (Ingress): создай Ingress с host и pathType: Prefix, проверь kubectl get ingress - появился ли ADDRESS. Запроси curl -H "Host: app.local" http://<ADDRESS>/.
  • Вариант B (Gateway API): поставь CRD Gateway API и Envoy Gateway, создай Gateway с listener на 80 и HTTPRoute на тот же бэкенд. Сравни kubectl describe httproute - найди condition Accepted и ResolvedRefs.
  • Бонус: добавь второй backendRef с weight и проверь, что часть запросов уходит на canary-версию.
Контрольные вопросы
  • Почему сам по себе объект Ingress не принимает трафик и что обязательно должно быть в кластере, чтобы он заработал?
  • Чем http01-челлендж cert-manager отличается от dns01 и в каком случае http01 в принципе не сработает?
  • Как Gateway API реализует разделение ролей между платформенной командой и командой приложения - какие ресурсы кому принадлежат?
  • Где проходит граница L4 и L7 в типичной связке "облачный балансировщик + ingress-контроллер" и почему canary по весу нельзя сделать на L4?
Итог

Ingress дал декларативный L7-вход, но беднота спеки утянула всю мощь в непереносимые и небезопасные аннотации - и в 2026-м флагманский ingress-nginx ушёл на покой. Профессиональный стандарт сегодня - Gateway API: типизированный, с разделением ролей, с canary/filters как полями, с поддержкой gRPC и L4. TLS в обоих мирах автоматизирует cert-manager поверх Let's Encrypt. На существующих кластерах планируй миграцию Ingress -> Gateway API, на новых - начинай сразу с Gateway. Это не мода, а закрытие реального риска на самом критичном периметре кластера.
👍3 ❤️ 🔥1 😄 🤔1
Аватара пользователя
midnightphoenix
Сообщения: 1
Зарегистрирован: 20 май 2026, 01:23

Re: Ingress, ingress-контроллеры и Gateway API

Сообщение midnightphoenix »

Перешли с ingress-nginx после ретайра, и реально - canary как backendRefs с weight это другое дело, никаких больше магических аннотаций. Спасибо что разжевали разделение ролей, наконец-то дошло зачем Gateway и HTTPRoute разнесли.
👍1 ❤️ 🔥 😄 🤔
Аватара пользователя
Murzik
Сообщения: 1
Зарегистрирован: 31 май 2026, 12:00

Re: Ingress, ingress-контроллеры и Gateway API

Сообщение Murzik »

Вопрос по cert-manager: у нас внутренний домен без публичного DNS, http01 висит в Pending как вы и написали. Правильно понимаю, что единственный путь - dns01 через API нашего провайдера, или есть вариант с self-signed ClusterIssuer для внутрянки?
👍2 ❤️1 🔥1 😄 🤔
Ответить
← Предыдущая глава
Сервисы и kube-proxy глубже: типы, IPVS, EndpointSlices
Следующая глава →
Секреты в кластере: шифрование, External Secrets, Vault

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

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

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

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

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