Envoy xDS Controller: Повний Envoy API як Kubernetes CRDs
Привіт, мене звати Юра, я займаюсь інфраструктурою у 1010s. Останні кілька років я займаюсь розробкою та підтримкою Envoy xDS Controller від початкового дизайну до продакшн-експлуатації. У цій статті я розповім, як ми побудували інгрес-рішення, здатне стабільно обробляти тисячі роутів та доменів.
Проблематика
З якою проблемою ми зустрілись — ми маємо Kubernetes-кластери в різних зонах доступності та необхідність завести трафік в них з сотень доменів та тисяч роутів. Конкретніше:
- Масштаб конфігурацій — платформа обслуговує 1,000+ маршрутів, які доволі часто можуть змінюватись.
- Мульти-зонна архітектура — кластери розподілені по різних зонах. Трафік потрібно доставляти в правильну зону з можливістю вмикати або вимикати зону для обслуговування.
- Envoy на VM поза Kubernetes — він працює на віртуальних машинах за межами кластерів. Це дає нам повний контроль над усім трафіком та можливість легко мігрувати та підміняти кластери без простою.
Ми робимо відкритим Envoy xDS Controller — Kubernetes-нативну панель управління, яка доставляє динамічну конфігурацію Envoy через gRPC, з CRD-ресурсами, що відповідають 1:1 нативному API Envoy.
Ми створили його, бо нам потрібно було керувати 1,000+ конфігураціями маршрутизації для інстансів Envoy, що працюють на віртуальних машинах за межами Kubernetes. Envoy Gateway та подібні інструменти приховують Envoy API за ресурсами Gateway API — нам потрібен був повний доступ до кожної функції Envoy, а не підмножина. Створення власного xDS-сервера на базі go-control-plane — це місяці інженерної роботи, які ми не хотіли повторювати.
Тому ми створили рішення посередині: Kubernetes CRD, які є конфігурацією Envoy без абстракцій, без обмежень, без шару трансляції і доставляються динамічно до будь-якого інстансу Envoy де завгодно.
Місце в екосистемі
Будемо відвертими. В цьому просторі є зрілі проєкти, і вони добре роблять свою справу.
Envoy Gateway — це офіційна панель управління проєкту Envoy. Він реалізує Kubernetes Gateway API, має підтримку CNCF та велику спільноту. Якщо вам потрібен стандартний Gateway API з Envoy як data plane — це ваш вибір.
kgateway та Contour — зрілі gateway на базі Envoy зі своїми перевагами у функціях API gateway та multi-team ingress.
Усі вони мають одне спільне архітектурне рішення: вони додають шар абстракції поверх Envoy.
Вони транслюють з концепцій вищого рівня (HTTPRoute з Gateway API, HTTPProxy з Contour) у конфігурацію Envoy. Це корисно — спрощує типові сценарії та захищає від помилок конфігурації. Але це також означає:
- Вони відкривають лише підмножину можливостей Envoy
- Коли Envoy випускає нову функцію, ви чекаєте, поки панель управління її підтримає
- Коли ваш сценарій не вписується в абстракцію, ви шукаєте обхідні рішення на кшталт
EnvoyPatchPolicy— які крихкі та часто документовані як «ніколи не стануть стабільними»
xDS Controller обирає протилежний підхід. Поля CRD генеруються безпосередньо з protobuf-визначень Envoy. Немає абстракції, яку потрібно обходити, бо абстракції просто немає. Якщо Envoy це підтримує — ви можете це налаштувати, сьогодні, через kubectl apply.

Працює поряд з вашим існуючим стеком
Важливий момент: xDS Controller не просить вас нічого замінювати. Він не розгортає Envoy, не інжектить sidecar-и, не керує життєвим циклом Envoy. Він просто доставляє конфігурацію будь-якому Envoy, який до нього підключається.
Це означає, що він працює поряд з тим, що ви вже використовуєте:

Вже використовуєте Envoy Gateway для Gateway API ingress? Залишайте. Але ті 5 інстансів Envoy на VM, яким потрібна низькорівнева xDS-конфігурація — xDS Controller обслуговує їх, не чіпаючи існуючий стек.
Використовуєте Contour для HTTP ingress, але потрібен TCP-проксі з конкретними функціями Envoy, які Contour не підтримує? Піднімайте нативний Envoy, направляйте його на xDS Controller.
Запускаєте звичайний Envoy на VM зі статичними конфігураційними файлами, які стають все більш громіздкими? Направте bootstrap Envoy на xDS Controller і починайте керувати конфігурацією через kubectl apply.
Це рішення для керування Envoy через Kubernetes, яке гарантує повний контроль над усією конфігурацією.
Чому саме Envoy, а не Nginx або Traefik?
Може виникнути логічне запитання: навіщо було будувати власну панель управління для Envoy, якщо на віртуальних машинах можна розгорнути умовний Nginx чи Traefik?
Чому нам не підійшов Nginx (Open Source)? У нас понад 1000 конфігурацій маршрутизації, які часто оновлюються автоматикою. В open-source версії Nginx застосування нових конфігів вимагає перезавантаження воркерів (nginx -s reload). При високій частоті оновлень (динамічне середовище) це призводить до сплесків використання CPU, накопичення старих процесів і, в гіршому випадку, до втрати keep-alive з’єднань або таймаутів. Динамічне управління роутами через API є лише у платній підписці Nginx Plus. До того ж gRPC-стрімінг конфігів в Envoy працює «з коробки» і застосовує оновлення за мілісекунди без перезавантаження процесів.
Чому не Traefik? Traefik чудово справляється з роллю Ingress-контролера в Kubernetes або при роботі з Docker Service Discovery. Але коли йдеться про запуск на «чистих» віртуальних машинах і складний контроль мережевого трафіку (різноманітні стратегії балансування, розширене обмеження швидкості (rate limiting), outlier detection, складна міграція legacy-роутингу), Traefik стає менш гнучким, бо ховає складність під власними абстракціями. Крім того, Envoy дозволяє архітектурно повністю відокремити Control Plane (у Kubernetes) від Data Plane (на «тупих» і швидких ВМ).
Як це працює
Єдиний контролер працює в Kubernetes, спостерігає за п’ятьма типами CRD та стрімить конфігурацію Envoy через gRPC у реальному часі.

Один CRD на кожен xDS-ресурс Envoy. Без шару трансляції.
| CRD | xDS-протокол | Що конфігурує |
|---|---|---|
Listener | LDS | Порти, протоколи, filter-chains — відповідає envoy.config.listener.v3.Listener |
Route | RDS | Домени, шляхи, віртуал хости, HTTP-фільтри — відповідає envoy.config.route.v3.RouteConfiguration |
Cluster | CDS | Апстріми, балансування навантаження, хелс чеки-відповідає envoy.config.cluster.v3.Cluster |
Endpoint | EDS | IP-адреси бекендів, пріоритети, зони — відповідає envoy.config.endpoint.v3.ClusterLoadAssignment |
TLSSecret | SDS | TLS-сертифікати, включаючи автоматизований Let’s Encrypt |
Поля CRD spec генеруються з protobuf-типів Envoy. lb_policy, filter_chains, virtual_hosts, health_checks — це поля Envoy, які використовуються напряму. Якщо ви раніше писали конфігурацію Envoy, ви вже знаєте цей API.
Кожна зміна CRD запускає reconciliation. Підключені Envoy отримують оновлення через постійний gRPC-стрім — без рестарту, без простою.
Як це виглядає?
Маршрут, який направляє трафік для api.example.com до кластера бекенду:
apiVersion: envoyxds.io/v1alpha1
kind: Route
metadata:
name: my-api
spec:
listener_refs:
- https-listener
tlssecret_ref: my-tls-cert
codec_type: AUTO
route_config:
name: my_api_route
virtual_hosts:
- name: api
domains: ["api.example.com"]
routes:
- match: { prefix: "/" }
route: { cluster: api-backend }
Кластер з ендпоінтами:
apiVersion: envoyxds.io/v1alpha1 kind: Cluster metadata: name: api-backend spec: connect_timeout: 5s type: STRICT_DNS lb_policy: ROUND_ROBIN load_assignment: cluster_name: api-backend endpoints: - lb_endpoints: - endpoint: address: socket_address: address: nginx.default.svc.cluster.local port_value: 80
Жодного нового DSL. Жодної нової моделі ресурсів для вивчення. Повна поверхня конфігурації Envoy доступна — CORS, компресія, Lua-скриптинг, JWT-автентифікація, rate limiting, gRPC-Web, QUIC/HTTP3, TCP-проксіювання, circuit breakers, outlier detection — через той самий патерн CRD.
Репозиторій включає 7 повних прикладів — базовий HTTP, HTTPS/TLS, TCP-проксі, балансування навантаження, розширені HTTP-функції, multi-environment targeting та gRPC — готових до kubectl apply.
Як ми це використовуємо: Envoy на VM + Kubernetes
Наш основний продакшен-сценарій — той, який більшість панелей управління розглядають як другорядний: Envoy, що працює на віртуальних машинах, керований з Kubernetes.

