После переезда с Ingress-NGINX на Gateway API часть адресов отдаёт 404: что изменилось в regex и rewrite
Манифесты применились без единой ошибки. Gateway в статусе Programmed, все HTTPRoute — Accepted=True, главная страница открывается, мониторинг зелёный. А через сутки прилетает: «не проходит оплата», «QR-код с афиши ведёт в пустоту», «форма записи отдаёт 404». Ниже — почему HTTPRoute, который выглядит точной копией Ingress, на самом деле матчит запросы по другим правилам, почему rewrite с regex в Gateway API так часто заканчивается 404, и как я проверяю миграцию до того, как её увидят пользователи.
Симптом: 404 при полностью зелёных статусах
Это самая неприятная категория аварий — та, где всё формально работает. Kubernetes принял ваши HTTPRoute, контроллер их разложил, статус Accepted стоит True, ни одного события в namespace. Проблема не в том, что маршрут не создался. Проблема в том, что он создался, но матчит другое множество запросов, чем матчил старый Ingress. Разница видна только на конкретных URL — и, как правило, на тех, которые никто не открывает руками: вебхуки, коллбэки платёжных шлюзов, эндпоинты обмена с CRM, старые ссылки из писем и QR-кодов, куски API, которые дёргает мобильный клиент трёхлетней давности.
Механика простая. Ingress-NGINX в итоге превращается в конфиг nginx с директивами location, и правила сопоставления там — nginx-овые. Gateway API — это спецификация, которая описывает матчинг явно и довольно строго, а реализует его уже конкретный контроллер: Envoy Gateway, Istio, Cilium, Traefik, NGINX Gateway Fabric. Спецификация живёт на gateway-api.sigs.k8s.io, и никакого требования «вести себя как ingress-nginx» в спецификации нет и быть не может. Поэтому перенос «один в один» по внешнему виду YAML — это перенос синтаксиса, а не поведения.
Чаще всего в первые дни после переезда отваливается вот это:
- адреса, которые кто-то извне дёргает в другом регистре: /API/v2/orders вместо /api/v2/orders;
- пути с «хвостом», где старый regex работал как префикс: /report-2026 при правиле /report;
- эндпоинты со слэшем на конце и без него — /api и /api/ перестают быть одним и тем же;
- health- и metrics-пробы, которые раньше случайно попадали под host-wide rewrite и работали «по недоразумению»;
- всё, что жило на pathType: ImplementationSpecific — у него в Gateway API прямого аналога нет вообще.
Ingress-NGINX: regex — это префикс, и он без учёта регистра
Первое, что надо понять про уходящий контроллер: включив regex, вы получаете не то, что написали. Ingress-NGINX генерирует location с модификатором регистронезависимого регулярного выражения и якорем в начале строки. То есть путь /[A-Z]{3} превращается не в «ровно три заглавные буквы и всё», а в «строка начинается с трёх любых букв, регистр не важен, дальше может быть что угодно». Под такое правило попадают /uuid, /UUID, /abcdef, /ipsum-lorem — практически весь сайт.
В официальной документации ingress-nginx это сказано прямым текстом про аннотацию use-regex: «When this annotation is set to true, the case insensitive regular expression location modifier will be enforced on ALL paths for a given host regardless of what Ingress they are defined on». Обратите внимание на две вещи: case insensitive — это не опция, а constant; и ALL paths for a given host — это не про один Ingress, а про весь хост.
Практический вывод: годами ваши пользователи и интеграции могли ходить в верхнем регистре, с лишним суффиксом, со слэшем и без — и всё работало, потому что nginx был снисходителен. Никто этого не замечал, потому что 200 в ответ вопросов не вызывает. Список «реально используемых URL» у вас в манифестах не написан. Он написан в логах.
- regex в ingress-nginx якорится слева (^), но не справа — это префикс, а не полное совпадение;
- модификатор ~* — регистр игнорируется всегда, отключить его аннотацией нельзя;
- pathType: Prefix в ingress-nginx, пока на хосте нет regex-режима, работает посегментно; но стоит соседнему Ingress включить use-regex или rewrite-target — и Prefix тоже превращается в строковый регистронезависимый префикс;
- аннотации разных Ingress-объектов одного host складываются в один server-блок nginx и влияют друг на друга.
use-regex и rewrite-target «заражают» весь хост целиком
Дальше начинается самое коварное. Аннотация use-regex, поставленная на один-единственный Ingress, включает regex-режим для всех путей этого host — включая пути, описанные в совершенно других Ingress-объектах, возможно, в другом namespace, возможно, добавленных чужим Helm-чартом полгода назад. Вы правите один сервис, а меняете поведение маршрутизации у соседей.
То же самое делает rewrite-target, причём даже без явного use-regex. В документации это отдельным абзацем: «Additionally, if the rewrite-target annotation is used on any Ingress for a given host, then the case insensitive regular expression location modifier will be enforced on ALL paths for a given host regardless of what Ingress they are defined on». То есть один чарт с rewrite-target переводит в regex-режим весь домен.
Инвентарь «заражённых» хостов я собираю одной командой ещё до того, как открою первый манифест. Она выводит namespace, имя Ingress и host для всех объектов, где стоит use-regex или rewrite-target:
kubectl get ingress -A -o json | jq -r '.items[] | select(.metadata.annotations // {} | keys[] | test("use-regex|rewrite-target")) | "\(.metadata.namespace)/\(.metadata.name)\t\(.spec.rules[].host)"' | sort -uСмотрите, что из этого получается на типичном манифесте:
- путь /api/v[0-9]+ вы писали как regex — он и работает как regex;
- соседний путь /static вы писали как литерал — но он тоже стал regex, и теперь ловит /static-cdn, /staticfiles, /STATIC;
- rewrite-target: /$2 применяется к правилам, у которых нет второй группы захвата, — путь схлопывается в /, и запрос уходит в корень бэкенда;
- health-проба /health, описанная в третьем Ingress, внезапно попадает под чужой rewrite и начинает отвечать 200 не тем, чем должна.
Gateway API считает пути иначе — и делает это строго
В Gateway API (группа gateway.networking.k8s.io, версия v1) тип сопоставления пути задаётся явно, и семантика описана в спецификации без пространства для трактовок. Exact: «Matches the URL path exactly and with case sensitivity. This means that an exact path match on /abc will only match requests to /abc, NOT /abc/, /Abc, or /abcd». То есть слэш на конце — уже другой путь, заглавная буква — уже другой путь. PathPrefix: «Matches based on a URL path prefix split by /. Matching is case-sensitive and done on a path element by element basis... For example, the paths /abc, /abc/, and /abc/def would all match the prefix /abc, but the path /abcd would not». Это принципиально: PathPrefix — посегментный, а не строковый. То, что в nginx матчилось как «строка начинается с», здесь матчиться перестанет.
RegularExpression в Gateway API есть, но это не спасательный круг. В спецификации он помечен как implementation-specific: «Matches if the URL path matches the given regular expression with case sensitivity. Since "RegularExpression" has implementation-specific conformance, implementations can support POSIX, PCRE, RE2 or any other regular expression dialect». Два следствия. Первое: регистр учитывается, автоматической регистронезависимости не будет. Второе: диалект и якорение зависят от контроллера. В Envoy Gateway это RE2 и полное совпадение с путём: если regex совпал только с частью :path, правило не сработает, так что шаблон, который в nginx ловил половину сайта, здесь поймает только точное соответствие. В NGINX Gateway Fabric (документация версии 2.7) тоже RE2, но шаблон автоматически якорится только к началу пути. У Cilium поддержку RegularExpression смотрите в отчёте конформности конкретной версии: в спецификации это не Core и не Extended, и реализация вправе его не поддерживать.
Отдельная мина — фильтр URLRewrite. Поле ReplacePrefixMatch в спецификации ограничено жёстко: «ReplacePrefixMatch is only compatible with a PathPrefix HTTPRouteMatch. Using any other HTTPRouteMatch type on the same HTTPRouteRule will result in the implementation setting the Accepted Condition for the Route to status: False». Никакой магии с превращением Exact или RegularExpression в переписываемый префикс не будет. Если вы привыкли к rewrite-target с группами захвата, это надо переписывать руками, а не переводить механически.
Теперь главное — откуда берутся 404 именно у связки regex + rewrite. В ingress-nginx было привычно написать path: /booking(/|$)(.*) и rewrite-target: /$2 — nginx сам подставлял группу захвата. В стандартном Gateway API групп захвата нет вообще. ReplacePrefixMatch с RegularExpression невалиден: Route получает Accepted=False, трафик на эти пути не маршрутизируется, и клиент видит 404 от Gateway. ReplaceFullPath формально принимается, но строку /$2 он подставляет буквально: бэкенд получает путь /$2 и честно отвечает 404. В NGINX Gateway Fabric есть открытое обсуждение поддержки групп захвата для RegularExpression, и конфигурация с /$2 там упирается в ошибку валидации. Если regex-rewrite действительно нужен, это делается только расширением конкретной реализации — в Envoy Gateway, например, через собственный ресурс HTTPRouteFilter с типом ReplaceRegexMatch:
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: HTTPRouteFilter
metadata:
name: booking-regex-rewrite
spec:
urlRewrite:
path:
type: ReplaceRegexMatch
replaceRegexMatch:
pattern: '^/booking(/.*)?$'
substitution: '\1'В HTTPRoute такой фильтр подключается через filters с type: ExtensionRef (group gateway.envoyproxy.io, kind HTTPRouteFilter). Работает, но маршрут после этого привязан к Envoy Gateway намертво. Там, где хватает префикса, я предпочитаю PathPrefix /booking плюс ReplacePrefixMatch: / — это Core-синтаксис, одинаково понятный любому контроллеру.
И последнее, что стоит держать в голове, — приоритет правил. Спецификация задаёт порядок — сначала Exact, затем PathPrefix с наибольшим числом символов, затем совпадение по методу, затем по наибольшему числу заголовков, затем по наибольшему числу query-параметров. При равенстве побеждает более старый по времени создания Route, дальше — алфавитный порядок «{namespace}/{name}», а внутри одного HTTPRoute — первое совпавшее правило. Это детерминированно и это хорошо, но это не тот же порядок, в котором location разбирал nginx.
Статусы после применения я проверяю не глазами в дашборде, а выборкой по всем HTTPRoute сразу — Accepted=False из-за несовместимого фильтра иначе легко пропустить:
kubectl get httproute -A -o custom-columns=NS:.metadata.namespace,NAME:.metadata.name,ACCEPTED:'.status.parents[*].conditions[?(@.type=="Accepted")].status'- Exact — Core-поддержка, регистрозависимо, /abc ≠ /abc/ ≠ /Abc ≠ /abcd;
- PathPrefix — Core-поддержка, регистрозависимо, посегментно, завершающий / в значении игнорируется;
- RegularExpression — implementation-specific, регистрозависимо, диалект и якорение на усмотрение контроллера (Envoy Gateway — RE2, полное совпадение; NGINX Gateway Fabric — RE2, якорь в начале);
- ReplacePrefixMatch работает ТОЛЬКО с PathPrefix, иначе Route уезжает в Accepted=False;
- фильтр URLRewrite целиком (ReplaceFullPath, ReplacePrefixMatch, Hostname) — уровень поддержки Extended, групп захвата в нём нет;
- value пути ограничен 1024 символами, по умолчанию «/», запрещены //, /./, /../, %2f, %2F и #.
Разбор из практики: музыкальная школа «Нотный дом», сайт с онлайн-записью и пять расхождений
Клиент — музыкальная школа «Нотный дом», 48 рабочих мест: преподаватели, администраторы, бухгалтерия. Мы у них ведём офисную ИТ-часть, а сайт школы с онлайн-записью на пробные занятия и оплатой абонементов сделал и держит сторонний веб-подрядчик — в своём небольшом кластере Kubernetes за ingress-nginx. После новостей о завершении проекта ingress-nginx подрядчик прислал план переезда на Envoy Gateway, и школа попросила нас посмотреть его независимым взглядом: для них сайт и запись — это заявки от родителей, и неделя с 404 на форме записи прямо бьёт по набору.
Масштаб честно небольшой: три публичных хоста (сайт, модуль записи, API для CRM и уведомлений платёжного сервиса), 11 объектов Ingress, два из них пришли с Helm-чартом мониторинга. Подрядчик прогнал ingress2gateway, поправил вывод руками: pathType: Prefix → PathPrefix, Exact → Exact, а правило с rewrite-target: /$2 на модуле записи переложил в URLRewrite с ReplaceFullPath. Всё применилось, все Route — Accepted=True, главная и форма записи открывались. Мы попросили до переключения поднять Gateway параллельно и прогнать через оба контура корпус путей: подрядчик выгрузил из access-логов за 60 дней около 1 300 уникальных адресов, дальше сравнивали коды ответов скриптом из следующего раздела.
Расхождений нашлось пять, и все из той же оперы, что описана в документации. Первое: платёжный сервис слал уведомления об оплате абонемента на /Payment/Notify с заглавными — в старом контуре хост был в регистронезависимом regex-режиме из-за того самого rewrite-target, и путь долетал; на Exact /payment/notify он стал 404, то есть оплаты перестали бы подтверждаться в CRM. Второе: QR-коды на весенних афишах отчётного концерта вели на /zapis-vesna, а правило было /zapis — строковый префикс nginx это прощал, посегментный PathPrefix нет. Третье: весь модуль записи под /booking/… — ReplaceFullPath подставлял строку /$2 буквально, и бэкенд отвечал 404 на все внутренние шаги формы, кроме первого экрана, который открывался по отдельному правилу. Ещё два расхождения — метрики и health-проба, попадавшие под чужой rewrite, — внешних пользователей не касались.
Чинили адресно, без «вернём regex на всё». Для уведомлений платёжного сервиса добавили второй match в то же правило — просить сервис поменять URL долго, а два лишних match ничем не рискуют. Под QR-коды завели явный Exact-маршрут /zapis-vesna: афиши уже напечатаны, и они будут висеть до конца сезона. Модуль записи переписали на PathPrefix /booking + ReplacePrefixMatch: / — групп захвата там по сути и не требовалось, нужен был просто срез префикса. Метрики и пробы вывели на явные маршруты. Итог: 9 HTTPRoute вместо 11 Ingress, переключение подрядчик сделал сменой DNS-записи в тихий час, обращений от родителей и администраторов после него не было. Наша часть работы — около четырёх часов на разбор плана, скрипт сравнения и разбор расхождений вместе с подрядчиком.
- было: 11 Ingress, 3 хоста, 1 объект с rewrite-target — но регистронезависимый regex-режим по факту действовал на весь хост модуля записи и API;
- стало: 9 HTTPRoute, 2 фильтра URLRewrite с ReplacePrefixMatch, 1 дублирующий match под верхний регистр, 1 явный маршрут под QR-коды;
- корпус проверки: около 1 300 уникальных путей за 60 дней из access-логов подрядчика;
- найдено расхождений: 5, из них 3 дали бы 404 внешним потребителям — платёжному сервису, родителям с афиш и форме записи;
- потрачено: около 4 часов нашей работы, 0 инцидентов после переключения.
Мой порядок миграции: теневой Gateway и диффометр по кодам ответов
Я не верю в миграцию маршрутизации «по манифестам». Я верю в сравнение фактического поведения на реальных путях. Схема, которую применяю каждый раз, простая: старый контур не трогаем вообще, рядом поднимаем Gateway на отдельном hostname (или на том же, но с проверкой через Host-заголовок и --resolve), и гоняем через оба один и тот же список URL, сравнивая коды ответов. Всё, что разошлось, — в список на разбор.
Стартовые манифесты удобно получить через ingress2gateway — это проект SIG Network, версия 1.0 вышла 20 марта 2026 года, генерирует ресурсы Gateway API v1.5.0 и для провайдера ingress-nginx переводит больше 30 распространённых аннотаций, включая regex-матчинг и rewrite. Но README проекта прямо говорит, что копировать аннотации один в один он не призван, поэтому его вывод для меня черновик, а не результат:
ingress2gateway print --providers=ingress-nginx --namespace school-site > gateway-draft.yamlКорпус путей собираю из логов, а не из головы. Если фронт за CDN — берите логи CDN, там будет честный регистр и честные суффиксы. Если логи уже уехали в Loki/ELK — доставайте оттуда, за 60–90 дней. Ниже — тот самый скрипт сравнения, который у меня лежит в снипетах и правится под каждый проект за пять минут.
#!/usr/bin/env bash
# paths.txt — уникальные пути из access-логов за 60 дней
OLD_IP=10.20.0.11 # ingress-nginx
NEW_IP=10.20.0.31 # Gateway API
HOST=school.example.ru
printf '%-46s %6s %6s\n' PATH OLD NEW
while read -r p; do
old=$(curl -s -o /dev/null -w '%{http_code}' \
--resolve "$HOST:443:$OLD_IP" "https://$HOST$p")
new=$(curl -s -o /dev/null -w '%{http_code}' \
--resolve "$HOST:443:$NEW_IP" "https://$HOST$p")
[ "$old" = "$new" ] || printf '%-46s %6s %6s\n' "$p" "$old" "$new"
done < paths.txtДальше — по списку расхождений. Регистр лечится дополнительным match в том же правиле (дублировать backendRefs не нужно, matches — это список). Пропавший «хвост» лечится либо отдельным маршрутом, либо честным RegularExpression, если ваш контроллер его поддерживает и вы приняли, что маршрут стал непереносимым. Rewrite — только ReplacePrefixMatch и только поверх PathPrefix.
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: payment-notify
spec:
parentRefs:
- name: public-gw
hostnames:
- api.school.example.ru
rules:
- matches:
- path:
type: Exact
value: /payment/notify
- path:
type: Exact
value: /Payment/Notify # legacy-вариант платёжного сервиса
backendRefs:
- name: crm-api
port: 8080- сгенерировать черновик манифестов через ingress2gateway и вычитать каждый URLRewrite и RegularExpression руками;
- снять корпус путей из access-логов/CDN за 60–90 дней, привести к уникальным значениям;
- поднять Gateway параллельно, боевой Ingress не трогать;
- прогнать скрипт сравнения, разобрать каждое расхождение отдельно, а не «включить regex обратно»;
- проверить status.parents[].conditions на Accepted и ResolvedRefs у всех HTTPRoute;
- переключать через DNS или через вес в балансировщике, с готовым откатом на старый IP;
- неделю после переключения держать алерт на всплеск 404 по каждому хосту.
Что чинить в первую очередь, а на что можно спокойно забить
Скажу прямо: соблазн «сделать как было» — сохранить регистронезависимость и префиксный regex на всём — я считаю вредным. Вы потратите время на то, чтобы законсервировать поведение, которое никто сознательно не выбирал: оно возникло как побочный эффект аннотаций nginx. Плюс RegularExpression в Gateway API implementation-specific, и вы своими руками прибьёте маршруты к конкретному контроллеру — ровно та зависимость, от которой уходили.
В первую очередь чините то, где на другом конце провода не вы. Внешние интеграции, уведомления платёжных сервисов, обмен с CRM, мобильные клиенты старых версий, ссылки в печатных материалах и QR-кодах. Там вы не можете попросить «поправьте регистр в запросе» — точнее, можете, но это займёт недели, а 404 у вас уже сегодня. Для них — явный дублирующий match, и живём дальше.
На что можно забить с чистой совестью: на регистр в путях, которые дёргает только ваш собственный фронт (правится в одном месте одним коммитом), на «красоту» маршрутов вроде /api-something, которое случайно матчилось на /api и по-хорошему вообще не должно было работать, и на попытки один в один воспроизвести приоритет location из nginx — в Gateway API приоритет описан в спецификации и он предсказуемее. Не бойтесь, что маршрутов станет больше: девять явных HTTPRoute читаются лучше, чем одиннадцать Ingress с аннотациями, которые тихо влияют друг на друга через общий host.
И про сроки. Сопровождение community-проекта ingress-nginx завершилось в марте 2026 года (анонс — ноябрь 2025, KubeCon + CloudNativeCon North America). Уже развёрнутые инсталляции не перестают работать в одну ночь, паниковать не нужно. Но обновлений безопасности для них больше нет, а входной контроллер — это то, что смотрит наружу. Заложите миграцию в план на ближайший квартал, а не «когда-нибудь». И не путайте: коммерческий NGINX Ingress Controller от F5 — отдельный живой продукт, к завершению community-проекта он отношения не имеет.
- высокий приоритет: внешние потребители — платёжные уведомления, вебхуки, обмен с CRM, ссылки и QR-коды в печатных материалах;
- средний: собственный фронт и мобильные приложения, которые вы контролируете и обновляете;
- низкий: внутренние сервисы, admin-панели, всё за VPN;
- не делать: тотальный перевод путей в RegularExpression ради обратной совместимости.
Частые вопросы
Почему после миграции 404 получают только некоторые адреса, а сайт в целом работает?
Потому что короткие популярные пути в нижнем регистре попадают в правило при любой семантике матчинга. Ломается то, что раньше матчилось «случайно»: другой регистр, лишний суффикс, слэш на конце, путь под чужим host-wide rewrite. Такие адреса обычно дёргают интеграции и старые клиенты, а не люди в браузере, поэтому проблема всплывает не сразу.
Можно ли в Gateway API вернуть регистронезависимое сопоставление путей?
Штатного переключателя нет: и Exact, и PathPrefix, и RegularExpression в спецификации описаны как регистрозависимые. Практических выхода два — добавить дополнительный match с нужным вариантом написания в то же правило (matches — это список, backendRefs дублировать не нужно) или использовать RegularExpression, если ваш контроллер его поддерживает. Второй вариант делает маршрут непереносимым между реализациями.
Чем PathPrefix в Gateway API отличается от pathType: Prefix в Ingress-NGINX?
PathPrefix сопоставляет посегментно: /abc, /abc/ и /abc/def попадут под префикс /abc, а /abcd — нет. В ingress-nginx, особенно когда на хосте включён regex-режим, сопоставление ведёт себя как строковый префикс, и /abcd матчился. Именно на этом теряются адреса вида /static-cdn при правиле /static.
Почему HTTPRoute применился, но трафик через него не идёт?
Смотрите status.parents[].conditions. Типовая причина — фильтр URLRewrite с ReplacePrefixMatch поверх match типа Exact или RegularExpression: спецификация требует, чтобы реализация выставила Accepted=False. kubectl apply при этом отработает без ошибки, маршрут просто молча не обслуживает запросы. Вторая частая причина — ResolvedRefs=False из-за отсутствующего сервиса или недостающего ReferenceGrant для бэкенда в другом namespace.
Почему rewrite с группами захвата, перенесённый из rewrite-target, даёт 404?
В стандартном URLRewrite Gateway API групп захвата нет. ReplacePrefixMatch поверх RegularExpression делает Route невалидным (Accepted=False), а ReplaceFullPath подставляет /$2 буквально — бэкенд получает несуществующий путь и отвечает 404. Решение — переписать правило на PathPrefix + ReplacePrefixMatch, если нужен срез префикса, либо использовать расширение конкретной реализации, например HTTPRouteFilter с ReplaceRegexMatch в Envoy Gateway.
Можно ли доверить миграцию ingress2gateway целиком?
Как генератор черновика — да, версия 1.0 переводит больше 30 аннотаций ingress-nginx, включая regex и rewrite. Но поведение хост-широкого регистронезависимого regex-режима и «случайно» работавших путей по манифестам не восстановить: их видно только в access-логах. Поэтому после генерации обязательно сравнение кодов ответов старого и нового контура на реальном корпусе путей.
Ingress-NGINX перестал работать в марте 2026? Надо срочно всё переносить?
Нет, уже развёрнутые инсталляции продолжают работать — завершилось сопровождение проекта, а не выключились контроллеры. Но обновлений, в том числе безопасности, для community-версии больше нет, а это компонент на периметре. Разумный горизонт — квартал: спокойно собрать корпус путей, прогнать параллельный контур, переключиться через DNS. И не путайте с коммерческим NGINX Ingress Controller от F5 — это отдельный продукт, он живой.
На какой контроллер Gateway API переходить?
Единого правильного ответа нет, выбор зависит от того, что у вас уже есть. Если в кластере Cilium как CNI, логично включить его встроенную поддержку Gateway API. Если есть или планируется service mesh — Istio. Если нужен просто входной шлюз — Envoy Gateway или NGINX Gateway Fabric. Ключевое при выборе: поддерживает ли контроллер RegularExpression и в каком диалекте (у Envoy Gateway и NGF — RE2, но якорение разное), какие Extended-фильтры реализованы и есть ли расширения под regex-rewrite, если без него никак.
Источники
- Kubernetes Blog — «Five Surprising Ingress-NGINX Behaviors Before Migration», 27 февраля 2026 — разбор regex-префиксов, регистронезависимости и host-wide действия аннотаций перед переездом на Gateway API. https://kubernetes.io/blog/2026/02/27/ingress-nginx-before-you-migrate/
- Gateway API — определения типов HTTPRoute v1 — kubernetes-sigs/gateway-api, apis/v1/httproute_types.go: определения PathMatchExact, PathMatchPathPrefix, PathMatchRegularExpression, ограничение ReplacePrefixMatch и правила приоритета матчинга. https://github.com/kubernetes-sigs/gateway-api/blob/main/apis/v1/httproute_types.go
- Kubernetes Blog — Ingress2Gateway 1.0 — «Announcing Ingress2Gateway 1.0: Your Path to Gateway API», 20 марта 2026 — поддержка 30+ аннотаций ingress-nginx, включая regex и rewrite. https://kubernetes.io/blog/2026/03/20/ingress2gateway-1-0-release/ ; репозиторий и CLI: https://github.com/kubernetes-sigs/ingress2gateway
- Ingress-NGINX — Annotations — Официальная документация ingress-nginx, раздел «Rewrite» / use-regex и rewrite-target: формулировка «will be enforced on ALL paths for a given host regardless of what Ingress they are defined on». https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/
- CNCF Blog — «Ingress NGINX retirement: Experience from end users», 2 апреля 2026 — сроки завершения проекта (анонс ноябрь 2025, retirement март 2026), опыт миграции CERN, Boeing и других на Gateway API, Cilium, Istio и Envoy Gateway. https://www.cncf.io/blog/2026/04/02/ingress-nginx-retirement-experience-from-end-users/
- Gateway API — документация проекта — Официальный сайт Gateway API (группа gateway.networking.k8s.io, версия ресурсов v1): типы HTTPRoute, HTTPRouteFilter, уровни поддержки Core/Extended/Implementation-specific. https://gateway-api.sigs.k8s.io/
- Envoy Gateway — HTTP URL Rewrite — Задача HTTP URL Rewrite: ReplacePrefixMatch, ReplaceFullPath и расширение HTTPRouteFilter с ReplaceRegexMatch (RE2). https://gateway.envoyproxy.io/latest/tasks/traffic/http-urlrewrite/
- NGINX Gateway Fabric — документация — Gateway API compatibility (URLRewrite: ReplaceFullPath, ReplacePrefixMatch) и Advanced routing (RegularExpression, RE2, якорь в начале пути). https://docs.nginx.com/nginx-gateway-fabric/overview/gateway-api-compatibility/ ; https://docs.nginx.com/nginx-gateway-fabric/traffic-management/advanced-routing/
- Ingress-NGINX — Path matching / Regular expressions — Раздел о порядке путей и модификаторе ~*: use-regex OR rewrite-target включают регистронезависимый regex на всех путях хоста. https://kubernetes.github.io/ingress-nginx/user-guide/ingress-path-matching/
