1. Wprowadzenie

Ostatnia aktualizacja: 2021-03-05
Dostrzegalność aplikacji
Dostrzegalność i OpenTelemetry
Obserwowalność to termin używany do opisania atrybutu systemu. System z obserwowalnością umożliwia zespołom aktywne debugowanie systemu. W tym kontekście 3 filary dostrzegalności – logi, dane i logi czasu – są podstawowymi narzędziami do instrumentacji systemu w celu uzyskania dostrzegalności.
OpenTelemetry to zestaw specyfikacji i pakietów SDK, które przyspieszają instrumentację i eksportowanie danych telemetrycznych (logów, wskaźników i logów czasu) wymaganych do dostrzegalności. OpenTelemetry to otwarty standard i projekt społecznościowy w ramach CNCF. Dzięki korzystaniu z bibliotek udostępnianych przez projekt i jego ekosystem deweloperzy mogą instrumentować aplikacje w sposób niezależny od dostawcy i w przypadku wielu architektur.
Distributed Trace
Ślad to dane telemetryczne, które informują o opóźnieniu określonej części procesu w systemie. Szczególnie w erze mikroserwisów śledzenie rozproszone jest silnym motorem do wykrywania wąskich gardeł w zakresie opóźnień w całym systemie rozproszonym.
Podczas analizowania rozproszonych śladów wizualizacja danych śledzenia jest kluczem do szybkiego zrozumienia ogólnych opóźnień systemu. W przypadku śledzenia rozproszonego obsługujemy zestaw wywołań w celu przetworzenia pojedynczego żądania do punktu wejścia systemu w formie śladu zawierającego wiele zakresów.
Span reprezentuje pojedynczą jednostkę pracy wykonaną w systemie rozproszonym, rejestrującą czas rozpoczęcia i zakończenia. Zakresy często mają między sobą relacje hierarchiczne – na ilustracji poniżej wszystkie mniejsze zakresy są zakresami podrzędnymi dużego zakresu /messages i są łączone w jeden ślad, który pokazuje ścieżkę pracy w systemie.

Google Cloud Trace to jedna z opcji backendu śledzenia rozproszonego, która jest dobrze zintegrowana z innymi usługami Google Cloud.
Co utworzysz
W tym ćwiczeniu w Codelabs dodasz instrumentację informacji o logach czasu w usługach o nazwie „Shakesapp”, które działają w klastrze Kubernetes w Google Kubernetes Engine. Architektura Shakesapp jest opisana poniżej:

- Klient wysyła do serwera ciąg zapytania
- Serwer akceptuje zapytanie od klienta, pobiera wszystkie dzieła Szekspira w formacie tekstowym z Google Cloud Storage, wyszukuje wiersze zawierające zapytanie i zwraca klientowi numer wiersza, który pasuje do zapytania.
Musisz instrumentować informacje o śledzeniu w całym żądaniu.
Czego się nauczysz
- Pierwsze kroki z bibliotekami śledzenia OpenTelemetry w projekcie w Pythonie
- Jak utworzyć zakres za pomocą biblioteki
- Jak propagować konteksty zakresów w sieci między komponentami aplikacji
- Jak wysyłać dane logu czasu do Google Cloud Trace
- Jak analizować ślad w Cloud Trace
To ćwiczenie pokazuje, jak instrumentować mikroserwisy. Aby ułatwić zrozumienie, ten przykład zawiera tylko 3 komponenty (generator obciążenia, klient i serwer), ale ten sam proces opisany w tym ćwiczeniu możesz zastosować w przypadku bardziej złożonych i większych systemów.
Czego potrzebujesz
- Znajomość języka Python 3
2. Konfiguracja i wymagania
Samodzielne konfigurowanie środowiska
Jeśli nie masz jeszcze konta Google (Gmail lub Google Apps), musisz je utworzyć. Zaloguj się w konsoli Google Cloud Platform ( console.cloud.google.com) i utwórz nowy projekt.
Jeśli masz już projekt, kliknij menu wyboru projektu w lewym górnym rogu konsoli:

