Ingress-nginx долгое время оставался стандартным ingress-контроллером для Kubernetes, но после объявления о завершении активной поддержки многим командам пришлось задуматься о миграции. В этой статье рассказываем, как мы в True Engineering выбирали новый ingress-контроллер, тестировали Traefik и постепенно готовим инфраструктуру к переходу на Gateway API без простоев и массового переписывания сервисов.
Почему тема смены ingress-контроллера стала актуальной
Большинство инженеров, работающих с Kubernetes, уже знают, что ingress-nginx уходит на пенсию. В официальном объявлении Kubernetes говорится, что поддержка ingress-nginx продолжится в режиме best-effort до марта 2026 года. После этого проект перестанет получать новые релизы, исправление ошибок и обновление безопасности.
Мы в True Engineering, как и многие команды в отрасли, долгое время использовали ingress-nginx в собственных и клиентских кластерах. Контроллер стабильно работает, хорошо изучен и закрывает базовые задачи маршрутизации трафика. При этом небольшой, но показательный опрос на Reddit показывает, что ingress-nginx до сих пор занимает почти половину рынка.
После появления официальной даты окончания поддержки ситуация резко изменилась. Вопрос уже не в том, нужно ли мигрировать, а в том, как сделать это безопасно и без серьезных изменений в инфраструктуре. Сейчас всем приходится отвечать на несколько вопросов:
- куда мигрировать
- какие риски возникают при переходе
- сколько будет стоить миграция
- какие ограничения и несовместимости появятся
Ingress API vs Gateway API
Параллельно в экосистеме Kubernetes развивается новый стандарт публикации сервисов — Gateway API. Постепенно он становится основным направлением развития вместо классического Ingress API.
Gateway API решает задачи, которые раньше приходилось закрывать сложными ingress-конфигурациями, аннотациями и дополнительными механизмами. Если говорить коротко, основная идея Gateway API — более четкое разделение ответственности и более гибкая маршрутизация. В классическом Ingress все обычно описывается в одном ingress-объекте: хост, правила маршрутизации, TLS, иногда дополнительные параметры через аннотации. По мере роста инфраструктуры такие конфигурации становятся все сложнее и хуже масштабируются.
В Gateway API архитектура сразу разделена на несколько логических уровней. Объект Gateway описывает точку входа в кластер для конкретного хоста, а Route-объекты отвечают за правила маршрутизации. Если провести аналогию с nginx:
• Gateway — уровень хоста
• Route — уровень location и маршрутизации внутри него
Такой подход позволяет разным командам независимо управлять своей частью конфигурации и упрощает сопровождение инфраструктуры.
Подробнее про различия API можно прочитать в официальной документации.
При этом переход на Gateway API требует определенных трудозатрат: нужно переписывать манифесты, обновлять Helm-чарты, менять CI/CD-пайплайны и тестировать маршрутизацию и TLS.
Поэтому мы решили разделить миграцию на несколько этапов. Сначала заменить ingress-контроллер на современное поддерживаемое решение с минимальными изменениями текущих сервисов, а затем постепенно переводить инфраструктуру на Gateway API по мере готовности процессов и инструментов.
Так мы снизим риски и не будем совмещать сразу несколько крупных изменений. Дополнительно важно учитывать текущее состояние экосистемы. Многие популярные Helm-чарты, включая Bitnami и другие широко используемые решения, до сих пор ориентированы на классический Ingress и только начинают добавлять поддержку Gateway API. Поэтому Ingress какое-то время останется частью production-инфраструктур, несмотря на развитие нового стандарта.
Наш контекст: инфраструктура и ограничения
Чтобы понять масштаб миграции, важно описать контекст нашей инфраструктуры.
Сейчас в эксплуатации находятся:
- 5 собственных Kubernetes-кластеров
- более 500 ingress-ресурсов
- десятки клиентских кластеров в публичных облаках, on-premise инфраструктуре и в средах заказчиков.
Любые изменения сетевого слоя затрагивают сразу большое количество систем с разными требованиями и уровнем критичности.
Отдельно стоит отметить production-окружения с высокой нагрузкой, где публикация сервисов наружу — критичная часть инфраструктуры. В таких системах любые изменения нужно выполнять максимально аккуратно, без простоев и влияния на пользователей. Это автоматически ограничивает варианты миграции. Нельзя просто переключить контроллер одним релизом или массово переписать конфигурации. Необходим постепенный переход с тестированием и возможностью отката.
Дополнительную сложность создают накопленные ingress-nginx-конфигурации. За годы эксплуатации мы активно использовали аннотации для настройки маршрутизации, безопасности и поведения прокси.
Например:
Механизмы аутентификации и интеграции с внешними сервисами
- auth-url
- auth-signin
- auth-response-headers
Управление протоколами и поведением backend-сервисов
- backend-protocol
- x-forwarded-prefix
- x-forwarded-proto
Настройки CORS
- enable-cors
- cors-allow-origin
- cors-allow-methods
- cors-allow-credentials
Параметры буферизации и таймауты
- proxy-body-size
- proxy-buffer-size
- proxy-buffers-number
- proxy-connect-timeout
- proxy-read-timeout
- proxy-send-timeout
- client-body-buffer-size
Маршрутизация и переписывания путей
- rewrite-target
Пользовательские сниппеты конфигурации
- configuration-snippet
- server-snippet
Последние два пункта особенно чувствительны при миграции. Они позволяют внедрять произвольные nginx-настройки прямо в конфигурацию ingress и дают очень высокую гибкость. Одновременно это создает сильную зависимость от конкретной реализации контроллера. Такие конструкции практически невозможно перенести на другое решение без изменений, и именно они чаще всего становятся основной точкой сложности при миграции.
Требования к новому ingress / gateway решению
Когда стало понятно, что оставаться на ingress-nginx в долгосрочной перспективе не получится, следующим шагом стало определение требований к новому решению. Нам нужен был инструмент, который стабильно работает с классическим Ingress, поддерживает Gateway API, позволяет мигрировать постепенно и минимально затрагивает текущие сервисы.
– Одним из ключевых критериев была зрелость проекта. Мы смотрели не только на функциональность, но и на активность разработки, частоту обновлений, качество документации и размер сообщества. Это напрямую связано с операционными рисками: чем шире используется решение, тем выше вероятность, что возникающие проблемы уже известны и имеют готовые способы решения.
– Не менее важной были простота и предсказуемость миграции. У нас уже есть сотни ingress-ресурсов и большое количество автоматизации вокруг них: Helm-чарты, пайплайны и шаблоны конфигураций. Поэтому мы искали решение, которое позволит максимально сохранить существующие манифесты и текущее поведение сервисов.
– Отдельно оценивались сложность настройки, удобство эксплуатации, логирование, мониторинг и удобство диагностики. Для production-окружений также критичны производительность и стабильность под нагрузкой, поэтому мы дополнительно изучали результаты нагрузочного тестирования и рекомендации сообщества.
Конечный список требований выглядел так:
- поддержка классического Ingress
- совместимость с существующими конфигурациями
- поддержка Gateway API
- активное развитие проекта
- минимальные изменения при миграции
- предсказуемое поведение
- высокая производительность
- возможность работы в облаках и on-premise инфраструктуре
Кандидаты на замену ingress-nginx
Основными причинами выбора Traefik на замену ingress-nginx стали:
- Зрелость проекта и качественная документация
- Автоматическое обнаружение новых сервисов
- Высокая производительность и средняя сложность настройки
- Поддержка Gateway API
Но самым главным фактором для нас стало наличие специального провайдера Kubernetes Ingress NGINX.
Данный провайдер по заверению документации позволяет мигрировать с ingress-nginx с минимальными изменениями в объектах Ingress. Он следит за объектами Ingress в k8s, у которых установлен ingressClassName: nginx и преобразует их в конфигурацию traefik.
Очень много конфигурации для ingress-nginx контроллера задавалось через аннотации в Ingress-объектах. Kubernetes Ingress NGINX поддерживает часть этих аннотаций, что и позволяет мигрировать на новый контроллер с минимальными изменениями.
В документации Traefik есть отдельная статья, как провести миграцию с минимальным даунтаймом.
Сам Traefik мы устанавливали из официального Helm-чарта.
Чтобы включить Kubernetes Ingress NGINX provider, достаточно добавить настройки в values-файл и установить Traefik:
helm upgrade --install traefik traefik/traefik --version=39.0.5 \
--namespace traefik --create-namespace \
-f values-<env>.yaml \
--atomic --wait --debug --timeout=600s
Какие проблемы возникли
Миграция через Kubernetes Ingress NGINX provider действительно работает, но в основном для относительно простых ingress-конфигураций без специфичных ingress-nginx-аннотаций.
Дело в том, что на текущий момент provider поддерживает только часть аннотаций ingress-nginx. Полный список поддерживаемых и неподдерживаемых аннотаций есть в документации.
В наших конфигурациях особенно не хватало поддержки следующих аннотаций:
nginx.ingress.kubernetes.io/rewrite-target
nginx.ingress.kubernetes.io/upstream-vhost
nginx.ingress.kubernetes.io/configuration-snippet
nginx.ingress.kubernetes.io/permanent-redirect
nginx.ingress.kubernetes.io/proxy-connect-timeout
nginx.ingress.kubernetes.io/x-forwarded-prefix
Список поддерживаемых аннотаций постепенно расширяется. Например, во время подготовки статьи уже появилась базовая поддержка rewrite-target, но до стабильного релиза изменения пока не дошли.
В GitHub-репозитории Traefik также открыто большое количество запросов на поддержку дополнительных ingress-nginx-аннотаций.
В некоторых случаях можно дождаться реализации нужной функции. Но если времени на ожидание нет, конфигурации приходится адаптировать вручную.
Как мы реализовали rewrite-target
Для части сервисов нам требовалось обрезать префиксы запросов: (/api и /microservice-a, /microservice-b)
Для этого мы создали middleware в Traefik:, реализующий функционал изменения пути в запросе:
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: app-strip-prefixes
namespace: test-ns
spec:
stripPrefixRegex:
regex:
- "/microservice-[a-z0-9\\-]+"
- "/api"
После этого добавили аннотации Traefik в Ingress-объект:
annotations:
traefik.ingress.kubernetes.io/router.entrypoints: websecure
traefik.ingress.kubernetes.io/router.middlewares: test-ns-app-strip-prefixes@kubernetescrd
и заменили ingressClassName: traefik.
После этого Ingress-объект начинает отслеживаться другим провайдером (Ingress Kubernetes). При этом аннотации ingress-nginx контроллера можно оставить, чтобы при необходимости быстро переключаться между контроллерами через изменение ingressClassName.
Переход на Gateway API
Если все равно нужно переписывать некоторые настройки Ingress-объектов, то почему бы сразу не переходить на GatewayAPI? Traefik вполне может работать одновременно и c IngressAPI и c GatewayAPI.
Вот пример манифеста объектов GatewayAPI. Нам также понадобится middleware app-strip-prefixes. —- apiVersion:
—-
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: app-strip-prefixes
namespace: test-ns
spec:
stripPrefixRegex:
regex:
- "/microservice-[a-z0-9\\-]+"
- "/api"
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: infra-gateway
namespace: test-ns
spec:
gatewayClassName: traefik
listeners:
- allowedRoutes:
namespaces:
from: Same
name: websecure
port: 8443
protocol: HTTPS
hostname: infra.example.com
tls:
certificateRefs:
- group: ""
kind: Secret
name: wildcard-example.com
namespace: test-ns
mode: Terminate
—-
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: app-a-route
namespace: test-ns
spec:
hostnames:
- infra.example.com
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: infra-gateway
namespace: test-ns
sectionName: websecure
rules:
- backendRefs:
- group: ""
kind: Service
name: app-a-svc
namespace: test-ns
port: 80
weight: 1
filters:
- extensionRef:
group: traefik.io
kind: Middleware
name: app-strip-prefixes
type: ExtensionRef
matches:
- path:
type: PathPrefix
value: /microservice-a
При этом в рамках одного хоста infra.example.com часть путей (Location) может продолжать работать с обычными Ingress-объектами, а часть уже использовать Gateway API.
Многие задачи, которые пока не решены через аннотации, в Traefik можно реализовать через middleware.
Со списком поддерживаемых middlewares можно ознакомиться тут. А тут список поддерживаемых аннотаций самого Traefik.
План миграции
После анализа вариантов и проверки гипотез мы сформировали следующий подход:
- устанавливаем Traefik рядом с ingress-nginx
- ingress-объекты с поддерживаемыми аннотациями оставляем без изменений
- сложные ingress-конфигурации сразу переводим на Gateway API
- постепенно отказываемся от Ingress API
Главный принцип миграции — постепенный переход с возможностью отката на любом этапе. Поскольку в одном Kubernetes-кластере могут одновременно работать несколько ingress-контроллеров, а также могут одновременно существовать Ingress и Gateway объекты, новый контроллер можно установить параллельно со старым и постепенно переносить нагрузку.
В итоге план миграции выглядит так:
- Инвентаризация ingress-ресурсов, используемых аннотаций и сложных конфигураций. Это позволяет заранее понять объем изменений и определить конфигурации, которые потребуют переписывания.
- Установка нового контроллера в k8s-кластер рядом со старым
- Тестирование на пилотном сервисе различных сценариев: Ingress API, Gateway API, TLS, маршрутизации и интеграций с backend-системами.
- Переключение «простых» ingress на Traefik. Нужно перенести те сервисы, в ingress которых нет неподдерживаемых аннотаций. Для переключения трафика достаточно изменить DNS-запись или backend балансировщика.
- Постепенный перевод «сложных» сервисов с неподдерживаемыми ingress-аннотациями на Gateway API.
Такой подход позволяет контролировать процесс перехода и минимизировать риски в production-инфраструктуре.
Сейчас мы находимся на завершающем этапе тестирования и переключаем первые сервисы. Инвентаризация и установка нового контроллера занимают немного времени. Основные трудозатраты связаны с тестированием сценариев и переписыванием сложных ingress-конфигураций с учетом всех деталей реализации.
Выводы
Если у вас простая конфигурация и используются типовые ingress-конфигурации, переход на Traefik может пройти почти незаметно. В таких случаях достаточно использовать провайдер совместимости Kubernetes Ingress NGINX, и большинство манифестов продолжат работать без изменений или с минимальными правками. После этого можно постепенно переходить на Gateway API.
Если же инфраструктура активно использует сможные механизмы - например, rewrite, кастомные сниппеты и нетиповые настройки прокси, то избежать изменений не получится. В таком случае нет большого смысла дважды переписывать конфигурации: сначала под Traefik + Ingress API, а потом под Gateway API. Логичнее сразу переходить на Gateway API как на основное направление развития экосистемы Kubernetes. Переход на Gateway API — это уже вопрос времени и ресурсов. Поэтому перед миграцией важно провести аудит конфигураций, оценить риски, спланировать этапы перехода и заранее заложить необходимые ресурсы.
Если вам нужна помощь команды, которая уже прошла этот путь — обращайтесь к нам!
UPD: пока статья готовилась к публикации вышел «долгожданный» релиз traefik v3.7.0, в котором добавилась поддержка гораздо большего числа аннотаций ingress-nginx, включая rewrite-target. Также обновился и helm-чарт traefik до версии 4.0.0. Мы уже протестировали новую версию на нескольких кластерах и теперь миграция практически не требует никаких изменений со стороны объектов Ingress