נתוני מעקב של הכלים באמצעות OpenTelemetry

1. מבוא

5af4a7e43b0feaab

עדכון אחרון:5 במרץ 2021

ניראות (observability) של האפליקציה

ניראות (observability) ו-OpenTelemetry

ניראות (observability) היא המונח שמשמש לתיאור תכונה של מערכת. מערכת עם ניראות (observability) מאפשרת לצוותים לנפות באגים במערכת באופן פעיל. בהקשר הזה, שלושה עמודי תווך של ניראות (observability); יומנים, מדדים ועקבות הם הכלים הבסיסיים שבאמצעותם המערכת יכולה להשיג ניראות (observability).

OpenTelemetry היא קבוצה של מפרטים וערכות SDK שמאיצות את המדידה והייצוא של נתוני טלמטריה (יומנים, מדדים ועקבות) שנדרשים לצורך ניראות (observability). OpenTelemetry הוא פרויקט פתוח בתקן פתוח ומבוסס-קהילה במסגרת CNCF. על ידי שימוש בספריות שהפרויקט והסביבה העסקית שלו מספקים, המפתחים יכולים להטמיע את האפליקציות שלהם באופן ניטרלי של הספקים ומול מספר ארכיטקטורות.

מעקב שהופץ

בין היומנים, המדדים והמעקבים, נתוני המעקב הם נתוני הטלמטריה שמציינת את זמן האחזור של חלק ספציפי בתהליך. במיוחד בעידן מיקרו-שירותים, מעקב מבוזר הוא הגורם המשמעותי ביותר למציאת צווארי בקבוק בזמן האחזור במערכת המבוזרת הכוללת.

כשמנתחים מעקבים מבוזרים, התצוגה החזותית של נתוני המעקב היא המפתח להבנת זמן האחזור הכולל של המערכת במבט מהיר. במעקב מבוזר, אנחנו מטפלים בקבוצה של קריאות כדי לעבד בקשה יחידה לנקודת הכניסה של המערכת בצורת נתוני מעקב, שמכילה מגוון קריאות.

טווח מייצג יחידת עבודה בודדת המבוצעת במערכת מבוזרת, והקלטה של זמני התחלה וסיום. לעיתים קרובות יש יחסים היררכיים ביניהם – בתמונה שמתחת לכל ההיקפים הקטנים יותר יש אזורים צאצאים של טווח /הודעות גדול, והם מורכבים מ-Trace להצגת נתיב העבודה במערכת.

adbd3ecd69d410cb.png

הכלי Google Cloud Trace הוא אחת מהאפשרויות לקצה העורפי של מעקב מבוזר, והוא משתלב היטב עם מוצרים אחרים ב-Google Cloud.

מה תפַתחו

ב-Codelab הזה, אתם תעקבו אחרי נתוני מעקב בשירותים שנקראים 'Shakesapp' שפועל על אשכול Kubernetes שפועל על Google Kubernetes Engine. הארכיטקטורה של שייקסאפ מתוארת בהמשך:

68873c018a7be7de.png

  • הלקוחות שולחים מחרוזת שאילתה לשרת
  • השרת מקבל את השאילתה מהלקוח, מאחזר את כל העבודות בפורמט טקסט מ-Google Cloud Storage, מחפש בשורות שמכילות את השאילתה ומחזיר את מספר השורה שהתאימה ללקוח.

את פרטי המעקב של הבקשה תמלאו.

מה תלמדו

  • איך מתחילים לעבוד עם ספריות OpenTelemetry Trace בפרויקט Python
  • איך ליצור span באמצעות הספרייה
  • איך להפיץ הקשרי טווח לאורך החוט בין רכיבי אפליקציה
  • איך לשלוח נתוני מעקב אל Google Cloud Trace
  • איך לנתח את המעקב ב-Google Cloud Trace

בשיעור הזה תקבלו הסבר על האופן שבו ניתן להגדיר מיקרו-שירותים (microservices). כדי לפשט את ההסברים, הדוגמה הזו מכילה רק 3 רכיבים (מחולל עומסים, לקוח ושרת), אבל אפשר להחיל את אותו התהליך שמוסבר במאמר הזה גם על מערכות מורכבות וגדולות יותר.

מה צריך להכין

  • ידע ב-Python 3

2. הגדרה ודרישות

הגדרת סביבה בקצב עצמאי