i w wyświetlonym oknie kliknij przycisk „NOWY PROJEKT”, aby utworzyć nowy projekt:

Jeśli nie masz jeszcze projektu, powinien wyświetlić się taki dialog, w którym możesz utworzyć pierwszy projekt:

W kolejnym oknie dialogowym tworzenia projektu możesz wpisać szczegóły nowego projektu:

Zapamiętaj identyfikator projektu, który jest unikalną nazwą we wszystkich projektach Google Cloud (podana powyżej nazwa jest już zajęta i nie będzie działać w Twoim przypadku). W dalszej części tych ćwiczeń z programowania będzie on nazywany PROJECT_ID.
Następnie, jeśli jeszcze tego nie zrobisz, musisz włączyć płatności w Konsoli deweloperów, aby korzystać z zasobów Google Cloud, i włączyć Cloud Trace API.

Wykonanie tego samouczka nie powinno kosztować więcej niż kilka dolarów, ale może okazać się droższe, jeśli zdecydujesz się wykorzystać więcej zasobów lub pozostawisz je uruchomione (patrz sekcja „Czyszczenie” na końcu tego dokumentu). Ceny Google Cloud Trace, Google Kubernetes Engine i Google Artifact Registry są podane w oficjalnej dokumentacji.
- Cennik Google Cloud Observability
- Cennik | Dokumentacja Kubernetes Engine
- Cennik Artifact Registry | Dokumentacja Artifact Registry
Nowi użytkownicy Google Cloud Platform mogą skorzystać z bezpłatnego okresu próbnego, w którym mają do dyspozycji środki w wysokości 300 USD, co powinno sprawić, że to ćwiczenie w Codelabs będzie całkowicie bezpłatne.
Konfiguracja Google Cloud Shell
Z Google Cloud i Google Cloud Trace można korzystać zdalnie na laptopie, ale w tym ćwiczeniu użyjemy Google Cloud Shell, czyli środowiska wiersza poleceń działającego w chmurze.
Ta maszyna wirtualna oparta na Debianie zawiera wszystkie potrzebne narzędzia dla programistów. Zawiera również stały katalog domowy o pojemności 5 GB i działa w Google Cloud, co znacznie zwiększa wydajność sieci i usprawnia proces uwierzytelniania. Oznacza to, że do ukończenia tego ćwiczenia potrzebujesz tylko przeglądarki (działa ona na Chromebooku).
Aby aktywować Cloud Shell w konsoli Cloud, kliknij Aktywuj Cloud Shell
(udostępnienie środowiska i połączenie się z nim powinno zająć tylko kilka chwil).


Po połączeniu z Cloud Shell zobaczysz, że uwierzytelnianie zostało już przeprowadzone, a projekt jest już ustawiony na Twój identyfikator projektu PROJECT_ID.
gcloud auth list
Wynik polecenia
Credentialed accounts: - <myaccount>@<mydomain>.com (active)
gcloud config list project
Wynik polecenia
[core] project = <PROJECT_ID>
Jeśli z jakiegoś powodu projekt nie jest ustawiony, po prostu wydaj to polecenie:
gcloud config set project <PROJECT_ID>
Szukasz urządzenia PROJECT_ID? Sprawdź, jakiego identyfikatora użyto w krokach konfiguracji, lub wyszukaj go w panelu konsoli Cloud:

Cloud Shell domyślnie ustawia też niektóre zmienne środowiskowe, które mogą być przydatne podczas wykonywania kolejnych poleceń.
echo $GOOGLE_CLOUD_PROJECT
Wynik polecenia
<PROJECT_ID>
Na koniec ustaw domyślną strefę i konfigurację projektu.
gcloud config set compute/zone us-central1-f
Możesz wybrać różne strefy. Więcej informacji znajdziesz w artykule Regiony i strefy.
Konfiguracja Pythona
W tym ćwiczeniu używamy narzędzia „poetry” do ścisłego zarządzania wersjami pakietów. Uruchom to polecenie w Cloud Shell:
curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python3 - source $HOME/.poetry/env
Konfigurowanie klastra Google Kubernetes
W tym ćwiczeniu uruchomisz klaster mikroserwisów w Google Kubernetes Engine (GKE). W tym ćwiczeniu wykonasz te czynności:
- Pobieranie projektu podstawowego do Cloud Shell
- Tworzenie mikroserwisów w kontenerach
- Przesyłanie kontenerów do Google Artifact Registry (GAR)
- Wdrażanie kontenerów w GKE
- Modyfikowanie kodu źródłowego usług na potrzeby instrumentacji śledzenia
- Przejdź do kroku 2
Włącz Kubernetes Engine
Najpierw skonfigurujemy klaster Kubernetes, w którym Shakesapp będzie działać w GKE, więc musimy włączyć GKE. Otwórz menu „Kubernetes Engine” i kliknij przycisk WŁĄCZ.

Teraz możesz utworzyć klaster Kubernetes.
Utwórz klaster Kubernetes
Aby utworzyć klaster Kubernetes, uruchom w Cloud Shell to polecenie: Sprawdź, czy wartość strefy znajduje się w regionie, którego używasz do tworzenia repozytorium Artifact Registry. Zmień wartość strefy us-central1-f, jeśli region repozytorium nie obejmuje tej strefy.
gcloud container clusters create otel-trace-codelab --zone us-central1-f \ --num-nodes 1 \ --machine-type e2-highcpu-4
Wynik polecenia
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
Konfigurowanie Artifact Registry i Skaffold
Mamy już klaster Kubernetes gotowy do wdrożenia. Następnie przygotowujemy rejestr kontenerów do przesyłania i wdrażania kontenerów. Aby to zrobić, musimy skonfigurować GAR i Skaffold.
Konfiguracja Artifact Registry
Przejdź do menu „Artifact Registry” i kliknij przycisk WŁĄCZ.

Po chwili zobaczysz przeglądarkę repozytorium GAR. Kliknij przycisk „UTWÓRZ REPOZYTORIUM” i wpisz nazwę repozytorium.

W tym ćwiczeniu nadam nowemu repozytorium nazwę trace-codelab. Format artefaktu to „Docker”, a typ lokalizacji to „Region”. Wybierz region zbliżony do tego, który został ustawiony jako domyślna strefa Google Compute Engine. W tym przykładzie powyżej wybrano „us-central1-f”, więc tutaj wybieramy „us-central1 (Iowa)”. Następnie kliknij przycisk „UTWÓRZ”.

W przeglądarce repozytorium zobaczysz teraz „trace-codelab”.

Później wrócimy tutaj, aby sprawdzić ścieżkę rejestru.
Konfiguracja Skaffold
Skaffold to przydatne narzędzie podczas tworzenia mikroserwisów działających w Kubernetes. Obsługuje przepływ pracy związany z tworzeniem, przesyłaniem i wdrażaniem kontenerów aplikacji za pomocą niewielkiej liczby poleceń. Skaffold domyślnie używa Docker Registry jako rejestru kontenerów, więc musisz skonfigurować Skaffold, aby rozpoznawał GAR podczas przesyłania kontenerów.
Ponownie otwórz Cloud Shell i sprawdź, czy narzędzie Skaffold jest zainstalowane. (Cloud Shell domyślnie instaluje Skaffold w środowisku). Uruchom to polecenie i sprawdź wersję Skaffold.
skaffold version
Wynik polecenia
v1.20.0
Teraz możesz zarejestrować domyślne repozytorium, z którego będzie korzystać narzędzie Skaffold. Aby uzyskać ścieżkę rejestru, otwórz panel Artifact Registry i kliknij nazwę repozytorium, które zostało skonfigurowane w poprzednim kroku.

U góry strony zobaczysz wtedy elementy menu nawigacyjnego. Kliknij ikonę
, aby skopiować ścieżkę rejestru do schowka.

