Im letzten Wir haben die grundlegenden Komponenten des Service Mesh Istio betrachtet, ein erstes Verständnis des Systems entwickelt und die häufigsten Fragen beantwortet, die zu Beginn der Nutzung von Istio auftreten. In diesem Teil schauen wir uns an, wie wir das Sammeln von Tracing-Informationen im Netzwerk organisieren können.

Das Erste, was vielen Entwicklern und Systemadministratoren in den Sinn kommt, wenn sie den Begriff Service Mesh hören, ist Tracing. Tatsächlich fügen wir jedem Knoten im Netzwerk einen speziellen Proxy-Server hinzu, über den der gesamte TCP-Verkehr geleitet wird. Es scheint also einfach, Informationen über alle Netzwerkinteraktionen zu senden. Leider gibt es jedoch in der Realität zahlreiche Nuancen, die berücksichtig werden müssen. Lassen Sie uns diese genauer betrachten.
Irrtum Nummer eins: Wir können kostenlos Daten über Netzwerkbesuche erhalten.
Tatsächlich können wir relativ kostenlos nur die verbundenen, durch Pfeile gekennzeichneten Knoten unseres Systems sowie die Datenrate erfassen, die zwischen den Diensten übertragen wird (im Wesentlichen die Anzahl der Bytes pro Zeiteinheit). In den meisten Fällen kommunizieren unsere Dienste jedoch über ein bestimmtes Anwendungsprotokoll wie HTTP, gRPC, Redis und so weiter. Natürlich möchten wir die Tracing-Informationen genau für diese Protokolle sehen, die Anfrage-Raten und nicht die Datenraten. Wir wollen die Latenzzeiten der Anfragen über unser Protokoll verstehen. Schließlich möchten wir den vollständigen Weg sehen, den eine Anfrage von ihrem Eingang in unser System bis zur Antwort an den Nutzer zurücklegt. Diese Aufgabe ist nicht so einfach zu lösen.
Zunächst wollen wir uns anschauen, wie das Senden von Tracing-Spans aus architektonischer Sicht in Istio aussieht. Wie wir aus dem ersten Teil wissen, hat Istio einen speziellen Bestandteil zur Sammlung von Telemetriedaten, der als Mixer bezeichnet wird. In der aktuellen Version 1.0.* erfolgt das Senden jedoch direkt von den Proxy-Servern, insbesondere vom Envoy-Proxy. Der Envoy-Proxy unterstützt das Senden von Tracing-Spans über das Zipkin-Protokoll standardmäßig. Andere Protokolle können angebunden werden, allerdings nur über Plugins. Mit Istio erhalten wir sofort einen konfigurierten Envoy-Proxy, der nur das Zipkin-Protokoll unterstützt. Wenn wir beispielsweise das Jaeger-Protokoll verwenden und Tracing-Spans über UDP senden möchten, müssen wir unser eigenes Istio-Proxy-Image erstellen. Die Unterstützung für kundenspezifische Plugins für den Istio-Proxy ist vorhanden, befindet sich jedoch noch in der Alpha-Phase. Daher verringert sich der Kreis der verwendeten Technologien zur Speicherung und Übertragung von Tracing-Spans, wenn wir eine große Anzahl an benutzerdefinierten Einstellungen vermeiden möchten. Von den Hauptsystemen können wir im Grunde jetzt entweder Zipkin selbst oder Jaeger verwenden, wobei wir alles über ein Zipkin-kompatibles Protokoll senden (was deutlich weniger effizient ist). Das Zipkin-Protokoll selbst sieht vor, dass alle Tracing-Informationen über das HTTP-Protokoll an die Collector-Server gesendet werden, was recht kostspielig ist.
Wie bereits erwähnt, möchten wir die Protokolle der Anwendungsebene nachverfolgen. Das bedeutet, dass die Proxy-Server, die neben jedem Dienst stehen, verstehen müssen, welche Interaktionen aktuell stattfinden. Standardmäßig konfiguriert Istio für alle Ports den Typ plain TCP, was bedeutet, dass keine Traces abgesendet werden. Um Traces zu senden, muss man zunächst diese Option in der Hauptkonfiguration des Mesh aktivieren und, was sehr wichtig ist, alle Ports der Kubernetes-Service-Entitäten gemäß dem Protokoll benennen, das im Dienst verwendet wird. Zum Beispiel so:
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
ports:
- port: 80
targetPort: 80
name: http
selector:
app: nginxMan kann auch zusammengesetzte Namen verwenden, wie zum Beispiel http-magic (Istio erkennt http und identifiziert diesen Port als http-Endpunkt). Das Format ist: proto-extra.
Um nicht eine Vielzahl von Konfigurationen zu patchen, um das Protokoll zu bestimmen, kann man einen umstrittenen Workaround nutzen: den Pilot-Komponente zu patchen, während er gerade . Letztendlich muss diese Logik natürlich auf die Standardlogik geändert werden, und wir müssen zur Benennungsrichtlinie aller Ports übergehen.
Um herauszufinden, ob das Protokoll wirklich korrekt definiert ist, sollten Sie in einen der Sidecar-Container mit dem Envoy-Proxy gehen und eine Anfrage an den Admin-Interface-Port von Envoy mit dem Pfad /config_dump stellen. In der resultierenden Konfiguration sollten Sie das Feld 'operation' für den gewünschten Dienst überprüfen. Dieses Feld wird in Istio als Identifikator verwendet, woher die Anfrage kommt. Um den Wert dieses Parameters in Istio anzupassen (denn wir werden ihn später in unserem Tracing-System sehen), müssen Sie beim Start des Sidecar-Containers das Flag serviceCluster angeben. Zum Beispiel kann es folgendermaßen aus den Variablen, die über die Downward API von Kubernetes bereitgestellt werden, berechnet werden:
--serviceCluster ${POD_NAMESPACE}.$(echo ${POD_NAME} | sed -e 's/-[a-z0-9]*-[a-z0-9]*$//g')
Ein gutes Beispiel dafür, wie Tracing in Envoy funktioniert, ist .
Der Endpunkt zum Senden von Tracing-Spans muss ebenfalls in den Startflags des Envoy-Proxys angegeben werden, beispielsweise: --zipkinAddress tracing-collector.tracing:9411
Irrtum Nummer zwei: Wir können komplette Traces von Anfragepfaden durch das System aus der Box kostengünstig erhalten.
Leider ist das nicht der Fall. Die Komplexität der Implementierung hängt davon ab, wie die Interaktion der Dienste bereits realisiert ist. Warum ist das so?
Der Punkt ist, dass es nicht ausreicht, den gesamten Datenverkehr nur abzufangen, damit der istio-proxy die Übereinstimmung zwischen eingehenden Anfragen an einen Dienst und den aus diesem Dienst herausgehenden Anfragen erkennen kann. Es ist erforderlich, einen bestimmten Verbindungsbezeichner zu haben. Im HTTP-envoy-proxy werden spezielle Header verwendet, anhand derer der Envoy versteht, welche Anfrage an den Dienst spezifische Anfragen an andere Dienste generiert. Die Liste solcher Header lautet:
- x-request-id,
- x-b3-traceid,
- x-b3-spanid,
- x-b3-parentspanid,
- x-b3-sampled,
- x-b3-flags,
- x-ot-span-context.
Wenn Sie einen zentralen Punkt haben, beispielsweise einen Basis-Client, in den Sie eine solche Logik einfügen können, ist alles in Ordnung. Sie müssen lediglich auf das Update dieser Bibliothek bei allen Clients warten. Aber wenn Sie ein sehr heterogenes System haben und keine Vereinheitlichung im Austausch zwischen den Diensten im Netzwerk besteht, wird das wahrscheinlich ein großes Problem sein. Ohne die Implementierung einer solchen Logik wird die gesamte Trace-Information lediglich "einlagig" sein. Das heißt, wir erhalten alle Interaktionen zwischen den Diensten, aber sie werden nicht zu einheitlichen Ketten im Netzwerk verbunden.
Fazit
Istio bietet ein hilfreiches Tool zum Sammeln von Tracing-Informationen im Netzwerk. Dabei ist jedoch zu beachten, dass Sie Ihr System anpassen und die Besonderheiten der Istio-Implementierung berücksichtigen müssen. Letztendlich müssen zwei wesentliche Punkte geklärt werden: die Definition des Anwendungsprotokolls (das vom Envoy-Proxy unterstützt werden muss) und die Konfiguration des Informationsflusses über die Zusammengehörigkeit von Anfragen zwischen Diensten (mittels Header, im Fall von HTTP-Protokoll). Wenn diese Fragen geklärt sind, haben wir ein leistungsstarkes Tool, das es ermöglicht, Informationen im Netzwerk transparent zu sammeln, selbst in sehr heterogenen Systemen, die in verschiedenen Programmiersprachen und Frameworks entwickelt wurden.
Im nächsten Artikel über Service Mesh werden wir eines der größten Probleme von Istio beleuchten – den hohen Speicherverbrauch jedes Sidecar-Proxy-Containers und diskutieren, wie man damit umgehen kann.
Quelle: habr.com
