безопасно перевести внешний трафик кластера с Ingress на Gateway API
Kubernetes Gateway API: паттерны миграции с Ingress
14 минут
Ingress смешивает маршрутизацию, TLS и политики в одном объекте и опирается на аннотации контроллера. Gateway API разделяет GatewayClass, Gateway и HTTPRoute по ролям — мигрируйте параллельно с ingress2gateway, ReferenceGrant и RequestMirror, и только потом переключайте DNS.
Почему Ingress становится узким местом платформы
Ingress всё ещё широко используют, но его модель мешает масштабировать владение. Один объект смешивает внешние слушатели, терминацию TLS и прикладную маршрутизацию. Нетривиальное поведение — лимиты запросов, правка заголовков, веса canary — обычно живёт в аннотациях контроллера, поэтому переход с nginx на другую реализацию — это переписывание. Ingress рассчитан на HTTP и HTTPS; TCP, UDP и нормальный gRPC требуют отдельных CRD. Команда платформы и команды приложений правят одни и те же объекты — отсюда трения RBAC. SIG-Network считает Gateway API преемником: иерархия ресурсов, переносимые возможности маршрутизации и контракт без привязки к одному контроллеру. Миграция — не поиск и замена: сначала сосуществование, конвертация маршрутов, проверка паритета, затем DNS.
Владение: GatewayClass, Gateway и HTTPRoute
GatewayClass выбирает реализацию контроллера, по смыслу как StorageClass; им владеют администраторы платформы. Gateway — край инфраструктуры: слушатели, порты, сертификаты TLS и то, каким namespace разрешено цеплять маршруты; этим владеет платформа или инфраструктура. HTTPRoute (и соседние типы вроде GRPCRoute) задаёт хосты, совпадения, фильтры и взвешенные backendRefs; ими владеют команды приложений и цепляют через parentRefs. Держите один Gateway на окружение или зону доступности, а не на каждый сервис. Ограничивайте слушатели селекторами allowedRoutes по меткам namespace. Ссылки на Secret или Service из другого namespace требуют явного ReferenceGrant в целевом namespace.
Паттерн миграции: параллельная работа
Установите CRD Gateway API и совместимый контроллер — Envoy Gateway, Istio, Cilium или nginx Gateway Fabric. Создайте GatewayClass и Gateway с теми же портами и сертификатами, что у текущего Ingress. Переведите правила Ingress в HTTPRoute с parentRef на новый Gateway, пока Ingress ещё обслуживает продакшен. Выделите второй VIP или хост для Gateway, проверьте статусы Accepted и Programmed, сравните задержку и ошибки, затем сдвиньте вес DNS или балансировщика. Удаляйте Ingress только когда путь через Gateway уже основной. Не ждите, что веса HTTPRoute сами разделят трафик между Ingress и Gateway — они балансируют backend за одним parent; переключение делают DNS, CDN или балансировщик.
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: production
spec:
controllerName: gateway.envoyproxy.io/gatewayclass-controller
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: production
namespace: infra
spec:
gatewayClassName: production
listeners:
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: Selector
selector:
matchLabels:
shared-gateway: "true"
- name: https
protocol: HTTPS
port: 443
tls:
mode: Terminate
certificateRefs:
- name: wildcard-tls
kind: Secret
allowedRoutes:
namespaces:
from: Selector
selector:
matchLabels:
shared-gateway: "true"apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: api-service
namespace: app-team-a
spec:
parentRefs:
- name: production
namespace: infra
hostnames:
- api.example.com
rules:
- matches:
- path:
type: PathPrefix
value: /v1
backendRefs:
- name: api-v1
port: 8080
weight: 90
- name: api-v2
port: 8080
weight: 10
- matches:
- headers:
- name: X-Debug
value: "true"
backendRefs:
- name: api-debug
port: 8080Конвертация через ingress2gateway и миграция по namespace
Инструмент SIG-Network ingress2gateway читает объекты Ingress и выдаёт YAML Gateway и HTTPRoute. Проверьте результат: пути и хосты обычно переводятся чисто; аннотации контроллера часто нужно вручную перенести в фильтры HTTPRoute или политики реализации. Мигрируйте по одному namespace приложений — повесьте метку доступа к Gateway, примените маршруты, проверьте статус httproute, затем снимите Ingress этого namespace. Храните сконвертированные манифесты в Git с тем же продвижением, что и остальной конфиг платформы.
#!/usr/bin/env bash
set -euo pipefail
# Install from upstream releases or: go install sigs.k8s.io/ingress2gateway@latest
ingress2gateway print --namespace app-team-a > ./gateway-manifests/app-team-a.yaml
kubectl get ingress -n app-team-a -o name
kubectl apply --dry-run=client -f ./gateway-manifests/app-team-a.yaml
kubectl get httproute -n app-team-a
kubectl describe gateway production -n infraАннотации → фильтры, политики и ReferenceGrant
До переключения проведите аудит всех аннотаций Ingress. Разложите их: нативные фильтры HTTPRoute (redirect, правка заголовков, mirror, URL rewrite), политики контроллера (BackendTrafficPolicy или ClientTrafficPolicy у Envoy Gateway) и то, что всё ещё требует расширения. Сначала берите переносимые фильтры. RequestMirror шлёт копию продакшен-запросов на backend за Gateway, пока Ingress остаётся основным — сравнивайте логи и метрики до смены DNS. Если Gateway ссылается на TLS Secret в другом namespace или маршрут целится в чужой Service, создайте ReferenceGrant в namespace владельца.
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: api-shadow
namespace: app-team-a
spec:
parentRefs:
- name: production
namespace: infra
hostnames:
- api.example.com
rules:
- matches:
- path:
type: PathPrefix
value: /v1
filters:
- type: RequestHeaderModifier
requestHeaderModifier:
add:
- name: X-Edge
value: gateway-api
remove:
- X-Internal-Debug
- type: RequestMirror
requestMirror:
backendRef:
name: api-shadow
port: 8080
backendRefs:
- name: api-v1
port: 8080apiVersion: gateway.networking.k8s.io/v1
kind: ReferenceGrant
metadata:
name: allow-app-routes
namespace: shared-services
spec:
from:
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: app-team-a
to:
- group: ""
kind: ServiceapiVersion: gateway.envoyproxy.io/v1alpha1
kind: BackendTrafficPolicy
metadata:
name: api-resilience
namespace: app-team-a
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: HTTPRoute
name: api-service
retry:
numRetries: 3
retryOn:
triggers:
- connect-failure
- retriable-status-codes
httpStatusCodes:
- 502
- 503TCP и gRPC за пределами HTTP Ingress
Слушатели Gateway могут говорить TCP и принимать TCPRoute из experimental-канала, если контроллер это поддерживает — удобно для брокеров или прокси к БД, где раньше нужны были отдельные CRD. Перед выносом баз на общий Gateway продумайте частную сеть и жёсткую аутентификацию. GRPCRoute — штатный путь для сопоставления по gRPC service и method, когда канал CRD его включает. Держите протокольные маршруты на отдельных слушателях с allowedRoutes kinds только под TCPRoute или GRPCRoute, чтобы HTTP-команды не цепляли неверный тип.
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: tcp-gateway
namespace: infra
spec:
gatewayClassName: production
listeners:
- name: redis
protocol: TCP
port: 6379
allowedRoutes:
kinds:
- kind: TCPRoute
---
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: TCPRoute
metadata:
name: redis
namespace: cache
spec:
parentRefs:
- name: tcp-gateway
namespace: infra
sectionName: redis
rules:
- backendRefs:
- name: redis-primary
port: 6379Практика устойчивого переключения
Фиксируйте версии CRD Gateway API и обновляйте осознанно — стандартный и experimental каналы движутся с разной скоростью. Считайте Gateway и HTTPRoute GitOps-конфигом с CODEOWNERS по модели владения. Во время сосуществования держите парные дашборды с одними SLO для Ingress и Gateway. Когда namespace зелёный на Gateway, сразу удаляйте его Ingress — иначе два источника истины. Опишите, кто может менять GatewayClass, слушатели Gateway и прикладные маршруты. Миграция удалась, когда яснее владение, меньше аннотаций и управление трафиком стало переносимым — а не когда в YAML просто сменился kind.
Взвешенные backend и canary на HTTPRoute сочетаются с гайдом по progressive delivery: canary и feature flags.
Когда маршруты лежат в Git, держите оверлеи в порядке по гайду по структуре GitOps-репозиториев для нескольких окружений.
