Migration von Nginx zu Envoy Proxy

Hallo, Habr! Hier ist eine Übersetzung des Beitrags: Migration von Nginx zu Envoy Proxy.

Envoy ist ein leistungsstarker verteilter Proxyserver (geschrieben in C++), der für einzelne Dienste und Anwendungen entwickelt wurde. Er ist außerdem ein Kommunikationsbus und eine „universelle Datenebene“ für große Microservice-„Service Mesh“-Architekturen. Bei der Erstellung wurden Lösungen für Probleme berücksichtigt, die bei der Entwicklung von Servern wie NGINX, HAProxy, Hardware Load Balancern und Cloud Load Balancern entstanden sind. Envoy arbeitet mit jeder Anwendung zusammen und abstrahiert das Netzwerk, um unabhängig von der Plattform gemeinsame Funktionen bereitzustellen. Wenn der gesamte Serviceverkehr in einer Infrastruktur durch das Envoy-Mesh fließt, können Problembereiche mit konsistenter Beobachtbarkeit einfach visualisiert, die Gesamtleistung optimiert und Kernfunktionen an einem bestimmten Standort hinzugefügt werden.

Capabilities

  • Out-of-Process-Architektur: Envoy ist ein eigenständiger Hochleistungsserver, der wenig RAM beansprucht. Es funktioniert in Verbindung mit jeder Anwendungssprache oder jedem Framework.
  • http/2- und grpc-Unterstützung: envoy verfügt über erstklassige http/2- und grpc-Unterstützung für ein- und ausgehende Verbindungen. Dies ist ein transparenter Proxy von http/1.1 bis http/2.
  • Erweiterter Lastausgleich: Envoy unterstützt erweiterte Lastausgleichsfunktionen, einschließlich automatischer Wiederholungsversuche, Kettenunterbrechung, globale Ratenbegrenzung, Anforderungsschatten, lokaler Zonenlastausgleich usw.
  • Konfigurationsverwaltungs-API: envoy bietet eine robuste API für die dynamische Verwaltung Ihrer Konfiguration.
  • Beobachtbarkeit: Umfassende Beobachtbarkeit des L7-Verkehrs, native Unterstützung für verteiltes Tracing und Beobachtbarkeit von Mongodb, Dynamodb und vielen anderen Anwendungen.

Schritt 1 – Beispiel einer NGINX-Konfiguration

Dieses Skript verwendet eine speziell gestaltete Datei nginx.conf, basierend auf dem vollständigen Beispiel von NGINX-Wiki. Durch Öffnen können Sie die Konfiguration im Editor einsehen nginx.conf

Nginx-Quellkonfiguration

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 typischerweise aus drei Schlüsselelementen:

  1. Konfigurieren des NGINX-Servers, der Protokollstruktur und der Gzip-Funktionalität. Dies ist in allen Fällen global definiert.
  2. Konfigurieren von NGINX zum Akzeptieren von Anfragen an den Host one.example.com auf Port 8080.
  3. Einrichten des Zielstandorts und Umgang mit Datenverkehr für verschiedene Teile der URL.

Nicht alle Konfigurationen gelten für Envoy Proxy und Sie müssen einige Einstellungen nicht konfigurieren. Envoy Proxy hat vier Schlüsseltypen, die die von NGINX angebotene Kerninfrastruktur unterstützen. Der Kern ist:

  • Zuhörer: Sie bestimmen, wie Envoy Proxy eingehende Anfragen entgegennimmt. Envoy Proxy unterstützt derzeit nur TCP-basierte Listener. Sobald eine Verbindung hergestellt ist, wird sie zur Verarbeitung an eine Reihe von Filtern weitergeleitet.
  • Filter: Sie sind Teil einer Pipeline-Architektur, die ein- und ausgehende Daten verarbeiten kann. Zu dieser Funktionalität gehören Filter wie Gzip, das die Daten komprimiert, bevor sie an den Client gesendet werden.
  • Router: Sie leiten den Datenverkehr an das gewünschte Ziel weiter, das als Cluster definiert ist.
  • Cluster: Sie definieren den Endpunkt für Datenverkehr und Konfigurationsparameter.

Wir werden diese vier Komponenten verwenden, um eine 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 verwendet die Basiskonfiguration statische, hartcodierte Einstellungen von NGINX.

Schritt 2 – NGINX-Konfiguration

Der erste Teil nginx.conf definiert einige NGINX-Interna, die konfiguriert werden müssen.

Arbeitnehmerverbindungen

Die folgende Konfiguration bestimmt die Anzahl der Arbeitsprozesse und Verbindungen. Dies zeigt, wie NGINX skaliert wird, um der Nachfrage gerecht zu werden.

worker_processes  2;

events {
  worker_connections   2000;
}

Envoy Proxy verwaltet Arbeitsabläufe und Verbindungen auf unterschiedliche Weise.

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

  1. Jedem Zuhörer zuhören
  2. Akzeptieren Sie neue Verbindungen
  3. Erstellen einer Reihe von Filtern für eine Verbindung
  4. Verarbeiten Sie alle E/A-Vorgänge während der Lebensdauer der Verbindung.