אם אין לכם עדיין חשבון Google (Gmail או Google Apps), עליכם ליצור חשבון. נכנסים למסוף Google Cloud Platform ( console.cloud.google.com) ויוצרים פרויקט חדש.

אם כבר יש לכם פרויקט, לוחצים על התפריט הנפתח לבחירת פרויקט בפינה השמאלית העליונה של המסוף:

15b8b6ac4d917005.png

ולוחצים על 'New project' (פרויקט חדש). בתיבת הדו-שיח שמתקבלת כדי ליצור פרויקט חדש:

7136b3ee36ebaf89.png

אם עדיין אין לכם פרויקט, אמורה להופיע תיבת דו-שיח כזו כדי ליצור את הפרויקט הראשון:

90977ce514204b51.png

בתיבת הדו-שיח הבאה ליצירת פרויקט תוכלו להזין את פרטי הפרויקט החדש:

6d9573e346e930b4.png

חשוב לזכור את מזהה הפרויקט, שהוא שם ייחודי בכל הפרויקטים ב-Google Cloud (השם שלמעלה כבר תפוס ולא מתאים לכם, סליחה). בהמשך ב-Codelab הזה, המערכת תתייחס אליה בתור PROJECT_ID.

בשלב הבא, אם עדיין לא עשית זאת, יהיה עליך להפעיל חיוב ב-Developers Console כדי להשתמש במשאבים של Google Cloud ולהפעיל את Cloud Trace API.

eb5325f65619ad6a.png

ההרצה של Codelab הזה לא אמורה לעלות לך יותר מכמה דולרים, אבל זה יכול להיות גבוה יותר אם תחליטו להשתמש ביותר משאבים או אם תשאירו אותם פועלים (עיינו בקטע 'ניקוי' בסוף המסמך). המחירים של Google Cloud Trace, Google Kubernetes Engine ו-Google Artifacat Registry מפורטים במסמכי התיעוד הרשמיים.

משתמשים חדשים ב-Google Cloud Platform זכאים לתקופת ניסיון בחינם בשווי 300$, שמאפשרת ל-Codelab הזה בחינם לגמרי.

הגדרת Google Cloud Shell

אפשר להפעיל את Google Cloud ואת Google Cloud Trace מרחוק מהמחשב הנייד, אבל ב-Codelab הזה נשתמש ב-Google Cloud Shell, סביבת שורת הפקודה שפועלת ב-Cloud.

המכונה הווירטואלית הזו שמבוססת על Debian נטענת עם כל הכלים למפתחים שדרושים לכם. יש בה ספריית בית בנפח מתמיד של 5GB והיא פועלת ב-Google Cloud, מה שמשפר משמעותית את ביצועי הרשת והאימות. כלומר, כל מה שדרוש ל-Codelab הזה הוא דפדפן (כן, הוא פועל ב-Chromebook).

כדי להפעיל את Cloud Shell ממסוף Cloud, לוחצים על Activate Cloud Shell gcLMt5IuEcJJNnMId-Bcz3sxCd0rZn7IzT_r95C8UZeqML68Y1efBG_B0VRp7hc7qiZTLAF-TXD7SsOadxn8uadgHhaLeASnVS3ZHK39eOlKJOgj9SJua_oeGhMxRrbOg3qigddS2A (ההקצאה וההתחברות של הסביבה אמורות להימשך כמה דקות).

ff81d016724c4f67.png

fbe156ee6edfbb2e.png

אחרי ההתחברות ל-Cloud Shell, אתם אמורים לראות שכבר בוצע אימות ושהפרויקט כבר מוגדר ל-PROJECT_ID שלכם.

gcloud auth list

פלט הפקודה

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

פלט הפקודה

[core]
project = <PROJECT_ID>

אם מסיבה כלשהי הפרויקט לא מוגדר, פשוט מריצים את הפקודה הבאה:

gcloud config set project <PROJECT_ID>

רוצה למצוא את ה-PROJECT_ID שלך? אתם יכולים לבדוק באיזה מזהה השתמשתם בשלבי ההגדרה או לחפש אותו במרכז הבקרה של מסוף Cloud:

a3e716fc9e7454e9.png

Cloud Shell גם מגדירה משתני סביבה כברירת מחדל, והוא יכול להיות שימושי כשמריצים פקודות עתידיות.

echo $GOOGLE_CLOUD_PROJECT

פלט תקשורת

<PROJECT_ID>