Po kliknięciu przycisku kopiowania u dołu przeglądarki pojawi się okno z komunikatem podobnym do tego:
Skopiowano „us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab”
Wróć do Cloud Shell. Uruchom polecenie skaffold config set default-repo z wartością skopiowaną z panelu.
skaffold config set default-repo us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab
Wynik polecenia
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
Musisz też skonfigurować rejestr w konfiguracji Dockera. Uruchom to polecenie:
gcloud auth configure-docker us-central1-docker.pkg.dev --quiet
Wynik polecenia
{
"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
Możesz teraz przejść do następnego kroku, czyli skonfigurowania kontenera Kubernetes w GKE.
Podsumowanie
W tym kroku skonfigurujesz środowisko do ćwiczeń z programowania:
- Konfigurowanie Cloud Shell
- Utworzono repozytorium Artifact Registry dla rejestru kontenerów.
- Konfigurowanie narzędzia Skaffold do korzystania z repozytorium kontenerów
- utworzyć klaster Kubernetes, w którym będą działać mikroserwisy z ćwiczenia;
Dalsze czynności
W następnym kroku skompilujesz, wypchniesz i wdrożysz mikrousługi w klastrze.
3. Tworzenie, wypychanie i wdrażanie mikroserwisów
Pobieranie materiałów do ćwiczeń z programowania
W poprzednim kroku skonfigurowaliśmy wszystkie wymagania wstępne dotyczące tego ćwiczenia. Teraz możesz uruchomić na nich całe mikroserwisy. Materiały do ćwiczeń w Codelabs są przechowywane na serwerze w GitHubie, więc pobierz je do środowiska powłoki Cloud Shell za pomocą tego polecenia git:
cd ~ git clone https://github.com/GoogleCloudPlatform/opentelemetry-trace-codelab-python.git
Struktura katalogów projektu jest następująca:
shakesapp-python
├── LICENSE
├── manifests
│ ├── client.yaml
│ ├── loadgen.yaml
│ └── server.yaml
├── proto
│ └── shakesapp.proto
├── skaffold.yaml
└── src
├── client
├── loadgen
└── server
- manifests: pliki manifestu Kubernetes
- proto: definicja proto komunikacji między klientem a serwerem
- src: katalogi z kodem źródłowym poszczególnych usług;
- skaffold.yaml: plik konfiguracyjny Skaffold
Uruchom polecenie Skaffold
Teraz możesz utworzyć, przesłać i wdrożyć całą zawartość w utworzonym właśnie klastrze Kubernetes. Brzmi to jak wiele kroków, ale w rzeczywistości skaffold robi wszystko za Ciebie. Wypróbujmy to za pomocą tego polecenia:
cd shakesapp-python skaffold run --tail
Po uruchomieniu polecenia zobaczysz dane wyjściowe dziennika docker build i będziesz mieć pewność, że zostały one przesłane do rejestru.
Wynik polecenia
... ---> 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
Po przesłaniu wszystkich kontenerów usług wdrożenia Kubernetes uruchamiają się automatycznie.
Wynik polecenia
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
Ostrzeżenie: jeśli pojawi się błąd „No push access to specified image repository” (Brak dostępu do przesyłania do określonego repozytorium obrazów), sprawdź, czy polecenie skaffold próbuje przesłać obrazy do Docker Hub (docker.io) niezależnie od konfiguracji domyślnego repozytorium w skaffold. W takim przypadku spróbuj dodać opcję „–default-repo” do polecenia „skaffold run”, jak poniżej.
$ skaffold run –tail –default-repo=us-central1-docker.pkg.dev/[project ID]/[repository name]
Po wdrożeniu w każdym kontenerze zobaczysz rzeczywiste dzienniki aplikacji emitowane do stdout, np. w ten sposób:
Wynik polecenia
[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"}
Na koniec możesz zinstrumentować aplikację za pomocą OpenTelemetry, aby śledzić rozproszone usługi.
Podsumowanie
Na tym etapie przygotowujesz materiały do ćwiczeń w swoim środowisku i sprawdzasz, czy skaffold działa zgodnie z oczekiwaniami.
Dalsze czynności
W następnym kroku zmodyfikujesz kod źródłowy usługi loadgen, aby instrumentować informacje o śledzeniu.
4. Instrumentacja HTTP
Koncepcja instrumentacji i propagacji śladów
Zanim zaczniesz edytować kod źródłowy, krótko wyjaśnię, jak działają ślady rozproszone.

W tym przykładzie instrumentujemy kod, aby eksportować informacje o śladach i zakresach do Cloud Trace oraz propagować kontekst śledzenia w żądaniu z usługi loadgen do usługi serwera.
Aby Cloud Trace mógł zebrać wszystkie spany o tym samym identyfikatorze logu czasu w jeden log czasu, aplikacja musi wysyłać metadane logu czasu, takie jak identyfikator logu czasu i identyfikator spanu. Aplikacja musi też propagować konteksty śledzenia (połączenie identyfikatora śledzenia i identyfikatora spanu spanu nadrzędnego) podczas wysyłania żądań do usług z serwera do klienta, aby mogły one wiedzieć, który kontekst śledzenia obsługują.
OpenTelemetry pomaga:
- generować unikalne identyfikatory logu czasu i zakresu,
- eksportować identyfikator logu czasu i identyfikator zakresu do backendu,
- przekazywać konteksty śledzenia do innych usług,
Instrument first span
Usługa generatora obciążenia instrumentu
Otwórz edytor Cloud Shell, klikając przycisk
w prawym górnym rogu Cloud Shell. Otwórz src/loadgen/loadgen.py w Eksploratorze w panelu po lewej stronie i znajdź funkcję 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)
W funkcji main zobaczysz pętlę wywołującą funkcję call_client. W obecnej implementacji sekcja zawiera 2 wiersze dziennika, które rejestrują początek i koniec wywołania funkcji. Teraz zinstrumentujmy informacje o spanie, aby śledzić opóźnienie wywołania funkcji.
Najpierw musisz utworzyć zakres z unikalnym identyfikatorem śledzenia i identyfikatorem zakresu. OpenTelemetry udostępnia przydatną bibliotekę. Dodaj te wiersze, aby zaimportować biblioteki OpenTelemetry do kodu.
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
Generator obciążenia wywołuje aplikację kliencką w HTTP za pomocą modułu requests, dlatego używamy pakietu rozszerzeń dla requests i włączamy instrumentację.
from opentelemetry.propagators.cloud_trace_propagator import CloudTraceFormatPropagator
+
+RequestsInstrumentor().instrument()
Następnie skonfiguruj instancję narzędzia Tracer, która obsługuje ustawienia kontekstu śledzenia i eksportera.
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}")
Pamiętaj, że w tym ćwiczeniu w Codelabs chcemy pokazać, jak działa instrumentacja logów czasu, dlatego konfigurujemy moduł Tracer tak, aby rejestrował każde żądanie i wysyłał je do backendu. (SimpleSpanProcessor()) Nie nadaje się to do środowisk produkcyjnych, więc pamiętaj, aby zmienić tę część podczas instrumentowania aplikacji produkcyjnej.
Teraz możesz instrumentować zakresy za pomocą narzędzia Tracer. Chodzi o to, że musisz jawnie wygenerować zakres i to wszystko. Chociaż istnieją 2 wiersze, które dodają metadane zdarzenia do zakresu, nie musisz ręcznie generować niepowtarzalnego identyfikatora śledzenia i identyfikatora zakresu ani osadzać ich w zakresie.
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)
Aby kompilacja Dockera pobrała wymagane pakiety OpenTelemetry, uruchom to polecenie:
poetry add "opentelemetry-exporter-gcp-trace=^1.0.0rc0" poetry add "opentelemetry-propagator-gcp=^1.0.0rc0" poetry add "opentelemetry-instrumentation-requests=^0.20b0"
Możesz sprawdzić, czy odpowiedni opis zależności jest zapisany w pyproject.toml.
Obsługa klienta dotycząca instrumentów
W poprzedniej sekcji zaimplementowaliśmy część zaznaczoną na czerwono na rysunku poniżej. W usłudze generatora obciążenia zaimplementowaliśmy informacje o zakresie. Podobnie jak w przypadku usługi generatora obciążenia musimy teraz instrumentować usługę klienta. Różnica w porównaniu z usługą generatora obciążenia polega na tym, że usługa klienta musi wyodrębnić informacje o identyfikatorze śledzenia propagowane z usługi generatora obciążenia w nagłówku HTTP i użyć tego identyfikatora do wygenerowania zakresów.

