Gateway API: новый стандарт traffic routing
Ingress появился в Kubernetes 1.1 (2015) и пережил 10 лет. За это время стало понятно, что у него есть фундаментальные ограничения:
- Слабая типизация — всё, что выходит за рамки basic HTTP, делается через annotations (vendor lock-in)
- Нет L4 (TCP, UDP) — только HTTP/HTTPS
- Нет gRPC как first-class (только через annotations)
- Нет role separation — все три роли (cluster admin, infra team, app team) меняют один и тот же Ingress объект
- Нет cross-namespace routing — TLS Secret и backend Service должны быть в одном namespace с Ingress
В 2019 году community начало работу над Gateway API — нового API, который решает все эти проблемы. К 2024 он достиг GA для core (v1.1) и стал de-facto стандартом для новых кластеров. На CKAD-экзамене Gateway API добавлен в curriculum с v1.33.
Разберём, как он устроен.
REST поверх HTTP: архитектурный стиль API
Три объекта вместо одного
Gateway API не один объект, а три, каждый принадлежит своей роли:
| Объект | Scope | Кто создаёт | Аналогия в Ingress |
|---|---|---|---|
| GatewayClass | Cluster | Cluster admin | IngressClass |
| Gateway | Namespace | Infrastructure team | Service type: LoadBalancer + Ingress controller config |
| HTTPRoute | Namespace | App team | Ingress rules |
Это и есть role separation — главная идея Gateway API. В мире Ingress всё (TLS, host, paths, backend) делается одним объектом, который правят все. В Gateway API каждая роль правит свой объект, и есть формальная граница между уровнями.
GatewayClass
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: envoy
spec:
controllerName: gateway.envoyproxy.io/gatewayclass-controller
Поля:
spec.controllerName— строка, по которой controller узнаёт “это про меня”- Cluster-scoped (не привязан к namespace)
- Создаётся обычно при установке controller (через Helm)
Аналогично IngressClass с spec.controller, просто другое имя поля.
Популярные controllers с Gateway API:
| Controller | controllerName |
|---|---|
| Envoy Gateway | gateway.envoyproxy.io/gatewayclass-controller |
| Cilium | io.cilium/gateway-controller |
| Istio | istio.io/gateway-controller |
| NGINX Gateway Fabric | gateway.nginx.org/nginx-gateway-controller |
| Kong | konghq.com/kic-gateway-controller |
| Google GKE Gateway | gke.io/gateway-controller (на GCP) |
| AWS Gateway API Controller | gateway.networking.k8s.io/aws-gateway-controller |
Gateway
Gateway — это реальный инстанс инфраструктуры. Когда вы его создаёте, controller (на основе GatewayClass) поднимает physical LB (cloud LB или Pods с nginx/Envoy).
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: shop-gateway
namespace: infra
spec:
gatewayClassName: envoy
listeners:
- name: http
protocol: HTTP
port: 80
- name: https
protocol: HTTPS
port: 443
tls:
mode: Terminate
certificateRefs:
- kind: Secret
name: shop-tls
hostname: "*.shop.example.com"
allowedRoutes:
namespaces:
from: Selector
selector:
matchLabels:
gateway-access: shop
Ключевые концепции:
- listeners — список endpoint-ов, на которых Gateway слушает. У каждого есть
protocol(HTTP, HTTPS, TCP, UDP, TLS),port, опциональноhostname,tls - tls.mode —
Terminate(расшифровать здесь, дальше plain HTTP в Service) илиPassthrough(передать TLS как есть в backend) - certificateRefs — Secret(ы) с сертификатами для этого listener
- allowedRoutes — какие HTTPRoute могут attach-иться к этому listener. Контроль доступа на уровне Gateway.
После создания controller выставит status.addresses[] — IP, на котором доступен Gateway.
kubectl get gateway -n infra shop-gateway
# NAME CLASS ADDRESS PROGRAMMED AGE
# shop-gateway envoy 1.2.3.4 True 2m
HTTPRoute
Самое интересное — описание routing-правил. Очень похоже на Ingress rules, но более выразительно и типизированно:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: api-route
namespace: shop
labels:
gateway-access: shop
spec:
parentRefs:
- name: shop-gateway
namespace: infra
hostnames:
- api.shop.example.com
rules:
- matches:
- path:
type: PathPrefix
value: /v1
method: GET
backendRefs:
- name: api-v1
port: 80
weight: 90
- name: api-v1-canary
port: 80
weight: 10
- matches:
- path:
type: PathPrefix
value: /v2
headers:
- name: X-Beta-Tester
value: "true"
backendRefs:
- name: api-v2-beta
port: 80
Ключевые отличия от Ingress:
- parentRefs — explicit ссылка на Gateway. Можно ссылаться на Gateway в другом namespace (cross-namespace routing).
- matches в правиле — массив. Можно матчить по
path,headers,method,queryParamsодновременно. - backendRefs — массив с
weight(built-in weighted routing для canary deployments!) - filters (не показано) — встроенные модификации запроса (rewrite, redirect, request/response header manipulation) без annotations
Weighted routing native в HTTPRoute — это огромное преимущество над Ingress. В Ingress canary делается через annotations или service mesh. В Gateway API — backendRefs: [{name: v1, weight: 90}, {name: v2, weight: 10}]. Простой, портативный, понятный.
pathType: PathPrefix, Exact, RegularExpression
Аналог pathType в Ingress, с тремя значениями:
- Exact — точное совпадение
- PathPrefix — то же, что Prefix в Ingress: matches
/foo,/foo/,/foo/bar, но НЕ/foobar - RegularExpression — full regex (поддержка зависит от controller)
matches:
- path:
type: PathPrefix
value: /api
Cross-namespace routing через ReferenceGrant
Главная новинка Gateway API после role separation. HTTPRoute из namespace shop может attach к Gateway в namespace infra. Но для этого нужно разрешение от owner ресурса — через объект ReferenceGrant.
Сценарий 1: HTTPRoute в одном NS, Gateway в другом
# В namespace infra: Gateway
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: shop-gateway
namespace: infra
spec:
listeners:
- name: https
port: 443
protocol: HTTPS
allowedRoutes:
namespaces:
from: All # любой namespace может attach
# В namespace shop: HTTPRoute
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: api
namespace: shop
spec:
parentRefs:
- name: shop-gateway
namespace: infra # <-- cross-namespace
rules: [ ... ]
Gateway.spec.listeners[].allowedRoutes.namespaces.from контролирует, кто может attach: All, Same (только тот же NS), Selector (по labels).
Сценарий 2: HTTPRoute ссылается на Service в другом NS
Для этого нужен ReferenceGrant — owner namespace явно разрешает использовать свои Service как backend.
# В namespace infra: ReferenceGrant
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
name: allow-shop-to-use-our-svc
namespace: infra
spec:
from:
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: shop
to:
- group: ""
kind: Service
name: legacy-api # конкретный Service
Теперь HTTPRoute в namespace shop может иметь backendRefs: [{name: legacy-api, namespace: infra, port: 80}].
Без ReferenceGrant — controller отклонит routing на cross-namespace Service.
ReferenceGrant — security mechanism. Без него Gateway API не позволил бы cross-NS, что блокировало бы многие use-cases. Но bidirectional explicit consent — это правильно: owner Service контролирует, кто может его использовать.
L4: TCPRoute, UDPRoute, TLSRoute, GRPCRoute
Gateway API не ограничен HTTP. Есть отдельные kind для других протоколов:
TCPRoute
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: TCPRoute
metadata:
name: postgres
spec:
parentRefs:
- name: tcp-gateway
sectionName: postgres
rules:
- backendRefs:
- name: postgres
port: 5432
Базовое TCP-проксирование, без HTTP-семантики. Подходит для БД, MQ, custom protocols.
UDPRoute
То же для UDP — DNS, метрики, gaming.
TLSRoute
Для TLS passthrough — backend сам терминирует TLS, Gateway только маршрутизирует по SNI (Server Name Indication):
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: TLSRoute
metadata:
name: tls-passthrough
spec:
parentRefs:
- name: tls-gateway
hostnames:
- secure.example.com
rules:
- backendRefs:
- name: app-with-mtls
port: 8443
Используется для mTLS, custom certificate validation, gRPC over TLS.
GRPCRoute
apiVersion: gateway.networking.k8s.io/v1
kind: GRPCRoute
metadata:
name: grpc-route
spec:
parentRefs:
- name: gateway
hostnames:
- grpc.example.com
rules:
- matches:
- method:
service: order.OrderService
method: ListOrders
backendRefs:
- name: orders-grpc
port: 50051
Native gRPC routing — матч по service и method proto-описания. В Ingress этого нет в принципе (только TCP proxy + annotation для HTTP/2).
Filters: встроенные модификации запроса
Вместо vendor annotations Gateway API предоставляет типизированные filters:
spec:
rules:
- matches:
- path: { type: PathPrefix, value: /api/v1 }
filters:
- type: URLRewrite
urlRewrite:
path:
type: ReplacePrefixMatch
replacePrefixMatch: /v1
- type: RequestHeaderModifier
requestHeaderModifier:
add:
- name: X-Forwarded-Service
value: api
remove:
- X-Internal-Token
backendRefs:
- name: api
port: 80
Типы filters:
RequestHeaderModifier— модификация request headersResponseHeaderModifier— модификация response headersURLRewrite— переписывание path / hostnameRequestRedirect— HTTP-редиректRequestMirror— зеркалирование запроса в другой backend (для тестов)ExtensionRef— расширение конкретного controller
Это эквивалент annotations в Ingress, но стандартизированный, портативный между controllers.
Status и observability
Gateway API богаче на status и conditions. Каждый объект имеет detailed status:
kubectl get gateway shop-gateway -o yaml | yq '.status'
# addresses:
# - type: IPAddress
# value: 1.2.3.4
# conditions:
# - type: Accepted
# status: "True"
# - type: Programmed
# status: "True"
# listeners:
# - name: https
# attachedRoutes: 5 # количество HTTPRoute прицепленных
# conditions:
# - type: Accepted
# status: "True"
# - type: Programmed
# status: "True"
# - type: ResolvedRefs
# status: "True"
kubectl get httproute api -o yaml | yq '.status'
# parents:
# - parentRef:
# name: shop-gateway
# namespace: infra
# conditions:
# - type: Accepted
# status: "True"
# - type: ResolvedRefs
# status: "True"
# - type: ResolvedRefs
# status: "False" # <-- если backend Service не найден
# reason: BackendNotFound
# message: "Service shop/api-v3 not found"
Это сильно облегчает troubleshooting — Gateway API явно говорит почему routing не работает (через conditions), а не оставляет догадываться.
Полный пример: GatewayClass + Gateway + HTTPRoute
# Cluster admin: GatewayClass
---
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: production-gateway
spec:
controllerName: gateway.envoyproxy.io/gatewayclass-controller
# Infrastructure team: Gateway
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: shop-gateway
namespace: infra
spec:
gatewayClassName: production-gateway
listeners:
- name: https
protocol: HTTPS
port: 443
hostname: "*.shop.example.com"
tls:
mode: Terminate
certificateRefs:
- name: shop-wildcard-tls
allowedRoutes:
namespaces:
from: All
# App team A: HTTPRoute для api
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: api-route
namespace: shop-api
spec:
parentRefs:
- name: shop-gateway
namespace: infra
hostnames:
- api.shop.example.com
rules:
- matches:
- path: { type: PathPrefix, value: /v1 }
backendRefs:
- name: api-v1
port: 80
- matches:
- path: { type: PathPrefix, value: /v2 }
filters:
- type: URLRewrite
urlRewrite:
path:
type: ReplacePrefixMatch
replacePrefixMatch: /
backendRefs:
- name: api-v2
port: 80
weight: 90
- name: api-v2-canary
port: 80
weight: 10
# App team B: HTTPRoute для web (другой namespace, тот же Gateway)
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: web-route
namespace: shop-web
spec:
parentRefs:
- name: shop-gateway
namespace: infra
hostnames:
- www.shop.example.com
rules:
- matches:
- path: { type: PathPrefix, value: / }
backendRefs:
- name: web
port: 80
Что мы получили:
- Один Gateway
shop-gatewayобслуживает всё семейство*.shop.example.com - TLS-сертификат настроен один раз на Gateway уровне
- Две независимые app team в разных namespace attach свои HTTPRoutes без передаравания YAML инфраструктурной команде
- Canary routing для api-v2 без annotations — нативно в spec
- URLRewrite фильтр без annotations
В Ingress всё это было бы один большой объект с annotations, проблемами cross-NS и vendor lock-in.
Не путать с Istio Gateway
В Istio есть свой Gateway объект — networking.istio.io/v1beta1. Это НЕ Gateway API. Это часть Istio API. До появления Gateway API Istio пытался решить те же проблемы по-своему.
| Объект | API | Кто реализует |
|---|---|---|
gateway.networking.k8s.io/Gateway | Gateway API (стандарт K8s SIG-Network) | многие controllers |
networking.istio.io/Gateway | Istio CRD | только Istio |
С 2024 Istio полностью поддерживает Gateway API, и community recommendation — использовать стандартный Gateway API, а не Istio Gateway, для нового кода.
CKAD scope
С Kubernetes v1.33 (релиз ~2025) Gateway API явно добавлен в CKAD curriculum. Уровень знания:
Концептуально:
- Понимать разницу между Ingress и Gateway API
- Знать три объекта (GatewayClass, Gateway, HTTPRoute) и их роли
- Понимать role separation
Практически:
- Создать простой HTTPRoute, attach к существующему Gateway
- Знать поля
parentRefs,hostnames,rules.matches.path,backendRefs
Не требуется (deeper Gateway API):
- ReferenceGrant в деталях
- TCPRoute, UDPRoute, TLSRoute, GRPCRoute
- Все типы filters
Pure Gateway API экзаменационный вопрос пока редкий — Ingress всё ещё чаще встречается. Но знать минимум, чтобы создать HTTPRoute по образцу, обязательно.
Установка для эксперимента
CRDs Gateway API не входят в default Kubernetes — их нужно ставить отдельно:
# CRD из upstream проекта (актуальную stable-версию см. в releases)
GATEWAY_VERSION=v1.2.1
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/${GATEWAY_VERSION}/standard-install.yaml
# Проверка
kubectl api-resources | grep gateway
# NAME APIVERSION KIND
# gateways gateway.networking.k8s.io/v1 Gateway
# gatewayclasses gateway.networking.k8s.io/v1 GatewayClass
# httproutes gateway.networking.k8s.io/v1 HTTPRoute
# referencegrants gateway.networking.k8s.io/v1beta1 ReferenceGrant
Потом — controller, поддерживающий Gateway API:
# Envoy Gateway (популярный community controller с Gateway API focus)
helm install envoy-gateway oci://docker.io/envoyproxy/gateway-helm \
--version v1.2.0 -n envoy-gateway-system --create-namespace
Или включить Gateway API в существующем controller-е:
- ingress-nginx поддерживает Gateway API параллельно с Ingress начиная с v1.10
- Istio включает gatewayAPI mode в IstioOperator config
- Cilium включает
gatewayAPI: enabled: trueв Helm values