Gateway API — современная альтернатива Ingress

Уровень: intermediate ~65 мин Практика: Gitea (продолжение M1.08) (MIT)

Что нужно знать перед уроком

  • M1.08 — Ingress — нужен запущенный Gitea из прошлого урока — мы переводим его на Gateway API
  • M1.11 — RBAC (забегая вперёд по смыслу) — ролевая модель Gateway API методически параллельна разделению прав в RBAC

Что нужно знать перед уроком

M1 урок 8 — Ingress, IngressClass, pathType, TLS-терминация, ловушка use-regex. У вас должен быть развёрнут Gitea с Ingress из прошлого урока — мы переведём его на HTTPRoute.

Теория

Ролевая модель — три персоны

Официальная документация Gateway API вводит ролевую модель из трёх персон, которая явно разделяет ответственность:

ПерсонаРольСоздаёт
Ian (infrastructure provider)владеет физической инфраструктурой балансировкиGatewayClass (cluster-scoped)
Chihiro (cluster operator)настраивает точки входа для команд разработкиGateway (обычно тоже администратор кластера)
Ana (application developer)разрабатывает конкретный сервистолько HTTPRoute/GRPCRoute в своём namespace
Прямая параллель с Application vs Module
Эта модель — методическое повторение уже пройденной границы: GatewayClass/Gateway — cluster-wide инфраструктура (как Module), HTTPRoute — namespaced объект, который вправе создавать сам разработчик (как Application). Тот же принцип разделения прав будет формализован в M1 уроке 11 (RBAC) и в M2 уроке 1.

Три ключевых ресурса

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# Создаёт Ian (инфраструктурный провайдер) — cluster-scoped
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata: { name: nginx-gwc }
spec: { controllerName: "k8s.io/nginx-gateway-controller" }
---
# Создаёт Chihiro (администратор кластера) — точка входа
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata: { name: course-gateway, namespace: gateway-infra }
spec:
  gatewayClassName: nginx-gwc
  listeners:
    - name: https
      protocol: HTTPS
      port: 443
      hostname: "*.course.local"
      tls: { certificateRefs: [{ name: course-wildcard-tls }] }
      allowedRoutes: { namespaces: { from: All } }
---
# Создаёт Ana (разработчик Application) — namespaced, в СВОЁМ namespace
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata: { name: gitea, namespace: course-m1-gateway }
spec:
  parentRefs:
    - name: course-gateway
      namespace: gateway-infra
      sectionName: https
  hostnames: ["gitea.course.local"]
  rules:
    - matches: [{ path: { type: PathPrefix, value: / } }]
      backendRefs: [{ name: gitea, port: 3000 }]

Матчинг и фильтры HTTPRoute

Матчинг задаётся в rules[].matches[] и может комбинировать несколько условий (логическое И внутри одного matches, ИЛИ между элементами списка matches):

1
2
3
4
5
6
rules:
  - matches:
      - path: { type: PathPrefix, value: /api }
        headers: [{ name: "X-Beta", value: "true" }]
        method: GET
        queryParams: [{ name: "debug", value: "1" }]

Три типа path-матчинга: Exact, PathPrefix (аналог Prefix у Ingress, по сегментам) — оба относятся к Core conformance (обязательны для всех реализаций); RegularExpressionштатное поле схемы API (в отличие от Ingress, где нужна отдельная аннотация конкретного контроллера с побочными эффектами на соседние правила, как use-regex у ingress-nginx), но при этом у него официально custom conformance: спецификация explicitly разрешает разным реализациям использовать разные regex-движки (POSIX, PCRE, RE2 и т. д.), поэтому поведение одного и того же выражения между разными контроллерами не гарантировано идентичным — портируем сам факт наличия поля в API, а не гарантированную семантику конкретного regex.

Фильтры трансформируют запрос/ответ до отправки на backend:

1
2
3
4
5
6
7
8
filters:
  - type: RequestHeaderModifier
    requestHeaderModifier:
      { add: [{ name: "X-Forwarded-Course", value: "m1" }] }
  - type: URLRewrite
    urlRewrite: { path: { type: ReplacePrefixMatch, replacePrefixMatch: "/" } }
  - type: RequestRedirect
    requestRedirect: { scheme: "https", statusCode: 301 }

Traffic splitting по весу — то, чего нет у обычного Ingress

Одна из главных практических причин выбирать Gateway API — нативная поддержка канареечных релизов через несколько backendRefs с разными весами, без сторонних CRD (Ingress для этого требует расширений конкретного контроллера, например аннотаций canary у ingress-nginx):

