Salve! Questo è un breve articolo che risponde a domande come: "che cos'è envoy?", "a cosa serve?" e "da dove iniziare?".
Che cos'è
Envoy è un bilanciatore L4-L7 scritto in C++, progettato per alte prestazioni e disponibilità. Da un lato, è in qualche modo simile a nginx e haproxy, comparabile con loro in termini di prestazioni. Dall'altro, è maggiormente orientato all'architettura a microservizi e offre funzionalità pari a quelle dei bilanciatori in java e go, come zuul o traefik.
Tabella di confronto haproxy/nginx/envoy, non pretende di essere la verità assoluta, ma fornisce una visione generale.
nginx
haproxy
envoy
traefik
stelle su github
11.2k/mirror
1.1k/mirror
12.4k
27.6k
scritto in
C
C
C++
go
API
no
socket only/push
dataplane/pull
pull
verifica della salute attiva
no
sì
sì
sì
Open tracing
plugin esterno
no
sì
sì
JWT
plugin esterno
no
sì
no
Estensione
Lua/C
Lua/C
Lua/C++
no
Perché
Questo è un progetto giovane, mancano molte funzionalità e alcune sono ancora in fase alpha. Ma envoy, anche per via della sua giovane età, sta evolvendo rapidamente e già ora ha molte interessanti caratteristiche: configurazione dinamica, numerosi filtri già pronti, e un'interfaccia semplice per scrivere i propri filtri.
Da questo derivano i campi di applicazione, ma per iniziare ci sono due anti-pattern:
- Consegna di statico.
Il fatto è che attualmente envoy non supporta la cache. I ragazzi di google stanno cercando di . L'idea è quella di implementare una volta sola tutte le complessità (zoo di intestazioni) di conformità agli RFC, e per le implementazioni specifiche di creare un'interfaccia. Ma per ora, è persino non in alpha, l'architettura è in discussione, envoy è aperto (mentre scrivevo l'articolo, hanno fuso una PR, ma questo punto è ancora attuale). Nel frattempo, utilizza nginx per il statico.
Configurazione statica.
- Può essere usata, ma
non è stata creata per questo. Le capacità nella configurazione statica non verranno svelate. Ci sono molti aspetti: envoy Modificando la configurazione in yaml, commetterai errori, maledirai gli sviluppatori per la verbosità e penserai che le configurazioni di nginx/haproxy, anche se meno strutturate, siano più concise. Questo è il punto. La configurazione di Nginx e Haproxy è stata progettata per essere modificata a mano, mentre
è stato creato per la generazione dal codice. L'intera configurazione è descritta in envoy protobuf Scenari canary, b/g deployment e molto altro si realizzano normalmente solo nella configurazione dinamica. Non dico che non si possa fare nella statica, lo facciamo tutti. Ma per questo è necessario ricorrere a vari espedienti, in qualsiasi bilanciatore,
incluso. envoy incluso.
Compiti in cui Envoy è indispensabile:
- Bilanciamento del traffico in sistemi complessi e dinamici. Qui rientra il service mesh, ma non è necessariamente solo questo.
- La necessità di funzionalità di tracciamento distribuito, complessa autorizzazione o altro che è presente in envoy out of the box o facilmente realizzabile, mentre in nginx/haproxy è necessario ricorrere a lua e a plugin discutibili.
Entrambi sono necessari per garantire alte prestazioni.
Come funziona
Envoy è distribuito nei binari solo come immagine docker. Nell'immagine c'è già un esempio di configurazione statica. Ma ci interessa solo per comprendere la struttura.
envoy.yaml configurazione statica
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
# Commenta la seguente riga per testare su reti 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.comConfigurazione dinamica
Quale problema stiamo cercando di risolvere? Non è possibile semplicemente ricaricare la configurazione del bilanciatore sotto carico, si verificheranno "piccole" problematiche:
- Validazione della configurazione.
Il configurazione può essere grande, può essere molto grande, se la carichiamo tutta in una volta, le probabilità che ci sia un errore da qualche parte aumentano.
- Connessioni di lunga durata.
Durante l'inizializzazione di un nuovo listener, è necessario occuparsi delle connessioni che funzionano sul vecchio, se i cambiamenti avvengono spesso e ci sono connessioni di lunga durata, sarà necessario trovare un compromesso. Ciao, ingress kubernetes su nginx.
- Health check attivi.
Se abbiamo health check attivi, dovremmo controllarli tutti sulla nuova configurazione prima di inviare il traffico. Se ci sono molti upstream, richiede tempo. Ciao, haproxy.
Come viene risolto in envoy, caricando la configurazione in modo dinamico, attraverso un pool di modelli, è possibile suddividerla in parti separate e non re-inizializzare quella parte che non è cambiata. Ad esempio, il listener, che è costoso da reinizializzare, cambia raramente.
Configurazione envoy (dal file sopra) ha le seguenti entità:
- listener — listener appeso a un determinato ip/porta
- virtual host — host virtuale per nome di dominio
- route — regola di bilanciamento
- cluster — gruppo di upstream con parametri di bilanciamento
- endpoint — indirizzo dell'istanza upstream
Ognuna di queste entità, più alcune altre, può essere riempita dinamicamente; a tal fine, nella configurazione viene specificato l'indirizzo del servizio da cui verrà ottenuta la configurazione. Il servizio può essere REST oppure gRPC, è preferibile utilizzare gRPC.
I servizi sono chiamati rispettivamente: LDS, VHDS, RDS, CDS e EDS. È possibile combinare configurazioni statiche e dinamiche, con la limitazione che una risorsa dinamica non può essere indicata in una configurazione statica.
Per la maggior parte dei compiti, è sufficiente implementare gli ultimi tre servizi; sono chiamati ADS (Aggregated Discovery Service), per e go ha un'implementazione gRPC dataplane pronta in cui è sufficiente riempire solo gli oggetti dalla propria sorgente.
La configurazione assume il seguente aspetto:
envoy.yaml configurazione dinamica
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: 6565Quando viene avviato envoy con questa configurazione, si connetterà al control-plane e cercherà di richiedere la configurazione RDS, CDS e EDS. Come avviene il processo di interazione è descritto .
In breve, envoy invia una richiesta, specificando il tipo di risorsa richiesta, la versione e i parametri della nodo. In risposta riceve la risorsa e la versione; se sul control-plane la versione non è cambiata, non risponde.
Ci sono 4 opzioni di interazione:
- Un flusso gRPC per tutti i tipi di risorse, viene inviato lo stato completo della risorsa.
- Flussi separati, stato completo.
- Un flusso, stato incrementale.
- Flussi separati, stato incrementale.
Incremental xDS consente di ridurre il traffico tra il control-plane e envoy, questo è rilevante per grandi configurazioni. Tuttavia, complica l'interazione, viene passato un elenco di risorse per la disiscrizione e l'iscrizione nella richiesta.
Nel nostro esempio viene utilizzato ADS — un flusso per RDS, CDS, EDS e modalità non incrementale. Per attivare la modalità incrementale, è necessario specificare api_type: DELTA_GRPC
Poiché nella richiesta ci sono parametri del nodo, possiamo inviare risorse diverse al control-plane per istanze diverse envoy, questo è comodo per costruire una rete di servizi.
Warmup
A envoy all'avvio o quando si riceve una nuova configurazione dal control-plane, viene avviato il processo di warmup delle risorse. È diviso in warmup degli listener e warmup dei cluster. Il primo si attiva quando ci sono cambiamenti in RDS/LDS, il secondo in CDS/EDS. Questo significa che se cambiano solo gli upstream, l'ascoltatore non viene ricreato.
Nel processo di riscaldamento, si attendono risorse dipendenti dal control-plane per un timeout. Se il timeout scade, l'inizializzazione non sarà riuscita, il nuovo ascoltatore non inizierà a monitorare la porta.
Ordine di inizializzazione: EDS, CDS, controllo attivo della salute, RDS, LDS. Con i controlli attivi della salute abilitati, il traffico andrà verso l'upstream solo dopo un controllo di salute riuscito.
Se l'ascoltatore è stato ricreato, il precedente passa allo stato DRAIN e sarà rimosso dopo la chiusura di tutte le connessioni o al termine del timeout --drain-time-s, di default 10 minuti.
Continua.
Fonte: habr.com
