Ingress в Kubernetes решил базовую задачу: дать единый способ направить внешний HTTP-трафик к сервисам внутри кластера. Но за годы использования стали видны его ограничения: слабая модель ролей, отсутствие поддержки TCP/UDP, зависимость от аннотаций конкретного контроллера и невозможность разделить ответственность между командами.
Gateway API — официальный ответ на эти проблемы. Не замена Ingress “один в один”, а переосмысление того, как описывать маршрутизацию трафика в Kubernetes с учётом реальных эксплуатационных потребностей.
В статье
- Что не так с Ingress
- Gateway API: основные объекты и модель
- Разделение ролей: инфраструктура vs приложение
- Сравнение: Ingress vs Gateway API
- Реализации: какие контроллеры поддерживают Gateway API
- С чего начать и когда переходить
- Что Gateway API не решает
- Типичные ошибки
- Из практики: почему мы остались на Ingress
Что не так с 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 вводит три уровня абстракции:
тип контроллера"] 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
-
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, перевести один сервис и мигрировать постепенно.
Комментарии