Migrazione da Nginx a Envoy Proxy

Ciao, Habr! Ti propongo la traduzione di un post: Migrazione da Nginx a Envoy Proxy.

Envoy è un server proxy distribuito ad alte prestazioni (scritto in C++), progettato per singoli servizi e applicazioni; è anche un bus di comunicazione e un "universal data plane", sviluppato per grandi architetture microservizi chiamate "service mesh". Durante la sua creazione sono state considerate le soluzioni ai problemi che si erano presentati nello sviluppo di server come NGINX, HAProxy, bilanciatori di carico hardware e bilanciatori di carico cloud. Envoy funziona con ogni applicazione ed astrae la rete, fornendo funzionalità comuni indipendentemente dalla piattaforma. Quando tutto il traffico di servizio nell'infrastruttura passa attraverso la rete Envoy, diventa facile visualizzare le aree problematiche attraverso un'osservabilità coerente, ottimizzando le performance generali e aggiungendo funzioni chiave in punti specifici.

Funzionalità

  • Architettura fuori processo: envoy è un server autonomo ad alte prestazioni che consuma poca memoria. Funziona con qualsiasi linguaggio di applicazione o framework.
  • Supporto per http/2 e grpc: envoy ha un supporto di prim'ordine per http/2 e grpc per le connessioni in entrata e in uscita. È un proxy trasparente da http/1.1 a http/2.
  • Bilanciamento del carico avanzato: envoy supporta funzioni avanzate di bilanciamento del carico, inclusi retry automatici, circuit breaking, limitazione della velocità globale, shadowing delle richieste, bilanciamento del carico locale e altro.
  • API per la gestione della configurazione: envoy fornisce una robusta API per la gestione dinamica della propria configurazione.
  • Osservabilità: osservabilità approfondita del traffico L7, supporto integrato per il tracing distribuito e osservabilità per mongodb, dynamodb e molte altre applicazioni.

Passo 1 - Esempio di configurazione NGINX

In questo scenario viene utilizzato un file creato appositamente nginx.conf, basato su un esempio completo da NGINX Wiki. Puoi visualizzare la configurazione nell'editor, aprendo nginx.conf

Configurazione originale nginx

user  www www;
pid /var/run/nginx.pid;
worker_processes  2;

events {
  worker_connections   2000;
}

http {
  gzip on;
  gzip_min_length  1100;
  gzip_buffers     4 8k;
  gzip_types       text/plain;

  log_format main      '$remote_addr - $remote_user [$time_local]  '
    '"$request" $status $bytes_sent '
    '"$http_referer" "$http_user_agent" '
    '"$gzip_ratio"';

  log_format download  '$remote_addr - $remote_user [$time_local]  '
    '"$request" $status $bytes_sent '
    '"$http_referer" "$http_user_agent" '
    '"$http_range" "$sent_http_content_range"';

  upstream targetCluster {
    172.18.0.3:80;
    172.18.0.4:80;
  }

  server {
    listen        8080;
    server_name   one.example.com  www.one.example.com;

    access_log   /var/log/nginx.access_log  main;
    error_log  /var/log/nginx.error_log  info;

    location / {
      proxy_pass         http://targetCluster/;
      proxy_redirect     off;

      proxy_set_header   Host             $host;
      proxy_set_header   X-Real-IP        $remote_addr;
    }
  }
}

Le configurazioni di NGINX di solito includono tre elementi chiave:

  1. La configurazione del server NGINX, la struttura dei log e la funzionalità di Gzip. Questo è definito a livello globale in tutti i casi.
  2. Configurazione di NGINX per ricevere richieste all'host one.example.com sulla porta 8080.
  3. Configurazione della destinazione, come gestire il traffico per diverse parti dell'URL.

