Informazioni di traccia degli strumenti utilizzando OpenTelemetry

1. Introduzione

5af4a7e43b0feaab.png

Ultimo aggiornamento: 2021-03-05

Osservabilità dell'applicazione

Osservabilità e OpenTelemetry

Osservabilità è il termine utilizzato per descrivere un attributo di un sistema. Un sistema con osservabilità consente ai team di eseguire il debug attivo del sistema. In questo contesto, i tre pilastri dell'osservabilità (log, metriche e tracce) sono l'instrumentazione fondamentale per acquisire l'osservabilità del sistema.

OpenTelemetry è un insieme di specifiche e SDK che accelera la strumentazione e l'esportazione dei dati di telemetria (log, metriche e tracce) richiesti dall'osservabilità. OpenTelemetry è un progetto open standard e guidato dalla community nell'ambito della CNCF. Utilizzando le librerie fornite dal progetto e dal suo ecosistema, gli sviluppatori sono in grado di instrumentare le proprie applicazioni in modo indipendente dal fornitore e su più architetture.

Trace distribuito

Tra log, metriche e tracce, la traccia è la telemetria che indica la latenza di una parte specifica del processo nel sistema. Soprattutto nell'era dei microservizi, il tracciamento distribuito è il principale motore per scoprire i colli di bottiglia della latenza nel sistema distribuito complessivo.

Quando analizzi le tracce distribuite, la visualizzazione dei dati di traccia è fondamentale per comprendere a colpo d'occhio le latenze complessive del sistema. Nella traccia distribuita, gestiamo un insieme di chiamate per elaborare una singola richiesta al punto di ingresso del sistema sotto forma di traccia contenente più intervalli.

Lo span rappresenta una singola unità di lavoro eseguita in un sistema distribuito, registrando gli orari di inizio e fine. Gli span spesso hanno relazioni gerarchiche tra loro. Nell'immagine seguente, tutti gli span più piccoli sono span secondari di uno span /messages di grandi dimensioni e vengono assemblati in una traccia che mostra il percorso di lavoro in un sistema.

adbd3ecd69d410cb.png

Google Cloud Trace è una delle opzioni per il backend di tracciamento distribuito ed è ben integrato con altri prodotti in Google Cloud.

Cosa creerai

In questo codelab, strumenterai le informazioni di traccia nei servizi chiamati "Shakesapp" che vengono eseguiti su un cluster Kubernetes in esecuzione su Google Kubernetes Engine. L'architettura di Shakesapp è descritta di seguito:

68873c018a7be7de.png

  • Il client invia una stringa di query al server
  • Il server accetta la query dal client, recupera tutte le opere di Shakespeare in formato di testo da Google Cloud Storage, cerca le righe che contengono la query e restituisce al client il numero della riga corrispondente.

Strumenterai le informazioni di tracciamento nella richiesta.

Cosa imparerai a fare

  • Come iniziare a utilizzare le librerie di tracciamento OpenTelemetry nel progetto Python
  • Come creare uno span con la libreria
  • Come propagare i contesti degli span tra i componenti dell'app
  • Come inviare dati di traccia a Google Cloud Trace
  • Come analizzare la traccia su Google Cloud Trace

Questo codelab spiega come instrumentare i microservizi. Per semplificare la comprensione, questo esempio contiene solo tre componenti (generatore di carico, client e server), ma puoi applicare lo stesso processo spiegato in questo codelab a sistemi più complessi e di grandi dimensioni.

Che cosa ti serve

  • Conoscenza di Python 3

2. Configurazione e requisiti

Configurazione dell'ambiente autonomo

Se non hai ancora un Account Google (Gmail o Google Apps), devi crearne uno. Accedi alla console di Google Cloud Platform ( console.cloud.google.com) e crea un nuovo progetto.

Se hai già un progetto, fai clic sul menu a discesa per la selezione dei progetti in alto a sinistra nella console:

15b8b6ac4d917005.png

e fai clic sul pulsante "NUOVO PROGETTO" nella finestra di dialogo risultante per creare un nuovo progetto:

7136b3ee36ebaf89.png

Se non hai ancora un progetto, dovresti visualizzare una finestra di dialogo come questa per creare il primo:

90977ce514204b51.png

La finestra di dialogo successiva per la creazione del progetto ti consente di inserire i dettagli del nuovo progetto:

6d9573e346e930b4.png

