Envoy. 1. Въведение

Здравейте! Това е кратка статия, отговаряща на въпросите: "какво е envoy?", "защо е необходим?" и "от къде да започнем?".

Какво е това

Envoy е L4-L7 балансировач, написан на C++, насочен към висока производителност и наличност. От една страна, той е подобен на nginx и haproxy, съизмерим с тях по производителност. От друга страна, е повече ориентиран към микросервисна архитектура и предлага функции, които не отстъпват на балансировачите на java и go, като zuul или traefik.

Таблица за сравнение на haproxy/nginx/envoy, която не претендира за абсолютна истина, но дава общо представа.

nginx
haproxy
envoy
traefik

звезди в github
11.2k/огледало
1.1k/огледало
12.4k
27.6k

написан на
C
C
C++
go

API
недостъпен
само сокет/пуш
dataplane/пул
pull

активен healthcheck
недостъпен
да
да
да

Open tracing
външен плъгин
недостъпен
да
да

JWT
външен плъгин
недостъпен
да
недостъпен

Разширение
Lua/C
Lua/C
Lua/C++
недостъпен

Защо

Това е млад проект, в него няма много функции, нещо е в ранна алфа. Но envoy, включително и благодарение на младостта, бързо се развива и вече има много интересни възможности: динамична конфигурация, много готови филтри, прост интерфейс за създаване на собствени филтри.
Това определя сферата на приложение, но за начало две антипатерна:

  • Предаване на статични файлове.

Факт е, че в момента в envoy няма поддръжка за кеширане. Хората от google се опитват да поправят. Идеята е веднъж да се реализира в на envoy всички тънкости (зоопарк заглавия) на съответствието с RFC, а за конкретни реализации да се създаде интерфейс. Но засега това дори не е алфа, архитектурата е в обсъждане, PR отворен (докато пишех статията, PR беше вмерзен, но този пункт все още е актуален).

А засега използвайте nginx за статични файлове.

  • Статична конфигурация.

Можете да я използвате, но envoy не е създадена за това. Възможностите в статичната конфигурация няма да се разкрият. Има много моменти:

Редактирайки конфигурацията в yaml, ще имате грешки, ще ругаете разработчиците за многословие и ще си мислите, че конфигурациите на nginx/haproxy, макар и по-малко структурирани, са по-лаконични. В това е същността. Конфигурацията на Nginx и Haproxy е изработена за ръчно редактиране, а в envoy е създадена за генериране от код. Цялата конфигурация е описана в protobuf, генерирайки я от proto файлове, е много по-трудно да се сбърка.

Сценарии за canary, b/g деплой и много други, се реализират нормално само в динамичната конфигурация. Не казвам, че не може да се направи в статична, ние всичко това правим. Но за това е нужно да се увират в костилки, във всеки от балансировачите, включително. envoy в това число.

Задачи, в които Envoy е незаменим:

  • Балансировката на трафика в сложни и динамични системи. Тук попада service mesh, но не е задължително само той.
  • Необходимостта от функционалността на разпределеното проследяване, сложната авторизация или друго, което е налично в envoy из коробки или удобно реализируемо, а в nginx/haproxy е нужно да се обгърне с lua и съмнителни плъгини.

И двете трябва да осигурят висока производителност, ако е необходимо.

Как работи това

Envoy се разпространява в бинарници единствено като docker образ. В образа вече има примерна статична конфигурация. Но ни интересува само за разбиране на структурата.

envoy.yaml статична конфигурация

static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address:
        protocol: TCP
        address: 0.0.0.0
        port_value: 10000
    filter_chains:
    - filters:
      - name: envoy.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager
          stat_prefix: ingress_http
          route_config:
            name: local_route
            virtual_hosts:
            - name: local_service
              domains: ["*"]
              routes:
              - match:
                  prefix: "\/"
                route:
                  host_rewrite: www.google.com
                  cluster: service_google
          http_filters:
          - name: envoy.router
  clusters:
  - name: service_google
    connect_timeout: 0.25s
    type: LOGICAL_DNS
    # Коментар към следния ред, за да се тестват мрежи v6
    dns_lookup_family: V4_ONLY
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: service_google
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: www.google.com
                port_value: 443
    transport_socket:
      name: envoy.transport_sockets.tls
      typed_config:
        "@type": type.googleapis.com/envoy.api.v2.auth.UpstreamTlsContext
        sni: www.google.com

Динамична конфигурация

Коя проблема търсим да решим? Не може просто да се рестартира конфигурацията на балансировчика под натоварване, ще възникнат "малки" проблеми:

  • Валидация на конфигурацията.

Конфигурацията може да е голяма, може да бъде много голяма, ако я презаредим изцяло, шансовете за грешка на някое място се увеличават.

  • Дългоживеещи връзки.

При инициализиране на нов слушател, трябва да се погрижим за връзките, работещи на стария, ако промените се случват често и има дългоживеещи връзки, ще се наложи да намерим компромис. Здравей, kubernetes ingress на nginx.

  • Активни хелсчеки.

Ако имаме активни хелсчеки, трябва да ги проверим всички на новата конфигурация преди да изпратим трафика. Ако има много upstream-и, това изисква време. Здравей, haproxy.

Как се решава в envoy, зареждайки конфигурацията динамично, по модел на пул, може да я разделите на отделни части и да не пренастройвате онази част, която не се е променила. Например, слушателя, който е скъп за пренастройване, а се променя рядко.

Конфигурация envoy (от горния файл) има следните entidades:

  • listener — слушател, който е свързан на определен ip/порт
  • virtual host — виртуален хост по име на домейн
  • route — правило за балансировка
  • cluster — група от upstream-и с параметри за балансировка
  • endpoint — адрес на инстанса на upstream

Всяка от тези сущности плюс някои други могат да бъдат заредени динамично, за това в конфигурацията се посочва адреса на услугата, от която ще бъде получена конфигурацията. Услугата може да бъде REST или gRPC, за предпочитане е да се използва gRPC.

Услугите се наричат съответно: LDS, VHDS, RDS, CDS и EDS. Може да се комбинира статична и динамична конфигурация, с ограничение, че динамичният ресурс не може да бъде посочен в статичния.

За повечето задачи е достатъчно да реализирате последните три услуги, които се наричат ADS (Aggregated Discovery Service), за java и go има готова имплементация на gRPC dataplane, в която е достатъчно само да запълните обектите от собствения си източник.

Конфигурацията придобива следния вид:

envoy.yaml динамическа конфигурация

dynamic_resources:
  ads_config:
    api_type: GRPC
    grpc_services:
      envoy_grpc:
        cluster_name: xds_clr
  cds_config:
    ads: {}
static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address:
        protocol: TCP
        address: 0.0.0.0
        port_value: 10000
    filter_chains:
    - filters:
      - name: envoy.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager
          stat_prefix: ingress_http
          rds:
            route_config_name: local_route
            config_source:
              ads: {}
          http_filters:
          - name: envoy.router
  clusters:
  - name: xds_clr
    connect_timeout: 0.25s
    type: LOGICAL_DNS
    dns_lookup_family: V4_ONLY
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: xds_clr
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: xds
                port_value: 6565

При стартиране envoy с тази конфигурация, той ще се свърже с control-plane и ще се опита да запита конфигурацията RDS, CDS и EDS. Как протича взаимодействието е описано тук..

Ако накратко, envoy изпраща заявка, указвайки типа на искания ресурс, версия и параметри на нодата. В отговор получава ресурса и версията, ако на control-plane версията не е променена, той не отговаря.
Има 4 варианта на взаимодействие:

  • Един gRPC стрийм за всички типове ресурси, изпраща се пълното състояние на ресурса.
  • Разделени потоци, пълно състояние.
  • Един поток, инкрементално състояние.
  • Разделени потоци, инкрементално състояние.

Инкременталният xDS позволява да се намали трафикът между контролния план и envoy, това е актуално за големи конфигурации. Но усложнява взаимодействието, в заявката се предава списък с ресурси за отписване и абонамент.

В нашия пример се използва ADS – един поток за RDS, CDS, EDS и неинкрементален режим. За да включите инкременталния режим, трябва да зададете api_type: DELTA_GRPC

Тъй като в заявката има параметри на нодата, можем на контролния план да изпращаме различни ресурси за различни инстанции envoy, което е удобно за изграждане на service mesh.

Затопляне

На envoy при стартиране или при получаване на нова конфигурация от контролния план започва процесът на затопляне на ресурсите. Той е разделен на затопляне на слушателя и затопляне на клъстера. Първото се стартира при промени в RDS/LDS, второто при CDS/EDS. Това означава, че ако се променят само апстримите, слушателят не се създава отново.

В процеса на затопляне, се очакват зависими ресурси от контролния план в течение на таймаута. Ако таймаутът изтече, инициализацията няма да бъде успешна, новият слушател няма да започне да слуша порта.
Редът на инициализация: EDS, CDS, активна проверка на състоянието, RDS, LDS. При включени активни проверки на състоянието, трафикът ще премине към апстрима, само след като бъде успешен един проверка.

Ако слушателят е бил създаден отново, старият преминава в състояние DRAIN и ще бъде премахнат след закриването на всички връзки или изтичането на таймаута --drain-time-s, по подразбиране 10 минути.

Продължението следва.

Източник: habr.com

Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри 🔥 Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри | ProHoster