בשלב האחרון, מגדירים את ברירת המחדל של האזור והפרויקט.

gcloud config set compute/zone us-central1-f

אפשר לבחור מגוון אזורים שונים. מידע נוסף זמין במאמר אזורים ו אזורים.

הגדרת Python

ב-Codelab הזה, אנחנו משתמשים ב"שירה" לניהול גרסאות של חבילות באופן קפדני. מריצים את הפקודה הבאה ב-Cloud Shell:

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

הגדרת אשכול של Google Kubernetes

ב-Codelab הזה, תריצו אשכול של מיקרו-שירותים (microservices) ב-Google Kubernetes Engine (GKE). התהליך של Codelab הזה הוא כך:

  1. הורדת פרויקט הבסיס אל Cloud Shell
  2. יצירת מיקרו-שירותים (microservices) בקונטיינרים
  3. העלאת קונטיינרים ל-Google Artifact Registry (GAR)
  4. פריסת קונטיינרים ב-GKE
  5. שינוי קוד המקור של השירותים עבור אינסטרומנטציה למעקב
  6. מעבר לשלב 2

הפעלת Kubernetes Engine

בשלב הראשון אנחנו מגדירים אשכול Kubernetes שבו Shakesapp פועל ב-GKE, ולכן עלינו להפעיל את GKE. עוברים לתפריט 'Kubernetes Engine'. ואז ללחוץ על לחצן ההפעלה.

56c680e93e169731.png

עכשיו אתם מוכנים ליצור אשכול Kubernetes.

יצירת אשכול Kubernetes

ב-Cloud Shell, מריצים את הפקודה הבאה כדי ליצור אשכול Kubernetes. צריך לוודא שערך התחום (zone) נמצא מתחת לאזור שבו השתמשתם ליצירת המאגר של Artifact Registry. אם האזור של המאגר לא מכסה את התחום, משנים את ערך התחום us-central1-f.

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

פלט הפקודה

