Gateway API: HTTPRoute
Почему роутинг разнесли на GatewayClass, Gateway и HTTPRoute и чем это отличается от Ingress.
Что не так с Ingress
Ingress работает десять лет и никуда не уходит. Он по-прежнему GA, его всё ещё используют повсюду, и в кластере его никто не запрещает. Но у него есть три неудобства, которые накапливаются с ростом команды.
Первое: один объект описывает сразу всё. Хосты, пути, TLS, иногда даже backend-параметры через аннотации. Тот, кто пишет Ingress, должен знать и про инфру (порты listener-а, сертификаты), и про роутинг своего Service.
Второе: расширения через аннотации. nginx.ingress.kubernetes.io/...,
traefik.ingress.kubernetes.io/.... Переехал с одного контроллера на
другой и половина YAML стала мусором. Именно так и вышло: ingress-nginx,
чьи аннотации разошлись по всем гайдам, сняли с поддержки в марте 2026, и
теперь эти строки надо переписывать под другую реализацию.
Третье: только HTTP/HTTPS. TCP, UDP, gRPC, mTLS заворачивают через те же аннотации или CRD-расширения от конкретного вендора.
Gateway API чинит это иначе: вместо одного объекта вводит три, с разными владельцами.
Три роли, три объекта
HTTPRoute ссылается на обычный Service типа ClusterIP, ровно так же, как
это делал Ingress. Новое здесь только разделение самого входа.
GatewayClass: traefik <- админ кластера выбрал имплементацию
|
v
Gateway: traefik-gateway <- ops владеет, в kube-system
| listens :80, *.example.com
v
HTTPRoute: helloroute <- команда приложения владеет, в своём ns
| hostnames: [helloapp.example.com]
| backendRefs: [helloapp:8080]
v
Service helloapp -> Pods
GatewayClass определяет, какой контроллер будет обрабатывать трафик (Traefik, Cilium, Istio, NGINX Gateway Fabric). Создаёт админ кластера один раз. Разработчику он нужен, только чтобы убедиться, что нужный контроллер вообще установлен.
Gateway это реальный listener: на каком порту слушаем, на каких
хостах, какой TLS. Создаёт инфра-команда. Лежит обычно в kube-system или
отдельном gateway-system. Некоторые контроллеры создают его сами, когда
включена поддержка Gateway API.
HTTPRoute правила приложения: какие хостнеймы и пути ловить, куда
форвардить. Создаёт разработчик в своём namespace. Цепляется к Gateway
через parentRefs.
Идея простая: ops держит входную дверь, разработчики раздают ключи к своим комнатам. Раньше всё было заперто в одной квартире.
Минимальный HTTPRoute
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: helloroute
spec:
parentRefs:
- name: traefik-gateway
namespace: kube-system
hostnames:
- helloapp.example.com
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: helloapp
port: 8080
Ключевые поля:
apiVersion: gateway.networking.k8s.io/v1это GA-версия. Она приехала с релизом Gateway API v1.0 в октябре 2023. Gateway API живёт вне ядра Kubernetes и ставится отдельными CRD, поэтому доступная версия зависит от того, какие CRD установлены в кластере, а не от версии самого Kubernetes. Видно толькоv1beta1илиv1alpha2- на кластере старые CRD, их обновляют.parentRefs.namespace: kube-systemобязательно, когда Gateway живёт в другом namespace. Разрешена ли такая ссылка, решает контроллер: в строгом сетапе в namespace Gateway-а нужен объектReferenceGrant.hostnamesэто массив. Можно подписать на один route несколько имён.path.type: PathPrefixименно так, в Gateway API. У Ingress было простоPrefix. Это частый источник опечаток при миграции.backendRefs[]принимает несколько backend-ов с весами. Для canary ставятweight: 90иweight: 10, и этого достаточно.
CRD Gateway API в кластере не установлены: kubectl get httproute
отвечает error: no matches for kind "HTTPRoute". Ставят Gateway API CRDs.
Сравнение с Ingress
| Что делает | Ingress | HTTPRoute |
|---|---|---|
| HTTP routing | да | да |
| TCP/UDP/TLS/gRPC | через аннотации/CRD вендора | отдельные типы Route |
| Host | rules[].host | spec.hostnames[] |
| Path match | pathType: Prefix/Exact | path.type: PathPrefix/Exact/RegularExpression |
| Несколько backend-ов с весами | через аннотации | backendRefs[].weight в спеке |
| Cross-namespace backend | через аннотации | backendRefs.namespace + ReferenceGrant |
| Модификация заголовков/redirect | через аннотации | filters в спеке |
| Стандарт между вендорами | минимальный | conformance suite |
| Статус | GA, не deprecated | GA с Gateway API v1.0, активно растёт |
Ingress никуда не делся. Если на Service приходится один Ingress и всем владеет одна команда, переезжать не нужно. Gateway API даёт смысл там, где больше двух команд или появляются не-HTTP протоколы.
Что реально нужно
Gateway API уже стал тем направлением, куда двигается экосистема. Толчок
дал конец ingress-nginx: контроллер, на котором сидела половина кластеров,
сняли с поддержки в марте 2026, и командам пришлось выбирать замену. Почти
все живые реализации сегодня делают ставку на Gateway API, а для переезда
есть утилита ingress2gateway, которая генерирует HTTPRoute из готовых
Ingress.
Ingress при этом читать всё равно надо: он GA, не deprecated, и его манифесты будут попадаться ещё годами. Но новое проектируют на HTTPRoute. Фундамент прежний, Service и NetworkPolicy, а Gateway API стоит слоем выше и занимается только входящим трафиком.
Что часто ломается
- Gateway не создан или не Programmed.
kubectl get gateway -Aпокажет статус. Если Gateway вPending, HTTPRoute не Accepted. - Cross-namespace без разрешения. Если контроллер строго следит за
namespace boundary, нужен
ReferenceGrantв namespace Gateway-а. PrefixвместоPathPrefix. Скопировали из Ingress, забыли переименовать. HTTPRoute не Accepted с понятным сообщением вkubectl describe.v1beta1вместоv1. Значит, в кластере лежат старые CRD Gateway API. Манифест валиден, но поведение может отличаться. Лучшеv1.
Команды для разведки
kubectl get gatewayclass
# traefik
kubectl get gateway -A
# kube-system/traefik-gateway traefik Programmed=True
kubectl get httproute -A
# HTTPRoute со списком hostname-ов
kubectl describe httproute helloroute
# смотреть в status.parents[0].conditions:
# Accepted=True означает, что Gateway согласился обрабатывать route
# ResolvedRefs=True означает, что Service найден и порт валидный
Filters: header rewrite, redirect, URL rewrite, mirror
В rules[].filters живут модификаторы запроса. Самые ходовые:
RequestHeaderModifier: добавить или удалить заголовки в запросе.ResponseHeaderModifier: то же для ответа.URLRewrite: поменять host или path до бэкенда. Удобно, когда внешний путь/api/users, а Service ждёт/users.RequestRedirect: отдать 301/302 без обращения к backend.RequestMirror: копию запроса в другой backend для shadow-тестов.
Пример URLRewrite:
rules:
- matches:
- path: { type: PathPrefix, value: /api }
filters:
- type: URLRewrite
urlRewrite:
path:
type: ReplacePrefixMatch
replacePrefixMatch: /
backendRefs:
- name: api-service
port: 80
Canary через backendRefs
В Gateway API сплит трафика встроен прямо в спеку:
backendRefs:
- name: helloapp-v1
port: 8080
weight: 90
- name: helloapp-v2
port: 8080
weight: 10
С Ingress такое делали через аннотации или два отдельных Ingress, что часто приводило к гонкам.
Домашка
Теорию закрепляет задание на своём кластере: 2 шага с проверкой. Кластер поднимается по треку Kubernetes локально, задания лежат в репозитории k8s-practice.
./run.sh start k8s-gateway-basics # развернуть стартовое состояние
./run.sh verify k8s-gateway-basics # проверить текущий шаг
Коротко
- Gateway API разносит вход на три объекта: GatewayClass (какой контроллер), Gateway (listener и TLS), HTTPRoute (правила приложения).
- HTTPRoute цепляется к Gateway через
parentRefsи шлёт трафик в Service черезbackendRefs. - В Gateway API префиксный матч называется
PathPrefix, а неPrefixкак в Ingress. - Веса backend-ов, редиректы и правка заголовков описаны в самой спеке, а не аннотациями конкретного вендора.
- CRD Gateway API ставятся отдельно от Kubernetes, поэтому доступная версия API зависит от того, что установили в кластер.
- Ingress остаётся GA и его надо уметь читать, но новое проектируют на HTTPRoute.
Прошли материал до конца? Отметьте урок пройденным.
Прогресс сохранён в этом браузере
Почистишь историю или откроешь с телефона, и отметки пропадут. Оставь почту, они переедут в аккаунт. Пароль придумывать не нужно.
Готово. теперь в аккаунте: прогресс виден с любого устройства. Мой прогресс