1. Einführung

Letzte Aktualisierung:05.03.2021
Beobachtbarkeit der Anwendung
Beobachtbarkeit und OpenTelemetry
„Beobachtbarkeit“ ist ein Begriff, der ein Attribut eines Systems beschreibt. Ein System mit Beobachtbarkeit ermöglicht es Teams, ihr System aktiv zu debuggen. In diesem Zusammenhang sind die drei Säulen der Beobachtbarkeit (Logs, Messwerte und Traces) die grundlegende Instrumentierung für das System, um Beobachtbarkeit zu erlangen.
OpenTelemetry ist eine Reihe von Spezifikationen und SDKs, die die Instrumentierung und den Export von Telemetriedaten (Logs, Messwerte und Traces) beschleunigen, die für die Observability erforderlich sind. OpenTelemetry ist ein offener Standard und ein Community-Projekt unter der CNCF. Durch die Verwendung von Bibliotheken, die das Projekt und sein Ökosystem bereitstellen, können Entwickler ihre Anwendungen anbieterneutral und für mehrere Architekturen instrumentieren.
Verteilter Trace
Von Logs, Messwerten und Traces ist der Trace die Telemetrie, die die Latenz eines bestimmten Teils des Prozesses im System angibt. Gerade im Zeitalter von Mikrodiensten ist das verteilte Tracing ein wichtiger Faktor, um Latenzengpässe im gesamten verteilten System zu ermitteln.
Bei der Analyse verteilter Traces ist die Visualisierung der Trace-Daten der Schlüssel, um die Latenzen des Gesamtsystems auf einen Blick zu erfassen. Beim verteilten Tracing werden mehrere Aufrufe verarbeitet, um eine einzelne Anfrage an den Systemeinstiegspunkt in Form eines Trace mit mehreren Spans zu bearbeiten.
Ein Span stellt eine einzelne Arbeitseinheit dar, die in einem verteilten System ausgeführt wird, und zeichnet Start- und Endzeiten auf. Spans haben oft hierarchische Beziehungen zueinander. Im Bild unten sind alle kleineren Spans untergeordnete Spans eines großen /messages-Spans und werden zu einem Trace zusammengefasst, der den Pfad der Arbeit durch ein System zeigt.

Google Cloud Trace ist eine der Optionen für das Backend für verteiltes Tracing und ist gut in andere Produkte in Google Cloud eingebunden.
Umfang
In diesem Codelab instrumentieren Sie Trace-Informationen in den Diensten namens „Shakesapp“, die in einem Kubernetes-Cluster in Google Kubernetes Engine ausgeführt werden. Die Architektur von Shakesapp ist wie unten beschrieben:

- Der Client sendet einen Abfragestring an den Server.
- Der Server akzeptiert die Anfrage vom Client, ruft alle Werke von Shakespeare im Textformat aus Google Cloud Storage ab, sucht nach den Zeilen, die die Anfrage enthalten, und gibt die Nummer der Zeile zurück, die mit dem Client übereinstimmt.
Sie instrumentieren die Trace-Informationen für die gesamte Anfrage.
Lerninhalte
- Erste Schritte mit den OpenTelemetry Trace-Bibliotheken in einem Python-Projekt
- Span mit der Bibliothek erstellen
- Spannenkontexte über das Netzwerk zwischen App-Komponenten weitergeben
- Trace-Daten an Google Cloud Trace senden
- Trace in Google Cloud Trace analysieren
In diesem Codelab wird beschrieben, wie Sie Ihre Mikrodienste instrumentieren. Dieses Beispiel enthält nur drei Komponenten (Load Generator, Client und Server), damit es leicht nachzuvollziehen ist. Sie können den in diesem Codelab beschriebenen Prozess jedoch auch auf komplexere und größere Systeme anwenden.
Voraussetzungen
- Kenntnisse von Python 3
2. Einrichtung und Anforderungen
Umgebung zum selbstbestimmten Lernen einrichten
Wenn Sie noch kein Google-Konto (Gmail oder Google Apps) haben, müssen Sie eines erstellen. Melden Sie sich in der Google Cloud Console ( console.cloud.google.com) an und erstellen Sie ein neues Projekt.
Wenn Sie bereits ein Projekt haben, klicken Sie oben links in der Console auf das Drop-down-Menü zur Projektauswahl:

Klicken Sie im angezeigten Dialogfeld auf die Schaltfläche „NEUES PROJEKT“, um ein neues Projekt zu erstellen:

Wenn Sie noch kein Projekt haben, wird ein Dialogfeld wie das folgende angezeigt, in dem Sie Ihr erstes Projekt erstellen können:

Im nachfolgenden Dialogfeld zum Erstellen von Projekten können Sie die Details Ihres neuen Projekts eingeben:

Merken Sie sich die Projekt-ID. Sie ist für alle Google Cloud-Projekte ein eindeutiger Name. Der Name oben ist bereits vergeben und kann nicht verwendet werden. Sie wird später in diesem Codelab als PROJECT_ID bezeichnet.
Als Nächstes müssen Sie, falls noch nicht geschehen, die Abrechnung in der Entwicklerkonsole aktivieren, um Google Cloud-Ressourcen verwenden zu können, und die Cloud Trace API aktivieren.