1
2
3
4
5
6
7
8
9
rules:
  - matches: [{ path: { type: PathPrefix, value: / } }]
    backendRefs:
      - name: gitea
        port: 3000
        weight: 90
      - name: gitea-canary
        port: 3000
        weight: 10

ReferenceGrant — устранение неявной «дыры доверия» Ingress

У обычного Ingress есть скрытая проблема: Ingress в namespace A может сослаться на Service в namespace B без какого-либо явного разрешения со стороны B (если версия/контроллер это позволяет) — то есть namespace B не может проконтролировать, кто на него ссылается. Gateway API решает это через обязательный (Core conformance) механизм ReferenceGrant, ресурс на apiVersion: gateway.networking.k8s.io/v1 (графован в GA вместе с остальными переходами на Standard channel в Gateway API v1.5.0, релиз 27 февраля 2026 — до этого релиза ресурс был на v1beta1):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
apiVersion: gateway.networking.k8s.io/v1
kind: ReferenceGrant
metadata: { name: allow-gateway-to-route, namespace: course-m1-gateway }
spec:
  from:
    - group: gateway.networking.k8s.io
      kind: Gateway
      namespace: gateway-infra
  to:
    - group: gateway.networking.k8s.io
      kind: HTTPRoute

Без соответствующего ReferenceGrant в namespace-получателе cross-namespace ссылка (GatewayHTTPRoute из другого namespace, GatewaySecret с TLS-сертификатом в другом namespace) будет отклонена — namespace явно контролирует, кто может на него ссылаться, а не наоборот.

Терминология при миграции: hosthostnames

IngressGateway APIНюанс
spec.rules[].host (одно правило — один host)spec.hostnames (список)правила HTTPRoute применяются ко всем hostnames Route одновременно, а не по одному, как у Ingress
pathType: Prefixpath.type: PathPrefixсемантика идентична
аннотации конкретного контроллераштатные filtersпортируемость между реализациями

Где заканчивается L7 и начинается L4

HTTPRoute/GRPCRoute — HTTP/HTTPS terminate (L7). TLSRoute — TLS terminate или passthrough (пограничный случай). TCPRoute/UDPRoute — чистый L4, без осведомлённости о содержимом трафика вообще. Application-разработчику в подавляющем большинстве случаев нужен только HTTPRoute.

Deckhouse-практика: модуль alb

В Deckhouse Gateway API реализован модулем alb. Административная часть (GatewayClass+Gateway в терминах ванильного Gateway API) объединена в один cluster-wide ресурс ClusterALBInstance, который создаёт администратор кластера. Но ListenerSet и HTTPRoute — уже namespaced-ресурсы, которые Application-разработчик создаёт сам, в своём namespace, ссылаясь на Gateway, доступный через status ClusterALBInstance. ListenerSet — не экспериментальная фича: ресурс графован в Standard channel (GA) начиная с Gateway API v1.5.0 (релиз 27 февраля 2026), то есть это такая же стабильная часть API, как HTTPRoute, а не alpha/beta-надстройка Deckhouse:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata: { name: gitea, namespace: course-m1-gateway }
spec:
  parentRefs:
    - name: <имя-Gateway-из-status-ClusterALBInstance>
      namespace: <namespace-ClusterALBInstance>
      sectionName: https
  hostnames: ["gitea.course.local"]
  rules:
    - matches: [{ path: { type: PathPrefix, value: / } }]
      backendRefs: [{ name: gitea, port: 3000 }]

Документация Deckhouse по модулю ALB перечисляет три равноправных способа L7-балансировки в Deckhouse: модуль ingress-nginx (классический Ingress), Gateway API через модуль alb, и istio (сервис-меш с собственной моделью). Официальная позиция платформы (FAQ по Ingress): ingress-nginx поддерживается весь жизненный цикл платформы независимо от статуса апстрима — это не «устаревающая технология под давлением», а осознанный путь миграции для тех, кому нужны traffic splitting и cross-namespace-безопасность из коробки.

Частые ошибки и подводные камни

  • Пытаться создать Gateway самостоятельно как Application-разработчик. По ролевой модели это ресурс администратора (Chihiro) — вам, как Ana, доступен только HTTPRoute (и в Deckhouse — ListenerSet), ссылающийся на существующий Gateway/ClusterALBInstance.
  • Забыть про ReferenceGrant при cross-namespace ссылках. Без него Gateway из инфраструктурного namespace не сможет легитимно принять HTTPRoute из вашего namespace, если контроллер строго следует Core conformance.
  • Ожидать поведение host-специфичных правил Ingress. hostnames HTTPRoute — список, и правила применяются к каждому имени из списка одинаково — в отличие от Ingress, где можно было явно завязать разные правила на разные host в одном объекте.

