Letzte Woche Wir haben die grundlegenden Komponenten des Service Mesh Istio betrachtet, das System kennengelernt und die häufigsten Fragen beantwortet, die zu Beginn der Arbeit mit Istio auftreten. In diesem Teil werden wir uns ansehen, 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 die Worte 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 läuft. Es scheint, als könnten wir jetzt problemlos Informationen über alle Netzwerkinteraktionen im Netzwerk senden. Leider gibt es in der Realität viele nuancierte Punkte zu beachten. Lassen Sie uns diese näher betrachten.
Irrtum Nummer eins: Wir können kostenlos Daten über Netzwerkzugriffe erhalten.
In Wirklichkeit können wir relativ kostenlos nur die verbundenen Knoten unseres Systems und die Rate der Daten, die zwischen den Diensten übertragen werden (im Grunde nur die Anzahl von Bytes pro Zeiteinheit), erhalten. In den meisten Fällen kommunizieren unsere Dienste jedoch über ein bestimmtes Anwendungsprotokoll, wie HTTP, gRPC, Redis und so weiter. Und natürlich möchten wir die Tracing-Informationen genau zu diesen Protokollen sehen, die Anfrage-Raten und nicht die Datenraten. Wir wollen die Latenz der Anfragen in unserem Protokoll verstehen. Schließlich wollen wir den gesamten Weg sehen, den eine Anfrage von dem Moment an, in dem sie unser System betritt, bis zur Antwort des Benutzers zurücklegt. Diese Aufgabe gestaltet sich dann nicht mehr so einfach.
Zunächst wollen wir betrachten, wie der Versand von Tracing-Spans aus architektonischer Sicht in Istio aussieht. Wie wir uns aus dem ersten Teil erinnern, gibt es einen speziellen Komponente in Istio, der Mixer heißt, um Telemetrie zu sammeln. In der aktuellen Version 1.0.* erfolgt der Versand jedoch direkt von den Proxy-Servern, genauer gesagt vom Envoy-Proxy. Der Envoy-Proxy unterstützt die native Absendung von Tracing-Spans über das Zipkin-Protokoll. Andere Protokolle können zwar hinzugefügt werden, allerdings nur über ein Plugin. 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 versenden wollen, müssen wir unser eigenes Istio-Proxy-Image erstellen. Es gibt Unterstützung für benutzerdefinierte Plugins für Istio-Proxy, jedoch befindet sich diese noch in der Alpha-Phase. Daher, wenn wir viele benutzerdefinierte Einstellungen vermeiden möchten, verringert sich der Kreis der verwendeten Technologien für die Speicherung und den Empfang von Tracing-Spans. Momentan können wir nur das Zipkin selbst oder Jaeger verwenden, wobei alles über ein zipkin-kompatibles Protokoll gesendet wird (was deutlich weniger effizient ist). Das Zipkin-Protokoll sieht vor, dass alle Tracing-Informationen an Sammler über HTTP gesendet werden, was recht aufwändig ist.
Wie ich bereits sagte, möchten wir die Protokolle auf Anwendungsebene nachverfolgen. Das bedeutet, dass die Proxy-Server, die neben jedem Dienst stehen, verstehen müssen, welche Interaktion derzeit stattfindet. Standardmäßig konfiguriert Istio für alle Ports den Typ Plain TCP, was bedeutet, dass keine Traces gesendet werden. Um Traces zu versenden, müssen wir zunächst diese Option in der Haupt-Mesh-Konfiguration 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: nginxEs ist auch möglich, zusammengesetzte Namen zu verwenden, z. B. http-magic (Istio sieht http und erkennt diesen Port als http-Endpunkt). Das Format ist so: proto-extra.
Um nicht eine große Anzahl von Konfigurationen patchen zu müssen, um das Protokoll zu bestimmen, kann man einen schmutzigen Workaround nutzen: das Pilot-Komponente patchen, während sie gerade . Am Ende muss diese Logik natürlich auf die Standardlogik geändert und auf die Namenskonvention aller Ports umgestellt werden.
Um zu verstehen, ob das Protokoll wirklich korrekt definiert ist, muss man in einen der Sidecar-Container mit dem Envoy-Proxy einsteigen und eine Anfrage an den Admin-Interface-Port von Envoy mit der Location /config_dump senden. In der erhaltenen Konfiguration muss man das Feld operation des entsprechenden Dienstes betrachten. Es wird in Istio als Identifikator verwendet, wohin die Anfrage geleitet wird. Um den Wert dieses Parameters in Istio anzupassen (wir werden ihn später in unserem Tracing-System sehen), ist es notwendig, beim Start des Sidecar-Containers das Flag serviceCluster anzugeben. Zum Beispiel kann man es so aus den Variablen, die man aus der Downward-API von Kubernetes erhält, berechnen:
--serviceCluster ${POD_NAMESPACE}.$(echo ${POD_NAME} | sed -e 's/-[a-z0-9]*-[a-z0-9]*$//g')
Ein gutes Beispiel zum Verständnis, wie Tracing in Envoy funktioniert, ist .
Der Endpunkt zum Senden von Tracing-Spans muss ebenfalls in den Flags zum Starten des Envoy-Proxys angegeben werden, zum Beispiel: --zipkinAddress tracing-collector.tracing:9411
Irrtum Nummer zwei: Wir können aus der Box günstige vollständige Traces der Anfrageverarbeitung durch das System erhalten.
Leider ist das nicht der Fall. Die Komplexität der Implementierung hängt davon ab, wie Ihre Interaktion zwischen den Diensten bereits umgesetzt ist. Warum ist das so?
Der Grund ist, dass der Istio-Proxy, um die Zuordnung eingehender Anfragen an einen Dienst mit den aus demselben Dienst herausgehenden Anfragen zu verstehen, nicht einfach den gesamten Verkehr abfangen kann. Es wird ein Identifikator benötigt. Im HTTP-Envoy-Proxy werden spezielle Header verwendet, anhand derer Envoy versteht, welcher spezifische Anfrage eines Dienstes konkrete Anfragen an andere Dienste auslöst. Die Liste dieser 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, zum Beispiel einen Basisclient, in dem Sie solche Logik hinzufügen können, ist alles in Ordnung. Sie müssen nur auf das Update dieser Bibliothek bei allen Clients warten. Aber wenn Sie ein sehr heterogenes System haben und keine Vereinheitlichung im Netzwerkzugang zwischen den Diensten existiert, wird das wahrscheinlich ein großes Problem sein. Ohne die Hinzufügung solcher Logik wird alle Tracing-Information nur „einadrig“ sein. Das heißt, wir werden alle Interaktionen zwischen den Diensten erhalten, aber sie werden nicht zu einem einzigen Durchlauf durch das Netzwerk zusammengeführt.
Fazit
Istio bietet ein nützliches Werkzeug zur Sammlung von Tracing-Informationen über das Netzwerk, jedoch muss man verstehen, dass es notwendig ist, das eigene System anzupassen und die Besonderheiten der Istio-Implementierung zu berücksichtigen. Letztendlich müssen zwei wesentliche Aspekte geklärt werden: die Bestimmung des Anwendungsprotokolls (das vom Envoy-Proxy unterstützt werden muss) und die Konfiguration der Weiterleitung von Informationen über die Anfragenverknüpfung im Service aus den Anfragen des Services (mithilfe von Headern, im Falle des HTTP-Protokolls). Wenn diese Fragen geklärt sind, erhalten wir ein leistungsstarkes Werkzeug, mit dem man Informationen transparent aus dem Netzwerk sammeln kann, selbst in sehr heterogenen Systemen, die in vielen verschiedenen Sprachen und Frameworks geschrieben sind.
Im nächsten Artikel über Service Mesh werden wir eines der größten Probleme von Istio betrachten – den hohen Speicherverbrauch jedes Sidecar-Proxy-Containers und diskutieren, wie man damit umgehen kann.
Quelle: habr.com
