Der HTTP Connection Manager und HTTP-Filter-Ketten
Wie Envoy rohe Bytes in HTTP-Anfragen verwandelt, auf die er reagieren kann – und die Wege, eigene Logik in diese Pipeline einzubinden.
Das meiste, was man im Alltag in Envoy konfiguriert – Header-Manipulation, Access Logging, Retries, externe Autorisierung –, geschieht innerhalb eines bestimmten Netzwerkfilters: dem HTTP Connection Manager. Diese Anleitung behandelt, was er tut, wie seine eigene Filter-Kette aufgebaut ist und auf welche Weisen du ihn um Logik erweitern kannst, die nicht eingebaut ist.
HCM: von Bytes zu HTTP
Die Filter-Kette eines Listeners beginnt auf Netzwerkebene und arbeitet auf einem rohen Byte-Strom ohne jedes Konzept einer „Anfrage“. Der HTTP Connection Manager (HCM) ist der Netzwerkfilter, der das ändert: Er parst den Byte-Strom zu HTTP-Anfragen, Headern, Bodys und Trailern, und ab diesem Punkt kann alles, was in der Kette dahinter folgt, mit HTTP-Semantik arbeiten statt mit rohen Bytes.
Hier leben auch die Funktionen auf Anfrageebene: Access Logging, Manipulation von Anfragen und Antworten und vor allem die eigene verschachtelte Kette von HTTP-Filtern des HCM, ein vom Netzwerkfilter-Ketten-Konzept, in dem sie sitzt, getrenntes Konzept.
Die HTTP-Filter-Kette
Innerhalb des HCM laufen HTTP-Filter in definierter Reihenfolge für jede HTTP-Anfrage: CORS-Behandlung, Rate Limiting, externe Autorisierung (ein Aufruf an einen anderen Service, der entscheidet, ob eine Anfrage erlaubt ist), Lua-Skripting, WebAssembly-Module (Wasm) und mehr. Der letzte Filter der Kette ist typischerweise ein terminaler Filter, fast immer der Router-Filter, dessen Aufgabe es ist, die Anfrage an das Route-Matching und von dort an einen Cluster zu übergeben.
Die Reihenfolge zählt. Ein Rate-Limiting-Filter vor einem Authentifizierungsfilter verhält sich anders als einer dahinter, und Envoys Konfiguration einer Filter-Kette ist explizit darüber, wo jeder Filter relativ zu den anderen sitzt, nicht nur darüber, welche Filter vorhanden sind.
Envoy erweitern: deine Optionen
Wenn keiner von Envoys eingebauten Filtern tut, was du brauchst, gibt es mehrere Wege, eigene Logik hinzuzufügen, jeweils mit anderen Kosten und anderer Reichweite:
- Native C++-Filter, direkt in einen eigenen Envoy-Build einkompiliert. Das ist die mächtigste und aufwendigste Option: Sie bedeutet, einen eigenen Envoy-Build zu pflegen, statt einen Upstream-Build zu nutzen. Istios eigene Envoy-Distribution geht für einen Teil ihres eingebauten Verhaltens diesen Weg.
- External Processing (ext_proc), bei dem Envoy mitten in der Anfrage einen separaten Service aufruft, dieser Service seine Verarbeitung erledigt und die Kontrolle an die Filter-Kette zurückgibt. Das hält eigene Logik vollständig außerhalb von Envoys eigenem Prozess, auf Kosten eines Netzwerk-Hops pro Anfrage.
- Lua-Skripting, bei dem ein Lua-Filter ein eingebettetes Skript gegen die Anfrage und/oder Antwort ausführt. Schnell zu schreiben und zu iterieren, ohne Rebuild oder separaten Service, auf Kosten der Beschränkung auf das, was Lua und Envoys Lua-API bieten.
- WebAssembly (Wasm), bei dem du einen Filter in einer Sprache deiner Wahl zu einem
.wasm-Modul kompilierst und Envoy es als Teil der Kette lädt und ausführt. Das ist der Erweiterungsmechanismus, der am stärksten darauf ausgerichtet ist, einen Filter als portables Artefakt zu verteilen und wiederzuverwenden – statt als Skript oder eigener Build.
Was passt, hängt davon ab, wie viel Kontrolle du brauchst und wie viel betrieblichen Mehraufwand du in Kauf nimmst: Ein Lua-Skript ist meist der schnellste Weg, etwas auszuprobieren, ein Wasm-Modul der portablere Weg, es auszuliefern, sobald du weißt, dass es funktioniert, und ein eigener C++-Build oder ein externer Service ist das, was bleibt, wenn keines davon leisten kann, was du brauchst.
Was ein Filter zur Konfiguration tatsächlich braucht
Welchen Erweiterungsmechanismus du auch nutzt: Die Konfiguration eines HTTP-Filters läuft immer auf drei Dinge hinaus:
- Den Namen des Filters, eine stabile Kennung.
- Seine Typ-URL, die Envoys Konfigurationssystem genau sagt, welche Art von Filter das ist und welche Form seine Konfiguration hat.
- Die filterspezifische Konfiguration selbst, die Felder, die dieser konkrete Filter tatsächlich akzeptiert.
Envoys eigene Dokumentationsseite zu jedem Filter listet seine Typ-URL und Konfigurationsfelder auf, wobei die Dokumentation eines Filters oft über mehrere verlinkte Referenzseiten verteilt ist statt an einem Ort. Die genaue Syntax eines bestimmten Felds zu finden bedeutet häufig, einer Kette von Links zu folgen, statt von oben nach unten zu lesen. Die Suche in öffentlichen Code-Hosts nach der Typ-URL eines Filters ist eine praktische Abkürzung, sobald du sie kennst: Für alles halbwegs Gängige hat meist schon jemand eine funktionierende Konfiguration veröffentlicht, mit der du beginnen kannst, statt eine allein aus Referenzdokumentation zusammenzubauen.
Wo das auftaucht, wenn du ein Service Mesh nutzt
Läuft Envoy als Sidecar unter Istio oder einem ähnlichen Mesh, schreibst du rohe HTTP-Filter-Konfiguration für gängige Fälle selten von Hand – die eigenen APIs des Mesh (Routing-Regeln, Sicherheits-Policies) erzeugen sie für dich. Für alles, was die übergeordneten APIs des Mesh nicht abdecken – und etwas deckt sie immer nicht ab –, konfigurierst du einen HTTP-Filter direkt über den Notausgang auf niedrigerer Ebene, den das Mesh bereitstellt. Die nächste Anleitung dieser Reihe behandelt genau das, am Beispiel von Istios EnvoyFilter-Ressource.
Beliebte Anleitungen
-
Envoy-Architektur: Listener, Cluster und Filter-Ketten Wie eine Anfrage tatsächlich durch Envoy läuft – vom Socket, an dem sie ankommt, bis zum Upstream, an den sie gesendet wird. -
Wo Envoy hineinpasst: Edge-, Front-Proxy- und Service-Mesh-Muster Derselbe Proxy, auf drei Arten betrieben – und warum „leicht genug, um pro Instanz zu laufen“ alle drei möglich macht.