Envoy xDS Controller: Повний Envoy API як Kubernetes CRDs

💡 Усі статті, обговорення, новини про DevOps — в одному місці. Приєднуйтесь до DevOps спільноти!

Привіт, мене звати Юра, я займаюсь інфраструктурою у 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. Без шару трансляції.

CRDxDS-протоколЩо конфігурує
ListenerLDSПорти, протоколи, filter-chains — відповідає envoy.config.listener.v3.Listener
RouteRDSДомени, шляхи, віртуал хости, HTTP-фільтри — відповідає envoy.config.route.v3.RouteConfiguration
ClusterCDSАпстріми, балансування навантаження, хелс чеки-відповідає envoy.config.cluster.v3.Cluster
EndpointEDSIP-адреси бекендів, пріоритети, зони — відповідає envoy.config.endpoint.v3.ClusterLoadAssignment
TLSSecretSDSTLS-сертифікати, включаючи автоматизований 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 — з покроковими інструкціями.

Посилання:

Ми вітаємо contributions, issues та зворотний зв’язок. Якщо ви запускаєте Envoy на масштабі і колись боролися з шаром абстракції, щоб налаштувати його так, як потрібно — спробуйте.

Envoy xDS Controller підтримується tentens-tech та випущений під Apache 2.0 ліцензією.

Сподобалась стаття? Підписуйтесь на автора, щоб отримувати сповіщення про нові публікації на пошту.

👍ПодобаєтьсяСподобалось12
До обраногоВ обраному7
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Дякую. Крута стаття. Для себе порівнював з Istio + VM istio.io/...​/install/virtual-machine, як загальний control plane. Для тих кому потрібен 100% контроль над envoy та edge це рішення має певні переваги.

Крута стаття, дякую що поділився досвідом.
Дуже цікаво було почитати про підхід з xDS Controller та керуванням Envoy через Kubernetes CRD

О дякую, норм стаття на доу. А є порівняння з istio контрол планом?

Дякую за запитання! Але тут не зовсім про service mesh, тут більше про динамічну конфігурацію та доставку її на Envoy.

Якщо коротко, то Istio використовує свої абстракції, схожі на Envoy (VirtualService, DestinationRule), але в будь-якому разі, як ми знаємо, це обгортка над Envoy з підтримкою sidecar, mTLS, телеметрією і т.д.

Тут же фокус саме на конфігурації самого Envoy через Kubernetes CRD. Ми працюємо безпосередньо зі специфікаціями Envoy і будуємо потрібну нам конфігурацію без додаткового шару трансляції. CRD відповідають майже 1:1 нативному API Envoy, оскільки ми будуємо всю CRD-конфігурацію динамічно з Envoy protobuf.

Все так, я добре знайомий з цим (колись портував istio на amd), починав з перших версії Ambassador, який народився саме на трансляції простого конфіга в складний конфіг енвоя. То istio це ж не тільки про сервіс меш, може просто інгрес бути і саме проблеми з росповсюдженням конфігурації xds, не завжди консистентні зміни на масштабному кластері + оверхед привносили багато проблем саме з істіо контрол планом. Питання саме про таке порівняння + підтримка gatewayapi. Взагалі ціную вашу роботу — колись не вистачало такої реалізації, а самостійно написати досвіду не було.

По суті: тут чиста імплементація, практично без нічого порівняно з Istio. Все, що робить контролер — збирає конфігурацію з CRD, пакує її в snapshot і віддає через gRPC-порт, на який ходить Envoy. Супер проста реалізація. Нова конфігурація, коли додається, потрапляє в snapshot буквально за кілька секунд. Без самого Envoy, контролер сам по собі безкорисний.

Підтримки Ingress чи Gateway API немає — так і планувалось. Для цього є Envoy Gateway та інші зрілі рішення. Тому порівнювати з Istio не зовсім коректно, на мою думку.
Окрім збірки та доставки конфігурації, тут також вбудований Let’s Encrypt/ACME клієнт (lego), який вміє запрошувати сертифікати та складати їх напряму у Vault або Secret. Це все.

Дякую за статтю 💪

Підписатись на коментарі