Creating cluster otel-trace-codelab in us-central1-f... Cluster is being health-checked (master is healthy)...done.
Created [https://container.googleapis.com/v1/projects/psychic-order-307806/zones/us-central1-f/clusters/otel-trace-codelab].
To inspect the contents of your cluster, go to: https://console.cloud.google.com/kubernetes/workload_/gcloud/us-central1-f/otel-trace-codelab?project=psychic-order-307806
kubeconfig entry generated for otel-trace-codelab.
NAME                LOCATION       MASTER_VERSION    MASTER_IP        MACHINE_TYPE  NODE_VERSION      NUM_NODES  STATUS
otel-trace-codelab  us-central1-f  1.18.12-gke.1210  104.154.162.176  e2-medium     1.18.12-gke.1210  3          RUNNING

הגדרת Artifact Registry ו-skaffold

עכשיו יש לנו אשכול Kubernetes מוכן לפריסה. בשלב הבא אנחנו מכינים רישום קונטיינרים לצורך דחיפה ופריסה של קונטיינרים. בשלב הזה צריך להגדיר GAR ו-skaffold כדי להשתמש בו.

הגדרה של Artifact Registry

עוברים לתפריט של Artifact Registry ולוחצים על לחצן ההפעלה.

f7493243bae0cdf7.png

אחרי כמה רגעים תראו את דפדפן המאגר של GAR. לוחצים על 'יצירת מאגר' ותזין את שם המאגר.

f97f337f5476651.png

ב-Codelab הזה, אקרא למאגר החדש trace-codelab. הפורמט של פריט המידע שנוצר בתהליך הפיתוח (Artifact) הוא 'Docker' וסוג המיקום הוא 'אזור'. בוחרים את האזור שקרוב לאזור שהגדרתם לאזור ברירת המחדל של Google Compute Engine. לדוגמה, בדוגמה הזו בחרו 'us-central1-f' למעלה, אז כאן אנחנו בוחרים את 'us-central1 (איווה)'. לאחר מכן לוחצים על 'יצירה' לחצן.

2f04143077ca56db.png

עכשיו מופיעה האפשרות 'trace-codelab' בדפדפן של המאגר.

7a3c1f47346bea15.png

נחזור לכאן מאוחר יותר כדי לבדוק את נתיב הרישום.

הגדרת Skaffold

Skaffold הוא כלי שימושי כשעובדים על פיתוח מיקרו-שירותים (microservices) שמריצים ב-Kubernetes. הוא מטפל בתהליך העבודה של פיתוח, דחיפה ופריסה של קונטיינרים של אפליקציות עם קבוצה קטנה של פקודות. כברירת מחדל, Skaffold משתמש ב-Docker Registry כרישום קונטיינרים, לכן צריך להגדיר את skaffold כך שיזהה GAR בדחיפת קונטיינרים אליהם.

פותחים שוב את Cloud Shell ובודקים אם skaffold מותקן. (Cloud Shell מתקינה את skaffold בסביבה כברירת מחדל). מריצים את הפקודה הבאה ובודקים את הגרסה של skaffold.

skaffold version

פלט הפקודה

v1.20.0

עכשיו אפשר לרשום את מאגר ברירת המחדל לשימוש ב-skaffold. כדי למצוא את נתיב הרישום, עוברים ללוח הבקרה של Artifact Registry ולוחצים על שם המאגר שהגדרתם בשלב הקודם.

55173fe922f40327.png

לאחר מכן יופיעו נתיבי ניווט בחלק העליון של הדף. לוחצים על סמל e157b1359c3edc06.png כדי להעתיק את נתיב הרישום ללוח.

a9b0fa44c37e0178.png

כשלוחצים על לחצן ההעתקה, תוצג תיבת דו-שיח בחלק התחתון של הדפדפן עם הודעה כמו:

&quot;us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab&quot; הועתק

חוזרים אל Cloud Shell. מריצים את הפקודה skaffold config set default-repo עם הערך שהעתקתם ממרכז הבקרה.

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

פלט הפקודה

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

בנוסף, צריך להגדיר את המרשם לתצורת Docker. מריצים את הפקודה הבאה:

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

פלט הפקודה

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

עכשיו אפשר להתחיל לשלב הבא של הגדרת קונטיינר Kubernetes ב-GKE.

סיכום

בשלב הזה מגדירים את סביבת Codelab:

  • הגדרת Cloud Shell
  • יצרתם מאגר Artifact Registy למרשם הקונטיינרים
  • הגדרת skaffold לשימוש במרשם הקונטיינרים
  • יצרתם אשכול Kubernetes שבו רצים מיקרו-שירותים של Codelab

הנושא הבא

בשלב הבא תפתחו, תדחוףו ותפרסו את המיקרו-שירותים (microservices) שלכם באשכול

3. פיתוח, דחיפה ופריסה של מיקרו-שירותים (microservices)

הורדת החומר של ה-Codelab

בשלב הקודם, הגדרנו את כל הדרישות המוקדמות ל-Codelab הזה. עכשיו אתם מוכנים להריץ עליהם מיקרו-שירותים שלמים. חומרי ה-Codelab מתארחים ב-GitHub, לכן צריך להוריד אותם לסביבת Cloud Shell באמצעות פקודת ה-Git הבאה.

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

מבנה הספריות של הפרויקט הוא:

shakesapp-python
├── LICENSE
├── manifests
│   ├── client.yaml
│   ├── loadgen.yaml
│   └── server.yaml
├── proto
│   └── shakesapp.proto
├── skaffold.yaml
└── src
    ├── client
    ├── loadgen
    └── server
  • מניפסטים: קובצי מניפסט של Kubernetes
  • proto: הגדרת אב לתקשורת בין לקוח לשרת
  • src: ספריות לקוד המקור של כל שירות
  • skaffold.yaml: קובץ התצורה של skaffold

הרצת פקודת skaffold

בסוף אתם מוכנים לפתח, לדחוף ולפרוס תוכן שלם באשכול Kubernetes שיצרתם. הצליל הזה כולל כמה שלבים, אבל הפוקוס עצמו עושה את כל מה שצריך. ננסה לפעול באמצעות הפקודה הבאה:

cd shakesapp-python
skaffold run --tail

מיד לאחר הרצת הפקודה, פלט היומן של docker build יופיע ואפשר לאשר שהם נדחפו בהצלחה למרשם.

פלט הפקודה

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

אחרי דחיפת כל קונטיינרים של השירות, הפריסות של Kubernetes יתחילו באופן אוטומטי.

פלט הפקודה

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

זהירות: אם מופיעה שגיאה כמו "No push access to specified image repository", צריך לבדוק אם פקודת skaffold מנסה לדחוף תמונות ל-Docker Hub (docker.io) בלי קשר להגדרות במאגר ברירת המחדל ב-skaffold. במקרה כזה, אפשר לנסות להוסיף "–default-repo" האפשרות "skaffold run" כמו שלמטה.

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

לאחר הפריסה, יומני האפליקציות שהתקבלו ל-stdout יופיעו בכל קונטיינרים בצורה הבאה:

פלט הפקודה

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

לבסוף, אתם מוכנים להתחיל לבצע אינסטרומנטציה לאפליקציה באמצעות OpenTelemetry לצורך מעקב מבוזר של השירותים.

סיכום

בשלב הזה הכנתם את חומר ה-Codelab בסביבה שלכם ואישרתם הפעלות של skaffold כמצופה.

הנושא הבא

בשלב הבא, תשנה את קוד המקור של שירות יצירת טעינה כדי להגדיר את פרטי המעקב.

4. אינסטרומנטציה ל-HTTP

מושג אינסטרומנטציה והפצה של מעקב

לפני עריכת קוד המקור, אסביר בקצרה איך פועלים מעקבים מבוזרים בתרשים פשוט.

c8c659deaa9c9091.png

בדוגמה הזו, אנחנו מגדירים את הקוד כדי לייצא מידע של Trace ו-Span ל-Cloud Trace, ולהפיץ את הקשר המעקב בין הבקשה משירות העומס אל שירות השרת.

האפליקציה צריכה לשלוח מטא-נתונים של Trace, כמו מזהה מעקב ו-Span ID, כדי ש-Cloud Trace ירכיב את כל החלקים שיש להם מזהה מעקב זהה למעקב אחד. בנוסף, האפליקציה צריכה להפיץ הקשרי מעקב (השילוב של מזהה מעקב ומזהה Span של span ההורה) לגבי בקשת שירותי downstream, כדי שהם יוכלו להיות מודעים להקשר המעקב שהם מטפלים בהם.

OpenTelemetry עוזרת לכם:

  • כדי ליצור מזהה מעקב ומזהה SPAN ייחודיים
  • כדי לייצא מזהה Trace ו-Span ID לקצה העורפי
  • להפיץ הקשרי מעקב לשירותים אחרים

היגוי הראשון של הכלי

שירות מחולל עומסים למכשירים

לוחצים על הלחצן 776a11bfb2122549.png בפינה הימנית העליונה של Cloud Shell כדי לפתוח את Cloud Shell Editor. פותחים את src/loadgen/loadgen.py מהכלי Explorer בחלונית הימנית ומחפשים את הפונקציה 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)

