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ží . 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, 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 , 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.comDynamická 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 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: 6565Př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 .
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