Envoy потрібне лише gRPC-з’єднання з контролером. Неважливо, що контролер працює в Kubernetes, а Envoy — на bare metal. Вся конфігурація керується через Kubernetes — з GitOps, RBAC, аудит-логуванням, code review через pull request.
Targeting на основі анотацій дозволяє одному контролеру обслуговувати декілька флотів Envoy. CRD з анотацією clusters: "production" потрапляють лише до Envoy з node.cluster=production. Один контролер — багато середовищ.
Готовий до продакшену
Окрім базової доставки xDS, контролер включає те, що нам було потрібно для роботи на масштабі:
Гнучке управління TLS-сертифікатами — CRD TLSSecret доставляє сертифікати до Envoy через SDS. Як саме ці сертифікати отримуються — вирішуєте ви:
Варіант 1: Вбудований Let’s Encrypt. Контролер має вбудований ACME-клієнт. Налаштуйте TLSSecret з DNS-провайдером, і сертифікати автоматично випускаються, зберігаються та оновлюються — без зовнішніх інструментів. Підтримує DNS-01 та HTTP-01 challenges, wildcard-сертифікати та множинні DNS-провайдери (Cloudflare, Route53, Google Cloud DNS, Azure DNS, DigitalOcean). Сертифікати можуть зберігатися у HashiCorp Vault або Kubernetes Secrets.
Варіант 2: Зовнішній cert-manager (або будь-яке джерело сертифікатів). Якщо ви вже використовуєте cert-manager або керуєте сертифікатами через інший процес, контролер не заважає. Вкажіть TLSSecret на існуючий Kubernetes Secret — контролер читає його та доставляє до Envoy через SDS.

Це означає, що ви можете використовувати cert-manager для управління життєвим циклом сертифікатів, а xDS Controller — виключно для доставки. Кожен інструмент робить те, що вміє найкраще. Контролер моніторить термін дії всіх сертифікатів незалежно від джерела та експортує метрику xds_cert_expiry_countdown.
Prometheus-метрики — Зворотний відлік до закінчення терміну дії сертифікатів, статус синхронізації snapshot-ів, активні з’єднання Envoy, кількість ресурсів, частота помилок.
xds_snapshot_version_match{node="envoy-01"} 1 # Конфіг синхронізовано
xds_envoy_stream_active 12 # Підключені Envoy
xds_cert_expiry_countdown{domain="example.com"} 43200 # Здоров'я сертифіката
xds_resource_count{type="route"} 1023 # Масштаб ресурсів
Для кого це?
Проєкт вам підійде, якщо:
- Ви знаєте Envoy і хочете використовувати його повний набір функцій — а не підмножину, обрану шаром абстракції
- Ви запускаєте Envoy на VM, bare metal або edge-локаціях і потребуєте централізовану панель управління
- Ви хочете Kubernetes-нативний GitOps для конфігурації Envoy без впровадження service mesh
- Вам потрібні функції, які реалізації Gateway API ще не підтримують
- Ви керуєте Envoy у різних середовищах, зонах або регіонах
Проєкт НЕ підійде, якщо:
- Вам потрібен стандарт Kubernetes Gateway API — використовуйте Envoy Gateway або kgateway
- Вам потрібен повноцінний service mesh — це інша задача, дивіться на Istio або Linkerd
- Ви не використовуєте Envoy
- Ви надаєте перевагу високорівневій абстракції, яка захищає від складності Envoy
xDS Controller — це не ще один gateway і не service mesh. Це Kubernetes-нативний control plane для тих, кому потрібен Envoy без абстракцій. Якщо ви хочете працювати з Envoy напряму, зберігаючи повний контроль над конфігурацією — саме для цього він створений.
Початок роботи
Репозиторій включає 7 повних прикладів — від базового HTTP до multi-environment gRPC — з покроковими інструкціями.
Посилання:
- GitHub: github.com/tentens-tech/xds-controller
- Приклади: github.com/tentens-tech/xds-controller/tree/main/examples
Ми вітаємо contributions, issues та зворотний зв’язок. Якщо ви запускаєте Envoy на масштабі і колись боролися з шаром абстракції, щоб налаштувати його так, як потрібно — спробуйте.
Envoy xDS Controller підтримується tentens-tech та випущений під Apache 2.0 ліцензією.
Сподобалась стаття? Підписуйтесь на автора, щоб отримувати сповіщення про нові публікації на пошту.
7 коментарів
Додати коментар Підписатись на коментаріВідписатись від коментарів