Migration von Nginx zu Envoy Proxy

Hallo, Habr! Ich präsentiere Ihnen die Übersetzung des Beitrags: Migration von Nginx zu Envoy Proxy.

Envoy ist ein leistungsstarker, verteilter Proxy-Server (in C++ geschrieben), der für einzelne Dienste und Anwendungen gedacht ist. Zudem fungiert er als Kommunikationsbus und „universelle Datenebene“, entwickelt für große mikroskopische Architekturen (Service Mesh). Bei seiner Erstellung wurden Lösungen für Probleme berücksichtigt, die bei der Entwicklung solcher Server wie NGINX, HAProxy, hardwaregestützter Lastenausgleich und Cloud-Lastenausgleich aufgetreten sind. Envoy arbeitet mit jeder Anwendung zusammen und abstrahiert das Netzwerk, um generische Funktionen unabhängig von der Plattform bereitzustellen. Wenn der gesamte Dienstverkehr in der Infrastruktur über das Envoy-Gitter läuft, wird es einfach, Problembereiche mit konsistenter Beobachtbarkeit zu visualisieren, die allgemeine Leistung einzustellen und grundlegende Funktionen an einem bestimmten Ort hinzuzufügen.

Funktionen

  • Prozessunabhängige Architektur: Envoy ist ein autonomer, leistungsstarker Server, der wenig Arbeitsspeicher benötigt. Er arbeitet mit jeder Programmiersprache oder jedem Framework zusammen.
  • Unterstützung von HTTP/2 und gRPC: Envoy bietet erstklassige Unterstützung für HTTP/2 und gRPC für eingehende und ausgehende Verbindungen. Es handelt sich um einen transparenten Proxy von HTTP/1.1 zu HTTP/2.
  • Erweiterte Lastenverteilung: Envoy unterstützt erweiterte Funktionen der Lastenverteilung, einschließlich automatischer Wiederholungen, Circuit Breaking, globale Geschwindigkeitsbegrenzung, Request Shadowing, lokale zonenspezifische Lastenverteilung usw.
  • API zur Verwaltung der Konfiguration: Envoy bietet eine zuverlässige API zur dynamischen Verwaltung seiner Konfiguration.
  • Beobachtbarkeit: Tiefe L7-Verkehrsüberwachung, integrierte Unterstützung für verteilte Nachverfolgung und Überwachung von MongoDB, DynamoDB und vielen anderen Anwendungen.

Schritt 1 — Beispielkonfiguration von NGINX

In diesem Szenario wird eine speziell erstellte Datei verwendet nginx.conf, die auf einem vollständigen Beispiel aus NGINX Wiki. Sie können die Konfiguration im Editor anzeigen, indem Sie nginx.conf

die ursprüngliche nginx-Konfiguration

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;
    }
  }
}

NGINX-Konfigurationen bestehen normalerweise aus drei Schlüsselelementen:

  1. Die Konfiguration des NGINX-Servers, die Protokollstruktur und die Gzip-Funktionalität. Dies wird global in allen Fällen definiert.
  2. Die NGINX-Konfiguration zum Empfangen von Anfragen an den Host one.example.com am Port 8080.
  3. Die Zielkonfiguration, wie der Verkehr für verschiedene Teile der URL verarbeitet wird.

Nicht alle Konfigurationen werden auf den Envoy-Proxy angewendet, und Sie müssen einige Parameter nicht konfigurieren. Der Envoy-Proxy hat vier Schlüsseltypen, die die grundlegende Infrastruktur unterstützen, die von NGINX angeboten wird. Der Kern besteht aus:

  • Listener: Sie definieren, wie der Envoy-Proxy eingehende Anfragen empfängt. Derzeit unterstützt der Envoy-Proxy nur TCP-basierte Listener. Sobald die Verbindung hergestellt ist, wird sie an eine Reihe von Filtern zur Verarbeitung weitergeleitet.
  • Filter: Diese sind Teil einer Pipeline-Architektur, die eingehende und ausgehende Daten verarbeiten kann. Diese Funktionalität umfasst Filter wie Gzip, das Daten komprimiert, bevor sie an den Client gesendet werden.
  • Router: Sie leiten den Verkehr an das erforderliche Ziel weiter, das als Cluster definiert ist.
  • Cluster: Sie definieren den Endpunkt für den Verkehr und die Konfigurationsparameter.

Wir werden diese vier Komponenten verwenden, um die Envoy-Proxy-Konfiguration zu erstellen, die einer bestimmten NGINX-Konfiguration entspricht. Das Ziel von Envoy ist die Arbeit mit APIs und dynamischer Konfiguration. In diesem Fall wird die grundlegende Konfiguration statische, festgelegte Parameter aus NGINX verwenden.

Schritt 2 - NGINX-Konfiguration

Erster Teil nginx.conf definiert einige interne Komponenten von NGINX, die konfiguriert werden müssen.

Worker Connections

Die folgende Konfiguration definiert die Anzahl der Arbeitsprozesse und Verbindungen. Dies gibt an, wie NGINX skalieren wird, um der Nachfrage gerecht zu werden.

worker_processes  2;

events {
  worker_connections   2000;
}

Envoy Proxy verwaltet Arbeitsprozesse und Verbindungen unterschiedlich.

Envoy erstellt einen Arbeits-Thread für jeden Hardware-Thread im System. Jeder Arbeits-Thread führt eine nicht blockierende Ereignisschleife aus, die verantwortlich ist für

  1. Das Abhören jedes Listeners
  2. Das Akzeptieren neuer Verbindungen
  3. Das Erstellen eines Satzes von Filtern für die Verbindung
  4. Die Verarbeitung aller Ein- und Ausgabeoperationen während der gesamten Dauer der Verbindung.

Die gesamte weitere Bearbeitung der Verbindung erfolgt vollständig im Arbeits-Thread, einschließlich jeglichen Umleitungsverhaltens.

Für jeden Arbeits-Thread in Envoy gibt es eine Verbindung im Pool. So stellen HTTP/2-Verbindungspools nur eine Verbindung für jeden externen Host gleichzeitig her, so dass bei vier Arbeits-Threads vier HTTP/2-Verbindungen für jeden externen Host im stabilen Zustand bestehen. Wenn alles in einem Arbeits-Thread gehalten wird, kann fast der gesamte Code ohne blockierende Elemente geschrieben werden, als wäre er ein einzelner Thread. Wenn mehr Arbeits-Threads zugewiesen werden, als notwendig sind, kann das zu einer ineffizienten Speichernutzung, der Schaffung von vielen im Leerlauf befindlichen Verbindungen und einer Verringerung der Rückführungen von Verbindungen in den Pool führen.

Für weitere Informationen besuchen Sie Envoy Proxy Blog.

HTTP-Konfiguration

Der folgende Block der NGINX-Konfiguration definiert HTTP-Einstellungen, wie:

  • Welche MIME-Typen unterstützt werden
  • Standard-Timeouts
  • Gzip-Konfiguration

Diese Aspekte können mit Filtern im Envoy Proxy konfiguriert werden, die wir später besprechen werden.

Schritt 3 – Serverkonfiguration

Im HTTP-Konfigurationsblock gibt die NGINX-Konfiguration an, den Port 8080 zu überwachen und auf eingehende Anfragen für die Domänen zu antworten. one.example.com und www.one.example.com.

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

Innerhalb von Envoy wird dies von den Listenern verwaltet.

Envoy-Listener

Der wichtigste Aspekt, um mit Envoy Proxy zu beginnen, ist die Definition der Listener. Sie müssen eine Konfigurationsdatei erstellen, die beschreibt, wie Sie Instanz von Envoy starten möchten.

Der nachstehende Abschnitt erstellt einen neuen Listener und verbindet ihn mit dem Port 8080. Die Konfiguration gibt an, an welchen Ports der Envoy Proxy für eingehende Anfragen gebunden sein soll.

Envoy Proxy verwendet YAML-Notation für seine Konfiguration. Um sich mit dieser Notation vertraut zu machen, schauen Sie hier vorbei. den Link.

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

Es ist nicht erforderlich, server_name, da die Filter von Envoy Proxy dies übernehmen.

Schritt 4 — Konfiguration des Standorts

Wenn eine Anfrage in NGINX eingeht, definiert der Standortblock, wie der Traffic verarbeitet und wohin er geleitet wird. Im folgenden Abschnitt wird der gesamte Traffic zur Website an das Upstream (Anmerkung des Übersetzers: Upstream sind in der Regel Anwendungserver) Cluster mit dem Namen targetCluster. Das Upstream-Cluster bestimmt die Knoten, die die Anfrage verarbeiten sollen. Wir werden dies im nächsten Schritt besprechen.

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

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

In Envoy erledigen das die Filter.

Envoy Filter

Für die statische Konfiguration bestimmen die Filter, wie eingehende Anfragen verarbeitet werden. In diesem Fall setzen wir Filter ein, die zu server_names aus dem vorherigen Schritt passen. Wenn eingehende Anfragen eintreffen, die bestimmten Domains und Routen entsprechen, wird der Traffic zum Cluster geleitet. Dies entspricht der Upstream-Konfiguration von 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

Name envoy.http_connection_manager ist ein integrierter Filter im Envoy Proxy. Weitere Filter sind Redis, Mongo, TCP. Eine vollständige Liste finden Sie in Dokumentation.

Für weitere Informationen zu anderen Lastverteilungspolitiken besuchen Sie die Envoy-Dokumentation.

Schritt 5 — Proxy- und Upstream-Konfiguration

In NGINX definiert die Upstream-Konfiguration eine Gruppe von Ziel-Servern, die den Traffic verarbeiten sollen. In diesem Fall wurden zwei Cluster zugewiesen.

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

In Envoy wird dies von Clustern verwaltet.

Envoy Cluster

Der Upstream-Eigenwert wird als Cluster definiert. In diesem Fall wurden Hosts bestimmt, die den Datenverkehr bedienen werden. Der Zugang zu den Hosts, wie z.B. die Wartezeit, wird als Clusterkonfiguration festgelegt. Dies ermöglicht eine genauere Kontrolle über die Granularität solcher Aspekte wie Wartezeit und Lastverteilung.

Copy to 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 }}
    ]

Bei Verwendung von Dienstentdeckung STRICT_DNS Envoy wird die angegebenen DNS-Ziele kontinuierlich und asynchron auflösen. Jede zurückgegebene IP-Adresse im Zuge der DNS-Anfrage wird als expliziter Host im Upstream-Cluster betrachtet. Das bedeutet, dass wenn die Anfrage zwei IP-Adressen zurückgibt, Envoy davon ausgeht, dass es zwei Hosts im Cluster gibt, die beide lastbalanciert werden sollten. Wird ein Host aus dem Ergebnis entfernt, geht Envoy davon aus, dass er nicht mehr existiert, und wird den Datenverkehr aus allen vorhandenen Verbindungspools herausziehen.

Für weitere Informationen siehe. Die Dokumentation des Envoy-Proxy.

Schritt 6 – Zugriff auf Logs und Fehler

Die endgültige Konfiguration – Registrierung. Anstatt Fehlerprotokolle auf die Festplatte zu übermitteln, verwendet der Envoy-Proxy einen Cloud-Ansatz. Alle Anwendungsprotokolle werden auf stdout und stderr.

Wenn Benutzer eine Anfrage stellen, sind Zugriffsprotokolle optional und standardmäßig deaktiviert. Um die Zugriffsprotokolle für HTTP-Anfragen zu aktivieren, aktivieren Sie die Konfiguration access_log für den HTTP-Verbindungs-Manager. Der Pfad kann entweder ein Gerät sein, wie stdout, oder eine Datei auf der Festplatte, abhängig von Ihren Anforderungen.

Die folgende Konfiguration leitet alle Zugriffsprotokolle an stdout (Hinweis des Übersetzers – stdout ist erforderlich, um Envoy innerhalb von Docker zu verwenden. Bei Verwendung ohne Docker ersetzen Sie /dev/stdout durch den Pfad zur regulären Logdatei). Kopieren Sie den Abschnitt in den Konfigurationsbereich für den Verbindungsmanager:

Copy to Clipboardaccess_log:
- name: envoy.file_access_log
  config:
    path: "/dev/stdout"

Die Ergebnisse sollten so aussehen:

      - 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:

Standardmäßig hat Envoy eine Formatzeile, die Details zur HTTP-Anfrage enthält:

[%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%"

Das Ergebnis dieser Formatzeile:

[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"

Der Ausgabeinhalt kann angepasst werden, indem das Feld für das Format festgelegt wird. Zum Beispiel:

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%"
"

Die Logzeile kann auch im JSON-Format ausgegeben werden, indem das Feld json_format. Zum Beispiel:

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

Für weitere Informationen zur Protokollierungsmethodik von Envoy besuchen Sie

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

Das Protokollieren ist nicht die einzige Möglichkeit, einen Einblick in die Funktionsweise des Envoy Proxys zu erhalten. Es sind fortschrittliche Möglichkeiten zur Verfolgung und Messung integriert. Sie können mehr erfahren in der Dokumentation zur Verfolgung oder über Das Skript zur interaktiven Verfolgung.

Schritt 7 — Start

Sie haben nun die Konfiguration von NGINX zu Envoy Proxy übertragen. Der letzte Schritt besteht darin, eine Instanz von Envoy Proxy zu starten, um sie zu testen.

Starten als Benutzer

Oben in der NGINX-Konfiguration lautet die Zeile user www www; die angibt, dass NGINX als ein Benutzer mit niedrigen Berechtigungen zur Erhöhung der Sicherheit ausgeführt wird.

Envoy Proxy verwendet einen Cloud-Ansatz zur Verwaltung dessen, wer der Prozessbesitzer ist. Wenn wir Envoy Proxy über einen Container starten, können wir einen Benutzer mit niedrigen Berechtigungen angeben.

Starten von Envoy Proxy

Der folgende Befehl startet den Envoy Proxy über einen Docker-Container auf dem Host. Dieser Befehl ermöglicht es Envoy, eingehende Anfragen über Port 80 zu empfangen. Wie in der Listener-Konfiguration angegeben, hört Envoy Proxy jedoch auf eingehenden Verkehr über Port 8080. Dies ermöglicht es, den Prozess als Benutzer mit niedrigen Berechtigungen auszuführen.

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

Tests

Mit dem gestarteten Proxy können nun Tests durchgeführt und verarbeitet werden. Der folgende cURL-Befehl gibt eine Anfrage mit dem in der Proxy-Konfiguration festgelegten Host-Header aus.

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

Die HTTP-Anfrage führt zu einem Fehler 503Dies liegt daran, dass aufsteigende Verbindungen nicht funktionieren und nicht verfügbar sind. Daher hat der Envoy Proxy keine verfügbaren Zieladressen für die Anfrage. Der folgende Befehl startet eine Reihe von HTTP-Diensten, die der für Envoy definierten Konfiguration entsprechen.

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

Mit den verfügbaren Diensten kann Envoy den Verkehr erfolgreich zum Ziel weiterleiten.

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

Sie sollten eine Antwort sehen, die angibt, welcher Docker-Container die Anfrage bearbeitet hat. In den Protokollen des Envoy Proxy sollten Sie auch die ausgegebene Zugriffszeile sehen.

Zusätzliche HTTP-Antwortheader (HTTP Response)

In den Headern der gültigen Anfrage sehen Sie zusätzliche HTTP-Header. Im Header wird die Zeit angezeigt, die der übergeordnete Host für die Bearbeitung der Anfrage benötigt hat. Diese wird in Millisekunden angegeben. Dies ist nützlich, wenn der Client die Bearbeitungszeit im Vergleich zur Netzwerkverzögerung bestimmen möchte.

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

Endkonfiguration

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 }

Zusätzliche Informationen vom Übersetzer

Die Installationsanweisungen für Envoy Proxy finden Sie auf der Website https://www.getenvoy.io/

Standardmäßig fehlt in rpm die systemd-Service-Konfiguration.

Fügen Sie die systemd-Service-Konfiguration /etc/systemd/system/envoy.service hinzu:

[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

Sie müssen das Verzeichnis /etc/envoy/ erstellen und die Konfiguration config.yaml dort ablegen.

Es gibt einen Telegram-Chat über Envoy Proxy: https://t.me/envoyproxy_ru

Envoy Proxy unterstützt keine Bereitstellung von statischen Inhalten. Daher können Sie für dieses Feature stimmen: https://github.com/envoyproxy/envoy/issues/378

Nur registrierte Benutzer können an der Umfrage teilnehmen. Bitte einloggen.

Hat dieser Beitrag Sie dazu angeregt, Envoy Proxy zu installieren und zu testen?

  • ja

  • nein

75 Benutzer stimmen zu. 18 Benutzer enthalten sich.

Quelle: habr.com

60GB SSD 8Gb DDR4