בפונקציה main מופיעה הלולאה שקוראת לפונקציה call_client שבה. בהטמעה הנוכחית, ל-sectoin יש 2 שורות יומן שמתעדות את ההתחלה והסיום של הבקשה להפעלת הפונקציה. עכשיו נשתמש במידע על Span כדי לעקוב אחרי זמן האחזור של הפעלת הפונקציה.

קודם כול צריך ליצור Span עם מזהה מעקב ומזהה Span ייחודיים. OpenTelemetry מספק ספרייה שימושית. כדי לייבא ספריות OpenTelemetry לקוד, צריך להוסיף את השורות הבאות.

 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

מכיוון שמחולל העומסים קורא לאפליקציית לקוח ב-HTTP באמצעות מודול requests, אנחנו משתמשים בחבילת התוספים של requests ומפעילים אינסטרומנטציה.

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

אחר כך צריך להגדיר מכונת Tracer שמטפלת בהגדרות של Trace Contenxt ובהגדרות של היצואן

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

שימו לב שבגלל שמדובר ב-Codelab כדי להבין איך פועל האינסטרומנטציה של מעקב, אנחנו מגדירים את ה-Tracer כך שיתעד כל בקשה בנפרד וישלח אותן לקצה העורפי. (SimpleSpanProcessor()) המודל הזה לא מתאים לסביבות ייצור, לכן חשוב לשנות את החלק הזה כשמגדירים את האפליקציה בסביבת הייצור.

עכשיו אפשר לנגן בספאן עם ה-Tracer. הנקודה כאן היא מה שצריך לעשות הוא ליצור טווח באופן מפורש, וזהו! יש שתי שורות שמוסיפות מטא-נתונים של אירועים ל-Span, אבל לא צריך ליצור מזהה Trace ו-Span ID באופן ידני ולהטמיע אותם ב-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)