Non tutta la configurazione sarà applicata al Proxy Envoy, e non è necessario configurare alcuni parametri. Il Proxy Envoy ha quattro tipi chiave, che supportano l'infrastruttura di base fornita da NGINX. Il nucleo è:

  • Ascoltatori: Definiscono come il Proxy Envoy accetta le richieste in ingresso. Attualmente, il Proxy Envoy supporta solo ascoltatori basati su TCP. Una volta stabilita la connessione, viene inviato a una serie di filtri per l'elaborazione.
  • Filtri: Fanno parte dell'architettura a pipeline, che può elaborare dati in ingresso e in uscita. Questa funzionalità include filtri come Gzip, che comprime i dati prima di inviarli al cliente.
  • Router: Reindirizzano il traffico alla destinazione richiesta, definita come cluster.
  • Cluster: Definiscono il punto finale per il traffico e i parametri di configurazione.

Utilizzeremo questi quattro componenti per creare una configurazione del Proxy Envoy in modo da rispettare una configurazione specifica di NGINX. L'obiettivo di Envoy è lavorare con API e configurazione dinamica. In questo caso, la configurazione di base utilizzerà parametri statici, fissi estratti da NGINX.

Passaggio 2 — Configurazione NGINX

Prima parte nginx.conf definisce alcuni componenti interni di NGINX che devono essere configurati.

Worker Connections (Collegamenti di lavoro)

La configurazione riportata di seguito definisce il numero di processi lavorativi e connessioni. Questo indica come NGINX si scalerà per soddisfare la domanda.

worker_processes  2;

events {
  worker_connections   2000;
}

Envoy Proxy gestisce in modo diverso i processi lavorativi e le connessioni.

Envoy crea un processo lavorativo per ogni thread hardware nel sistema. Ogni processo lavorativo esegue un ciclo di eventi non bloccante, responsabile di

  1. Ascoltare ogni listener
  2. Accettare nuove connessioni
  3. Creare un insieme di filtri per la connessione
  4. Gestire tutte le operazioni di input/output nel tempo di vita della connessione.

Tutta la successiva gestione della connessione viene completamente eseguita nel processo lavorativo, inclusi eventuali comportamenti di reindirizzamento.

Per ogni processo lavorativo in Envoy esiste una connessione nel pool. Pertanto, i pool di connessioni HTTP/2 stabiliscono solo una connessione per ogni host esterno alla volta, quindi con quattro processi lavorativi ci saranno quattro connessioni HTTP/2 per ogni host esterno in uno stato stabile. Mantenendo tutto in un solo processo lavorativo, quasi tutto il codice può essere scritto senza blocchi, come se fosse multithread. Se vengono allocati più processi lavorativi del necessario, ciò può portare a un uso inefficiente della memoria, alla creazione di un gran numero di connessioni inattive e a una diminuzione del numero di ritorni delle connessioni nel pool.

Per ulteriori informazioni visita Envoy Proxy blog.

Configurazione HTTP

Il blocco di configurazione NGINX seguente definisce le impostazioni HTTP, come:

  • Quali tipi di mime sono supportati
  • Timeout predefiniti
  • Configurazione Gzip

Puoi configurare questi aspetti tramite filtri in Envoy Proxy, di cui parleremo più avanti.

Passaggio 3 — Configurazione Server