Практика в кластере

🧩 Практика урока: Gitea (продолжение M1.08) · лицензия MIT

Переводим уже развёрнутый в прошлом уроке Gitea с Ingress на пару ListenerSet+HTTPRoute (в терминах модуля alb — упрощаем до ванильного API Gateway API, если alb не включён на вашем CE-кластере, синтаксис ресурсов совпадает).

  1. Проверьте, что в кластере включён Gateway API CRD и (если используете Deckhouse) модуль alb:
1
2
kubectl get crd | grep gateway.networking.k8s.io
d8 k get module alb 2>/dev/null || echo "alb недоступен на этом CE-кластере — используем ванильный Gateway API контроллер"
  1. Создайте HTTPRoute, ссылающийся на существующий Gateway/ClusterALBInstance (или на тестовый Gateway, если ставите ванильный контроллер отдельно):
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
kubectl apply -n course-m1-gateway -f - <<'EOF'
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata: { name: gitea }
spec:
  parentRefs: [{ name: course-gateway, namespace: gateway-infra, sectionName: https }]
  hostnames: ["gitea.course.local"]
  rules:
    - matches: [{ path: { type: PathPrefix, value: / } }]
      backendRefs: [{ name: gitea, port: 3000 }]
EOF
  1. Проверьте статус привязки HTTPRoute к Gateway (условие Accepted/ResolvedRefs в status.parents):
1
kubectl get httproute gitea -n course-m1-gateway -o yaml
  1. Добавьте canary-роут с весовым сплитом на вторую (тестовую) версию Gitea:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
kubectl apply -n course-m1-gateway -f - <<'EOF'
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata: { name: gitea-canary }
spec:
  parentRefs: [{ name: course-gateway, namespace: gateway-infra, sectionName: https }]
  hostnames: ["gitea.course.local"]
  rules:
    - matches: [{ path: { type: PathPrefix, value: / } }]
      backendRefs:
        - { name: gitea, port: 3000, weight: 90 }
        - { name: gitea-canary, port: 3000, weight: 10 }
EOF
  1. Удалите старый Ingress из M1.08, оставив только Gateway API-путь:
1
kubectl delete ingress gitea -n course-m1-gateway --ignore-not-found

Практика разработки

Ресурсы Gateway API — чистые манифесты Kubernetes, отдельной сборки в этом уроке нет.

Шпаргалка команд урока

1
2
3
4
5
kubectl get gatewayclass
kubectl get gateway -A
kubectl get httproute [-n <ns>]
kubectl get httproute <name> -n <ns> -o yaml   # status.parents.conditions
kubectl get referencegrant -n <ns>

Вопросы для самопроверки

Кто по ролевой модели Gateway API создаёт HTTPRoute?

HTTPRoute — единственный из трёх ключевых ресурсов, который по модели вправе создавать сам разработчик приложения в своём namespace.

Источник: Gateway API — Roles and personas

Чем traffic splitting по весу в HTTPRoute отличается от возможностей обычного Ingress?

weight — часть штатной спецификации backendRefs у HTTPRoute; для canary в Ingress нужны нестандартные аннотации, специфичные для каждого контроллера.

Источник: Gateway API — HTTPRoute

Для чего нужен ReferenceGrant?

ReferenceGrant — Core conformance механизм, который получатель ссылки (namespace) явно выставляет, разрешая конкретные типы cross-namespace ссылок.

Источник: Gateway API — ReferenceGrant

В модуле alb платформы Deckhouse какой ресурс объединяет GatewayClass+Gateway в один cluster-wide объект администратора?

ClusterALBInstance — cluster-wide ресурс alb, аналог связки GatewayClass+Gateway ванильного API, создаётся администратором; ListenerSet и HTTPRoute — namespaced, доступны разработчику.

Источник: Deckhouse — Alb gateway api

Официальная позиция Deckhouse по поводу будущего ingress-nginx на платформе?

Официальная FAQ-позиция: команда Deckhouse продолжает поддерживать ingress-nginx на всём жизненном цикле платформы и предоставляет путь миграции на Gateway API для тех, кому нужны его возможности.

Источник: Deckhouse — Ingress support

Рекомендуемая литература

Официальная документация

Статьи и блоги

Книги

  • Marko Lukša. Kubernetes in Action. 2nd ed., 2022. ISBN 978-1617297618.
  • Kelsey Hightower, Brendan Burns, Joe Beda. Kubernetes: Up and Running. 3rd ed., 2022. ISBN 978-1098110201.
  • Michael Hausenblas, Stefan Schimanski. Programming Kubernetes. 2019. ISBN 978-1492047107.

Связанные материалы