В марте 2026 года завершается жизненный цикл классического контроллера ingress-nginx. Десятилетие он оставался рабочим стандартом для маршрутизации трафика в Kubernetes, однако проект подошел к логическому пределу. Накопленный багаж архитектурных компромиссов, регулярные бреши из-за директив configuration-snippet и нехватка ресурсов мейнтейнеров подвели черту: эра монолитного Ingress завершена. На смену ему пришел стандарт Kubernetes Gateway API, а одним из его флагманских контроллеров стал Envoy Gateway.
Однако наивный перевод продакшена на новый контроллер часто превращается в минное поле. Инженеры, привыкшие механически переносить манифесты, моментально удваивают счета за облако и ломают TLS-терминацию. На примере боевой миграции кластера инженера Мейндерта Стёя (Mijndert Stuij) разбираем, почему Gateway API требует смены ментальной модели, как избежать лишних балансировщиков и почему аннотации nginx распадаются на цепочку типизированных политик.
Ловушка персональных шлюзов и переход к разделяемой инфраструктуре
Главная концептуальная ошибка при первом знакомстве с Gateway API — попытка рассматривать ресурс Gateway как прямой аналог старого Ingress. Во многих командах Helm-чарт каждого микросервиса содержал собственный манифест Ingress. Когда разработчики точно так же добавляют Gateway в каждый сервисный чарт, наступает инфраструктурный шок.
В Gateway API ресурс Gateway описывает физическую точку входа сетевого трафика. Создание шлюза заставляет контроллер запросить у облачного провайдера отдельный балансировщик нагрузки (AWS NLB или ALB). В результате проект из тридцати сервисов внезапно порождает тридцать облачных балансировщиков. Это взвинчивает расходы, фрагментирует внешние IP-адреса и размывает зону ответственности.
Архитектурно верное решение — строгое разделение ролей, заложенное создателями Gateway API:
- Инфраструктурная платформа: команда SRE создает всего два разделяемых шлюза (
shared-publicдля внешнего интернет-трафика иshared-privateдля корпоративных вызовов) в пространствеenvoy-gateway-system. - Прикладные сервисы: чарты приложений содержат только легковесные ресурсы маршрутизации
HTTPRoute, подключаемые к разделяемому шлюзу через параметрparentRefs.
Проблема перекрестных пространств имен и магия ReferenceGrant
Разделение ролей вскрывает вторую проблему — работу с TLS-сертификатами. В старом ingress-nginx контроллер работал под суперпривилегиями и беспрепятственно читал Secret с сертификатом в любом пользовательском пространстве имен.

