Kubernetes Gateway API: чем он лучше Ingress и когда переходить

Gateway API — новый стандарт управления входящим трафиком в Kubernetes. Чем он отличается от Ingress, какие задачи решает лучше, как оценивать готовность реализаций к production и когда переход действительно оправдан.

Ingress в Kubernetes решил базовую задачу: дать единый способ направить внешний HTTP-трафик к сервисам внутри кластера. Но за годы использования стали видны его ограничения: слабая модель ролей, отсутствие поддержки TCP/UDP, зависимость от аннотаций конкретного контроллера и невозможность разделить ответственность между командами.

Gateway API — официальный ответ на эти проблемы. Не замена Ingress “один в один”, а переосмысление того, как описывать маршрутизацию трафика в Kubernetes с учётом реальных эксплуатационных потребностей.

В статье

Что не так с Ingress

Ingress работает, но его модель имеет несколько фундаментальных проблем:

  • Одна роль на всё. Ingress-ресурс описывает и инфраструктурный слой (какой балансировщик, какие TLS-сертификаты), и прикладной (какие пути к каким сервисам). В большой команде это создаёт конфликты: разработчик хочет добавить маршрут, но вынужден править ресурс, за который отвечает платформенная команда.

  • Аннотации вместо API. Расширенная функциональность (rate limiting, rewrite, auth) реализуется через аннотации, специфичные для каждого контроллера. Переход с nginx-ingress на Traefik или Envoy часто означает переписывание всех Ingress-ресурсов.

  • Только HTTP/HTTPS. Ingress не поддерживает TCP, UDP и gRPC как first-class citizens. Для них нужны отдельные CRD или Service типа LoadBalancer.

  • Нет стандартной модели для traffic splitting. Canary, weighted routing, header-based routing — всё через аннотации или отдельные CRD, у каждого контроллера свои.

Gateway API: основные объекты и модель

Важно сразу: Gateway API — не часть ядра Kubernetes. Это отдельный набор CRD (bundle), который ставится в кластер; «появился в 1.26» — миф. Базовые типы (GatewayClass, Gateway, HTTPRoute, GRPCRoute) — GA; L4-типы (TCPRoute, UDPRoute) пока экспериментальные.

Gateway API вводит три уровня абстракции:

