Перейти к содержимому
Hogin Hogin
Назад

Gateway API вместо Ingress: миграция, пока ingress-nginx не умер

8 мин чтения

24 марта 2026 kubernetes/ingress-nginx — самый популярный ingress-контроллер в кластерах — официально ушёл в End-of-Life. Репозиторий заморожен: ни багфиксов, ни security-патчей, ни ответов на issue. Если он до сих пор держит трафик в вашем кластере, вопрос не «стоит ли мигрировать», а «сколько времени осталось до первой непропатченной уязвимости». Gateway API — не альтернативный синтаксис для Ingress, а его официальная замена в самом Kubernetes, и SIG Network уже выпустил инструмент для миграции. Разберём, как перейти без ночного аврала.

Содержание

Открыть содержание

Почему Ingress оказался в тупике

Ingress был специфицирован в 2015-м как минимальный общий знаменатель: один ресурс, host/path-матчинг, TLS-секция — и всё. Реальные контроллеры почти сразу упёрлись в потолок этой спецификации: canary-релизы, rate limiting, rewrite-правила, mTLS между сервисами — ничего этого в API нет. Каждый контроллер закрывал дыры через nginx.ingress.kubernetes.io/...-аннотации, и в итоге получился не портируемый API, а набор диалектов. Манифест, написанный под ingress-nginx, не запускался на Traefik или HAProxy без переписывания половины аннотаций.

Вторая проблема — роли. В реальной организации инфраструктурная команда владеет балансировщиком и TLS-сертификатами, а команда сервиса — только своими маршрутами. Ingress этого не различает: один YAML-файл, и либо разработчик получает права на весь балансировщик, либо platform-команда становится узким местом, вручную согласовывая каждый PR с новым path.

Что меняет Gateway API

Gateway API — не патч поверх Ingress, а другая модель ресурсов, спроектированная сразу с учётом ролей и типизации.

Ingress: один ресурс и вендорские аннотации против Gateway API: роли и типизированные ресурсы

Модель ресурсов: GatewayClass → Gateway → HTTPRoute

Три ресурса, и каждый решает свой уровень задачи.

GatewayClass — кластерный ресурс, который объявляет доступную реализацию (Envoy Gateway, NGINX Gateway Fabric, облачный LB) примерно как StorageClass объявляет доступный тип диска. Его создаёт platform-команда или сам оператор реализации при установке.

apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: envoy-gateway
spec:
  controllerName: gateway.envoyproxy.io/gatewayclass-controller

Gateway — конкретный экземпляр точки входа: порты, протоколы, TLS-сертификаты, ограничение на то, какие namespace могут к нему подключать маршруты. Тоже в зоне platform-команды.

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: public-gateway
  namespace: infra
spec:
  gatewayClassName: envoy-gateway
  listeners:
    - name: https
      protocol: HTTPS
      port: 443
      tls:
        certificateRefs:
          - name: wildcard-tls
      allowedRoutes:
        namespaces:
          from: Selector
          selector:
            matchLabels: { gateway-access: "allowed" }

HTTPRoute — маршруты конкретного сервиса, живёт в namespace команды и ссылается на Gateway через parentRefs. Здесь же canary-сплит по весам — без единой аннотации.

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: checkout
  namespace: checkout-team
spec:
  parentRefs:
    - name: public-gateway
      namespace: infra
  hostnames: ["checkout.example.com"]
  rules:
    - matches:
        - path: { type: PathPrefix, value: /api }
      backendRefs:
        - name: checkout-stable
          port: 80
          weight: 90
        - name: checkout-canary
          port: 80
          weight: 10

GatewayClass задаёт реализацию, Gateway — точку входа, HTTPRoute — маршруты команды

ingress2gateway: конвертация без переписывания вручную

SIG Network выпустил ingress2gateway 1.0 именно под волну миграций с EOL ingress-nginx. Инструмент читает существующие Ingress-ресурсы кластера (включая часть распространённых аннотаций) и генерирует эквивалентные Gateway/HTTPRoute.

# ставим CLI
go install sigs.k8s.io/ingress2gateway@latest

# читаем текущие Ingress из кластера и печатаем сгенерированные манифесты
ingress2gateway print --namespace checkout-team > gateway-generated.yaml