כדי שמערכת Docker תוכל לאחזר את חבילות OpenTelemetry הנדרשות, מריצים את הפקודה הבאה:

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

אתם יכולים לוודא שהתיאור התואם של התלות כתוב ב-pyproject.toml.

שירות לקוח לכלים

בקטע הקודם, הטמענו את החלק שמוקף במלבן האדום בשרטוט למטה. השתמשנו בנתוני span בשירות מחולל עומסים. בדומה לשירות מחולל העומסים, עכשיו אנחנו צריכים לבצע אינסטלציה לשירות הלקוח. ההבדל משירות מחולל העומסים הוא ששירות הלקוח צריך לחלץ את פרטי מזהה המעקב המופצים משירות מחולל העומסים בכותרת ה-HTTP ולהשתמש במזהה כדי ליצור Spans.

ae074d4513c9931f.png

פותחים את Cloud Shell Editor ומוסיפים את המודולים הנדרשים כמו שעשינו לשירות מחולל העומסים.

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

שמתם לב שייבאתם עכשיו את FlaskInstrumentor, שמאפשר זיהוי אוטומטי של אפליקציית Flask בשם משתמשים כדי לחלץ כותרות HTTP כדי לקבל הקשרי מעקב באמצעות שורת קוד אחת. קהילת OpenTelemetry מספקת שילובים שימושיים דומים עם ספריות גדולות אחרות. מידע נוסף זמין במסמכים הרשמיים.

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

לפני התחלת האינסטרומנטציה, שוב, עליכם להכין את מכונת Tracer באופן דומה למה שעשינו בשירות מחולל העומסים.

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

עכשיו הוא מוכן להוסיף אינסטרומנטציה ל-handler. מחפשים את main_handler() ומשנים את החלק שמפעיל בקשת gRPC לשירות השרת.

@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

בדומה לטעינת שירות מחולל, יש להוסיף את החבילות הנדרשות אל pyproject.toml באמצעות הפקודה הבאה.

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

לאחר מכן נסו להפעיל את האפליקציה באמצעות הפקודה skaffold run ולראות מה מוצג בלוח הבקרה של Cloud Trace:

skaffold run --tail

אחרי שרואים הודעות ליצירה, דחיפה ופריסה של הודעות, תראו יומני אפליקציות בפורמט JSON. עוברים אל Cloud Trace > רשימת נתוני מעקב כדי לבדוק אם אתם מקבלים את פרטי המעקב. מכיוון ששירות מחולל העומסים שולח בקשות לשירות לקוח מדי פעם, והפעלתם מעקבים לכל הבקשות, יתחילו להופיע הרבה נקודות ברשימת המעקב.

f7440360551980e.png

אם תלחצו על אחד מהפריטים האלה, תראו תרשים של Waterfall כמו למטה, שמראה את זמן האחזור של כל חלק במהלך הבקשה והתגובה. מאתרים את תיבת הסימון ליד 'הצגת אירועים'. ההערות יוצגו בתוך תרשים ה-Waterfall. הערות אלה הן אלו שהוספת לקוד באמצעות השיטה span.add_event().

67596a4a313738.png

ייתכן שתבחינו בכך שאתם לא רואים את ה-spans של שירות השרת. זה נכון כי לא צירפנו בכלל שירות ל-Spans לשירות השרת.

סיכום

בשלב הזה הגדרתם אינסטרומנטציה של השירות של מחולל העומסים ושל שירות הלקוח, ואישרתם שאתם יכולים להפיץ בהצלחה הקשר של Trace בין השירותים ולייצא מידע מ-Span משני השירותים אל Cloud Trace.

הנושא הבא

בשלב הבא, תגדירו לשירות הלקוח ולשירות השרת כדי לאשר את אופן ההפצה של Trace Context דרך gRPC.

5. אינסטרומנטציה ל-gRPC

בשלב הקודם, שייכנו את המחצית הראשונה של הבקשה במיקרו-שירותים (microservices) הזה. בשלב הזה, ננסה ליצור אלמנטים של תקשורת gRPC בין שירות הלקוח לבין שירות השרת. (מלבן ירוק וסגול בתמונה למטה)

c4dec3e741c3ab4f.png

תיוג אוטומטי של לקוח gRPC