Dieses Codelab sollte Sie nicht mehr als ein paar Dollar kosten, aber es könnte mehr sein, wenn Sie sich für mehr Ressourcen entscheiden oder wenn Sie sie laufen lassen (siehe Abschnitt „Bereinigen“ am Ende dieses Dokuments). Die Preise für Google Cloud Trace, Google Kubernetes Engine und Google Artifact Registry finden Sie in der offiziellen Dokumentation.
- Preise für Google Cloud Observability
- Preise | Kubernetes Engine-Dokumentation
- Artifact Registry – Preise | Artifact Registry-Dokumentation
Neuen Nutzern der Google Cloud Platform steht eine kostenlose Testversion mit einem Guthaben von 300$ zur Verfügung. Dieses Codelab sollte damit vollständig kostenlos sein.
Google Cloud Shell einrichten
Während Sie Google Cloud und Google Cloud Trace von Ihrem Laptop aus per Fernzugriff nutzen können, wird in diesem Codelab Google Cloud Shell verwendet, eine Befehlszeilenumgebung, die in der Cloud ausgeführt wird.
Diese Debian-basierte virtuelle Maschine verfügt über alle Entwicklungstools, die Sie benötigen. Sie bietet ein Basisverzeichnis mit 5 GB nichtflüchtigem Speicher und läuft in Google Cloud, was die Netzwerkleistung und Authentifizierung erheblich verbessert. Für dieses Codelab benötigen Sie also nur einen Browser (es funktioniert auch auf einem Chromebook).
Klicken Sie zum Aktivieren von Cloud Shell in der Cloud Console einfach auf „Cloud Shell aktivieren“
. Die Bereitstellung und Verbindung mit der Umgebung sollte nur wenige Augenblicke dauern.


Sobald die Verbindung mit der Cloud Shell hergestellt ist, sehen Sie, dass Sie bereits authentifiziert sind und für das Projekt schon Ihre PROJECT_ID eingestellt ist.
gcloud auth list
Befehlsausgabe
Credentialed accounts: - <myaccount>@<mydomain>.com (active)
gcloud config list project
Befehlsausgabe
[core] project = <PROJECT_ID>
Wenn das Projekt aus irgendeinem Grund nicht festgelegt ist, führen Sie einfach den folgenden Befehl aus:
gcloud config set project <PROJECT_ID>
Suchst du nach deinem PROJECT_ID? Sehen Sie nach, welche ID Sie in den Einrichtungsschritten verwendet haben, oder suchen Sie sie im Cloud Console-Dashboard:

In Cloud Shell werden auch einige Umgebungsvariablen standardmäßig festgelegt, die für zukünftige Befehle nützlich sein können.
echo $GOOGLE_CLOUD_PROJECT
Befehlsausgabe
<PROJECT_ID>
Legen Sie zum Schluss die Standardzone und die Projektkonfiguration fest.
gcloud config set compute/zone us-central1-f
Sie können verschiedene Zonen auswählen. Weitere Informationen finden Sie unter Regionen und Zonen.
Python-Einrichtung
In diesem Codelab verwenden wir „poetry“, um Paketversionen genau zu verwalten. Führen Sie den folgenden Befehl in Cloud Shell aus:
curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python3 - source $HOME/.poetry/env
Google Kubernetes-Cluster einrichten
In diesem Codelab führen Sie einen Cluster von Mikrodiensten in Google Kubernetes Engine (GKE) aus. In diesem Codelab gehen wir so vor:
- Baseline-Projekt in Cloud Shell herunterladen
- Mikrodienste in Containern erstellen
- Container in Google Artifact Registry (GAR) hochladen
- Container in GKE bereitstellen
- Quellcode von Diensten für die Trace-Instrumentierung ändern
- Zu Schritt 2
Kubernetes Engine aktivieren
Zuerst richten wir einen Kubernetes-Cluster ein, in dem Shakesapp in GKE ausgeführt wird. Dazu müssen wir GKE aktivieren. Rufen Sie das Menü „Kubernetes Engine“ auf und klicken Sie auf die Schaltfläche „AKTIVIEREN“.