Otwórz edytor Cloud Shell i dodaj wymagane moduły, tak jak w przypadku usługi generatora obciążenia.
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
Zauważasz, że właśnie zaimportowano FlaskInstrumentor, który umożliwia automatyczne instrumentowanie aplikacji Flask w imieniu użytkowników w celu wyodrębniania nagłówków HTTP i uzyskiwania kontekstów śledzenia za pomocą jednego wiersza kodu. Społeczność OpenTelemetry udostępnia podobne przydatne integracje z innymi popularnymi bibliotekami. Więcej informacji znajdziesz w oficjalnej dokumentacji.
app = flask.Flask(__name__)
+FlaskInstrumentor().instrument_app(app)
Zanim zaczniesz instrumentację, musisz przygotować instancję narzędzia do śledzenia w podobny sposób jak w usłudze generatora obciążenia.
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():
....
Teraz możesz dodać instrumentację w procedurze obsługi. Znajdź main_handler() i zmodyfikuj część, która wysyła żądanie gRPC do usługi serwera.
@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
Podobnie jak w przypadku usługi generatora obciążenia dodaj wymagane pakiety do pyproject.toml za pomocą tego polecenia.
poetry add "opentelemetry-exporter-gcp-trace=^1.0.0rc0" poetry add "opentelemetry-propagator-gcp=^1.0.0rc0" poetry add "opentelemetry-instrumentation-flask=^0.20b0"
Następnie spróbuj uruchomić aplikację za pomocą polecenia skaffold run i sprawdź, co wyświetla panel Cloud Trace:
skaffold run --tail
Po wyświetleniu kilku komunikatów o kompilacji, przesyłaniu i wdrażaniu zobaczysz dzienniki aplikacji w formacie JSON. Otwórz Cloud Trace > Lista logów czasu, aby sprawdzić, czy otrzymujesz informacje o logach czasu. Usługa generatora obciążenia okresowo wysyła żądania do usługi klienta, a Ty włączyłeś śledzenie wszystkich żądań, więc na liście śladów zobaczysz wiele kropek.

Po kliknięciu jednego z nich zobaczysz wykres kaskadowy podobny do tego poniżej, który pokazuje opóźnienie każdej części procesu żądania i odpowiedzi. Znajdź pole wyboru obok opcji „Pokaż zdarzenia”, a następnie wyświetl adnotacje na wykresie kaskadowym. Są to adnotacje, które zostały zaimplementowane w kodzie za pomocą metody span.add_event().

Możesz zauważyć, że nie widzisz zakresów z usługi serwera. Jest to prawidłowe, ponieważ w usłudze serwera nie mamy żadnych zakresów.
Podsumowanie
W tym kroku przeprowadzono instrumentację usługi generatora obciążenia i usługi klienta oraz potwierdzono, że można skutecznie propagować kontekst śledzenia między usługami i eksportować informacje o przedziałach z obu usług do Cloud Trace.
Dalsze czynności
W następnym kroku zinstrumentujesz usługę klienta i usługę serwera, aby sprawdzić, jak propagować kontekst śledzenia za pomocą gRPC.
5. Instrumentacja gRPC
W poprzednim kroku zaimplementowaliśmy pierwszą połowę żądania w tych mikroserwisach. W tym kroku spróbujemy instrumentować komunikację gRPC między usługą klienta a usługą serwera. (Zielony i fioletowy prostokąt na obrazie poniżej)

Automatyczne instrumentowanie klienta gRPC
Ekosystem OpenTelemetry oferuje wiele przydatnych bibliotek, które pomagają deweloperom w instrumentacji aplikacji. W poprzednim kroku użyliśmy automatycznego instrumentowania modułu „requests”. W tym kroku, ponieważ próbujemy propagować kontekst śledzenia za pomocą gRPC, używamy do tego biblioteki.
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()
W przypadku obsługi klienta to, co musimy zrobić w zakresie instrumentacji, jest dość proste. Chcemy propagować kontekst śledzenia, czyli kombinację identyfikatora śledzenia i identyfikatora spanu bieżącego spanu za pomocą gRPC. Wywołujemy więc GrpcInstrumentatorClient.instrument(), aby klient gRPC w funkcji obsługi mógł umieścić kontekst śledzenia w nagłówku HTTP.
Pamiętaj, aby dodać nowe zależności do pyproject.toml za pomocą polecenia poetry add:
poetry add "opentelemetry-instrumentation-grpc=^0.20b0"
Automatyczne instrumentowanie serwera gRPC
Podobnie jak w przypadku klienta gRPC, wywołujemy automatyczne instrumentowanie serwera gRPC. U góry pliku dodaj instrukcje importu, np. te poniżej, i wywołaj funkcję GrpcInstrumentationServer().instrument().
Uwaga: zadzwoń
GrpcInstrumentationServe()
w tym kroku, a nie
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()
+
Następnie dodasz eksporter, aby wysyłać informacje o śledzeniu do backendu Cloud Trace. Dodaj ten kod do funkcji 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)
Pamiętaj, aby dodać nowo dodane pakiety do usługi serwera.
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"
Uruchom mikroserwis i potwierdź log czasu
Następnie uruchom zmodyfikowany kod za pomocą polecenia skaffold.
skaffold run --tail
Na stronie z listą logów czasu w Cloud Trace ponownie zobaczysz wiele logów czasu. Kliknij jeden ze śladów. Zobaczysz, że obejmuje on zakres żądania od usługi generatora obciążenia do usługi serwera.

Podsumowanie
W tym kroku zintegrowaliśmy komunikację opartą na gRPC z bibliotekami ekosystemu OpenTelemetry. Potwierdzasz też, że kontekst śledzenia wygenerowany w usłudze generatora obciążenia został pomyślnie dostarczony do usługi serwera.
6. Gratulacje
Udało Ci się utworzyć rozproszone logi czasu za pomocą OpenTelemetry i potwierdzić opóźnienia żądań w mikrousłudze w Cloud Trace.
W przypadku rozbudowanych ćwiczeń możesz samodzielnie wypróbować te tematy.
- Obecna implementacja wysyła wszystkie zakresy wygenerowane przez kontrolę stanu. Jak odfiltrować te zakresy z Cloud Trace? Wskazówka jest tutaj.
- Powiąż dzienniki zdarzeń z zakresami i zobacz, jak to działa w Google Cloud Trace i Google Cloud Logging. Wskazówka jest tutaj.
- Zastąpienie usługi inną w innym języku i spróbowanie instrumentacji za pomocą OpenTelemetry w tym języku
Uwaga: Google Kubernetes Engine i Google Artifact Registry stale zużywają zasoby.
Czyszczenie danych
Po ukończeniu tego ćwiczenia zatrzymaj klaster Kubernetes i usuń projekt, aby uniknąć nieoczekiwanych opłat za Google Kubernetes Engine, Google Cloud Trace i Google Artifact Registry.
Najpierw usuń klaster za pomocą tego polecenia:
skaffold delete
Wynik polecenia
Cleaning up... - deployment.apps "clientservice" deleted - service "clientservice" deleted - deployment.apps "loadgen" deleted - deployment.apps "serverservice" deleted - service "serverservice" deleted
Po usunięciu klastra w panelu menu wybierz „IAM i administracja” > „Ustawienia”, a następnie kliknij przycisk „WYŁĄCZ”.

Następnie w formularzu w oknie wpisz identyfikator projektu (nie nazwę projektu) i potwierdź wyłączenie.