Wdrażanie danych logu czasu za pomocą OpenTelemetry

1. Wprowadzenie

5af4a7e43b0feaab.png

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.

adbd3ecd69d410cb.png

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:

68873c018a7be7de.png

  • 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:

15b8b6ac4d917005.png

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

7136b3ee36ebaf89.png

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

90977ce514204b51.png

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

6d9573e346e930b4.png

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.

eb5325f65619ad6a.png

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.

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 gcLMt5IuEcJJNnMId-Bcz3sxCd0rZn7IzT_r95C8UZeqML68Y1efBG_B0VRp7hc7qiZTLAF-TXD7SsOadxn8uadgHhaLeASnVS3ZHK39eOlKJOgj9SJua_oeGhMxRrbOg3qigddS2A (udostępnienie środowiska i połączenie się z nim powinno zająć tylko kilka chwil).

ff81d016724c4f67.png

fbe156ee6edfbb2e.png

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:

a3e716fc9e7454e9.png

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:

  1. Pobieranie projektu podstawowego do Cloud Shell
  2. Tworzenie mikroserwisów w kontenerach
  3. Przesyłanie kontenerów do Google Artifact Registry (GAR)
  4. Wdrażanie kontenerów w GKE
  5. Modyfikowanie kodu źródłowego usług na potrzeby instrumentacji śledzenia
  6. 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.

56c680e93e169731.png

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.

f7493243bae0cdf7.png

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

f97f337f5476651.png

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

2f04143077ca56db.png

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

7a3c1f47346bea15.png

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.

55173fe922f40327.png

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

a9b0fa44c37e0178.png

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.

c8c659deaa9c9091.png

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 776a11bfb2122549.pngw 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.

ae074d4513c9931f.png

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.

f7440360551980e.png

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

67596a4a313738.png

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)

c4dec3e741c3ab4f.png

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.

141cb620245b689d.png

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

578ca2b72a161e9d.png

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