Ricorda l'ID progetto, che è un nome univoco tra tutti i progetti Google Cloud (il nome sopra è già stato utilizzato e non funzionerà per te, mi dispiace). In questo codelab verrà indicato come PROJECT_ID.

Successivamente, se non l'hai ancora fatto, devi abilitare la fatturazione in Developers Console per utilizzare le risorse Google Cloud e abilitare l'API Cloud Trace.

eb5325f65619ad6a.png

L'esecuzione di questo codelab non dovrebbe costarti più di qualche dollaro, ma potrebbe essere più cara se decidi di utilizzare più risorse o se le lasci in esecuzione (vedi la sezione "Pulizia" alla fine di questo documento). I prezzi di Google Cloud Trace, Google Kubernetes Engine e Google Artifact Registry sono indicati nella documentazione ufficiale.

I nuovi utenti di Google Cloud Platform possono beneficiare di una prova senza costi di 300$, che dovrebbe rendere questo codelab completamente senza costi.

Configurazione di Google Cloud Shell

Sebbene Google Cloud e Google Cloud Trace possano essere gestiti da remoto dal tuo laptop, in questo codelab utilizzeremo Google Cloud Shell, un ambiente a riga di comando in esecuzione nel cloud.

Questa macchina virtuale basata su Debian viene caricata con tutti gli strumenti di sviluppo di cui avrai bisogno. Offre una home directory permanente da 5 GB e viene eseguita in Google Cloud, migliorando notevolmente le prestazioni e l'autenticazione della rete. Ciò significa che per questo codelab ti servirà solo un browser (sì, funziona su Chromebook).