Die gesamte weitere Verbindungsverarbeitung wird vollständig im Worker-Thread abgewickelt, einschließlich etwaigem Weiterleitungsverhalten.

Für jeden Worker-Thread in Envoy gibt es einen Verbindungspool. Daher stellen HTTP/2-Verbindungspools jeweils nur eine Verbindung pro externem Host her. Wenn vier Arbeitsthreads vorhanden sind, gibt es in einem stabilen Zustand vier HTTP/2-Verbindungen pro externem Host. Indem alles in einem Arbeitsthread gehalten wird, kann fast der gesamte Code ohne Blockierung geschrieben werden, als wäre er Single-Threaded. Wenn mehr Arbeitsthreads als nötig zugewiesen werden, kann dies zu einer Verschwendung von Speicher führen, wodurch eine große Anzahl inaktiver Verbindungen entsteht und die Anzahl der Verbindungen, die an den Pool zurückgegeben werden, verringert wird.

Für weitere Informationen besuchen Sie Envoy Proxy-Blog.

HTTP-Konfiguration

Der folgende NGINX-Konfigurationsblock definiert HTTP-Einstellungen wie:

  • Welche MIME-Typen werden unterstützt?
  • Standardzeitüberschreitungen
  • Gzip-Konfiguration

Sie können diese Aspekte mithilfe von Filtern in Envoy Proxy anpassen, worauf wir später noch eingehen.

Schritt 3 – Serverkonfiguration

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

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

Innerhalb von Envoy wird es von Listenern gesteuert.

Gesandte Zuhörer

Der wichtigste Aspekt beim Einstieg in Envoy Proxy ist die Definition der Listener. Sie müssen eine Konfigurationsdatei erstellen, die beschreibt, wie Sie die Envoy-Instanz ausführen möchten.

Der folgende Codeausschnitt erstellt einen neuen Listener und bindet ihn an Port 8080. Die Konfiguration teilt Envoy Proxy mit, an welche Ports er sich für eingehende Anfragen binden soll.

Envoy Proxy verwendet für seine Konfiguration die YAML-Notation. Eine Einführung in diese Notation finden Sie hier Link.

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

Keine Notwendigkeit zur Definition Servername, da Envoy-Proxy-Filter dies handhaben.

Schritt 4 – Standortkonfiguration

Wenn eine Anfrage bei NGINX eingeht, bestimmt der Standortblock, wie der Datenverkehr verarbeitet und wohin er weitergeleitet werden soll. Im folgenden Fragment wird der gesamte Datenverkehr zur Site an einen Upstream-Cluster (Anmerkung des Übersetzers: Upstream ist normalerweise ein Anwendungsserver) mit dem Namen übertragen ZielCluster. Der Upstream-Cluster definiert 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;
}

Bei Envoy erledigt Filters dies.

Envoy-Filter

Bei einer statischen Konfiguration bestimmen Filter, wie eingehende Anfragen verarbeitet werden. In diesem Fall setzen wir passende Filter Servernamen im vorherigen Schritt. Wenn eingehende Anfragen eingehen, die mit bestimmten Domänen und Routen übereinstimmen, wird der Datenverkehr an den Cluster weitergeleitet. Dies entspricht einer NGINX-Bottom-up-Konfiguration.

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 in Envoy Proxy. Andere Filter umfassen Redis, Mongo, TCP. Die vollständige Liste finden Sie unter Dokumentation.

Weitere Informationen zu anderen Lastausgleichsrichtlinien finden Sie unter Envoy-Dokumentation.

Schritt 5 – Proxy- und Upstream-Konfiguration

In NGINX definiert die Upstream-Konfiguration eine Reihe von Zielservern, die den Datenverkehr verarbeiten. In diesem Fall wurden zwei Cluster zugewiesen.

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

In Envoy wird dies durch Cluster verwaltet.

Envoy-Cluster

Das Upstream-Äquivalent wird als Cluster definiert. In diesem Fall wurden die Hosts definiert, die den Datenverkehr bedienen. Die Art und Weise, wie auf Hosts zugegriffen wird, beispielsweise Timeouts, wird als Clusterkonfiguration definiert. Dies ermöglicht eine detailliertere Kontrolle über Aspekte wie Latenz und Lastausgleich.

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 der Diensterkennung STRICT_DNS Envoy löst die angegebenen DNS-Ziele kontinuierlich und asynchron auf. Jede vom DNS-Ergebnis zurückgegebene IP-Adresse wird als expliziter Host im Upstream-Cluster betrachtet. Das heißt, wenn eine Anfrage zwei IP-Adressen zurückgibt, geht Envoy davon aus, dass es zwei Hosts im Cluster gibt und beide einen Lastausgleich durchführen müssen. Wenn ein Host aus dem Ergebnis entfernt wird, geht Envoy davon aus, dass er nicht mehr existiert, und ruft den Datenverkehr aus allen vorhandenen Verbindungspools ab.