בסביבה העסקית של OpenTelemetry יש הרבה ספריות שימושיות שעוזרות למפתחים לשלב אפליקציות בכלים. בשלב הקודם השתמשנו בהגדרת תגים אוטומטית ל'בקשות'. של מודל טרנספורמר. בשלב הזה, כשאנחנו מנסים להפיץ הקשר של מעקב דרך gRPC, אנחנו משתמשים בספרייה עבורו.

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

לגבי שירות לקוחות, מה שאנחנו צריכים לעשות בשביל האינסטרומנטציה הוא די קטן. אנחנו רוצים להפיץ את ההקשר של נתוני המעקב, שהוא השילוב של מזהה נתוני המעקב ומזהה ה-Span של ה-Span הנוכחי דרך gRPC. לכן אנחנו קוראים לפונקציה GrpcInstrumentatorClient.instrument() כדי שלקוח gRPC בפונקציה הידית יוכל להטמיע את ההקשר של המעקב בכותרת ה-HTTP שמתחת.

חשוב להוסיף יחסי תלות חדשים ל-pyproject.toml באמצעות הפקודה poetry add:

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

תיוג אוטומטי של שרת gRPC

בדומה למה שעשינו בשביל לקוח gRPC, אנחנו קוראים לתיוג אוטומטי עבור שרת gRPC. אפשר להוסיף פעולות ייבוא כמו מעקבים, ולהפעיל את GrpcInstrumentationServer().instrument() בחלק העליון של הקובץ.

זהירות: לא לשכוח להתקשר

GrpcInstrumentationServe() 

בשלב הזה,

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

בשלב הבא צריך להוסיף את היצואן כדי לשלוח פרטי מעקב לקצה העורפי של Cloud Trace. מוסיפים את הקוד הבא בפונקציה 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)

יש להקפיד להוסיף חבילות חדשות שנוספו בשירות השרת.

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"

מפעילים את המיקרו-שירות (microservice) ומאשרים את המעקב

לאחר מכן מריצים את הקוד שעבר שינוי באמצעות פקודת skaffold.

skaffold run --tail

שוב, אתם רואים קבוצה של מעקבים בדף רשימת נתוני המעקב של Cloud Trace. לוחצים על אחד מכלי המעקב. אחרי שתעשו את זה, תראו את הפעולה הזו מתפרסת על פני הבקשה משירות מחולל העומסים ועד לשירות השרת.

141cb620245b689d.png

סיכום

בשלב הזה בוצעה אינסטרומנטציה של תקשורת שמבוססת על gRPC עם התמיכה מספריות הסביבה של OpenTelemetry. בנוסף, אישרתם שהקשר המעקב שנוצר בשירות מחולל העומסים נשלח בהצלחה לשירות השרת.

6. מזל טוב

יצרת בהצלחה מעקבים מבוזרים באמצעות OpenTelemery ואישרת את זמני האחזור של הבקשות במיקרו-שירות (microservice) ב-Google Cloud Trace.

בתרגילים מורחבים, אתם יכולים לנסות את הנושאים הבאים בעצמכם.

  • ההטמעה הנוכחית שולחת את כל החלקים שנוצרו על ידי בדיקת התקינות. איך מסננים את החלקים האלה מ-Cloud Traces? הרמז נמצא כאן.
  • קורלציה בין יומני אירועים ל-span – כדי לראות איך זה עובד ב-Google Cloud Trace וב-Google Cloud Logging. הרמז נמצא כאן.
  • מחליפים חלק מהשירות בשירות בשפה אחרת ומנסים להשתמש ב-OpenTelemetry באותה שפה

זהירות: Google Kubernetes Engine ו-Google Artifact Registry צורכים את המשאב כל הזמן.

פינוי מקום

אחרי שתעשו את ה-codelab הזה, צריך להפסיק את אשכול Kubernetes ולוודא למחוק את הפרויקט כדי שלא יתקבלו חיובים לא צפויים ב-Google Kubernetes Engine, ב-Google Cloud Trace ו-Google Artifact Registry.

קודם מוחקים את האשכול באמצעות הפקודה הבאה:

skaffold delete

פלט הפקודה

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

אחרי מחיקת האשכול, בחלונית התפריט, בוחרים באפשרות 'IAM & Admin" (אדמין) &gt; 'הגדרות', ולאחר מכן ללחוץ על 'להורדה' לחצן.

578ca2b72a161e9d.png

אחר כך מזינים בטופס את מזהה הפרויקט (לא שם הפרויקט) בתיבת הדו-שיח ומאשרים את הכיבוי.