Bei Diensten, die auf Kubernetes ausgeführt werden, ermöglicht ein Service Mesh wie Istio das verteilte Tracing von Dienst-zu-Dienst-Traffic ohne spezielle Instrumentierung. Möglicherweise möchten Sie jedoch mehr Kontrolle über die Traces haben. Eventuell müssen Sie die internen Strukturen der Anwendung in den Trace-Informationen erfassen oder Code verfolgen, der nicht in Kubernetes ausgeführt wird. OpenCensus ist eine Open-Source-Bibliothek, die die Instrumentierung verteilter Mikrodienstanwendungen ermöglicht, um Traces und Messwerte für eine Vielzahl von Sprachen, Plattformen und Umgebungen zu erfassen.
Diese Anleitung richtet sich an Entwickler, SREs und DevOps-Entwickler, die die Grundlagen des verteilten Tracings verstehen möchten, um sie auf ihre Dienste anzuwenden und deren Beobachtbarkeit zu verbessern.
In dieser Anleitung wird davon ausgegangen, dass Sie mit Folgendem vertraut sind:
- Go (Programmiersprache)
- Google Kubernetes Engine (GKE)
Die State of DevOps-Berichte haben Faktoren aufgezeigt, die die Leistung bei der Softwarebereitstellung beeinflussen. Diese Anleitung hilft Ihnen bei den folgenden Faktoren:
Ziele
- GKE-Cluster erstellen und Beispielanwendung bereitstellen
- OpenCensus-Instrumentierungscode prüfen
- Von der Instrumentierung generierte Traces und Logs prüfen
Referenzarchitektur
Das folgende Diagramm zeigt die Architektur, die Sie in dieser Anleitung bereitstellen:
Wie im obigen Diagramm dargestellt, erstellen Sie zwei GKE-Cluster und stellen in jedem der Cluster eine Anwendung bereit. Nutzertraffic wird an die Front-End-Anwendung im Front-End-Cluster gesendet. Der Front-End-Pod im Front-End-Cluster kommuniziert mit dem Back-End-Pod im Back-End-Cluster. Der Back-End-Pod ruft einen externen API-Endpunkt auf.
Sie verwenden Cloud Build – eine vollständig verwaltete Plattform für Continuous Integration, Continuous Delivery und die kontinuierliche Bereitstellung –, um aus dem Beispielcode Container-Images zu erstellen und in Container Registry zu speichern. Zum Zeitpunkt der Bereitstellung werden die Images von den GKE-Clustern aus Container Registry abgerufen.
Beispiel-App
Die Beispielanwendung in dieser Anleitung besteht aus zwei Mikrodiensten, die in Go geschrieben sind.
Der Front-End-Dienst akzeptiert HTTP-Anfragen an die URL /
und ruft den Back-End-Dienst auf. Die Adresse des Back-End-Dienstes wird durch die Umgebungsvariable BACKEND
definiert. Der Wert dieser Variablen wird in einem ConfigMap-Objekt festgelegt, das Sie erstellen.
Der Back-End-Dienst akzeptiert HTTP-Anfragen an die URL /
und ruft eine externe URL auf, wie in der Umgebungsvariablen DESTINATION_URL
definiert. Der Wert der Variablen wird über ein ConfigMap
-Objekt festgelegt. Nach Abschluss des externen Aufrufs gibt der backend
-Dienst den HTTP-Statuscode, z. B. 200,
, zurück an den Aufrufer.
Informationen zu Traces, Spans und Kontext
Das Konzept des verteilten Tracings ist am besten in der von Google veröffentlichten Dapper-Studie beschrieben. In dieser zeigt das folgende Diagramm fünf Spans in einem Trace.
Das Diagramm zeigt eine Front-End-Anfrage, die zwei Back-End-Anfragen stellt. Für den zweiten Back-End-Aufruf sind zwei Hilfsaufrufe erforderlich. Jeder Aufruf ist mit seiner eigenen Span-ID sowie der ID des übergeordneten Spans gekennzeichnet.
Ein Trace ist die Gesamtzahl der Informationen, die beschreiben, wie ein verteiltes System auf eine Nutzeranfrage reagiert. Traces bestehen aus Spans, wobei jeder Span ein bestimmtes Anfrage- und Antwortpaar darstellt, das an der Verarbeitung der Nutzeranfrage beteiligt ist. Der übergeordnete Span beschreibt die vom Endnutzer beobachtete Latenz. Jede der untergeordneten Bereiche beschreibt, wie ein bestimmter Dienst im verteilten System aufgerufen und beantwortet wurde, wobei jeweils Latenzinformationen erfasst werden.
Eine Herausforderung beim Tracing in verteilten Systemen besteht darin, dass Informationen zur ursprünglichen Front-End-Anfrage nicht automatisch weitergegeben werden, wenn nachfolgende Anfragen an verschiedene Back-End-Dienste gestellt werden. In Go können Sie Anfragen mit Kontext (der Cluster-IP-Adresse und den Anmeldedaten) stellen. Dies bedeutet, dass zusätzliche Informationen in den HTTP-Header geladen werden. Das Konzept des Kontexts wird mit OpenCensus erweitert, um Span-Kontext einzubeziehen, wobei Sie bei jeder nachfolgenden Anfrage Informationen über den übergeordneten Span aufnehmen können. Sie können anschließend untergeordnete Bereiche anfügen, um den gesamten Trace zu erstellen. So können Sie sehen, wie die Nutzeranfrage das System durchlaufen hat und schließlich an den Nutzer zurückgegeben wurde.
Der Kontext ist nicht spezifisch für Go. Weitere Informationen zu den Sprachen, in denen OpenCensus das Feature SpanContext
unterstützt, finden Sie in der Feature-Matrix von OpenCensus.
Kosten
In dieser Anleitung werden die folgenden kostenpflichtigen Komponenten von Google Cloud verwendet:
Mit dem Preisrechner können Sie eine Kostenschätzung für Ihre voraussichtliche Nutzung vornehmen. Neuen Google Cloud-Nutzern steht möglicherweise eine kostenlose Testversion zur Verfügung.
Nach Abschluss dieser Anleitung können Sie weitere Kosten vermeiden, indem Sie die erstellten Ressourcen löschen. Weitere Informationen finden Sie unter Bereinigen.
Vorbereitung
-
Melden Sie sich bei Ihrem Google-Konto an.
Wenn Sie noch kein Konto haben, melden Sie sich hier für ein neues Konto an.
-
Wählen Sie in der Google Cloud Console auf der Seite der Projektauswahl ein Google Cloud-Projekt aus oder erstellen Sie eines.
-
Die Abrechnung für das Cloud-Projekt muss aktiviert sein. So prüfen Sie, ob die Abrechnung für Ihr Projekt aktiviert ist.
- GKE, Cloud Trace, Cloud Build, Cloud Storage, and Container Registry APIs aktivieren.
Umgebung einrichten
In diesem Abschnitt richten Sie Ihre Umgebung mit den Tools ein, die Sie in dieser Anleitung verwenden. Alle Terminalbefehle in dieser Anleitung werden über Cloud Shell ausgeführt.
-
Aktivieren Sie Cloud Shell in der Cloud Console.
Unten in der Cloud Console wird eine Cloud Shell-Sitzung gestartet und eine Eingabeaufforderung angezeigt. Cloud Shell ist eine Shell-Umgebung, in der das Cloud SDK einschließlich des
gcloud
-Befehlszeilentools vorinstalliert ist. Die Werte sind bereits für Ihr aktuelles Projekt festgelegt. Das Initialisieren der Sitzung kann einige Sekunden dauern. - Legen Sie Umgebungsvariablen fest:
export PROJECT_ID=$(gcloud config list --format 'value(core.project)' 2>/dev/null)
- Laden Sie die erforderlichen Dateien für diese Anleitung herunter. Klonen Sie dafür das folgende Git-Repository:
git clone https://github.com/GoogleCloudPlatform/gke-observability-tutorials.git cd $HOME/gke-observability-tutorials/gke-opencensus-stackdriver/go/http WORKDIR=$(pwd)
Legen Sie den Repository-Ordner als
$WORKDIR
-Ordner fest, über den Sie alle Aufgaben für diese Anleitung ausführen. Wenn Sie die Anleitung durchgearbeitet haben, können Sie den Ordner löschen.
Tools installieren
Installieren Sie in Cloud Shell
kubectx
undkubens
.git clone https://github.com/ahmetb/kubectx $WORKDIR/kubectx export PATH=$PATH:$WORKDIR/kubectx
Mithilfe dieser Tools können Sie mit mehreren Kubernetes-Clustern, Kontexten und Namespaces arbeiten.
Installieren Sie in Cloud Shell Apache Bench, ein Open-Source-Tool zur Lastgenerierung:
sudo apt-get install apache2-utils
GKE-Cluster erstellen
In diesem Abschnitt erstellen Sie zwei GKE-Cluster, in denen Sie die Beispielanwendung bereitstellen. GKE-Cluster werden standardmäßig nur mit Schreibzugriff auf die Cloud Trace API erstellt, sodass Sie den Zugriff beim Erstellen der Cluster nicht definieren müssen.
Erstellen Sie die Cluster in Cloud Shell:
gcloud container clusters create backend-cluster \ --zone=us-west1-a --enable-stackdriver-kubernetes \ --verbosity=none --async gcloud container clusters create frontend-cluster \ --zone=us-west1-a --enable-stackdriver-kubernetes \ --verbosity=none
In dieser Anleitung befinden sich die Cluster in der Zone
us-west1-a
. Weitere Informationen hierzu finden Sie unter Geografie und Regionen.Rufen Sie die Anmeldedaten für die Cluster ab und speichern Sie sie lokal:
gcloud container clusters get-credentials backend-cluster --zone=us-west1-a gcloud container clusters get-credentials frontend-cluster --zone=us-west1-a
Benennen Sie die Kontexte der Cluster um, damit Sie später in der Anleitung leichter darauf zugreifen können:
kubectx backend=gke_${PROJECT_ID}_us-west1-a_backend-cluster kubectx frontend=gke_${PROJECT_ID}_us-west1-a_frontend-cluster
OpenCensus-Instrumentierung prüfen
Prüfen Sie in den folgenden Abschnitten den Code der Beispielanwendung, um zu erfahren, wie Sie mithilfe der Kontextweitergabe Spans aus mehreren Anfragen an einen einzelnen übergeordneten Trace anhängen können.
Front-End-Code prüfen
Der Code des Front-End-Dienstes enthält drei Importe:
- Die Importe
go.opencensus.io/plugin/ochttp
undgo.opencensus.io/plugin/ochttp/propagation/tracecontext
enthalten das Plug-inochttp
, das Kontext an Anfragen weitergibt. Der Kontext enthält Informationen über den Trace, an den nachfolgende Spans angehängt werden. - Der Import
contrib.go.opencensus.io/exporter/stackdriver
exportiert Traces in Cloud Trace. Die Liste der Back-Ends, die OpenCensus unterstützt, finden Sie unter Exporter. - Der Import
github.com/gorilla/mux
ist die Bibliothek, die die Beispielanwendung für die Anfrageverarbeitung verwendet.
- Die Importe
Die Funktion
main()
richtet den Export von Traces in Cloud Trace ein und verwendet einen Mux-Router, um Anfragen an die URL/
zu verarbeiten:- Der Handler verwendet die HTTP-Weitergabe, um Kontexte zu Anfragen hinzuzufügen.
- In dieser Anleitung ist das Sampling auf
AlwaysSample
gesetzt. In OpenCensus erfolgt das Sampling von Traces standardmäßig mit einer vordefinierten Rate, die Sie mit diesem Parameter steuern können.
Prüfen Sie die
mainHandler()
-Funktion:Diese Funktion erstellt den Haupt-Span, um die gesamte Anfragelatenz zu erfassen. Nachfolgende Spans hängen Sie an den Haupt-Span an.
// create root span ctx, rootspan := trace.StartSpan(context.Background(), "incoming call") defer rootspan.End()
Zur zeitlichen Messung des
backend
-Aufrufs wird ein untergeordneter Span erstellt.// create child span for backend call _, childspan := trace.StartSpan(ctx, "call to backend") defer childspan.End()
Durch die Funktion wird eine Anfrage an das Back-End erstellt.
// create request for backend call req, err := http.NewRequest("GET", backendAddr, nil) if err != nil { log.Fatalf("%v", err) } childCtx, cancel := context.WithTimeout(req.Context(), 1000*time.Millisecond) defer cancel() req = req.WithContext(childCtx)
Durch die Funktion wird der Span-Kontext zu dieser Anfrage hinzugefügt.
// add span context to backend call and make request format := &tracecontext.HTTPFormat{} format.SpanContextToRequest(rootspan.SpanContext(), req)
Back-End-Code prüfen
Die
main()
-Funktion für den Back-End-Code ist identisch mit dermain()
-Funktion des Front-End-Dienstes. Sie richtet den Trace-Exporter ein und verwendet einen Mux-Router zur Verarbeitung von Anfragen an die URL/
mit dermainHandler()
-Funktion.Die
mainHandler()
-Funktion verwendet die eingehende Anfrage, um sowohl den von Go bereitgestellten HTTP-Kontext als auch den von OpenCensus bereitgestellten Trace-Kontext abzurufen. Dann wird durch die Funktion ein untergeordneter Span erstellt und dem Trace-Kontext hinzugefügt. Schließlich wird diecallRemoteEndpoint()
-Funktion aufgerufen, um einen weiteren Aufruf auszuführen, dessen Latenz erfasst werden soll.Die
callRemoteEndpoint()
-Funktion verwendet die HTTP-Bibliothek für einen Remote-Endpunktaufruf. Da das Tracing für diesen Aufruf in der übergeordneten Funktion verarbeitet wird, muss der Trace-Kontext nicht verarbeitet werden und es müssen keine weiteren untergeordneten Spans erstellt werden.
App bereitstellen
In diesem Abschnitt verwenden Sie Cloud Build, um Container-Images für die Back-End- und Front-End-Dienste zu erstellen und in ihren GKE-Clustern bereitzustellen.
Back-End-Dienst erstellen
Wechseln Sie in Cloud Shell zum Verzeichnis
backend
:cd $WORKDIR/backend/
Reichen Sie den Build ein:
gcloud builds submit . --tag=gcr.io/$PROJECT_ID/backend:latest
Prüfen Sie, ob das Container-Image erfolgreich erstellt wurde und in Container Registry verfügbar ist:
gcloud container images list
Das Container-Image wurde erfolgreich erstellt, wenn die Ausgabe der folgenden ähnelt, wobei
project-id
Ihre Cloud-Projekt-ID ist:NAME gcr.io/project-id/backend
Back-End-Dienst bereitstellen
Legen Sie in Cloud Shell Ihren
kubectx
-Kontext auf den Clusterbackend
fest:kubectx backend
Stellen Sie die Datei
configmap
bereit:export PROJECT_ID=$(gcloud info --format='value(config.project)') envsubst < backend-configmap.yaml | kubectl apply -f -
Erstellen Sie die Bereitstellungsdatei
backend
:envsubst < backend-deployment.yaml | kubectl apply -f -
Prüfen Sie, ob die Pods ausgeführt werden.
kubectl get pods
Die Ausgabe zeigt den
Status
Running
an:NAME READY STATUS RESTARTS AGE backend-645859d95b-7mx95 1/1 Running 0 52s backend-645859d95b-qfdnc 1/1 Running 0 52s backend-645859d95b-zsj5m 1/1 Running 0 52s
Machen Sie die
backend
-Bereitstellung mithilfe eines Load-Balancers verfügbar:kubectl expose deployment backend --type=LoadBalancer
Rufen Sie die IP-Adresse des
backend
-Dienstes ab:kubectl get services backend
Die Ausgabe sieht etwa so aus:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE backend LoadBalancer 10.11.247.58 34.83.88.143 8080:30714/TCP 70s
Wiederholen Sie diesen Befehl, bis sich das Feld
EXTERNAL-IP
Ihres Dienstes von<pending>
in eine IP-Adresse ändert.Erfassen Sie die IP-Adresse aus dem vorherigen Schritt als Variable:
export BACKEND_IP=$(kubectl get svc backend -ojson | jq -r '.status.loadBalancer.ingress[].ip')
Front-End-Dienst erstellen
Wechseln Sie in Cloud Shell zum Verzeichnis
frontend
:cd $WORKDIR/frontend/
Reichen Sie den Build ein:
gcloud builds submit . --tag=gcr.io/$PROJECT_ID/frontend:latest
Prüfen Sie, ob das Container-Image erfolgreich erstellt wurde und in Container Registry verfügbar ist:
gcloud container images list
Das Container-Image wurde erfolgreich erstellt, wenn die Ausgabe in etwa so aussieht:
NAME gcr.io/qwiklabs-gcp-47a7dcba55b334f7/backend gcr.io/qwiklabs-gcp-47a7dcba55b334f7/frontend
Front-End-Dienst bereitstellen
Legen Sie in Cloud Shell Ihren
kubectx
-Kontext auf den Back-End-Cluster fest:kubectx frontend
Stellen Sie die Datei
configmap
bereit:export PROJECT_ID=$(gcloud info --format='value(config.project)') envsubst < frontend-configmap.yaml | kubectl apply -f -
Erstellen Sie die Bereitstellungsdatei
frontend
:envsubst < frontend-deployment.yaml | kubectl apply -f -
Prüfen Sie, ob die Pods ausgeführt werden.
kubectl get pods
Die Ausgabe zeigt den
Status
Running
an:NAME READY STATUS RESTARTS AGE frontend-747b445499-v7x2w 1/1 Running 0 57s frontend-747b445499-vwtmg 1/1 Running 0 57s frontend-747b445499-w47pf 1/1 Running 0 57s
Machen Sie die
frontend
-Bereitstellung mithilfe eines Load-Balancers verfügbar:kubectl expose deployment frontend --type=LoadBalancer
Rufen Sie die IP-Adresse des
frontend
-Dienstes ab:kubectl get services frontend
Die Ausgabe sieht etwa so aus:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE frontend LoadBalancer 10.27.241.93 34.83.111.232 8081:31382/TCP 70s
Wiederholen Sie diesen Befehl, bis sich das Feld
EXTERNAL-IP
Ihres Dienstes von<pending>
in eine IP-Adresse ändert.Erfassen Sie die IP-Adresse aus dem vorherigen Schritt als Variable:
export FRONTEND_IP=$(kubectl get svc frontend -ojson | jq -r '.status.loadBalancer.ingress[].ip')
Anwendung laden und Traces prüfen
In diesem Abschnitt verwenden Sie das Apache Bench-Dienstprogramm, um Anfragen für Ihre Anwendung zu erstellen und die resultierenden Traces in Trace zu prüfen.
Verwenden Sie in Cloud Shell Apache Bench, um 1.000 Anfragen mit drei gleichzeitigen Threads zu generieren:
ab -c 3 -n 1000 http://${FRONTEND_IP}:8081/
Wechseln Sie in der Cloud Console zu Seite Trace-Liste.
Klicken Sie zum Prüfen der Zeitachse auf einen der URIs mit der Bezeichnung
incoming call
.Dieser Trace enthält drei Spans mit den folgenden Namen:
- Der Span
incoming call
erfasst die vom Client beobachtete End-to-End-Latenz. - Der Span
call to backend
erfasst die vom Front-End beobachtete Latenz des Back-End-Aufrufs. - Der Span
call remote endpoint
erfasst die vom Back-End beobachtete Latenz des externen Endpunktaufrufs.
- Der Span
Bereinigen
Am einfachsten können Sie die Abrechnung deaktivieren, wenn Sie das Cloud-Projekt löschen, das Sie für die Anleitung erstellt haben. Alternativ haben Sie die Möglichkeit, die einzelnen Ressourcen zu löschen.Projekt löschen
- Wechseln Sie in der Cloud Console zur Seite Ressourcen verwalten.
- Wählen Sie in der Projektliste das Projekt aus, das Sie löschen möchten, und klicken Sie dann auf Löschen.
- Geben Sie im Dialogfeld die Projekt-ID ein und klicken Sie auf Shut down (Beenden), um das Projekt zu löschen.
Nächste Schritte
- Weitere Informationen zu OpenCensus
- Weitere Informationen zum verteilten Tracing mit OpenCensus
- Weitere Informationen zur Weitergabe von HTTP-Kontext in Go
- Weitere Google Cloud-Features mit unseren Anleitungen testen
- Ressourcen zu DevOps
- Mehr über die DevOps-Ressourcen aus dieser Anleitung erfahren:
- Über den DevOps Quick Check erfahren, wo Sie im Vergleich zum Rest der Branche stehen