Weitere Informationen finden Sie unter Envoy-Proxy-Dokumentation.

Schritt 6 – Protokollzugriff und Fehler

Die endgültige Konfiguration ist die Registrierung. Anstatt Fehlerprotokolle auf die Festplatte zu übertragen, verfolgt Envoy Proxy einen cloudbasierten Ansatz. Alle Anwendungsprotokolle werden an ausgegeben stdout и stderr.

Wenn Benutzer eine Anfrage stellen, sind Zugriffsprotokolle optional und standardmäßig deaktiviert. Um Zugriffsprotokolle für HTTP-Anfragen zu aktivieren, aktivieren Sie die Konfiguration access_log für den HTTP-Verbindungsmanager. Der Pfad kann entweder ein Gerät wie z stdoutoder eine Datei auf der Festplatte, je nach Ihren Anforderungen.

Die folgende Konfiguration leitet alle Zugriffsprotokolle um stdout (Anmerkung des Übersetzers – stdout ist erforderlich, um Envoy in Docker zu verwenden. Bei Verwendung ohne Docker ersetzen Sie /dev/stdout durch den Pfad zu einer regulären Protokolldatei.) Kopieren Sie den Ausschnitt in den Konfigurationsabschnitt 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 verfügt Envoy über eine Formatzeichenfolge, die die Details der 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%"n

Das Ergebnis dieser Formatzeichenfolge ist:

[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 durch Festlegen des Formatfelds angepasst werden. 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%"n"

Durch Setzen des Feldes kann die Protokollzeile auch im JSON-Format ausgegeben werden 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)%"}

Weitere Informationen zur Envoy-Registrierungsmethodik finden Sie unter

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

Die Protokollierung ist nicht die einzige Möglichkeit, Einblicke in die Arbeit mit Envoy Proxy zu gewinnen. Es verfügt über erweiterte Ablaufverfolgungs- und Metrikfunktionen. Mehr erfahren Sie unter Rückverfolgungsdokumentation oder über Interaktives Ablaufverfolgungsskript.

Schritt 7 – Starten

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

Als Benutzer ausführen

Ganz oben in der NGINX-Konfigurationszeile Benutzer www www; Gibt an, NGINX als Benutzer mit geringen Berechtigungen auszuführen, um die Sicherheit zu verbessern.

Envoy Proxy verfolgt einen cloudbasierten Ansatz zur Verwaltung der Eigentümer eines Prozesses. Wenn wir Envoy Proxy über einen Container ausführen, können wir einen Benutzer mit geringen Berechtigungen angeben.

Envoy Proxy starten

Mit dem folgenden Befehl wird Envoy Proxy über einen Docker-Container auf dem Host ausgeführt. Dieser Befehl gibt Envoy die Möglichkeit, auf eingehende Anfragen auf Port 80 zu warten. Wie in der Listener-Konfiguration angegeben, lauscht Envoy Proxy jedoch auf eingehenden Datenverkehr auf Port 8080. Dadurch kann der Prozess als Benutzer mit geringen Berechtigungen ausgeführt werden.

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

Testing

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

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

Die HTTP-Anfrage führt zu einem Fehler 503. Dies liegt daran, dass Upstream-Verbindungen nicht funktionieren und nicht verfügbar sind. Daher verfügt Envoy Proxy über keine verfügbaren Ziele 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 Datenverkehr erfolgreich an sein Ziel weiterleiten.

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

Sie sollten eine Antwort sehen, die angibt, welcher Docker-Container die Anfrage verarbeitet hat. In den Envoy-Proxy-Protokollen sollte auch eine Zugriffszeichenfolgenausgabe angezeigt werden.

Zusätzliche HTTP-Antwortheader

In den Antwortheadern der eigentlichen Anfrage werden zusätzliche HTTP-Header angezeigt. Der Header zeigt die Zeit an, die der Upstream-Host mit der Verarbeitung der Anfrage verbracht hat. Ausgedrückt in Millisekunden. Dies ist nützlich, wenn der Client die Servicezeit im Vergleich zur Netzwerklatenz ermitteln möchte.

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

Endgültige Konfiguration

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

Anweisungen zur Installation von Envoy Proxy finden Sie auf der Website https://www.getenvoy.io/

Standardmäßig verfügt rpm über keine systemd-Dienstkonfiguration.

Systemd-Dienstkonfiguration /etc/systemd/system/envoy.service hinzufügen:

[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 ein Verzeichnis /etc/envoy/ erstellen und die config.yaml-Konfiguration dort ablegen.

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

Envoy Proxy unterstützt die Bereitstellung statischer Inhalte nicht. Wer kann also für das Feature stimmen: https://github.com/envoyproxy/envoy/issues/378

An der Umfrage können nur registrierte Benutzer teilnehmen. Einloggenbitte.

Hat Sie dieser Beitrag dazu ermutigt, den Envoy-Proxy zu installieren und zu testen?

  • ja

  • Nein

75 Benutzer haben abgestimmt. 18 Benutzer enthielten sich der Stimme.

Source: habr.com

Kommentar hinzufügen