Jetzt können Sie einen Kubernetes-Cluster erstellen.
Kubernetes-Cluster erstellen
Führen Sie in Cloud Shell den folgenden Befehl aus, um einen Kubernetes-Cluster zu erstellen. Prüfen Sie, ob der Zonenwert in der Region liegt, die Sie zum Erstellen des Artifact Registry-Repositorys verwendet haben. Ändern Sie den Zonenwert us-central1-f, wenn Ihre Repository-Region die Zone nicht abdeckt.
gcloud container clusters create otel-trace-codelab --zone us-central1-f \ --num-nodes 1 \ --machine-type e2-highcpu-4
Befehlsausgabe
Creating cluster otel-trace-codelab in us-central1-f... Cluster is being health-checked (master is healthy)...done. Created [https://container.googleapis.com/v1/projects/psychic-order-307806/zones/us-central1-f/clusters/otel-trace-codelab]. To inspect the contents of your cluster, go to: https://console.cloud.google.com/kubernetes/workload_/gcloud/us-central1-f/otel-trace-codelab?project=psychic-order-307806 kubeconfig entry generated for otel-trace-codelab. NAME LOCATION MASTER_VERSION MASTER_IP MACHINE_TYPE NODE_VERSION NUM_NODES STATUS otel-trace-codelab us-central1-f 1.18.12-gke.1210 104.154.162.176 e2-medium 1.18.12-gke.1210 3 RUNNING
Artifact Registry und Skaffold einrichten
Jetzt haben wir einen Kubernetes-Cluster, der bereit für die Bereitstellung ist. Als Nächstes bereiten wir eine Container Registry für das Pushen und Bereitstellen von Containern vor. Für diese Schritte müssen wir GAR und Skaffold einrichten.
Artifact Registry einrichten
Rufen Sie das Menü von „Artifact Registry“ auf und drücken Sie die Schaltfläche „AKTIVIEREN“.

Nach kurzer Zeit wird der Repository-Browser von GAR angezeigt. Klicken Sie auf die Schaltfläche „REPOSITORY ERSTELLEN“ und geben Sie den Namen des Repositorys ein.

In diesem Codelab nenne ich das neue Repository trace-codelab. Das Format des Artefakts ist „Docker“ und der Standorttyp ist „Region“. Wählen Sie die Region aus, die der Region entspricht, die Sie für die Google Compute Engine-Standardzone festgelegt haben. Im obigen Beispiel wurde „us-central1-f“ ausgewählt. Hier wählen wir also „us-central1 (Iowa)“ aus. Klicken Sie dann auf die Schaltfläche „ERSTELLEN“.

Im Repository-Browser wird jetzt „trace-codelab“ angezeigt.

Wir kehren später hierher zurück, um den Registrierungspfad zu prüfen.
Skaffold einrichten
Skaffold ist ein praktisches Tool, wenn Sie Mikrodienste entwickeln, die in Kubernetes ausgeführt werden. Skaffold übernimmt den Workflow zum Erstellen, Übertragen und Bereitstellen von Anwendungscontainern mit einer kleinen Anzahl von Befehlen. Skaffold verwendet standardmäßig Docker Registry als Container-Registry. Sie müssen Skaffold also so konfigurieren, dass GAR beim Übertragen von Containern erkannt wird.
Öffnen Sie Cloud Shell noch einmal und prüfen Sie, ob Skaffold installiert ist. (In Cloud Shell wird Skaffold standardmäßig in der Umgebung installiert.) Führen Sie den folgenden Befehl aus, um die Skaffold-Version zu sehen.
skaffold version
Befehlsausgabe
v1.20.0
Sie können jetzt das Standard-Repository für Skaffold registrieren. Um den Registrierungspfad zu erhalten, rufen Sie das Artifact Registry-Dashboard auf und klicken Sie auf den Namen des Repositorys, das Sie im vorherigen Schritt eingerichtet haben.

Oben auf der Seite sehen Sie dann Navigationspfade. Klicken Sie auf das Symbol
, um den Registrierungspfad in die Zwischenablage zu kopieren.

Wenn Sie auf die Schaltfläche „Kopieren“ klicken, wird unten im Browser ein Dialogfeld mit einer Meldung wie der folgenden angezeigt:
„us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab“ wurde kopiert
Kehren Sie zur Cloud Shell zurück. Führen Sie den Befehl skaffold config set default-repo mit dem Wert aus, den Sie gerade aus dem Dashboard kopiert haben.
skaffold config set default-repo us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab
Befehlsausgabe
set value default-repo to us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab for context gke_stackdriver-sandbox-3438851889_us-central1-b_stackdriver-sandbox
Außerdem müssen Sie die Registry für die Docker-Konfiguration konfigurieren. Führen Sie dazu diesen Befehl aus:
gcloud auth configure-docker us-central1-docker.pkg.dev --quiet
Befehlsausgabe
{
"credHelpers": {
"gcr.io": "gcloud",
"us.gcr.io": "gcloud",
"eu.gcr.io": "gcloud",
"asia.gcr.io": "gcloud",
"staging-k8s.gcr.io": "gcloud",
"marketplace.gcr.io": "gcloud",
"us-central1-docker.pkg.dev": "gcloud"
}
}
Adding credentials for: us-central1-docker.pkg.dev
Jetzt können Sie mit dem nächsten Schritt fortfahren und einen Kubernetes-Container in GKE einrichten.
Zusammenfassung
In diesem Schritt richten Sie Ihre Codelab-Umgebung ein:
- Cloud Shell einrichten
- Sie haben ein Artifact Registry-Repository für die Container Registry erstellt.
- Skaffold für die Verwendung der Container Registry einrichten
- Sie haben einen Kubernetes-Cluster erstellt, in dem die Mikrodienste des Codelabs ausgeführt werden.
Als Nächstes
Im nächsten Schritt erstellen Sie Ihre Microservices, übertragen sie per Push und stellen sie im Cluster bereit.
3. Mikrodienste erstellen, übertragen und bereitstellen
Codelab-Material herunterladen
Im vorherigen Schritt haben wir alle Voraussetzungen für dieses Codelab eingerichtet. Jetzt können Sie ganze Microservices darauf ausführen. Die Codelab-Materialien werden auf GitHub gehostet. Laden Sie sie mit dem folgenden Git-Befehl in die Cloud Shell-Umgebung herunter.
cd ~ git clone https://github.com/GoogleCloudPlatform/opentelemetry-trace-codelab-python.git
Die Verzeichnisstruktur des Projekts sieht so aus:
shakesapp-python
├── LICENSE
├── manifests
│ ├── client.yaml
│ ├── loadgen.yaml
│ └── server.yaml
├── proto
│ └── shakesapp.proto
├── skaffold.yaml
└── src
├── client
├── loadgen
└── server
- manifests: Kubernetes-Manifestdateien
- proto: Proto-Definition für die Kommunikation zwischen Client und Server
- src: Verzeichnisse für den Quellcode der einzelnen Dienste
- skaffold.yaml: Konfigurationsdatei für Skaffold
Skaffold-Befehl ausführen
Jetzt können Sie die Inhalte erstellen, per Push übertragen und im Kubernetes-Cluster bereitstellen, den Sie gerade erstellt haben. Das klingt nach mehreren Schritten, aber tatsächlich erledigt Skaffold alles für Sie. Versuchen Sie es mit dem folgenden Befehl:
cd shakesapp-python skaffold run --tail
Sobald Sie den Befehl ausführen, sehen Sie die Logausgabe von docker build und können bestätigen, dass die Dateien erfolgreich in das Repository übertragen wurden.
Befehlsausgabe
... ---> Running in c39b3ea8692b ---> 90932a583ab6 Successfully built 90932a583ab6 Successfully tagged us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/serverservice:step1 The push refers to repository [us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/serverservice] cc8f5a05df4a: Preparing 5bf719419ee2: Preparing 2901929ad341: Preparing 88d9943798ba: Preparing b0fdf826a39a: Preparing 3c9c1e0b1647: Preparing f3427ce9393d: Preparing 14a1ca976738: Preparing f3427ce9393d: Waiting 14a1ca976738: Waiting 3c9c1e0b1647: Waiting b0fdf826a39a: Layer already exists 88d9943798ba: Layer already exists f3427ce9393d: Layer already exists 3c9c1e0b1647: Layer already exists 14a1ca976738: Layer already exists 2901929ad341: Pushed 5bf719419ee2: Pushed cc8f5a05df4a: Pushed step1: digest: sha256:8acdbe3a453001f120fb22c11c4f6d64c2451347732f4f271d746c2e4d193bbe size: 2001
Nachdem alle Dienstcontainer übertragen wurden, werden die Kubernetes-Bereitstellungen automatisch gestartet.
Befehlsausgabe
sha256:b71fce0a96cea08075dc20758ae561cf78c83ff656b04d211ffa00cedb77edf8 size: 1997 Tags used in deployment: - serverservice -> us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/serverservice:step4@sha256:8acdbe3a453001f120fb22c11c4f6d64c2451347732f4f271d746c2e4d193bbe - clientservice -> us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/clientservice:step4@sha256:b71fce0a96cea08075dc20758ae561cf78c83ff656b04d211ffa00cedb77edf8 - loadgen -> us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/loadgen:step4@sha256:eea2e5bc8463ecf886f958a86906cab896e9e2e380a0eb143deaeaca40f7888a Starting deploy... - deployment.apps/clientservice created - service/clientservice created - deployment.apps/loadgen created - deployment.apps/serverservice created - service/serverservice created
Achtung: Wenn Sie den Fehler „No push access to specified image repository“ (Kein Push-Zugriff auf das angegebene Image-Repository) erhalten, prüfen Sie, ob der skaffold-Befehl versucht, Images auf Docker Hub (docker.io) zu übertragen, unabhängig von Ihrer Konfiguration des Standard-Repositorys in skaffold. In diesem Fall können Sie versuchen, die Option „–default-repo“ wie unten gezeigt zu „skaffold run“ hinzuzufügen.
$ skaffold run –tail –default-repo=us-central1-docker.pkg.dev/[project ID]/[repository name]
Nach dem Deployment werden die tatsächlichen Anwendungslogs, die in stdout ausgegeben werden, in jedem Container so angezeigt:
Befehlsausgabe
[server] {"event": "starting server: 0.0.0.0:5050", "severity": "info", "timestamp": "2021-03-17T05:25:56.758575Z"}
[client] [2021-03-17 05:25:54 +0000] [1] [INFO] Starting gunicorn 20.0.4
[client] [2021-03-17 05:25:54 +0000] [1] [INFO] Listening at: http://0.0.0.0:8080 (1)
[client] [2021-03-17 05:25:54 +0000] [1] [INFO] Using worker: threads
[client] [2021-03-17 05:25:54 +0000] [7] [INFO] Booting worker with pid: 7
[client] {"event": "server address is serverservice:5050", "severity": "info", "timestamp": "2021-03-17T05:25:54.888627Z"}
[client] {"event": "request to server with query: world", "severity": "info", "timestamp": "2021-03-17T05:26:11.550923Z"}
[server] {"event": "query: world", "severity": "info", "timestamp": "2021-03-17T05:26:11.567048Z"}
[loadgen] {"event": "check connectivity: http://clientservice:8080/_healthz", "severity": "info", "timestamp": "2021-03-17T05:26:11.533605Z"}
[loadgen] {"event": "/_healthz response: ok", "severity": "info", "timestamp": "2021-03-17T05:26:11.544267Z"}
[loadgen] {"event": "confirmed connection ot clientservice", "severity": "info", "timestamp": "2021-03-17T05:26:11.544527Z"}
Jetzt können Sie Ihre Anwendung mit OpenTelemetry für das verteilte Tracing der Dienste instrumentieren.
Zusammenfassung
In diesem Schritt haben Sie das Codelab-Material in Ihrer Umgebung vorbereitet und bestätigt, dass Skaffold wie erwartet ausgeführt wird.
Als Nächstes
Im nächsten Schritt ändern Sie den Quellcode des Loadgen-Dienstes, um die Trace-Informationen zu instrumentieren.
4. Instrumentierung für HTTP
Konzept der Trace-Instrumentierung und -Weitergabe
Bevor wir den Quellcode bearbeiten, möchte ich kurz anhand eines einfachen Diagramms erklären, wie verteilte Traces funktionieren.

In diesem Beispiel instrumentieren wir den Code, um Trace- und Span-Informationen nach Cloud Trace zu exportieren und den Trace-Kontext über die Anfrage vom Loadgen-Dienst zum Serverdienst weiterzugeben.
Die Anwendung muss Trace-Metadaten wie Trace-ID und Span-ID senden, damit Cloud Trace alle Spans mit derselben Trace-ID zu einem Trace zusammenfügen kann. Außerdem muss die Anwendung Trace-Kontexte (die Kombination aus Trace-ID und Span-ID des übergeordneten Spans) beim Anfordern von Downstream-Diensten weitergeben, damit diese wissen, welchen Trace-Kontext sie verarbeiten.
OpenTelemetry bietet folgende Vorteile:
- eindeutige Trace-ID und Span-ID zu generieren.
- Trace-ID und Span-ID ins Backend exportieren
- Trace-Kontexte an andere Dienste weiterzugeben
Ersten Span instrumentieren
Load-Generator-Dienst instrumentieren
Öffnen Sie Cloud Shell Editor, indem Sie oben rechts in Cloud Shell auf die Schaltfläche
klicken. Öffnen Sie src/loadgen/loadgen.py über den Explorer im linken Bereich und suchen Sie nach der Funktion main.
src/loadgen/loadgen.py
def main():
...
# start request loop to client service
logger.info("start client request loop")
addr = f"http://{target}"
while True:
logger.info("start request to client")
call_client(addr)
logger.info("end request to client")
time.sleep(2.0)
In der Funktion main sehen Sie die Schleife, in der die Funktion call_client aufgerufen wird. In der aktuellen Implementierung enthält der Abschnitt zwei Logzeilen, in denen der Beginn und das Ende des Funktionsaufrufs aufgezeichnet werden. Jetzt instrumentieren wir die Spanneninformationen, um die Latenz des Funktionsaufrufs zu erfassen.
Zuerst müssen Sie einen Span mit einer eindeutigen Trace-ID und Span-ID erstellen. OpenTelemetry bietet dafür eine praktische Bibliothek. Fügen Sie die folgenden Zeilen hinzu, um OpenTelemetry-Bibliotheken in Ihren Code zu importieren.
import structlog
+from opentelemetry import propagate, trace
+from opentelemetry.exporter.cloud_trace import CloudTraceSpanExporter
+from opentelemetry.sdk.trace import TracerProvider
+from opentelemetry.instrumentation.requests import RequestsInstrumentor
+from opentelemetry.sdk.trace.export import SimpleSpanProcessor
+from opentelemetry.propagators.cloud_trace_propagator import CloudTraceFormatPropagator
Da der Load-Generator die Clientanwendung in HTTP über das requests-Modul aufruft, verwenden wir das Erweiterungspaket für requests und aktivieren die Instrumentierung.
from opentelemetry.propagators.cloud_trace_propagator import CloudTraceFormatPropagator
+
+RequestsInstrumentor().instrument()
Richten Sie dann die Tracer-Instanz ein, die den Trace-Kontext und die Exporter-Einstellungen verarbeitet.
target = os.environ.get("CLIENT_ADDR", "0.0.0.0:8080")
+ exporter = CloudTraceSpanExporter()
+ trace.get_tracer_provider().add_span_processor(SimpleSpanProcessor(exporter))
+ tracer = trace.get_tracer(__name__)
+ propagate.set_global_textmap(CloudTraceFormatPropagator())
+ trace.set_tracer_provider(TracerProvider())
+
# connectivity check to client service
healthz = f"http://{target}/_healthz"
logger.info(f"check connectivity: {healthz}")
Da es sich hierbei um ein Codelab handelt, in dem Sie erfahren, wie die Trace-Instrumentierung funktioniert, konfigurieren wir den Tracer so, dass jede einzelne Anfrage aufgezeichnet und an das Backend gesendet wird. (SimpleSpanProcessor()) Dies ist nicht für Produktionsumgebungen geeignet. Ändern Sie diesen Teil daher unbedingt, wenn Sie Ihre Produktionsanwendung instrumentieren.
Jetzt können Sie Spans mit dem Tracer instrumentieren. Der Punkt ist, dass Sie explizit einen Span generieren müssen. Es gibt zwar zwei Zeilen, mit denen Ereignismetadaten in den Span eingefügt werden, aber Sie müssen die eindeutige Trace-ID und Span-ID nicht manuell generieren und in den Span einbetten.
logger.info("start client request loop")
addr = f"http://{target}"
while True:
- logger.info("start request to client")
- call_client(addr)
- logger.info("end request to client")
+ with tracer.start_as_current_span("loadgen") as root_span:
+ root_span.add_event(name="request_start")
+ logger.info("start request to client")
+ call_client(addr)
+ root_span.add_event(name="request_end")
+ logger.info("end request to client")
time.sleep(2.0)
Damit Docker Build die erforderlichen OpenTelemetry-Pakete abrufen kann, führen Sie den folgenden Befehl aus:
poetry add "opentelemetry-exporter-gcp-trace=^1.0.0rc0" poetry add "opentelemetry-propagator-gcp=^1.0.0rc0" poetry add "opentelemetry-instrumentation-requests=^0.20b0"
Sie können bestätigen, dass die entsprechende Abhängigkeitsbeschreibung in pyproject.toml geschrieben ist.
Kundenservice für Instrumente
Im vorherigen Abschnitt haben wir den Teil instrumentiert, der im folgenden Bild im roten Rechteck enthalten ist. Wir haben die Spanneninformationen im Load Generator-Dienst instrumentiert. Ähnlich wie beim Load Generator-Dienst müssen wir jetzt den Clientdienst instrumentieren. Der Unterschied zum Load-Generator-Dienst besteht darin, dass der Clientdienst die vom Load-Generator-Dienst im HTTP-Header weitergegebenen Trace-ID-Informationen extrahieren und die ID zum Generieren von Spans verwenden muss.

Öffnen Sie den Cloud Shell-Editor und fügen Sie die erforderlichen Module hinzu, wie wir es für den Load Generator-Dienst getan haben.
src/client/client.py
import flask
import grpc
import structlog
+from opentelemetry import propagate, trace
+from opentelemetry.exporter.cloud_trace import CloudTraceSpanExporter
+from opentelemetry.instrumentation.flask import FlaskInstrumentor
+from opentelemetry.sdk.trace import TracerProvider
+from opentelemetry.sdk.trace.export import SimpleSpanProcessor
+from opentelemetry.propagators.cloud_trace_propagator import \
+ CloudTraceFormatPropagator
import shakesapp_pb2
import shakesapp_pb2_grpc
Sie haben gerade FlaskInstrumentor importiert. Damit wird die automatische Instrumentierung für Flask-Anwendungen im Namen von Nutzern aktiviert, um HTTP-Header zu extrahieren und Trace-Kontexte mit einer einzigen Codezeile abzurufen. Die OpenTelemetry-Community bietet ähnliche nützliche Integrationen mit anderen wichtigen Bibliotheken. Weitere Informationen finden Sie in der offiziellen Dokumentation.
app = flask.Flask(__name__)
+FlaskInstrumentor().instrument_app(app)
Bevor Sie mit der Instrumentierung beginnen, müssen Sie die Tracer-Instanz wie im Load Generator-Dienst vorbereiten.
logger.info(f"server address is {SERVER_ADDR}")
+exporter = CloudTraceSpanExporter()
+trace.get_tracer_provider().add_span_processor(SimpleSpanProcessor(exporter))
+propagate.set_global_textmap(CloudTraceFormatPropagator())
+trace.set_tracer_provider(TracerProvider())
@app.route("/")
def main_handler():
....
Jetzt können Sie dem Handler die Instrumentierung hinzufügen. Suchen Sie nach main_handler() und ändern Sie den Teil, der die gRPC-Anfrage an den Serverservice sendet.
@app.route("/")
def main_handler():
q, count = random.choice(list(queries.items()))
# get Tracer
tracer = trace.get_tracer(__name__)
with tracer.start_as_current_span("client") as cur_span:
channel = grpc.insecure_channel(SERVER_ADDR)
stub = shakesapp_pb2_grpc.ShakespeareServiceStub(channel)
logger.info(f"request to server with query: {q}")
cur_span.add_event("server_call_start")
resp = stub.GetMatchCount(shakesapp_pb2.ShakespeareRequest(query=q))
cur_span.add_event("server_call_end")
if count != resp.match_count:
raise UnexpectedResultError(
f"The expected count for '{q}' was {count}, but result was {resp.match_count } obtained"
)
result = str(resp.match_count)
logger.info(f"matched count for '{q}' is {result}")
return result
Fügen Sie wie beim Load-Generator-Dienst die erforderlichen Pakete mit dem folgenden Befehl in pyproject.toml ein.
poetry add "opentelemetry-exporter-gcp-trace=^1.0.0rc0" poetry add "opentelemetry-propagator-gcp=^1.0.0rc0" poetry add "opentelemetry-instrumentation-flask=^0.20b0"
Starten Sie dann die Anwendung mit dem Befehl skaffold run und sehen Sie sich das Cloud Trace-Dashboard an:
skaffold run --tail
Nachdem Sie einige Build-, Push- und Bereitstellungsmeldungen gesehen haben, werden Anwendungslogs im JSON-Format angezeigt. Rufen Sie Cloud Trace > Trace-Liste auf, um zu prüfen, ob Sie die Trace-Informationen erhalten. Da der Dienst für die Generierung von Lasten Anfragen regelmäßig an den Clientdienst sendet und Sie Traces für alle Anfragen aktiviert haben, sehen Sie viele Punkte in der Traceliste.

Wenn Sie auf einen der Links klicken, wird ein Wasserfalldiagramm wie unten angezeigt, in dem die Latenz der einzelnen Teile während des Anfrage- und Antwortprozesses erläutert wird. Suchen Sie das Kästchen neben „Ereignisse anzeigen“. Wenn Sie es anklicken, werden die Anmerkungen im Wasserfalldiagramm angezeigt. Diese Anmerkungen haben Sie im Code mit der Methode span.add_event() eingefügt.

Möglicherweise stellen Sie fest, dass die Spans vom Serverservice nicht angezeigt werden. Das ist richtig, da wir Spans im Serverservice überhaupt nicht instrumentiert haben.
Zusammenfassung
In diesem Schritt haben Sie den Load-Generator-Dienst und den Clientdienst instrumentiert und bestätigt, dass Sie den Trace-Kontext erfolgreich über Dienste hinweg weitergeben und Informationen zu Spans aus beiden Diensten in Cloud Trace exportieren können.
Als Nächstes
Im nächsten Schritt instrumentieren Sie den Client- und den Serverdienst, um zu sehen, wie der Trace-Kontext über gRPC weitergegeben wird.
5. Instrumentierung für gRPC
Im vorherigen Schritt haben wir die erste Hälfte der Anfrage in diesen Mikrodiensten instrumentiert. In diesem Schritt versuchen wir, die gRPC-Kommunikation zwischen dem Client- und dem Serverdienst zu instrumentieren. (Grünes und violettes Rechteck im Bild unten)

Automatische Instrumentierung für gRPC-Client
Das Ökosystem von OpenTelemetry bietet viele praktische Bibliotheken, die Entwicklern bei der Instrumentierung von Anwendungen helfen. Im vorherigen Schritt haben wir die automatische Instrumentierung für das Modul „requests“ verwendet. In diesem Schritt verwenden wir die Bibliothek, um den Trace-Kontext über gRPC weiterzugeben.
src/client/client.py
import flask
import grpc
import structlog
from opentelemetry import propagate, trace
from opentelemetry.exporter.cloud_trace import CloudTraceSpanExporter
from opentelemetry.instrumentation.flask import FlaskInstrumentor
+from opentelemetry.instrumentation.grpc import GrpcInstrumentorClient
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import SimpleSpanProcessor
from opentelemetry.propagators.cloud_trace_propagator import \
CloudTraceFormatPropagator
import shakesapp_pb2
import shakesapp_pb2_grpc
app = flask.Flask(__name__)
FlaskInstrumentor().instrument_app(app)
+GrpcInstrumentorClient().instrument()
Für den Kundenservice ist der Aufwand für die Instrumentierung gering. Wir möchten den Trace-Kontext, also die Kombination aus Trace-ID und Span-ID des aktuellen Spans, über gRPC weitergeben. Wir rufen also GrpcInstrumentatorClient.instrument() auf, damit der gRPC-Client in der Handler-Funktion den Trace-Kontext in den HTTP-Header einbetten kann.
Achten Sie darauf, neue Abhängigkeiten mit dem Befehl poetry add zu pyproject.toml hinzuzufügen:
poetry add "opentelemetry-instrumentation-grpc=^0.20b0"
Automatische Instrumentierung für gRPC-Server
Wie beim gRPC-Client nennen wir das automatische Instrumentierung für gRPC-Server. Fügen Sie Importe wie die folgenden hinzu und rufen Sie GrpcInstrumentationServer().instrument() oben in der Datei auf.
Achtung: Rufen Sie
GrpcInstrumentationServe()
in diesem Schritt nicht
GrpcInstrumentationClient()
.
src/server/server.py
import grpc
import structlog
from google.cloud import storage
from grpc_health.v1 import health_pb2, health_pb2_grpc
+from opentelemetry import propagate, trace
+from opentelemetry.exporter.cloud_trace import CloudTraceSpanExporter
+from opentelemetry.instrumentation.grpc import GrpcInstrumentorServer
+from opentelemetry.sdk.trace import TracerProvider
+from opentelemetry.sdk.trace.export import SimpleSpanProcessor
+from opentelemetry.propagators.cloud_trace_propagator import CloudTraceFormatPropagator
import shakesapp_pb2
import shakesapp_pb2_grpc
BUCKET_NAME = "dataflow-samples"
BUCKET_PREFIX = "shakespeare/"
+# enable auto gRPC server trace instrumentation
+GrpcInstrumentorServer().instrument()
+
Als Nächstes fügen Sie den Exporter hinzu, um Trace-Informationen an das Cloud Trace-Backend zu senden. Fügen Sie den folgenden Code in die serve()-Funktion ein.
def serve():
+ # start trace exporter
+ trace.set_tracer_provider(TracerProvider())
+ trace.get_tracer_provider().add_span_processor(
+ SimpleSpanProcessor(CloudTraceSpanExporter())
+ )
+ propagators.set_global_textmap(CloudTraceFormatPropagator())
+
+ # add gRPC services to server
server = grpc.server(futures.ThreadPoolExecutor(max_workers=4))
service = ShakesappService()
shakesapp_pb2_grpc.add_ShakespeareServiceServicer_to_server(service, server)
health_pb2_grpc.add_HealthServicer_to_server(service, server)
Fügen Sie neu hinzugefügte Pakete dem Serverservice hinzu.
poetry add "opentelemetry-exporter-gcp-trace=^1.0.0rc0" poetry add "opentelemetry-instrumentation-grpc=^0.20b0" poetry add "opentelemetry-propagator-gcp=^1.0.0rc0" poetry add "opentelemetry-instrumentation=^0.20b0"
Mikrodienst ausführen und Trace bestätigen
Führen Sie dann den geänderten Code mit dem Skaffold-Befehl aus.
skaffold run --tail
Nun sehen Sie wieder eine Reihe von Traces auf der Seite „Trace-Liste“ von Cloud Trace. Klicken Sie auf einen der Traces. Sie sehen nun Spans für die Anfrage vom Load-Generator-Dienst zum Serverdienst.

Zusammenfassung
In diesem Schritt haben Sie die gRPC-basierte Kommunikation mit Unterstützung der OpenTelemetry-Ökosystembibliotheken instrumentiert. Außerdem haben Sie bestätigt, dass der im Load Generator-Dienst generierte Trace-Kontext erfolgreich an den Serverdienst gesendet wurde.
6. Glückwunsch
Sie haben mit OpenTelemetry verteilte Traces erstellt und die Anfragelatenzen für den Mikrodienst in Google Cloud Trace bestätigt.
Bei den erweiterten Übungen können Sie die folgenden Themen selbst ausprobieren.
- Bei der aktuellen Implementierung werden alle Spans gesendet, die von der Systemdiagnose generiert werden. Wie filtere ich diese Spans aus Cloud Traces heraus? Hier finden Sie einen Hinweis.
- Ereignislogs mit Spans in Beziehung setzen und sehen, wie das in Google Cloud Trace und Google Cloud Logging funktioniert. Hier finden Sie einen Hinweis.
- Ersetzen Sie einen Dienst durch den Dienst in einer anderen Sprache und versuchen Sie, ihn mit OpenTelemetry für diese Sprache zu instrumentieren.
Achtung: Google Kubernetes Engine und Google Artifact Registry verbrauchen die Ressource ständig.
Aufräumen
Nach dieser Codelab-Anleitung sollten Sie den Kubernetes-Cluster beenden und das Projekt löschen, damit Ihnen keine unerwarteten Gebühren für Google Kubernetes Engine, Google Cloud Trace und Google Artifact Registry in Rechnung gestellt werden.
Löschen Sie zuerst den Cluster mit dem folgenden Befehl:
skaffold delete
Befehlsausgabe
Cleaning up... - deployment.apps "clientservice" deleted - service "clientservice" deleted - deployment.apps "loadgen" deleted - deployment.apps "serverservice" deleted - service "serverservice" deleted
Nachdem Sie den Cluster gelöscht haben, wählen Sie im Menübereich „IAM & Admin“ > „Einstellungen“ aus und klicken Sie dann auf die Schaltfläche „HERUNTERFAHREN“.

Geben Sie dann die Projekt-ID (nicht den Projektnamen) in das Formular im Dialogfeld ein und bestätigen Sie das Herunterfahren.