В Gateway API модель безопасности строже. Шлюз shared-public в пространстве envoy-gateway-system по умолчанию лишен прав на чтение секретов за пределами своего namespace. Если сослаться в параметре certificateRefs шлюза на Secret в пространстве default, Envoy Gateway откажется монтировать ключ со статусом ResolvedRefs: False.
Для безопасного связывания был введен ресурс ReferenceGrant. Принципиально важно место его размещения: ReferenceGrant создается строго в том пространстве имен, где хранится целевой защищаемый ресурс (сертификат). Этим владелец пространства декларирует разрешение шлюзу прочитать конкретный секрет.
Манифест платформенного разделяемого шлюза в пространстве envoy-gateway-system:
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: shared-public
namespace: envoy-gateway-system
spec:
gatewayClassName: envoy-gateway
listeners:
- name: http
port: 80
protocol: HTTP
allowedRoutes:
namespaces:
from: All
- name: https
port: 443
protocol: HTTPS
tls:
mode: Terminate
certificateRefs:
- group: ""
kind: Secret
name: domain-wildcard-cert
namespace: default
allowedRoutes:
namespaces:
from: All
Манифест разрешения ReferenceGrant в пространстве имен default:
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
name: domain-cert-grant
namespace: default
spec:
from:
- group: gateway.networking.k8s.io
kind: Gateway
namespace: envoy-gateway-system
to:
- group: ""
kind: Secret
name: domain-wildcard-cert
Анатомия HTTPRoute: ловушка sectionName и чистый редирект
После запуска шлюза разработчики подключают правила маршрутизации. Манифест HTTPRoute привязывается к шлюзу через параметр parentRefs. И здесь инженеров подстерегает поле sectionName.
Поле sectionName указывает конкретный слушатель на шлюзе — например, http или https. Если при написании манифеста допустить опечатку в имени слушателя, контроллер примет ресурс со статусом Accepted: True, однако трафик на сервис не пойдет, заставляя инженера часами изучать дампы.
Второй нюанс — перенаправление с HTTP на HTTPS. В ingress-nginx для этого использовалась аннотация ssl-redirect: "true". В стандарте Gateway API редирект — это полноценное правило маршрутизации. Для него создается независимый манифест HTTPRoute, слушающий секцию http на 80 порту и использующий фильтр RequestRedirect с кодом 301.
Манифест основного прикладного маршрута сервиса:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: example-app-httproute
namespace: production
spec:
parentRefs:
- name: shared-public
namespace: envoy-gateway-system
sectionName: https
hostnames:
- "app.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: example-app-service
port: 3000
Манифест автоматического перенаправления с незащищенного HTTP на HTTPS:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: example-app-https-redirect
namespace: production
spec:
parentRefs:
- name: shared-public
namespace: envoy-gateway-system
sectionName: http
hostnames:
- "app.example.com"
rules:
- filters:
- type: RequestRedirect
requestRedirect:
scheme: https
statusCode: 301
Декомпозиция аннотаций: переход к типизированным политикам Envoy
Монолитный Ingress страдал от разрастания аннотаций: таймауты, лимиты тел запросов, CORS и правила базовой аутентификации сваливались в один неструктурированный YAML-словарь.
Envoy Gateway разносит эти настройки по строго структурированным объектам:
ClientTrafficPolicy: управляет поведением клиентского соединения на входе в шлюз (таймауты keep-alive,client_max_body_size, буферизация TCP) на уровне платформы.BackendTrafficPolicy: привязывается к сервису и определяет взаимодействие с апстримом: таймауты ожидания ответа, пулы соединений и бюджеты повторных попыток (retries).SecurityPolicy: отвечает за прикладную защиту маршрута — авторизацию через токены илиbasicAuth, правила CORS и проверку mTLS.
Такая декомпозиция делает конфигурацию прозрачной: компилятор манифестов валидирует типы полей по схеме OpenAPI, исключая опечатки.
Канареечные выкатки с Argo Rollouts и безопасный переходный контур
При переходе на Envoy Gateway аннотации canary из Argo Rollouts перестают работать. Для взаимодействия с Gateway API используется плагин rollouts-plugin-trafficrouter-gatewayapi, модифицирующий веса в блоке backendRefs ресурса HTTPRoute. Чтобы ArgoCD не считал динамическое изменение весов рассинхронизацией, в чарт добавляется блок ignoreDifferences.
Для проведения бесшовной миграции применяется стратегия двойного контура:
- В значениях сервисов временно включаются оба флага:
ingress.enabled: trueиgateway.enabled: trueдля параллельной маршрутизации. - Инженеры проверяют доступность сервиса через IP-адрес нового Envoy Gateway с помощью
curl, явно передавая заголовокHost. - После прогрева DNS-запись домена переключается на CNAME нового балансировщика.
- В течение 24–48 часов отслеживаются метрики задержек. После стабилизации флаг
ingress.enabledпереводится вfalse, а старый контроллер удаляется.
Итоговый вердикт: кому переходить прямо сейчас
Миграция с ingress-nginx на Envoy Gateway — неизбежная эволюция сетевой архитектуры Kubernetes. Старый контроллер исчерпал свой ресурс, а Gateway API стал зрелым стандартом с четким разграничением прав.
Главное правило — не воспроизводить структуру Ingress один в один. Создавайте разделяемые шлюзы, осваивайте ReferenceGrant для доступа к сертификатам и декомпозируйте аннотации на типизированные политики. Это гарантирует прозрачность сети, снижение расходов и стабильность продакшена.
