Learning Platform
Глоссарий Troubleshooting
Урок 10.04 · 25 мин
Продвинутый
Gateway APIGatewayClassHTTPRouteReferenceGrantRole separationL4 routing

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
GatewayClassClusterCluster adminIngressClass
GatewayNamespaceInfrastructure teamService type: LoadBalancer + Ingress controller config
HTTPRouteNamespaceApp teamIngress rules
Три роли, три объекта
GatewayClass (cluster-scoped)Cluster admin: 'У нас будет контроллер X'. Аналогично IngressClass — указывает, какой controller обслуживает этот тип Gateway. spec.controllerName идентифицирует controller, например gateway.envoyproxy.io/gatewayclass-controller.
референсится из Gateway
Gateway (namespaced)Infrastructure / platform team: 'У нас будет Gateway на 80/443, для домена *.shop.example.com, TLS вот этим сертификатом'. Создаёт реальный LB (controller на основе этого spec поднимает actual cloud LB или nginx Pod-ы). Может содержать несколько listeners.
attached via parentRefs
HTTPRoute (namespaced)App team: 'Запросы с path /api → мой service api-v2:80'. Описывает только routing, не привязан к конкретной инфраструктуре. Один Gateway может иметь много HTTPRoutes от разных team-ов, которые safely шарят инфраструктуру.

Это и есть 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:

ControllercontrollerName
Envoy Gatewaygateway.envoyproxy.io/gatewayclass-controller
Ciliumio.cilium/gateway-controller
Istioistio.io/gateway-controller
NGINX Gateway Fabricgateway.nginx.org/nginx-gateway-controller
Kongkonghq.com/kic-gateway-controller
Google GKE Gatewaygke.io/gateway-controller (на GCP)
AWS Gateway API Controllergateway.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.modeTerminate (расшифровать здесь, дальше 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
TIP

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.

Cross-namespace routing с ReferenceGrant
namespace: shopHTTPRoute в namespace shop хочет direct backend в Service из другого namespace (legacy-api в infra). По умолчанию это запрещено — нужно явное разрешение от owner namespace.
cross-NS reference
namespace: infraOwner namespace создаёт ReferenceGrant, который явно разрешает HTTPRoute из shop ссылаться на конкретный Service legacy-api. Без этого grant — controller отклонит routing, защита от unauthorized cross-NS доступа.
Service legacy-apiРеальный backend. Controller теперь маршрутизирует HTTPRoute из shop → этот Service в infra. Можно ограничить grant конкретными Service-ами (поле to.name) или открыть для всего namespace (без name).
WARNING

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 headers
  • ResponseHeaderModifier — модификация response headers
  • URLRewrite — переписывание path / hostname
  • RequestRedirect — 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/GatewayGateway API (стандарт K8s SIG-Network)многие controllers
networking.istio.io/GatewayIstio 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
NOTE

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

Проверка знанийKnowledge check
Команда платформы в namespace `platform` хочет владеть Gateway-ом, который обслуживает все приложения компании. Команда `shop` в namespace `shop` хочет подключить свой HTTPRoute к этому Gateway без участия platform-team в каждом релизе. Какие три объекта нужно создать и какие поля настроить, чтобы это работало безопасно?
ОтветAnswer
1) **Gateway** в namespace `platform`. Ключевое поле: `spec.listeners[].allowedRoutes.namespaces` — указать `from: Selector` с label-selector-ом (например, `matchLabels: { team-tier: production }`), либо `from: All` если открываем для всех. Это даёт platform-team контроль, кто может attach. 2) **HTTPRoute** в namespace `shop`. Ключевое поле: `spec.parentRefs[]` с `name: <gateway>` и `namespace: platform` — cross-namespace ссылка на Gateway в другом NS. На HTTPRoute должны быть нужные labels (если Gateway использует Selector). 3) Если HTTPRoute в shop ссылается на backend Service в platform namespace — нужен **ReferenceGrant** в namespace platform с `from.kind: HTTPRoute, from.namespace: shop` и `to.kind: Service, to.name: <service>`. Без grant — controller откажет в routing. Безопасность: platform-team контролирует доступ через allowedRoutes (на Gateway) и ReferenceGrant (на свои Services). Shop-team управляет своими HTTPRoute независимо. Это и есть role separation, которого нет в Ingress.

Проверьте понимание

Результат: 0 из 0
Концептуальный
Вопрос 1 из 5. Какие три объекта составляют основу Gateway API, и какие роли их создают?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 5