Per attivare Cloud Shell dalla console Cloud, fai clic su Attiva Cloud Shell gcLMt5IuEcJJNnMId-Bcz3sxCd0rZn7IzT_r95C8UZeqML68Y1efBG_B0VRp7hc7qiZTLAF-TXD7SsOadxn8uadgHhaLeASnVS3ZHK39eOlKJOgj9SJua_oeGhMxRrbOg3qigddS2A (bastano pochi istanti per eseguire il provisioning e connettersi all'ambiente).

ff81d016724c4f67.png

fbe156ee6edfbb2e.png

Una volta eseguita la connessione a Cloud Shell, dovresti vedere che il tuo account è già autenticato e il progetto è già impostato sul tuo PROJECT_ID.

gcloud auth list

Output comando

Credentialed accounts:
 - <myaccount>@<mydomain>.com (active)
gcloud config list project

Output comando

[core]
project = <PROJECT_ID>

Se per qualche motivo il progetto non è impostato, esegui questo comando:

gcloud config set project <PROJECT_ID>

Stai cercando il tuo PROJECT_ID? Controlla l'ID che hai utilizzato nei passaggi di configurazione o cercalo nella dashboard della console Cloud:

a3e716fc9e7454e9.png

Cloud Shell imposta anche alcune variabili di ambiente per impostazione predefinita, che potrebbero essere utili quando esegui i comandi futuri.

echo $GOOGLE_CLOUD_PROJECT

Output comando

<PROJECT_ID>

Infine, imposta la zona e la configurazione del progetto predefinite.

gcloud config set compute/zone us-central1-f

Puoi scegliere una serie di zone diverse. Per saperne di più, consulta Regioni e zone.

Configurazione di Python

In questo codelab, utilizziamo "poetry" per gestire rigorosamente le versioni dei pacchetti. Esegui questo comando su Cloud Shell:

curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python3 -
source $HOME/.poetry/env

Configura un cluster Google Kubernetes

In questo codelab, eseguirai un cluster di microservizi su Google Kubernetes Engine (GKE). La procedura di questo codelab è la seguente:

  1. Scarica il progetto di base in Cloud Shell
  2. Creare microservizi in container
  3. Carica i container in Google Artifact Registry (GAR)
  4. Esegui il deployment dei container su GKE
  5. Modificare il codice sorgente dei servizi per l'instrumentazione delle tracce
  6. Vai al passaggio 2

Abilita Kubernetes Engine

Innanzitutto, configuriamo un cluster Kubernetes in cui Shakesapp viene eseguito su GKE, quindi dobbiamo abilitare GKE. Vai al menu "Kubernetes Engine" e premi il pulsante ATTIVA.

56c680e93e169731.png

Ora puoi creare un cluster Kubernetes.

Crea un cluster Kubernetes

In Cloud Shell, esegui questo comando per creare un cluster Kubernetes. Verifica che il valore della zona rientri nella regione che hai utilizzato per la creazione del repository Artifact Registry. Modifica il valore della zona us-central1-f se la regione del repository non copre la zona.

gcloud container clusters create otel-trace-codelab --zone us-central1-f \
--num-nodes 1 \
--machine-type e2-highcpu-4

Output comando

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

Configurazione di Artifact Registry e Skaffold

Ora abbiamo un cluster Kubernetes pronto per il deployment. Successivamente, ci prepariamo per un container registry per il push e il deployment dei container. Per questi passaggi, dobbiamo configurare GAR e Skaffold per utilizzarli.

Configurazione di Artifact Registry

Vai al menu di "Artifact Registry" e premi il pulsante ATTIVA.

f7493243bae0cdf7.png

Dopo qualche istante, vedrai il browser del repository di GAR. Fai clic sul pulsante "CREA REPOSITORY" e inserisci il nome del repository.

f97f337f5476651.png

In questo codelab, il nuovo repository viene chiamato trace-codelab. Il formato dell'artefatto è "Docker" e il tipo di località è "Regione". Scegli la regione più vicina a quella impostata per la zona predefinita di Google Compute Engine. Ad esempio, nell'esempio precedente è stato scelto "us-central1-f", quindi qui scegliamo "us-central1 (Iowa)". Poi fai clic sul pulsante "CREA".

2f04143077ca56db.png

Ora vedi "trace-codelab" nel browser del repository.

7a3c1f47346bea15.png

Torneremo qui più tardi per controllare il percorso del registro.

Configurazione di Skaffold

Skaffold è uno strumento utile quando lavori alla creazione di microservizi eseguiti su Kubernetes. Gestisce il workflow di creazione, push ed esecuzione del deployment dei container delle applicazioni con un piccolo insieme di comandi. Per impostazione predefinita, Skaffold utilizza Docker Registry come registro dei container, quindi devi configurare Skaffold in modo che riconosca GAR quando esegui il push dei container.

Riapri Cloud Shell e verifica se Skaffold è installato. Cloud Shell installa Skaffold nell'ambiente per impostazione predefinita. Esegui questo comando e visualizza la versione di Skaffold.

skaffold version

Output comando

v1.20.0

Ora puoi registrare il repository predefinito da utilizzare per Skaffold. Per ottenere il percorso del registro, vai alla dashboard di Artifact Registry e fai clic sul nome del repository che hai appena configurato nel passaggio precedente.

55173fe922f40327.png

Poi vedrai le tracce di breadcrumb nella parte superiore della pagina. Fai clic sull'icona e157b1359c3edc06.png per copiare il percorso del registro negli appunti.

a9b0fa44c37e0178.png

Se fai clic sul pulsante di copia, nella parte inferiore del browser viene visualizzata la finestra di dialogo con il messaggio:

"us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab" è stato copiato

Torna a Cloud Shell. Esegui il comando skaffold config set default-repo con il valore che hai appena copiato dalla dashboard.

skaffold config set default-repo us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab

Output comando

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

Inoltre, devi configurare il registro nella configurazione Docker. Esegui questo comando:

gcloud auth configure-docker us-central1-docker.pkg.dev --quiet

Output comando

{
  "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

Ora puoi procedere al passaggio successivo per configurare un container Kubernetes su GKE.

Riepilogo

In questo passaggio, configurerai l'ambiente del codelab:

  • Configura Cloud Shell
  • È stato creato un repository Artifact Registry per il registro dei container
  • Configura Skaffold per utilizzare Container Registry
  • Creazione di un cluster Kubernetes in cui vengono eseguiti i microservizi del codelab

Avanti

Nel passaggio successivo, creerai, invierai ed eseguirai il deployment dei microservizi nel cluster.

3. Crea, esegui il push e il deployment dei microservizi

Scarica il materiale del codelab

Nel passaggio precedente, abbiamo configurato tutti i prerequisiti per questo codelab. Ora puoi eseguire microservizi completi sopra. Il materiale del codelab è ospitato su GitHub, quindi scaricalo nell'ambiente Cloud Shell con il seguente comando git.

cd ~
git clone https://github.com/GoogleCloudPlatform/opentelemetry-trace-codelab-python.git

La struttura delle directory del progetto è la seguente:

shakesapp-python
├── LICENSE
├── manifests
│   ├── client.yaml
│   ├── loadgen.yaml
│   └── server.yaml
├── proto
│   └── shakesapp.proto
├── skaffold.yaml
└── src
    ├── client
    ├── loadgen
    └── server
  • manifests: file manifest Kubernetes
  • proto: definizione del protocollo per la comunicazione tra client e server
  • src: directory per il codice sorgente di ogni servizio
  • skaffold.yaml: file di configurazione per Skaffold

Esegui il comando skaffold

Infine, puoi creare, eseguire il push e il deployment dell'intero contenuto nel cluster Kubernetes che hai appena creato. Sembra che ci siano più passaggi, ma in realtà Skaffold fa tutto per te. Proviamo con il seguente comando:

cd shakesapp-python
skaffold run --tail

Non appena esegui il comando, visualizzi l'output del log di docker build e puoi confermare che sono stati inviati correttamente al registro.

Output comando

...
---> 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

Dopo il push di tutti i contenitori di servizi, i deployment Kubernetes vengono avviati automaticamente.

Output comando

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

Attenzione: se viene visualizzato l'errore "No push access to specified image repository", controlla se il comando skaffold sta tentando di eseguire il push delle immagini su Docker Hub (docker.io) indipendentemente dalla configurazione del repository predefinito in skaffold. In questo caso, prova ad aggiungere l'opzione "–default-repo" a "skaffold run" come di seguito.

$ skaffold run –tail –default-repo=us-central1-docker.pkg.dev/[project ID]/[repository name]

Dopo il deployment, vedrai i log dell'applicazione effettivi emessi in stdout in ogni container nel seguente modo:

Output comando

[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"}

Infine, puoi iniziare a instrumentare la tua applicazione con OpenTelemetry per il tracciamento distribuito dei servizi.

Riepilogo

In questo passaggio, hai preparato il materiale del codelab nel tuo ambiente e hai verificato che Skaffold venga eseguito come previsto.

Avanti

Nel passaggio successivo, modificherai il codice sorgente del servizio loadgen per instrumentare le informazioni di traccia.

4. Strumentazione per HTTP

Concetto di strumentazione e propagazione delle tracce

Prima di modificare il codice sorgente, ti spiego brevemente come funzionano le tracce distribuite in un semplice diagramma.

c8c659deaa9c9091.png

In questo esempio, strumentiamo il codice per esportare le informazioni su traccia e span in Cloud Trace e propagare il contesto di traccia nella richiesta dal servizio loadgen al servizio server.

L'applicazione deve inviare i metadati di Trace, come l'ID traccia e l'ID span, in modo che Cloud Trace possa assemblare tutti gli span con lo stesso ID traccia in una traccia. Inoltre, l'applicazione deve propagare i contesti di traccia (la combinazione di ID traccia e ID intervallo dell'intervallo principale) quando richiede servizi downstream, in modo che possano essere a conoscenza del contesto di traccia che stanno gestendo.

OpenTelemetry ti aiuta a:

  • per generare ID traccia e ID intervallo univoci
  • per esportare l'ID traccia e l'ID intervallo nel backend
  • per propagare i contesti di traccia ad altri servizi

Intervallo del primo strumento

Servizio di generazione del carico dello strumento

Apri l'editor di Cloud Shell premendo il pulsante 776a11bfb2122549.png in alto a destra di Cloud Shell. Apri src/loadgen/loadgen.py da Explorer nel riquadro a sinistra e trova la funzione 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)

Nella funzione main, vedi il ciclo che chiama la funzione call_client. Nell'implementazione attuale, la sezione contiene due righe di log che registrano l'inizio e la fine della chiamata di funzione. Ora strumentiamo le informazioni sullo span per monitorare la latenza della chiamata di funzione.

Innanzitutto, devi creare uno span con un ID traccia e un ID span univoci. OpenTelemetry fornisce una libreria utile per questo scopo. Aggiungi le seguenti righe per importare le librerie OpenTelemetry nel tuo codice.

 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

Poiché il generatore di carico chiama l'applicazione client in HTTP tramite il modulo requests, utilizziamo il pacchetto di estensione per requests e attiviamo la strumentazione.

 from opentelemetry.propagators.cloud_trace_propagator import CloudTraceFormatPropagator
+
+RequestsInstrumentor().instrument()

Quindi, configura l'istanza Tracer che gestisce le impostazioni di Trace Context e dell'esportatore.

     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}")

Tieni presente che, poiché si tratta di un codelab per capire come funziona l'instrumentazione di traccia, configuriamo il tracciatore in modo che registri ogni singola richiesta e la invii al backend. (SimpleSpanProcessor()) Questo non è adatto agli ambienti di produzione, quindi assicurati di modificare questa parte quando strumentalizzi l'applicazione di produzione.

Ora puoi instrumentare gli span con Tracer. Il punto è che devi generare uno span in modo esplicito e basta. Sebbene ci siano due righe che aggiungono i metadati evento in Span, non è necessario generare manualmente ID traccia e ID span univoci e incorporarli in Span.

     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)

Affinché Docker build recuperi i pacchetti OpenTelemetry richiesti, esegui questo comando:

poetry add "opentelemetry-exporter-gcp-trace=^1.0.0rc0"
poetry add "opentelemetry-propagator-gcp=^1.0.0rc0"
poetry add "opentelemetry-instrumentation-requests=^0.20b0"

Puoi verificare che la descrizione della dipendenza corrispondente sia scritta in pyproject.toml.

Servizio clienti dello strumento

Nella sezione precedente, abbiamo instrumentato la parte racchiusa nel rettangolo rosso nel disegno riportato di seguito. Abbiamo instrumentato le informazioni sugli span nel servizio di generazione del carico. Analogamente al servizio di generazione del carico, ora dobbiamo instrumentare il servizio client. La differenza rispetto al servizio di generazione del carico è che il servizio client deve estrarre le informazioni sull'ID traccia propagate dal servizio di generazione del carico nell'intestazione HTTP e utilizzare l'ID per generare gli intervalli.

ae074d4513c9931f.png

Apri Cloud Shell Editor e aggiungi i moduli richiesti come abbiamo fatto per il servizio di generazione del carico.

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

Noti di aver appena importato FlaskInstrumentor che attiva la strumentazione automatica per l'applicazione Flask per conto degli utenti per estrarre le intestazioni HTTP e ottenere i contesti di traccia con una sola riga di codice. La community OpenTelemetry fornisce integrazioni utili simili con altre librerie principali. Per ulteriori informazioni, puoi consultare la documentazione ufficiale.

 app = flask.Flask(__name__)
+FlaskInstrumentor().instrument_app(app)

Prima di iniziare la strumentazione, devi preparare l'istanza Tracer in modo simile a quanto fatto nel servizio di generazione del carico.

 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():
    ....

Ora è pronto per aggiungere la strumentazione nel gestore. Trova main_handler() e modifica la parte che invia la richiesta gRPC al servizio server.

@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

Analogamente al servizio di generazione del carico, aggiungi i pacchetti richiesti in pyproject.toml con il seguente comando.

poetry add "opentelemetry-exporter-gcp-trace=^1.0.0rc0"
poetry add "opentelemetry-propagator-gcp=^1.0.0rc0"
poetry add "opentelemetry-instrumentation-flask=^0.20b0"

Quindi, prova ad avviare l'applicazione con il comando skaffold run e vedi cosa mostra la dashboard di Cloud Trace:

skaffold run --tail

Dopo aver visualizzato alcuni messaggi di build, push e deployment, vedrai i log dell'applicazione in formato JSON. Vai a Cloud Trace > Elenco tracce per verificare se ricevi le informazioni di traccia. Poiché il servizio di generazione del carico invia periodicamente richieste al servizio client e hai attivato le tracce per tutte le richieste, inizi a vedere molti punti nell'elenco delle tracce.

f7440360551980e.png

Se fai clic su uno di questi, vedrai un grafico a cascata come quello riportato di seguito che spiega la latenza di ogni parte durante il processo di richiesta e risposta. Trova la casella di controllo accanto a "Mostra eventi", quindi visualizzerai le annotazioni all'interno del grafico a cascata. Queste annotazioni sono quelle che hai instrumentato nel codice con il metodo span.add_event().

67596a4a313738.png

Potresti notare che non vedi gli intervalli del servizio server. È corretta perché non abbiamo instrumentato gli span nel servizio server.

Riepilogo

In questo passaggio, hai instrumentato il servizio di generazione del carico e il servizio client e hai verificato di poter propagare correttamente il contesto di traccia tra i servizi ed esportare le informazioni sugli intervalli da entrambi i servizi a Cloud Trace.

Avanti

Nel passaggio successivo, strumenterai il servizio client e il servizio server per verificare come propagare il contesto di traccia tramite gRPC.

5. Strumentazione per gRPC

Nel passaggio precedente, abbiamo instrumentato la prima metà della richiesta in questi microservizi. In questo passaggio, proviamo a instrumentare la comunicazione gRPC tra il servizio client e il servizio server. (Rettangolo verde e viola nell'immagine qui sotto)

c4dec3e741c3ab4f.png

Strumentazione automatica per il client gRPC

L'ecosistema di OpenTelemetry offre molte librerie utili che aiutano gli sviluppatori a instrumentare le applicazioni. Nel passaggio precedente, abbiamo utilizzato la strumentazione automatica per il modulo "richieste". In questo passaggio, poiché stiamo tentando di propagare il contesto di traccia tramite gRPC, utilizziamo la libreria.

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()

Per il servizio client, ciò che dobbiamo fare per l'instrumentazione è piuttosto semplice. Ciò che vogliamo fare è propagare il contesto di traccia, ovvero la combinazione di ID traccia e ID span dello span corrente tramite gRPC. Quindi chiamiamo GrpcInstrumentatorClient.instrument() in modo che il client gRPC nella funzione di gestione possa incorporare il contesto di traccia nell'intestazione HTTP sottostante.

Assicurati di aggiungere nuove dipendenze a pyproject.toml con il comando poetry add:

poetry add "opentelemetry-instrumentation-grpc=^0.20b0"

Strumentazione automatica per il server gRPC

Come abbiamo fatto per il client gRPC, chiamiamo strumentazione automatica per il server gRPC. Aggiungi importazioni come following e call GrpcInstrumentationServer().instrument() all'inizio del file.

Attenzione: assicurati di chiamare

GrpcInstrumentationServe() 

in questo passaggio, non

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()
+

Poi aggiungerai l'esportatore per inviare le informazioni di traccia al backend di Cloud Trace. Aggiungi il seguente codice alla funzione serve().

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)

Assicurati di aggiungere i pacchetti appena aggiunti nel servizio server.

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"

Esegui il microservizio e conferma la traccia

Poi esegui il codice modificato con il comando skaffold.

skaffold run --tail

Ora, di nuovo, vedi una serie di tracce nella pagina Elenco Trace di Cloud Trace. Fai clic su una delle tracce e vedrai che si estendono alla richiesta dal servizio di generazione del carico al servizio server.

141cb620245b689d.png

Riepilogo

In questo passaggio, hai instrumentato la comunicazione basata su gRPC con il supporto delle librerie dell'ecosistema OpenTelemetry. Inoltre, hai confermato che il contesto di traccia generato nel servizio di generazione del carico è stato inviato correttamente al servizio server.

6. Complimenti

Hai creato correttamente tracce distribuite con OpenTelemetry e hai confermato le latenze delle richieste nel microservizio su Google Cloud Trace.

Per esercizi più lunghi, puoi provare i seguenti argomenti da solo.

  • L'implementazione attuale invia tutti gli span generati dal controllo di integrità. Come si filtrano questi intervalli da Cloud Trace? Il suggerimento è qui.
  • Metti in correlazione i log eventi con gli intervalli e scopri come funziona su Google Cloud Trace e Google Cloud Logging. Il suggerimento è qui.
  • Sostituisci un servizio con quello in un'altra lingua e prova a instrumentarlo con OpenTelemetry per quella lingua

Attenzione: Google Kubernetes Engine e Google Artifact Registry utilizzano costantemente la risorsa.

Pulizia

Al termine di questo codelab, arresta il cluster Kubernetes e assicurati di eliminare il progetto in modo da non ricevere addebiti imprevisti in Google Kubernetes Engine, Google Cloud Trace e Google Artifact Registry.

Innanzitutto, elimina il cluster con il seguente comando:

skaffold delete

Output comando

Cleaning up...
 - deployment.apps "clientservice" deleted
 - service "clientservice" deleted
 - deployment.apps "loadgen" deleted
 - deployment.apps "serverservice" deleted
 - service "serverservice" deleted

Dopo aver eliminato il cluster, seleziona "IAM e amministrazione" > "Impostazioni" dal riquadro del menu e poi fai clic sul pulsante "ARRESTA".

578ca2b72a161e9d.png

Poi inserisci l'ID progetto (non il nome del progetto) nel modulo della finestra di dialogo e conferma l'arresto.