flowchart TD subgraph platform["Платформенная команда"] GC["GatewayClass
тип контроллера"] end subgraph infrateam["Инфра / платформа"] GW["Gateway
порты, протоколы, TLS"] end subgraph devs["Команды разработки"] R1["HTTPRoute"] R2["GRPCRoute"] R3["TCPRoute / UDPRoute
(Experimental)"] end GC --> GW GW --> R1 GW --> R2 GW --> R3

flowchart TD
    subgraph platform["Платформенная команда"]
        GC["GatewayClass
тип контроллера"] end subgraph infrateam["Инфра / платформа"] GW["Gateway
порты, протоколы, TLS"] end subgraph devs["Команды разработки"] R1["HTTPRoute"] R2["GRPCRoute"] R3["TCPRoute / UDPRoute
(Experimental)"] end GC --> GW GW --> R1 GW --> R2 GW --> R3
Три уровня Gateway API и кто каким владеет
  • GatewayClass — описывает тип инфраструктуры (какой контроллер обслуживает трафик). Аналог StorageClass, но для сетевого слоя. Создаётся платформенной командой.

  • Gateway — конкретный экземпляр точки входа: на каких портах слушать, какие протоколы принимать, какой TLS-сертификат использовать. Создаётся инфраструктурной командой или платформой.

  • HTTPRoute / TCPRoute / GRPCRoute — правила маршрутизации трафика к сервисам. Создаются командами разработки. Привязываются к Gateway через parentRefs.

Ключевое отличие от Ingress: каждый уровень может управляться отдельной командой с отдельными правами RBAC.

Разделение ролей: инфраструктура vs приложение

RBAC Kubernetes ложится на эту модель почти дословно. GatewayClass — кластерный ресурс, Gateway живёт в инфраструктурном namespace (обоими владеет платформа), а разработчикам выдаётся право только на HTTPRoute в их собственном namespace:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: route-editor
  namespace: team-a
rules:
  - apiGroups: ["gateway.networking.k8s.io"]
    resources: ["httproutes"]
    verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: team-a-route-editors
  namespace: team-a
subjects:
  - kind: Group
    name: team-a
    apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: route-editor
  apiGroup: rbac.authorization.k8s.io

То, какие namespace и какие Route разрешено подключать к конкретному Gateway, контролирует сама платформа через spec.listeners[].allowedRoutes в Gateway, а ссылки на бэкенды в чужих namespace разрешаются объектом ReferenceGrant (особый случай: он в Standard channel, но всё ещё v1beta1). Прав на httproutes у разработчика недостаточно, чтобы «прицепиться» к чужой точке входа без явного разрешения.

В реальных организациях это даёт конкретную пользу:

  • платформенная команда контролирует, какие точки входа существуют, какие TLS-политики применяются и какие протоколы разрешены;
  • команды разработки самостоятельно описывают маршруты к своим сервисам, не трогая инфраструктурный слой;
  • RBAC Kubernetes естественно ложится на эту модель: Gateway — в infra namespace, HTTPRoute — в namespace приложения.

Сравнение: Ingress vs Gateway API

Возможность Ingress Gateway API
HTTP-маршрутизация Да Да (HTTPRoute, GA)
gRPC Через CRD контроллера GRPCRoute — GA (Standard)
TCP / UDP (L4) Через CRD контроллера TCPRoute / UDPRoute — Experimental (Alpha)
Traffic splitting (canary) Аннотации (не стандартизированы) Нативно (backendRefs с weight)
Header-based routing Аннотации Нативно (HTTPRouteMatch)
Разделение ролей Нет GatewayClass → Gateway → Route
Переносимость между контроллерами Низкая (аннотации) Высокая (стандартный API)
Зрелость Stable, повсеместно Зависит от Route-типа: HTTPRoute/GRPCRoute — GA, L4 — экспериментальные

Реализации: какие контроллеры поддерживают Gateway API

Gateway API — это спецификация и набор CRD, а не контроллер. Реализаций уже много, и большинство популярных входных контроллеров поддерживают её как первоклассный API:

  • Envoy Gateway — реализация поверх Envoy, простой вход в Gateway API.
  • Istio — Gateway API стал рекомендуемым способом конфигурации; покрывает и ingress, и mesh (GAMMA).
  • Cilium — Gateway API «из коробки» (HTTP, TLS, gRPC), удобно, если CNI уже Cilium.
  • NGINX Gateway Fabric — официальная реализация от NGINX (отдельный проект, не путать с ingress-nginx, который Gateway API не реализует).
  • Traefik, Kong — поддерживают Gateway API наряду со своими Ingress-контроллерами.

Снимок conformance на июнь 2026 (статус быстро меняется — это не замена проверке):

Реализация Gateway-профиль (conformance) Mesh (GAMMA)
Cilium Conformant Да
Istio Conformant Да
NGINX Gateway Fabric Conformant Нет
Traefik Conformant Нет
Envoy Gateway Partially conformant Частично

Поддержка конкретных Route-типов (особенно L4: TCPRoute/UDPRoute) и расширений меняется от версии к версии. Перед выбором обязательно сверяйтесь с актуальным списком реализаций и conformance-отчётами и проверяйте именно те профили и Route-типы, что нужны вам.

С чего начать и когда переходить

Переходить стоит, если узнаёте свою ситуацию:

  • несколько команд делят один вход и конфликтуют за Ingress-ресурсы — разделение ролей Gateway API снимает это;
  • нужны gRPC или штатный weighted/header-based routing без зоопарка аннотаций (L4 — TCP/UDP — пока экспериментальный, проверьте поддержку);
  • хочется переносимости между контроллерами (стандартный API вместо вендорных аннотаций);
  • разворачиваете кластер с нуля и контроллер (Cilium, Istio, Envoy Gateway) уже умеет Gateway API.

Переход не обязан быть «всё и сразу»: Gateway API спокойно работает рядом с Ingress. Платформа поднимает один общий Gateway, разработчики прицепляют к нему свои HTTPRoute, проверяете на одном сервисе — и мигрируете по одному.

Сначала — точка входа, которой владеет платформа: тип контроллера, слушатели и то, кому разрешено прицепляться:

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: shared-gateway
  namespace: infra
spec:
  gatewayClassName: cilium          # тип контроллера; см. kubectl get gatewayclass
  listeners:
    - name: https
      protocol: HTTPS
      port: 443
      tls:
        certificateRefs:
          - name: wildcard-tls
      allowedRoutes:                 # какие namespace могут прицеплять Route
        namespaces:
          from: Selector
          selector:
            matchLabels:
              gateway-access: "true"

Затем разработчик в своём namespace описывает маршрут и привязывает его к этому Gateway через parentRefs:

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: app
  namespace: team-a
spec:
  parentRefs:
    - name: shared-gateway
      namespace: infra
  hostnames: ["app.example.com"]
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /
      backendRefs:
        - name: app
          port: 80

Перед миграцией прогоните короткий чеклист — он ловит почти все проблемы заранее:

  • kubectl get gatewayclass — контроллер установлен и в статусе Accepted;
  • conformance выбранного контроллера для нужных профиля и Route-типов (HTTP / gRPC / L4);
  • parity аннотаций: вендорные rewrite / auth / rate-limit из ваших Ingress выразимы в Gateway API или через расширение реализации;
  • proxy-protocol / client IP / TLS passthrough — сквозной стык edge ↔ Gateway реально работает (ниже — наш кейс, где это и стало стопором);
  • перевод одного сервиса на HTTPRoute и проверка трафика;
  • rollback наготове: старый Ingress остаётся рядом, откат — переключением.

Что Gateway API не решает

Gateway API стандартизирует маршрутизацию, а не весь функционал «продуктового» API gateway. За его рамками остаются:

  • WAF, аутентификация, rate limiting, авторизация — через policy attachment или расширения конкретной реализации, не единым стандартом;
  • Наблюдаемость (метрики, трейсы, access-логи) — зависит от контроллера;
  • Сложные трансформации (rewrite, mirroring, тонкие retry/timeout) — частично в Standard, частично в расширениях.

То есть Gateway API — про то, кто и как описывает маршруты, а не замена Kong / Apigee / облачного API gateway по фичам. Если нужно полноценное управление API как продуктом, Gateway API будет лишь точкой входа, а политики — отдельным слоем.

Типичные ошибки

  • Преждевременный переход. Если у вас один Ingress на пару сервисов и команда из двух человек — Gateway API не даст выигрыша, только добавит сущностей. Его ценность раскрывается на масштабе команд и протоколов.
  • Миграция «большим взрывом». Переписывать все Ingress разом рискованно. Gateway API сосуществует с Ingress — переводите по сервису.
  • Игнорирование RBAC-модели. Если выдать всем права на Gateway и GatewayClass, теряется главный смысл — разделение ответственности. Разработчикам — только HTTPRoute в их namespace.
  • Забыть про ReferenceGrant и allowedRoutes. Кросс-namespace ссылки и подключение к чужому Gateway по умолчанию запрещены — это не баг, а защита; настраивается явно.
  • Расчёт на полный паритет с аннотациями. Часть вендорных фич Ingress (специфичные rewrite, auth) в Gateway API выражается иначе или через расширения конкретной реализации — проверьте заранее, что нужные возможности есть.

Из практики: почему мы остались на Ingress

Мы хотели перейти на Gateway API в собственном homelab-кластере на Cilium, но упёрлись в сохранение реального IP клиента. На входе стоит HAProxy, который отдаёт бэкенду PROXY protocol (send-proxy-v2) — чтобы кластер видел адрес источника, а не адрес edge-балансировщика. Связку «HAProxy → Cilium Gateway API + proxy-protocol» завести надёжно не удалось, и мы осознанно остались на Cilium Ingress: там приём proxy-protocol работает предсказуемо, а client IP доезжает до приложений.

Вывод не «Gateway API хуже». Вывод в том, что миграцию блокирует не сравнение фич на бумаге, а конкретный стык вашего edge с реализацией: proxy-protocol, TLS passthrough, сохранение client IP, поведение под нагрузкой. Пока этот стык реально не работает в вашем окружении — переходить рано, каким бы привлекательным ни был стандарт. Gateway API остаётся целью, но дату миграции назначает не релиз-нота, а зелёный прогон этой интеграции у вас.

Итог

Gateway API — не «Ingress 2.0 ради моды», а другая модель: инфраструктура и маршруты разделены, HTTP/gRPC-маршрутизация и traffic splitting стандартизированы (HTTPRoute/GRPCRoute — GA), а L4 вынесена в экспериментальные TCPRoute/UDPRoute и требует отдельной проверки поддержки; конфигурация переносима между контроллерами. Для одиночного сервиса это избыточно; для нескольких команд за общим входом — заметное упрощение эксплуатации и прав. Практичный путь — поднять Gateway рядом с Ingress, перевести один сервис и мигрировать постепенно.

Документация и первоисточники

Обсуждение в Telegram

Присоединиться →

Комментарии