Hallo Habr! Ich mache Sie auf die Übersetzung des Beitrags aufmerksam: Migration von Nginx zu Envoy Proxy .
Envoy ist ein leistungsstarker verteilter Proxyserver (in C ++ geschrieben), der für einzelne Dienste und Anwendungen entwickelt wurde. Er ist auch ein Kommunikationsbus und eine „universelle Datenebene“, die für große „Service Mesh“ -Architekturen mit Mikrodiensten entwickelt wurde. 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 auftraten. Envoy arbeitet mit jeder Anwendung und abstrahiert das Netzwerk und bietet unabhängig von der Plattform gemeinsame Funktionen. Wenn der gesamte Büroverkehr in der Infrastruktur über das Envoy-Raster geleitet wird, können Problembereiche mit konsistenter Beobachtbarkeit, Optimierung der Gesamtleistung und Hinzufügen grundlegender Funktionen an einem bestimmten Ort leicht visualisiert werden.
Die Möglichkeiten
- Außerhalb der Prozessarchitektur: envoy ist ein eigenständiger Hochleistungsserver, der wenig RAM benötigt. Es funktioniert in Verbindung mit jeder Anwendungssprache oder jedem Framework.
- Unterstützung für http / 2 und grpc: envoy bietet erstklassige Unterstützung für http / 2 und grpc für eingehende und ausgehende Verbindungen. Dies ist ein transparenter Proxy von http / 1.1 bis http / 2.
- Verbesserter Lastausgleich: envoy unterstützt erweiterte Lastausgleichsfunktionen, einschließlich automatischer Wiederholungsversuche, offener Stromkreis, globales Tempolimit, Shadowing-Anforderungen, Lastausgleich in der lokalen Zone usw.
- Konfigurationsverwaltungs-API: envoy bietet eine robuste API zur dynamischen Verwaltung der Konfiguration.
- Beobachtbarkeit: tiefe Beobachtbarkeit des L7-Verkehrs, integrierte Unterstützung für die verteilte Verfolgung und Beobachtbarkeit von Mongodb, Dynamodb und vielen anderen Anwendungen.
Schritt 1 - Beispiel NGINX Config
Dieses Skript verwendet eine speziell erstellte Datei nginx.conf , die auf einem vollständigen Beispiel aus dem NGINX-Wiki basiert. Sie können die Konfiguration im Editor anzeigen, indem Sie die Datei nginx.conf öffnen
Quell-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 haben normalerweise drei Schlüsselelemente:
- Konfigurieren des NGINX-Servers, der Protokollstruktur und der Gzip-Funktionalität. Dies wird in allen Fällen global bestimmt.
- Konfigurieren von NGINX zum Akzeptieren von Anforderungen für one.example.com- Host an Port 8080.
- Festlegen Ihres Zielorts, wie der Datenverkehr für verschiedene Teile der URL behandelt wird.
Nicht alle Konfigurationen werden auf Envoy Proxy angewendet, und Sie müssen einige Einstellungen nicht konfigurieren. Envoy Proxy verfügt über vier Schlüsseltypen , die die von NGINX angebotene zugrunde liegende Infrastruktur unterstützen. Der Kern ist:
- Listener: Sie bestimmen, wie Envoy Proxy eingehende Anforderungen akzeptiert. Envoy Proxy unterstützt derzeit nur TCP-basierte Listener. Sobald die Verbindung hergestellt ist, wird sie zur Verarbeitung an eine Reihe von Filtern übertragen.
- Filter: Sie sind Teil einer Pipeline-Architektur, die eingehende und ausgehende Daten verarbeiten kann. Diese Funktionalität umfasst Filter wie Gzip, die die Daten komprimieren, bevor sie an den Client gesendet werden.
- Router: Sie leiten den Datenverkehr zum gewünschten Ziel um, das als Cluster definiert ist.
- Cluster: Sie definieren den Endpunkt für die Verkehrs- und Konfigurationseinstellungen.
Wir werden diese vier Komponenten verwenden, um die Envoy Proxy-Konfiguration zu erstellen, die der spezifischen NGINX-Konfiguration entspricht. Das Ziel von Envoy ist die Arbeit mit der API und der dynamischen Konfiguration. In diesem Fall verwendet die Grundkonfiguration statische, fest codierte Parameter von NGINX.
Schritt 2 - Konfigurieren Sie NGINX
Der erste Teil von nginx.conf definiert einige der internen NGINX-Komponenten, die konfiguriert werden müssen.
Arbeiterverbindungen
Die folgende Konfiguration bestimmt die Anzahl der Arbeitsprozesse und Verbindungen. Dies zeigt an, wie NGINX skaliert wird, um die Nachfrage zu befriedigen.
worker_processes 2; events { worker_connections 2000; }
Envoy Proxy verwaltet Workflows und Verbindungen unterschiedlich.
Envoy erstellt einen Workflow für jeden Hardware-Thread im System. Jeder Arbeitsthread führt eine nicht blockierende Ereignisschleife aus, für die er verantwortlich ist
- Jedem Zuhörer zuhören
- Akzeptiere neue Verbindungen
- Erstellen eines Filtersatzes für eine Verbindung
- Behandlung aller E / A-Vorgänge über die Lebensdauer einer Verbindung.
Die gesamte weitere Verbindungsverarbeitung wird vollständig im Workflow verarbeitet, einschließlich des Weiterleitungsverhaltens.
Für jeden Workflow in Envoy gibt es eine Verbindung im Pool. Daher stellen HTTP / 2-Verbindungspools jeweils nur eine Verbindung für jeden externen Host her. Wenn vier Arbeitsthreads vorhanden sind, gibt es vier HTTP / 2-Verbindungen für jeden externen Host in einem stabilen Zustand. Durch Speichern von allem in einem Workflow kann fast der gesamte Code ohne Sperren geschrieben werden, als wäre er Single-Threaded. Wenn mehr als die erforderlichen Workflows zugewiesen werden, kann dies zu einer ineffizienten Speichernutzung, der Erstellung einer großen Anzahl inaktiver Verbindungen und einer Verringerung der Anzahl der an den Pool zurückgegebenen Verbindungen führen.
Weitere Informationen finden Sie im Envoy Proxy-Blog .
HTTP-Konfiguration
Der folgende NGINX-Konfigurationsblock definiert HTTP-Einstellungen, z.
- Welche MIME-Typen werden unterstützt?
- Standardzeitüberschreitungen
- Gzip-Konfiguration
Sie können diese Aspekte mithilfe von Filtern in Envoy Proxy konfigurieren, auf die wir später noch eingehen werden.
Schritt 3 - Serverkonfiguration
Im HTTP-Konfigurationsblock werden Sie in der NGINX-Konfiguration angewiesen, Port 8080 abzuhören und auf eingehende Anforderungen für die Domänen one.example.com und www.one.example.com zu antworten .
server { listen 8080; server_name one.example.com www.one.example.com;
In Envoy kontrollieren die Zuhörer es.
Gesandte Zuhörer
Der wichtigste Aspekt beim Einstieg in Envoy Proxy ist die Identifizierung von Listenern. Sie müssen eine Konfigurationsdatei erstellen, die beschreibt, wie Sie eine Envoy-Instanz ausführen möchten.
Das folgende Snippet erstellt einen neuen Listener und ordnet ihn Port 8080 zu. Die Konfiguration teilt Envoy Proxy mit, an welche Ports er für eingehende Anforderungen gebunden werden soll.
Envoy Proxy verwendet für die Konfiguration die YAML-Notation. Um sich mit dieser Notation vertraut zu machen, klicken Sie auf den Link hier.
Copy to Editorstatic_resources: listeners: - name: listener_0 address: socket_address: { address: 0.0.0.0, port_value: 8080 }
Es ist nicht erforderlich, Servernamen zu definieren, da Envoy Proxy-Filter dies verarbeiten können.
Schritt 4 - Standortkonfiguration
Wenn eine Anforderung bei NGINX eintrifft, bestimmt der Standortblock, wie der Datenverkehr verarbeitet und wohin geleitet 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 targetCluster übertragen . Der Upstream-Cluster definiert die Knoten, die die Anforderung verarbeiten sollen. Wir werden dies im nächsten Schritt diskutieren.
location / { proxy_pass http://targetCluster/; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; }
Bei Envoy macht Filter das.
Gesandte Filter
Bei einer statischen Konfiguration bestimmen Filter, wie eingehende Anforderungen behandelt werden. In diesem Fall setzen wir Filter, die mit Servernamen im vorherigen Schritt übereinstimmen. Wenn eingehende Anforderungen eingehen, die bestimmten Domänen und Routen entsprechen, wird der Datenverkehr an den Cluster weitergeleitet. Dies entspricht der NGINX-Upstream-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
Der Name envoy.http_connection_manager ist ein in Envoy Proxy integrierter Filter. Andere Filter sind Redis , Mongo , TCP . Die vollständige Liste finden Sie in der Dokumentation .
Weitere Informationen zu anderen Lastausgleichsrichtlinien finden Sie in der Envoy-Dokumentation .
Schritt 5 - Proxy- und Upstream-Konfiguration
In NGINX definiert die Upstream-Konfiguration die Zielserver, 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 es clusterverwaltet.
Gesandte Cluster
Das Äquivalent von Upstream wird als Cluster definiert. In diesem Fall wurden die Hosts identifiziert, die den Datenverkehr bedienen. Eine Methode für den Zugriff auf Hosts, z. B. ein Timeout, wird als Clusterkonfiguration definiert. Auf diese Weise können Sie die Granularität von Aspekten wie Latenz und Lastausgleich genauer steuern.
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 löst Envoy die angegebenen DNS-Ziele kontinuierlich und asynchron auf. Jede als Ergebnis von DNS zurückgegebene IP-Adresse wird als expliziter Host im Upstream-Cluster betrachtet. Wenn die Anforderung zwei IP-Adressen zurückgibt, geht Envoy davon aus, dass sich zwei Hosts im Cluster befinden und beide einen Lastausgleich aufweisen müssen. Wenn der Host aus dem Ergebnis entfernt wird, geht Envoy davon aus, dass er nicht mehr vorhanden ist, und wählt Datenverkehr aus vorhandenen Verbindungspools aus.
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, verwendet Envoy Proxy einen Cloud-basierten Ansatz. Alle Anwendungsprotokolle werden in stdout und stderr angezeigt.
Wenn Benutzer eine Anfrage stellen, sind Zugriffsprotokolle optional und standardmäßig deaktiviert. Aktivieren Sie zum Aktivieren von Zugriffsprotokollen für HTTP-Anforderungen die Konfiguration access_log für den HTTP-Verbindungsmanager. Der Pfad kann je nach Ihren Anforderungen entweder ein Gerät wie stdout oder eine Datei auf der Festplatte sein.
Die folgende Konfiguration leitet alle Zugriffsprotokolle an stdout um (Anmerkung des Übersetzers - stdout ist für die Verwendung von envoy im Docker erforderlich. Wenn Sie ohne Docker verwenden, ersetzen Sie / dev / stdout durch den Pfad zur regulären Protokolldatei). Kopieren Sie das Snippet in den Konfigurationsabschnitt für den Verbindungsmanager:
Copy to Clipboardaccess_log: - name: envoy.file_access_log config: path: "/dev/stdout"
Die Ergebnisse sollten folgendermaßen 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-Anforderung 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:
[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 Inhalt der Ausgabe 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"
Die Protokollzeichenfolge kann auch im JSON-Format ausgegeben werden, indem das Feld json_format festgelegt wird. 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 zu den Registrierungstechniken für Gesandte 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, sich ein Bild von der Arbeit mit Envoy Proxy zu machen. Es verfügt über integrierte erweiterte Funktionen für die Ablaufverfolgung und Metriken. Weitere Informationen finden Sie in der Ablaufverfolgungsdokumentation oder im interaktiven Ablaufverfolgungsskript .
Schritt 7 - Starten
Jetzt haben Sie die Konfiguration von NGINX auf Envoy Proxy übertragen. Der letzte Schritt besteht darin, eine Instanz von Envoy Proxy auszuführen, um sie zu testen.
Vom Benutzer ausführen
Oben in der NGINX-Konfiguration befindet sich der Leitungsbenutzer www www; gibt an, dass NGINX als Benutzer mit geringen Berechtigungen gestartet wurde, um die Sicherheit zu verbessern.
Envoy Proxy verfolgt einen Cloud-basierten Ansatz, um zu verwalten, wem der Prozess gehört. Wenn wir Envoy Proxy über den Container ausführen, können wir einen Benutzer mit einer niedrigen Berechtigungsstufe angeben.
Starten Sie Envoy Proxy
Mit dem folgenden Befehl wird Envoy Proxy über den Docker-Container auf dem Host gestartet. Dieser Befehl bietet Envoy die Möglichkeit, über Port 80 auf eingehende Anforderungen zu warten. Wie in der Listener-Konfiguration angegeben, wartet Envoy Proxy jedoch auf eingehenden Datenverkehr über 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
Testen
Bei laufenden Proxys können jetzt Tests durchgeführt und verarbeitet werden. Der folgende Befehl cURL gibt eine Anforderung mit dem in der Proxy-Konfiguration definierten Host-Header aus.
curl -H "Host: one.example.com" localhost -i
Eine HTTP-Anfrage führt zu Fehler 503 . Dies liegt daran, dass Upstream-Verbindungen nicht funktionieren und nicht verfügbar sind. Daher verfügt Envoy Proxy über keine verfügbaren Zielziele für die Anforderung. Mit dem folgenden Befehl wird eine Reihe von HTTP-Diensten gestartet, 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 Anforderung verarbeitet hat. In Envoy Proxy-Protokollen sollte auch die angezeigte Zugriffszeichenfolge angezeigt werden.
Zusätzliche HTTP-Antwortheader
In den Antwortheadern der tatsächlichen Anforderung werden zusätzliche HTTP-Header angezeigt. Der Header zeigt die Zeit an, die der Upstream-Host für die Verarbeitung der Anforderung aufgewendet hat. Es wird in Millisekunden ausgedrückt. Dies ist nützlich, wenn der Client die Servicezeit im Vergleich zur Netzwerklatenz bestimmen 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 }
Installationsanweisungen für Envoy Proxy finden Sie unter https://www.getenvoy.io/
Standardmäßig gibt es in rpm keine systemd service config.
Fügen Sie den systemd-Dienst config /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 dort die config.yaml-Konfiguration ablegen.
Per Envoy Proxy gibt es einen Telegramm-Chat: https://t.me/envoyproxy_ru
Envoy Proxy unterstützt keine statische Inhaltsverteilung. Wer kann also für das Feature stimmen: https://github.com/envoyproxy/envoy/issues/378