1. מבוא
עדכון אחרון:5 במרץ 2021
ניראות (observability) של האפליקציה
ניראות (observability) ו-OpenTelemetry
ניראות (observability) היא המונח שמשמש לתיאור תכונה של מערכת. מערכת עם ניראות (observability) מאפשרת לצוותים לנפות באגים במערכת באופן פעיל. בהקשר הזה, שלושה עמודי תווך של ניראות (observability); יומנים, מדדים ועקבות הם הכלים הבסיסיים שבאמצעותם המערכת יכולה להשיג ניראות (observability).
OpenTelemetry היא קבוצה של מפרטים וערכות SDK שמאיצות את המדידה והייצוא של נתוני טלמטריה (יומנים, מדדים ועקבות) שנדרשים לצורך ניראות (observability). OpenTelemetry הוא פרויקט פתוח בתקן פתוח ומבוסס-קהילה במסגרת CNCF. על ידי שימוש בספריות שהפרויקט והסביבה העסקית שלו מספקים, המפתחים יכולים להטמיע את האפליקציות שלהם באופן ניטרלי של הספקים ומול מספר ארכיטקטורות.
מעקב שהופץ
בין היומנים, המדדים והמעקבים, נתוני המעקב הם נתוני הטלמטריה שמציינת את זמן האחזור של חלק ספציפי בתהליך. במיוחד בעידן מיקרו-שירותים, מעקב מבוזר הוא הגורם המשמעותי ביותר למציאת צווארי בקבוק בזמן האחזור במערכת המבוזרת הכוללת.
כשמנתחים מעקבים מבוזרים, התצוגה החזותית של נתוני המעקב היא המפתח להבנת זמן האחזור הכולל של המערכת במבט מהיר. במעקב מבוזר, אנחנו מטפלים בקבוצה של קריאות כדי לעבד בקשה יחידה לנקודת הכניסה של המערכת בצורת נתוני מעקב, שמכילה מגוון קריאות.
טווח מייצג יחידת עבודה בודדת המבוצעת במערכת מבוזרת, והקלטה של זמני התחלה וסיום. לעיתים קרובות יש יחסים היררכיים ביניהם – בתמונה שמתחת לכל ההיקפים הקטנים יותר יש אזורים צאצאים של טווח /הודעות גדול, והם מורכבים מ-Trace להצגת נתיב העבודה במערכת.
הכלי Google Cloud Trace הוא אחת מהאפשרויות לקצה העורפי של מעקב מבוזר, והוא משתלב היטב עם מוצרים אחרים ב-Google Cloud.
מה תפַתחו
ב-Codelab הזה, אתם תעקבו אחרי נתוני מעקב בשירותים שנקראים 'Shakesapp' שפועל על אשכול Kubernetes שפועל על Google Kubernetes Engine. הארכיטקטורה של שייקסאפ מתוארת בהמשך:
- הלקוחות שולחים מחרוזת שאילתה לשרת
- השרת מקבל את השאילתה מהלקוח, מאחזר את כל העבודות בפורמט טקסט מ-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) ויוצרים פרויקט חדש.
אם כבר יש לכם פרויקט, לוחצים על התפריט הנפתח לבחירת פרויקט בפינה השמאלית העליונה של המסוף:
ולוחצים על 'New project' (פרויקט חדש). בתיבת הדו-שיח שמתקבלת כדי ליצור פרויקט חדש:
אם עדיין אין לכם פרויקט, אמורה להופיע תיבת דו-שיח כזו כדי ליצור את הפרויקט הראשון:
בתיבת הדו-שיח הבאה ליצירת פרויקט תוכלו להזין את פרטי הפרויקט החדש:
חשוב לזכור את מזהה הפרויקט, שהוא שם ייחודי בכל הפרויקטים ב-Google Cloud (השם שלמעלה כבר תפוס ולא מתאים לכם, סליחה). בהמשך ב-Codelab הזה, המערכת תתייחס אליה בתור PROJECT_ID.
בשלב הבא, אם עדיין לא עשית זאת, יהיה עליך להפעיל חיוב ב-Developers Console כדי להשתמש במשאבים של Google Cloud ולהפעיל את Cloud Trace API.
ההרצה של Codelab הזה לא אמורה לעלות לך יותר מכמה דולרים, אבל זה יכול להיות גבוה יותר אם תחליטו להשתמש ביותר משאבים או אם תשאירו אותם פועלים (עיינו בקטע 'ניקוי' בסוף המסמך). המחירים של Google Cloud Trace, Google Kubernetes Engine ו-Google Artifacat Registry מפורטים במסמכי התיעוד הרשמיים.
- תמחור הניראות (observability) של Google Cloud
- תמחור | מסמכי תיעוד של Kubernetes Engine
- תמחור של Artifact Registry | חומרי עזר של Artifact 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 (ההקצאה וההתחברות של הסביבה אמורות להימשך כמה דקות).
אחרי ההתחברות ל-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:
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 הזה הוא כך:
- הורדת פרויקט הבסיס אל Cloud Shell
- יצירת מיקרו-שירותים (microservices) בקונטיינרים
- העלאת קונטיינרים ל-Google Artifact Registry (GAR)
- פריסת קונטיינרים ב-GKE
- שינוי קוד המקור של השירותים עבור אינסטרומנטציה למעקב
- מעבר לשלב 2
הפעלת Kubernetes Engine
בשלב הראשון אנחנו מגדירים אשכול Kubernetes שבו Shakesapp פועל ב-GKE, ולכן עלינו להפעיל את GKE. עוברים לתפריט 'Kubernetes Engine'. ואז ללחוץ על לחצן ההפעלה.
עכשיו אתם מוכנים ליצור אשכול 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 ולוחצים על לחצן ההפעלה.
אחרי כמה רגעים תראו את דפדפן המאגר של GAR. לוחצים על 'יצירת מאגר' ותזין את שם המאגר.
ב-Codelab הזה, אקרא למאגר החדש trace-codelab
. הפורמט של פריט המידע שנוצר בתהליך הפיתוח (Artifact) הוא 'Docker' וסוג המיקום הוא 'אזור'. בוחרים את האזור שקרוב לאזור שהגדרתם לאזור ברירת המחדל של Google Compute Engine. לדוגמה, בדוגמה הזו בחרו 'us-central1-f' למעלה, אז כאן אנחנו בוחרים את 'us-central1 (איווה)'. לאחר מכן לוחצים על 'יצירה' לחצן.
עכשיו מופיעה האפשרות 'trace-codelab' בדפדפן של המאגר.
נחזור לכאן מאוחר יותר כדי לבדוק את נתיב הרישום.
הגדרת Skaffold
Skaffold הוא כלי שימושי כשעובדים על פיתוח מיקרו-שירותים (microservices) שמריצים ב-Kubernetes. הוא מטפל בתהליך העבודה של פיתוח, דחיפה ופריסה של קונטיינרים של אפליקציות עם קבוצה קטנה של פקודות. כברירת מחדל, Skaffold משתמש ב-Docker Registry כרישום קונטיינרים, לכן צריך להגדיר את skaffold כך שיזהה GAR בדחיפת קונטיינרים אליהם.
פותחים שוב את Cloud Shell ובודקים אם skaffold מותקן. (Cloud Shell מתקינה את skaffold בסביבה כברירת מחדל). מריצים את הפקודה הבאה ובודקים את הגרסה של skaffold.
skaffold version
פלט הפקודה
v1.20.0
עכשיו אפשר לרשום את מאגר ברירת המחדל לשימוש ב-skaffold. כדי למצוא את נתיב הרישום, עוברים ללוח הבקרה של Artifact Registry ולוחצים על שם המאגר שהגדרתם בשלב הקודם.
לאחר מכן יופיעו נתיבי ניווט בחלק העליון של הדף. לוחצים על סמל כדי להעתיק את נתיב הרישום ללוח.
כשלוחצים על לחצן ההעתקה, תוצג תיבת דו-שיח בחלק התחתון של הדפדפן עם הודעה כמו:
"us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab" הועתק
חוזרים אל 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
מושג אינסטרומנטציה והפצה של מעקב
לפני עריכת קוד המקור, אסביר בקצרה איך פועלים מעקבים מבוזרים בתרשים פשוט.
בדוגמה הזו, אנחנו מגדירים את הקוד כדי לייצא מידע של Trace ו-Span ל-Cloud Trace, ולהפיץ את הקשר המעקב בין הבקשה משירות העומס אל שירות השרת.
האפליקציה צריכה לשלוח מטא-נתונים של Trace, כמו מזהה מעקב ו-Span ID, כדי ש-Cloud Trace ירכיב את כל החלקים שיש להם מזהה מעקב זהה למעקב אחד. בנוסף, האפליקציה צריכה להפיץ הקשרי מעקב (השילוב של מזהה מעקב ומזהה Span של span ההורה) לגבי בקשת שירותי downstream, כדי שהם יוכלו להיות מודעים להקשר המעקב שהם מטפלים בהם.
OpenTelemetry עוזרת לכם:
- כדי ליצור מזהה מעקב ומזהה SPAN ייחודיים
- כדי לייצא מזהה Trace ו-Span ID לקצה העורפי
- להפיץ הקשרי מעקב לשירותים אחרים
היגוי הראשון של הכלי
שירות מחולל עומסים למכשירים
לוחצים על הלחצן בפינה הימנית העליונה של 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.
פותחים את 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 > רשימת נתוני מעקב כדי לבדוק אם אתם מקבלים את פרטי המעקב. מכיוון ששירות מחולל העומסים שולח בקשות לשירות לקוח מדי פעם, והפעלתם מעקבים לכל הבקשות, יתחילו להופיע הרבה נקודות ברשימת המעקב.
אם תלחצו על אחד מהפריטים האלה, תראו תרשים של Waterfall כמו למטה, שמראה את זמן האחזור של כל חלק במהלך הבקשה והתגובה. מאתרים את תיבת הסימון ליד 'הצגת אירועים'. ההערות יוצגו בתוך תרשים ה-Waterfall. הערות אלה הן אלו שהוספת לקוד באמצעות השיטה span.add_event()
.
ייתכן שתבחינו בכך שאתם לא רואים את ה-spans של שירות השרת. זה נכון כי לא צירפנו בכלל שירות ל-Spans לשירות השרת.
סיכום
בשלב הזה הגדרתם אינסטרומנטציה של השירות של מחולל העומסים ושל שירות הלקוח, ואישרתם שאתם יכולים להפיץ בהצלחה הקשר של Trace בין השירותים ולייצא מידע מ-Span משני השירותים אל Cloud Trace.
הנושא הבא
בשלב הבא, תגדירו לשירות הלקוח ולשירות השרת כדי לאשר את אופן ההפצה של Trace Context דרך gRPC.
5. אינסטרומנטציה ל-gRPC
בשלב הקודם, שייכנו את המחצית הראשונה של הבקשה במיקרו-שירותים (microservices) הזה. בשלב הזה, ננסה ליצור אלמנטים של תקשורת gRPC בין שירות הלקוח לבין שירות השרת. (מלבן ירוק וסגול בתמונה למטה)
תיוג אוטומטי של לקוח 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. לוחצים על אחד מכלי המעקב. אחרי שתעשו את זה, תראו את הפעולה הזו מתפרסת על פני הבקשה משירות מחולל העומסים ועד לשירות השרת.
סיכום
בשלב הזה בוצעה אינסטרומנטציה של תקשורת שמבוססת על 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" (אדמין) > 'הגדרות', ולאחר מכן ללחוץ על 'להורדה' לחצן.
אחר כך מזינים בטופס את מזהה הפרויקט (לא שם הפרויקט) בתיבת הדו-שיח ומאשרים את הכיבוי.