Дайджесты новостей
Концептуальная иллюстрация миграции с устаревающего ingress-nginx на Envoy Gateway с единым разделяемым шлюзом и структурированными маршрутами HTTPRoute.

Миграция с ingress-nginx на Envoy Gateway: уроки и архитектурные грабли

В марте 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:

  1. Инфраструктурная платформа: команда SRE создает всего два разделяемых шлюза (shared-public для внешнего интернет-трафика и shared-private для корпоративных вызовов) в пространстве envoy-gateway-system.
  2. Прикладные сервисы: чарты приложений содержат только легковесные ресурсы маршрутизации HTTPRoute, подключаемые к разделяемому шлюзу через параметр parentRefs.

Проблема перекрестных пространств имен и магия ReferenceGrant

Разделение ролей вскрывает вторую проблему — работу с TLS-сертификатами. В старом ingress-nginx контроллер работал под суперпривилегиями и беспрепятственно читал Secret с сертификатом в любом пользовательском пространстве имен.

Схема безопасного доступа шлюза Envoy Gateway к секрету с TLS-сертификатом через ресурс ReferenceGrant между пространствами имен

В 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 разносит эти настройки по строго структурированным объектам:

  1. ClientTrafficPolicy: управляет поведением клиентского соединения на входе в шлюз (таймауты keep-alive, client_max_body_size, буферизация TCP) на уровне платформы.
  2. BackendTrafficPolicy: привязывается к сервису и определяет взаимодействие с апстримом: таймауты ожидания ответа, пулы соединений и бюджеты повторных попыток (retries).
  3. SecurityPolicy: отвечает за прикладную защиту маршрута — авторизацию через токены или basicAuth, правила CORS и проверку mTLS.

Такая декомпозиция делает конфигурацию прозрачной: компилятор манифестов валидирует типы полей по схеме OpenAPI, исключая опечатки.

Канареечные выкатки с Argo Rollouts и безопасный переходный контур

При переходе на Envoy Gateway аннотации canary из Argo Rollouts перестают работать. Для взаимодействия с Gateway API используется плагин rollouts-plugin-trafficrouter-gatewayapi, модифицирующий веса в блоке backendRefs ресурса HTTPRoute. Чтобы ArgoCD не считал динамическое изменение весов рассинхронизацией, в чарт добавляется блок ignoreDifferences.

Для проведения бесшовной миграции применяется стратегия двойного контура:

  1. В значениях сервисов временно включаются оба флага: ingress.enabled: true и gateway.enabled: true для параллельной маршрутизации.
  2. Инженеры проверяют доступность сервиса через IP-адрес нового Envoy Gateway с помощью curl, явно передавая заголовок Host.
  3. После прогрева DNS-запись домена переключается на CNAME нового балансировщика.
  4. В течение 24–48 часов отслеживаются метрики задержек. После стабилизации флаг ingress.enabled переводится в false, а старый контроллер удаляется.

Итоговый вердикт: кому переходить прямо сейчас

Миграция с ingress-nginx на Envoy Gateway — неизбежная эволюция сетевой архитектуры Kubernetes. Старый контроллер исчерпал свой ресурс, а Gateway API стал зрелым стандартом с четким разграничением прав.

Главное правило — не воспроизводить структуру Ingress один в один. Создавайте разделяемые шлюзы, осваивайте ReferenceGrant для доступа к сертификатам и декомпозируйте аннотации на типизированные политики. Это гарантирует прозрачность сети, снижение расходов и стабильность продакшена.