← Все статьи

С ingress-nginx на Envoy Gateway без простоя: 27 Ingress, 39 HTTPRoute

ingress-nginx ретирован и блокирует апгрейды Kubernetes. Как мы перевели 16 публичных хостов на Envoy Gateway: подняли новый вход рядом со старым и в самом конце поменяли только адрес.

В Optimacros кластер Kubernetes обслуживает публичные маркетинговые сайты компании. Community ingress-nginx ретировали в марте 2026 года, а его последние релизы ограничивают версию Kubernetes: одна линейка упирается в 1.33, финальная — в 1.35. Апгрейд до 1.36 без замены входа был невозможен.

Итог: 16 хостов переехали на Gateway API, 27 объектов Ingress превратились в 39 HTTPRoute, ни одного расхождения с прежним поведением, и прод не падал.

Схема, которая сделала переезд безопасным

Ключ был не в манифестах, а в порядке. Новый вход поднимается на свободном адресе рядом со старым, и в самом конце меняется только адрес.

  1. Envoy Gateway на запасном адресе, пока прод остаётся на ingress-nginx.
  2. Сверка всех 16 хостов на обоих адресах.
  3. Адреса меняются местами — по одной аннотации на каждый. Это единственный момент хоть какого-то влияния.
  4. Старый вход остаётся жив на запасном адресе, так что откат — одна аннотация.

Сверка — это не «страница открылась». По каждому хосту я сравнивал код ответа и код редиректа через заголовок Host и SNI на обоих адресах одновременно. Совпали 16 из 16.

Ловушка 1: домен кластера не всегда cluster.local

Этот кластер унаследовал от kubespray нестандартный домен. С дефолтом чарта прокси-под резолвил свой xDS-сервер в несуществующее имя, получал NXDOMAIN и висел в 1/2 Running с no healthy upstream. cat /etc/resolv.conf в любом поде покажет настоящий search-домен. Тот же домен попадает в SAN сертификатов, которые генерирует чарт, поэтому одной правки значения мало — сертификаты тоже нужно перевыпустить.

Ловушка 2: Helm-hook не перезапускается рефрешем

Генератор сертификатов — это pre-install и pre-upgrade hook. Если Application уже Synced, Argo CD не видит работы и не запускает его, а ServiceAccount хука тоже удаляется после отработки. Я отрендерил этот набор через helm template, убрал hook-аннотации и применил руками.

Ловушка 3: basic auth только в формате {SHA}

ingress-nginx хранил хеши apr1. SecurityPolicy в Envoy Gateway отвергает их с unsupported htpasswd format: please use {SHA}, а ключ должен называться .htpasswd. Где пароль был известен, я пересчитал хеш. Где существовал только хеш apr1, пароль восстановить было нельзя — только ротировать. Старый ключ я оставил рядом с новым: пока оба формата лежат в одном Secret, работают оба входа, и откат остаётся живым.

Ловушка 4: аннотации без прямого аналога

ingress-nginx Gateway API
ssl-redirect отдельный HTTPRoute на listener :80 с RequestRedirect, статус 308, как у nginx
auth-type: basic SecurityPolicy.basicAuth на отдельный маршрут, иначе пароль спросят на всём сайте
rewrite-target с regex часто это просто замена префикса: ReplacePrefixMatch
backend-protocol: HTTPS BackendTLSPolicy, которому нужен стабильный CA
именованный порт бэкенда в backendRefs.port только числа

Сервер Argo CD генерирует свежий сертификат в памяти при каждом старте, так что CA, из которого можно построить BackendTLSPolicy, просто нет. За внешней терминацией TLS штатный ответ — server.insecure=true, и одновременно нужно снять аннотацию HTTPS-бэкенда со старого Ingress.

Ловушка 5: инвентаризация врёт, пока не проверишь по сети

  • Восемь TLS-секретов оказались двумя сертификатами: один wildcard лежал пятью копиями под разными именами и уже покрывал apex.
  • Двух упомянутых секретов не существовало вовсе. Эти хосты годами отдавали fake-сертификат ingress-контроллера, и никто не замечал.
  • Два Ingress были остатками удалённого приложения: нет DNS, нет Service, 503 на проде. Их удалили, а не переносили.

Мелочи, съевшие время

  • Папка kustomize применяет только то, что перечислено в resources:. Файл, положенный рядом, молча игнорируется.
  • Политика Kyverno, клонировавшая TLS-секрет при появлении Ingress, на Gateway не срабатывает. Нужно отдельное правило и RBAC на gateways.
  • App-of-apps обновляется сверху вниз: рефреш ребёнка, пока родитель на старой ревизии, ничего не даёт.
  • Ссылка из Gateway на Secret в другом namespace требует ReferenceGrant в namespace владельца.

Что взять с собой

  • Поднимайте новый вход рядом со старым и меняйте только адрес. Тогда переключение и откат — по одной аннотации.
  • Перед переключением сверьте коды ответа и редиректа по каждому хосту на обоих адресах.
  • Проверьте домен кластера, прежде чем ставить что-то, что резолвит внутрикластерные имена.
  • Сверяйте TLS-секреты с тем, что реально отдаёт прод.
  • Не удаляйте старый вход в день переключения. Это ваш откат.