# то же самое, но по конкретному провайдеру аннотаций (например, nginx)
ingress2gateway print --providers=ingress-nginx --namespace checkout-team

Дальше сгенерированный YAML — черновик, а не финальный результат: нужно проверить parentRefs (совпадает ли имя и namespace Gateway, который вы уже создали), убедиться, что TLS подтянулся из правильного Gateway-listener’а, а не остался пустым, и прогнать через kubectl apply --dry-run=server, чтобы поймать ошибки схемы до реального применения.

Выбор реализации

Gateway API — это спецификация, а не рабочий контроллер; для работы нужна реализация, которая её поддерживает.

Критерий выбора почти всегда один: не «какая реализация технически мощнее», а «что уже стоит в кластере». Если CNI — Cilium, добавление отдельного L7-балансировщика ради Gateway API — лишний компонент в дата-плейне; если инфраструктура целиком в облаке и L7 уже отдан управляемому LB, естественнее включить Gateway API поддержку там же, а не поднимать Envoy Gateway рядом. Самостоятельная установка (Envoy Gateway, NGINX Gateway Fabric) имеет смысл там, где нужен контроль над конкретной версией и нет привязки к одному облаку.

Сравнение: Ingress и Gateway API

IngressGateway API
РолиОдин ресурс, права на всё сразуGatewayClass/Gateway — platform, HTTPRoute — команда
Canary/weight-роутингЧерез вендорские аннотации, не портируетсяПоле weight в схеме backendRefs
Портируемость между контроллерамиНизкая — аннотации у каждого вендора своиВысокая — общая типизированная схема
ПротоколыТолько HTTP/HTTPSHTTP, gRPC, TCP, TLS — отдельные типы маршрутов
Кросс-namespace ссылкиНестандартные флаги контроллераReferenceGrant, явное разрешение
Статус проектаingress-nginx: EOL с марта 2026Активная разработка, GA с v1.0

Что нужно, чтобы мигрировать

Порядок действий, который не ломает продакшн-трафик в процессе:

  1. Установить CRD Gateway APIkubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.3.0/standard-install.yaml.
  2. Поставить одну реализацию — например, Envoy Gateway через Helm-чарт, и создать GatewayClass + Gateway для нового публичного входа.
  3. Прогнать существующие Ingress через ingress2gateway для каждого namespace и получить черновик HTTPRoute.
  4. Проверить каждый сгенерированный HTTPRoute вручную — особенно аннотации, у которых нет 1:1 аналога (rate limiting, кастомные заголовки, снипеты Lua/nginx.conf) — их придётся переносить через ExtensionRef конкретной реализации или переписывать логику отдельно.
  5. Запустить Gateway и HTTPRoute параллельно со старым Ingress, направив на новый вход небольшую долю трафика через DNS-вес или отдельный тестовый hostname — не выключать Ingress сразу.
  6. Постепенно поднимать canary-вес в HTTPRoute с 10% до 100%, наблюдая за метриками, и только после этого удалять старые Ingress-ресурсы.

Ingress → ingress2gateway → HTTPRoute черновик → canary 10% → 100%, старый Ingress выключается последним

Ловушки миграции

Как проверить, что всё работает

После применения манифестов — три быстрые проверки. Статус самого Gateway: kubectl get gateway public-gateway -n infra -o jsonpath='{.status.conditions}' должен показывать Programmed: True и Accepted: True. Статус конкретного маршрута: kubectl get httproute checkout -n checkout-team -o jsonpath='{.status.parents}' подтверждает, что Gateway принял этот HTTPRoute, а не просто создал ресурс без привязки. И живой трафик: curl -H "Host: checkout.example.com" https://<gateway-ip>/api/health несколько раз подряд должен показать распределение между checkout-stable и checkout-canary близкое к заданным весам.

Итог

ingress-nginx не сломается в одну ночь — он будет работать ровно до первой уязвимости, на которую уже не выйдет патч. Это делает миграцию не вопросом выбора «удобнее или нет», а вопросом времени: чем раньше начать перевод трафика на Gateway API параллельно со старым Ingress, тем меньше шансов встретить security-инцидент на мёртвом коде в проде. ingress2gateway закрывает большую часть рутинной конвертации, но ручная проверка каждого нестандартного правила — обязательный шаг, а не опция.


Поделиться:

Следующая статья
Backstage за выходные: IDP и golden paths для маленькой команды