Nel blocco di configurazione HTTP, la configurazione NGINX indica di ascoltare sulla porta 8080 e di rispondere alle richieste in entrata per i domini one.example.com e www.one.example.com.

 server {
    listen        8080;
    server_name   one.example.com  www.one.example.com;

All'interno di Envoy, ciò è gestito dai Listener.

Listener di Envoy

L'aspetto più importante per iniziare a lavorare con Envoy Proxy è definire i listener. È necessario creare un file di configurazione che descriva come si desidera avviare un'istanza di Envoy.

Il frammento sottostante creerà un nuovo listener e lo collegherà alla porta 8080. La configurazione indica all'Envoy Proxy a quali porte deve essere collegato per le richieste in entrata.

L'Envoy Proxy utilizza la notazione YAML per la sua configurazione. Per familiarizzare con questa notazione, guarda qui il link.

Copy to Editorstatic_resources:
  listeners:
  - name: listener_0
    address:
      socket_address: { address: 0.0.0.0, port_value: 8080 }

Non è necessario definire server_name, poiché i filtri dell'Envoy Proxy si occupano di questo.

Passo 4 — Configurazione della posizione

Quando una richiesta arriva a NGINX, il blocco di posizione definisce come elaborare e dove indirizzare il traffico. Nel frammento seguente, tutto il traffico verso il sito viene inviato a un cluster upstream (nota del traduttore: upstream è solitamente un server applicativo) chiamato targetCluster. Il cluster upstream definisce i nodi che devono elaborare la richiesta. Ne discuteremo nel passo successivo.

location / {
    proxy_pass         http://targetCluster/;
    proxy_redirect     off;

    proxy_set_header   Host             $host;
    proxy_set_header   X-Real-IP        $remote_addr;
}

In Envoy si occupa di questo Filters.

Filtri Envoy

Per la configurazione statica, i filtri definiscono come elaborare le richieste in ingresso. In questo caso, impostiamo i filtri che corrispondono a server_names nel passo precedente. Quando arrivano richieste in ingresso che corrispondono a determinati domini e percorsi, il traffico viene indirizzato al cluster. Questo è equivalente alla configurazione upstream di NGINX.

Copy to Editor    filter_chains:
    - filters:
      - name: envoy.http_connection_manager
        config:
          codec_type: auto
          stat_prefix: ingress_http
          route_config:
            name: local_route
            virtual_hosts:
            - name: backend
              domains:
                - "one.example.com"
                - "www.one.example.com"
              routes:
              - match:
                  prefix: "\/"
                route:
                  cluster: targetCluster
          http_filters:
          - name: envoy.router

Nome envoy.http_connection_manager è un filtro incorporato nell'Envoy Proxy. Altri filtri comprendono Redis, Mongo, TCP. Puoi trovare un elenco completo in documentazione.

Per ulteriori informazioni su altre politiche di bilanciamento del carico, visita Documentazione Envoy.

Passo 5 — Configurazione Proxy e Upstream

In NGINX, la configurazione upstream definisce un insieme di server di destinazione che gestiranno il traffico. In questo caso, sono stati assegnati due cluster.

  upstream targetCluster {
    172.18.0.3:80;
    172.18.0.4:80;
  }

In Envoy, questo è gestito dai cluster.

Cluster Envoy

L'equivalente upstream è definito come cluster. In questo caso, sono stati identificati gli host che gestiranno il traffico. Il modo di accesso agli host, come ad esempio il timeout, è definito come configurazione del cluster. Questo consente di controllare con maggiore precisione la granularità di aspetti come il tempo di attesa e il bilanciamento del carico.

Copia negli editor clusters:
  - name: targetCluster
    connect_timeout: 0.25s
    type: STRICT_DNS
    dns_lookup_family: V4_ONLY
    lb_policy: ROUND_ROBIN
    hosts: [
      { socket_address: { address: 172.18.0.3, port_value: 80 }},
      { socket_address: { address: 172.18.0.4, port_value: 80 }}
    ]

Quando si utilizza la rilevazione dei servizi STRICT_DNS Envoy risolverà continuamente e in modo asincrono le destinazioni DNS specificate. Ogni indirizzo IP restituito come risultato della risoluzione DNS sarà considerato un host esplicito nel cluster upstream. Ciò significa che se una richiesta restituisce due indirizzi IP, Envoy presuppone che nel cluster ci siano due host e entrambi devono essere bilanciati. Se un host viene rimosso dal risultato, Envoy presuppone che non esista più e inizierà a prelevare traffico da eventuali pool di connessioni esistenti.

Per ulteriori informazioni, vedere la documentazione del proxy Envoy.

Passaggio 6 – Accesso ai log e agli errori

La configurazione finale è la registrazione. Invece di inviare i log degli errori su disco, Envoy Proxy utilizza un approccio cloud. Tutti i log delle applicazioni vengono scritti in stdout e stderr.

Quando gli utenti effettueranno una richiesta, i log degli accessi sono facoltativi e disattivati per impostazione predefinita. Per abilitare i log degli accessi per le richieste HTTP, attivare la configurazione access_log per il gestore delle connessioni HTTP. Il percorso può essere un dispositivo, come stdout, oppure un file su disco, a seconda delle tue esigenze.

La seguente configurazione reindirizzerà tutti i log degli accessi in stdout (nota del traduttore: stdout è necessario per utilizzare envoy all'interno di docker. Se utilizzato senza docker, sostituire /dev/stdout con il percorso di un normale file di log). Copia il frammento nella sezione di configurazione per il gestore delle connessioni:

Copia negli appuntiaccess_log:
- name: envoy.file_access_log
  config:
    path: "/dev/stdout"

I risultati dovrebbero apparire così:

      - name: envoy.http_connection_manager
        config:
          codec_type: auto
          stat_prefix: ingress_http
          access_log:
          - name: envoy.file_access_log
            config:
              path: "/dev/stdout"
          route_config:

Per impostazione predefinita, Envoy ha una stringa di formato che include i dettagli della richiesta HTTP:

[%START_TIME%] "%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%" %RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT% %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% "%REQ(X-FORWARDED-FOR)%" "%REQ(USER-AGENT)%" "%REQ(X-REQUEST-ID)%" "%REQ(:AUTHORITY)%" "%UPSTREAM_HOST%"n

Il risultato di questa stringa di formato:

[2018-11-23T04:51:00.281Z] "GET / HTTP/1.1" 200 - 0 58 4 1 "-" "curl/7.47.0" "f21ebd42-6770-4aa5-88d4-e56118165a7d" "one.example.com" "172.18.0.4:80"

Il contenuto dell'output può essere configurato impostando il campo di formato. Ad esempio:

access_log:
- name: envoy.file_access_log
  config:
    path: "/dev/stdout"
    format: "[%START_TIME%] "%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%" %RESPONSE_CODE% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% "%REQ(X-REQUEST-ID)%" "%REQ(:AUTHORITY)%" "%UPSTREAM_HOST%"n"

La stringa del registro può anche essere emessa in formato JSON impostando il campo json_format. Ad esempio:

access_log:
- name: envoy.file_access_log
  config:
    path: "/dev/stdout"
    json_format: {"protocol": "%PROTOCOL%", "duration": "%DURATION%", "request_method": "%REQ(:METHOD)%"}

Per ulteriori informazioni sulla metodologia di registrazione di Envoy, visita

https://www.envoyproxy.io/docs/envoy/latest/configuration/access_log#config-access-log-format-dictionaries

La registrazione non è l'unico modo per ottenere una visione del funzionamento di Envoy Proxy. Sono integrate funzionalità avanzate di tracciamento e metriche. Puoi saperne di più nella documentazione sul tracciamento o tramite Scenari di tracciamento interattivo.

Passaggio 7 — Avvio

Hai ora tradotto la configurazione da NGINX a Envoy Proxy. L'ultimo passaggio è avviare un'istanza di Envoy Proxy per testarla.

Avvio come utente

Nella parte superiore della configurazione di NGINX, la riga user www www; indica di avviare NGINX come utente a basso livello di privilegio per aumentare la sicurezza.

Envoy Proxy utilizza un approccio cloud per gestire chi è il proprietario del processo. Quando avviamo Envoy Proxy tramite un contenitore, possiamo specificare un utente a basso livello di privilegio.

Avvio di Envoy Proxy

Il comando qui sotto avvierà Envoy Proxy tramite un contenitore Docker sull'host. Questo comando consente a Envoy di ascoltare le richieste in entrata sulla porta 80. Tuttavia, come indicato nella configurazione del listener, Envoy Proxy ascolta il traffico in entrata sulla porta 8080. Questo consente al processo di essere eseguito come utente a basso privilegio.

docker run --name proxy1 -p 80:8080 --user 1000:1000 -v /root/envoy.yaml:/etc/envoy/envoy.yaml envoyproxy/envoy

Test

Con il proxy in esecuzione, ora possono essere eseguiti e gestiti dei test. Il seguente comando cURL emette una richiesta con l'intestazione host definita nella configurazione del proxy.

curl -H "Host: one.example.com" localhost -i

La richiesta HTTP genererà un errore 503Questo è dovuto al fatto che le connessioni in uscita non funzionano e non sono disponibili. Pertanto, Envoy Proxy non ha destinatari disponibili per la richiesta. Il comando seguente avvierà una serie di servizi HTTP che corrispondono alla configurazione definita per Envoy.

docker run -d katacoda/docker-http-server; docker run -d katacoda/docker-http-server;

Con i servizi disponibili, Envoy può inoltrare correttamente il traffico alla destinazione.

curl -H "Host: one.example.com" localhost -i

Dovresti vedere una risposta che indica quale container Docker ha elaborato la richiesta. Nei registri di Envoy Proxy dovresti anche vedere la stringa di accesso emessa.

Intestazioni aggiuntive della risposta HTTP

Nelle intestazioni della risposta della richiesta valida vedrai intestazioni HTTP aggiuntive. Nell'intestazione viene mostrato il tempo impiegato dall'host upstream per elaborare la richiesta. È espresso in millisecondi. Questo è utile se il cliente desidera determinare il tempo di servizio rispetto alla latenza di rete.

x-envoy-upstream-service-time: 0
server: envoy

Configurazione finale

static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address: { address: 0.0.0.0, port_value: 8080 }
    filter_chains:
    - filters:
      - name: envoy.http_connection_manager
        config:
          codec_type: auto
          stat_prefix: ingress_http
          route_config:
            name: local_route
            virtual_hosts:
            - name: backend
              domains:
                - "one.example.com"
                - "www.one.example.com"
              routes:
              - match:
                  prefix: "\/"
                route:
                  cluster: targetCluster
          http_filters:
          - name: envoy.router
          clusters:
  - name: targetCluster
    connect_timeout: 0.25s
    type: STRICT_DNS
    dns_lookup_family: V4_ONLY
    lb_policy: ROUND_ROBIN
    hosts: [
      { socket_address: { address: 172.18.0.3, port_value: 80 }},
      { socket_address: { address: 172.18.0.4, port_value: 80 }}
    ]

admin:
  access_log_path: \/tmp\/admin_access.log
  address:
    socket_address: { address: 0.0.0.0, port_value: 9090 }

Informazioni aggiuntive dal traduttore

Puoi trovare le istruzioni per l'installazione di Envoy Proxy sul sito https://www.getenvoy.io/

Per impostazione predefinita, nel pacchetto rpm manca la configurazione del servizio systemd.

Aggiungi la configurazione del servizio systemd /etc/systemd/system/envoy.service:

[Unit]
Description=Envoy Proxy
Documentation=https://www.envoyproxy.io/
After=network-online.target
Requires=envoy-auth-server.service
Wants=nginx.service

[Service]
User=root
Restart=on-failure
ExecStart=\/usr\/bin\/envoy --config-path \/etc\/envoy\/config.yaml
[Install]
WantedBy=multi-user.target

Devi creare la directory \/etc\/envoy\/ e posizionarvi il file di configurazione config.yaml.

Esiste un gruppo Telegram per envoy proxy: https://t.me/envoyproxy_ru

Envoy Proxy non supporta la distribuzione di contenuti statici. Quindi, chi può, per favore voti per la funzionalità: https://github.com/envoyproxy/envoy/issues/378

Solo gli utenti registrati possono partecipare al sondaggio. Accedi, per favore.

Questo post ti ha spinto a installare e testare envoy proxy?

  • no

Hanno votato 75 utenti. Si sono astenuti 18 utenti.

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster