Envoy. 1. Úvod

Dobrý den! Tento krátký článek odpovídá na otázky: "co je envoy?", "k čemu je potřeba?" a "jak začít?".

Co to je

Envoy je L4-L7 vyrovnávač zátěže napsaný v C++, zaměřený na vysoký výkon a dostupnost. Na jedné straně je to do jisté míry analog nginx a haproxy, srovnatelný s nimi výkonností. Na druhé straně je více zaměřen na mikroservisní architekturu a má funkcionalitu, která není horší než vyrovnávače v javě a go, jako jsou zuul nebo traefik.

Tabulka porovnání haproxy/nginx/envoy, která si nenárokuje absolutní pravdu, ale poskytuje celkový přehled.

nginx
haproxy
envoy
traefik

hvězd na githubu
11.2k/mirror
1.1k/mirror
12.4k
27.6k

napsáno v
C
C
C++
go

API
ne
socket only/push
dataplane/pull
pull

aktivní zdravotní kontrola
ne
ano
ano
ano

Open tracing
externí plugin
ne
ano
ano

JWT
externí plugin
ne
ano
ne

Rozšíření
Lua/C
Lua/C
Lua/C++
ne

Proč

Toto je mladý projekt, ve kterém není mnoho věcí, něco je v rané alfě. Ale envoy, částečně díky mladosti, rychle se rozvíjí a již má mnoho zajímavých možností: dynamickou konfiguraci, mnoho hotových filtrů, jednoduché rozhraní pro psaní vlastních filtrů.
Z toho vyplývají oblasti použití, ale pro začátek 2 antipatterny:

  • Podávání statiky.

Skutečnost je taková, že v envoy není podpora caching. Kluci z google se to snaží opravit. Myšlenka je jednou implementovat v na envoy všechny nuance (zoo headerů) souladu s RFC, a pro konkrétní realizace udělat rozhraní. Ale zatím to není ani alfa, architektura je v diskusi, PR otevřeno (zatímco jsem psal článek, PR byl sloučen, ale tento bod je stále aktuální).

A zatím používejte pro statiku nginx.

  • Statická konfigurace.

Lze ji použít, ale envoy byla vytvořena pro jiné účely. Možnosti ve statické konfiguraci nebudou plně využity. Je tu mnoho aspektů:

Při úpravě konfigurace v yaml se budete mýlit, nadávat vývojářům za zbytečné složitosti a přemýšlet, že konfigurace nginx/haproxy, ačkoli méně strukturované, jsou stručnější. V tom je podstata. Konfigurace Nginx a Haproxy byla navržena pro ruční úpravy, zatímco envoy byla navržena k generování z kódu. Celá konfigurace je popsána v protobuf, generování pomocí proto souborů je mnohem těžší udělat chybu.

Scénáře canary, b/g nasazení a mnoho dalších se normálně realizují pouze v dynamické konfiguraci. Neříkám, že to nelze udělat ve statice, děláme to všechno. Ale k tomu je potřeba mít mnoho obstrukcí, v jakémkoli z vyrovnávačů, v envoy toho včetně.

Úkoly, ve kterých je Envoy nenahraditelný:

  • Vyvažování provozu v složitých a dynamických systémech. Sem patří service mesh, ale není to pouze to.
  • Potřeba funkce distribuovaného trasování, složité autorizace nebo něco jiného, co existuje v envoy out-of-the-box nebo se dá pohodlně implementovat, zatímco v nginx/haproxy musíme využít lua a pochybné pluginy.

Oboje je třeba zajistit vysoký výkon, pokud je to nutné.

Jak to funguje

Envoy je distribuován ve formě binárních souborů pouze jako docker obraz. V obraze již existuje příklad statické konfigurace. Ale zajímá nás pouze pro pochopení struktury.

envoy.yaml statická konfigurace

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
    # Zkomentujte následující řádek, abyste testovali na v6 sítích
    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

Dynamická konfigurace

Jaký problém se snažíme vyřešit? Nelze jen tak vzít a přetížit konfiguraci vyvážiče zatížení, vzniknou "malé" problémy:

  • Validace konfigurace.

Konfigurace může být velká, může být velmi velká, a pokud ji přetěžujeme najednou, zvyšuje se pravděpodobnost, že se vyskytne chyba.

  • Dlouhodobé připojení.

Při inicializaci nového listeneru je třeba dbát na připojení pracující na starém, pokud se změny provádí často a existují dlouhodobé připojení, bude potřeba hledat kompromis. Ahoj, kubernetes ingress na nginx.

  • Aktivní health-checky.

Pokud máme aktivní health-checky, měly by být všechny znovu zkontrolovány na nové konfiguraci ještě předtím, než budeme směrovat provoz. Pokud je mnoho upstreamů, zabere to čas. Ahoj, haproxy.

Jak se to řeší v envoy, načítáním konfigurace dynamicky, pomocí modelu pool, lze ji rozdělit na jednotlivé části a neprovádět znovu inicializaci části, která se nezměnila. Například listener, jehož opětovná inicializace je nákladná, se mění zřídka.

Konfigurace envoy (z výše uvedeného souboru) obsahuje následující entity:

  • listener — listener visící na určitém ip/portu
  • virtual host — virtuální host podle názvu domény
  • route — pravidlo vyvažování
  • cluster — skupina upstreamů s parametry vyvažování
  • endpoint — adresa instance upstreamu

Každou z těchto entit plus některé další lze vyplnit dynamicky, k tomu je v konfiguraci uvedena adresa služby, odkud bude konfigurace získána. Služba může být REST nebo gRPC, preferuje se použití gRPC.

Služby se nazývají podle následujícího: LDS, VHDS, RDS, CDS a EDS. Lze kombinovat statickou a dynamickou konfiguraci, s omezením, že dynamický zdroj nelze uvést ve statickém.

Pro většinu úkolů stačí implementovat poslední tři služby, nazývají se ADS (Aggregated Discovery Service), pro java a go má připravenou implementaci gRPC dataplane, ve které je potřeba pouze vyplnit objekty z vlastního zdroje.

Konfigurace nabývá následující podoby:

envoy.yaml dynamická konfigurace

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

Při spuštění envoy s touto konfigurací se připojí k control-plane a pokusí se požádat o konfiguraci RDS, CDS a EDS. Jak probíhá proces interakce je popsáno zde.

Pokud stručně, envoy odešle požadavek s uvedením typu požadovaného zdroje, verzí a parametry uzlu. V odpověď dostane zdroj a verzi, pokud se na control-plane verze nezměnila, neodpovídá.
Existují 4 varianty interakce:

  • Jeden gRPC stream pro všechny typy zdrojů, zasílá se úplný stav zdroje.
  • Oddělené streamy, plný stav.
  • Jeden stream, inkrementální stav.
  • Oddělené streamy, inkrementální stav.

Inkrementální xDS umožňuje snížit provoz mezi kontrolní rovinou a envoy, což je relevantní pro velké konfigurace. Ale ztěžuje interakci, v žádosti se předává seznam zdrojů pro odhlášení a přihlášení.

V našem příkladu používáme ADS — jeden stream pro RDS, CDS, EDS a neinkrementální režim. Pro zapnutí inkrementálního režimu je třeba uvést api_type: DELTA_GRPC

Protože v žádosti jsou parametry uzlu, můžeme na kontrolní rovině posílat různé zdroje pro různé instance envoy, což usnadňuje budování service mesh.

Warmup

Na envoy při spuštění nebo při získávání nové konfigurace od kontrolní roviny se spouští proces warmup zdrojů. Je rozdělen na warmup listenere a warmup clusteru. První se spouští při změnách v RDS/LDS, druhý při CDS/EDS. To znamená, že pokud se mění pouze upstreamy, listener se nepřetváří.

Během procesu warmup se očekávají závislé zdroje od kontrolní roviny během časového limitu. Pokud časový limit vypršel, inicializace nebude úspěšná, nový listener nezačne naslouchat portu.
Pořadí inicializace: EDS, CDS, aktivní health check, RDS, LDS. Při zapnutých aktivních health checkech bude provoz směřovat na upstream až po jednom úspěšném health checku.

Pokud byl listener znovu vytvořen, starý přechází do stavu DRAIN a bude odstraněn po uzavření všech spojení nebo po uplynutí časového limitu --drain-time-s, ve výchozím nastavení 10 minut.

Pokračování následuje.

Zdroj: habr.com

Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery 🔥 Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery | ProHoster