Saluti! Questo è un breve articolo che risponde alle domande: “cos’è Envoy?”, “perché è necessario?” e "da dove cominciare?".
Cos'è questo?
Envoy è un bilanciatore L4-L7 scritto in C++, focalizzato su prestazioni elevate e disponibilità. Da un lato, questo è in qualche modo un analogo di nginx e haproxy, paragonabili a loro in termini di prestazioni. D'altra parte, è più orientato all'architettura dei microservizi e ha funzionalità non peggiori dei bilanciatori Java e Go, come zuul o traefik.
Tabella comparativa di haproxy/nginx/envoy, non pretende di essere la verità assoluta, ma fornisce un quadro generale.
nginx
aproxy
inviato
traefik
stelle su github
11.2k/specchio
1.1k/specchio
12.4k
27.6k
scritto in
C
C
C++
go
API
no
solo presa/push
dataplane/tirare
tirare
controllo sanitario attivo
no
sì
sì
sì
Tracciamento aperto
plug-in esterno
no
sì
sì
J.W.T.
plug-in esterno
no
sì
no
estensione
Lua/C
Lua/C
Lua/C++
no
Per cosa?
Questo è un progetto giovane, mancano molte cose, alcune nella prima fase alfa. Ma inviato, anche per la sua giovinezza, si sta sviluppando rapidamente e dispone già di molte funzionalità interessanti: configurazione dinamica, tanti filtri già pronti, un'interfaccia semplice per scrivere i propri filtri.
Da ciò conseguono ambiti di applicazione, ma prima ci sono 2 antipattern:
- Rinculo statico.
Il fatto è che in questo momento inviato nessun supporto per la memorizzazione nella cache. I ragazzi di Google ci stanno provando
Per ora, usa nginx per le statistiche.
- Configurazione statica.
Puoi usarlo, ma inviato Non è per questo che è stato creato. Le funzionalità in una configurazione statica non verranno esposte. Ci sono molti momenti:
Quando modifichi la configurazione in yaml, ti sbaglierai, rimprovererai gli sviluppatori per la verbosità e penserai che le configurazioni nginx/haproxy, sebbene meno strutturate, siano più concise. Questo è il punto. La configurazione di Nginx e Haproxy è stata creata per la modifica manuale e inviato per la generazione dal codice. L'intera configurazione è descritta in
Gli scenari di distribuzione Canary, b/g e molto altro sono normalmente implementati solo in una configurazione dinamica. Non sto dicendo che questo non si possa fare staticamente, lo facciamo tutti. Ma per questo è necessario indossare le stampelle, in uno qualsiasi dei bilanciatori, dentro inviato compresi.
Compiti per i quali Envoy è indispensabile:
- Bilanciamento del traffico in sistemi complessi e dinamici. Ciò include la rete di servizi, ma non è necessariamente l'unica.
- La necessità di funzionalità di tracciamento distribuito, autorizzazione complessa o altre funzionalità disponibili in inviato pronto all'uso o opportunamente implementato, ma in nginx/haproxy devi essere circondato da lua e plugin dubbi.
Entrambi, se necessario, garantiscono prestazioni elevate.
Come funziona
Envoy è distribuito in file binari solo come immagine docker. L'immagine contiene già un esempio di configurazione statica. Ma a noi interessa solo per comprenderne la struttura.
configurazione statica 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
# Comment out the following line to test on v6 networks
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
Configurazione dinamica
A quale problema stiamo cercando una soluzione? Non puoi semplicemente ricaricare la configurazione del bilanciatore sotto carico; sorgeranno "piccoli" problemi:
- Convalida della configurazione.
La configurazione può essere grande, può essere molto grande, se la sovraccarichiamo tutta in una volta, aumentano le possibilità che si verifichi un errore da qualche parte.
- Connessioni di lunga durata.
Quando inizializzi un nuovo ascoltatore, devi prenderti cura delle connessioni in esecuzione su quello vecchio; se i cambiamenti si verificano frequentemente e ci sono connessioni di lunga durata, dovrai cercare un compromesso. Ciao, ingresso Kubernetes su nginx.
- Controlli sanitari attivi.
Se abbiamo controlli di integrità attivi, dobbiamo ricontrollarli tutti nella nuova configurazione prima di inviare traffico. Se ci sono molti upstream, questo richiede tempo. Ciao aproxy.
Come si risolve questo problema? inviatoCaricando la configurazione dinamicamente, in base al modello della piscina, è possibile dividerla in parti separate e non reinizializzare la parte che non è cambiata. Ad esempio, un ascoltatore, che è costoso da reinizializzare e cambia raramente.
Configurazione inviato (dal file sopra) ha le seguenti entità:
- ascoltatore — ascoltatore bloccato su un IP/porta specifico
- host virtuale - host virtuale per nome di dominio
- route - regola di bilanciamento
- gruppo — un gruppo di upstream con parametri di bilanciamento
- endpoint — indirizzo dell'istanza upstream
Ognuna di queste entità più alcune altre possono essere compilate dinamicamente; per questo, la configurazione specifica l'indirizzo del servizio da cui verrà ricevuta la configurazione. Il servizio può essere REST o gRPC, è preferibile gRPC.
I servizi sono denominati rispettivamente: LDS, VHDS, RDS, CDS ed EDS. È possibile combinare la configurazione statica e dinamica, con la limitazione che una risorsa dinamica non può essere specificata in una risorsa statica.
Per la maggior parte dei compiti è sufficiente implementare gli ultimi tre servizi, chiamati ADS (Aggregate Discovery Service), per
La configurazione assume la seguente forma:
configurazione dinamica 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
Quando si esegue inviato con questa configurazione, si connetterà al piano di controllo e proverà a richiedere la configurazione RDS, CDS ed EDS. Viene descritto come avviene il processo di interazione
In breve, inviato invia una richiesta indicando il tipo di risorsa richiesta, la versione e i parametri del nodo. In risposta riceve una risorsa e una versione; se la versione sul piano di controllo non è cambiata, non risponde.
Sono disponibili 4 opzioni di interazione:
- Un flusso gRPC per tutti i tipi di risorse, viene inviato lo stato completo della risorsa.
- Flussi separati, condizioni complete.
- Un flusso, stato incrementale.
- Flussi separati, stato incrementale.
xDS incrementale consente di ridurre il traffico tra il piano di controllo e inviato, questo è rilevante per le configurazioni di grandi dimensioni. Ma complica l'interazione; la richiesta contiene un elenco di risorse per annullare l'iscrizione e iscriversi.
Il nostro esempio utilizza ADS: un flusso per RDS, CDS, EDS e modalità non incrementale. Per abilitare la modalità incrementale, è necessario specificare api_type: DELTA_GRPC
Poiché la richiesta contiene parametri del nodo, possiamo inviare risorse diverse al piano di controllo per istanze diverse inviato, questo è utile per creare una rete di servizi.
Riscaldamento
Su inviato all'avvio o quando si riceve una nuova configurazione dal piano di controllo, viene avviato il processo di riscaldamento delle risorse. È diviso in riscaldamento del listener e riscaldamento del cluster. Il primo viene lanciato quando ci sono cambiamenti in RDS/LDS, il secondo quando CDS/EDS. Ciò significa che se cambiano solo gli upstream, il listener non viene ricreato.
Durante il processo di riscaldamento, sono previste risorse dipendenti dal piano di controllo durante il timeout. Se si verifica il timeout, l'inizializzazione non avrà esito positivo e il nuovo ascoltatore non inizierà ad ascoltare sulla porta.
Ordine di inizializzazione: EDS, CDS, controllo sanitario attivo, RDS, LDS. Con i controlli di integrità attivi abilitati, il traffico andrà a monte solo dopo un controllo di integrità riuscito.
Se il listener è stato ricreato, quello vecchio entra nello stato DRAIN e verrà eliminato dopo che tutte le connessioni saranno chiuse o allo scadere del timeout --drain-time-s
, predefinito 10 minuti.
Per essere continuato.
Fonte: habr.com