במדריך הזה מוסבר איך לפתור בעיות בשירות Knative Serving באמצעות כלי Stackdriver לגילוי, ואיך להשתמש בתהליך עבודה מקומי לפיתוח כדי לבדוק את הבעיה.
המדריך המפורט הזה הוא 'מקרה לדוגמה' שנועד לעזור לכם להשתמש במדריך לפתרון בעיות. הוא כולל פרויקט לדוגמה שגורם לשגיאות בזמן הריצה כשפורסים אותו. אתם יכולים לפתור את הבעיות האלה כדי למצוא ולתקן את הבעיה.
מטרות
- כתיבה, פיתוח ופריסה של שירות למילוי בקשות מסוג Knative
- שימוש ב-Cloud Logging כדי לזהות שגיאה
- אחזור קובץ אימג' של קונטיינר מ-Container Registry לצורך ניתוח שורש הבעיה
- לתקן את שירות ה'ייצור', ואז לשפר את השירות כדי לצמצם את הסיכון לבעיות עתידיות
עלויות
במסמך הזה משתמשים ברכיבים הבאים של Google Cloud, והשימוש בהם כרוך בתשלום:
כדי להעריך את ההוצאות בהתאם לתחזית השימוש שלכם, אתם יכולים להיעזר במחשבון העלויות.
לפני שמתחילים
- במדריך הזה אנחנו מניחים שהתקנתם והגדרתם את Knative serving באשכול שלכם.
- מוודאים שסביבת שורת הפקודה מוגדרת והכלים מעודכנים:
- כדי לנסות את השירות, מתקינים את curl.
- מתקינים את Docker באופן מקומי.
הרכבת הקוד
בונים שירות חדש של Knative serving greeter שלב אחר שלב. לתזכורת, השירות הזה יוצר שגיאת זמן ריצה בכוונה לצורך תרגיל פתרון הבעיות.
כדי ליצור פרויקט חדש:
Node.js
יוצרים פרויקט Node.js על ידי הגדרת חבילת השירות, התלויות הראשוניות וכמה פעולות נפוצות.יוצרים ספרייה בשם
hello-service:mkdir hello-service cd hello-serviceיוצרים קובץ
package.json:npm init --yes npm install express@4פותחים את הקובץ החדש
package.jsonבכלי העריכה ומגדירים סקריפטstartלהרצתnode index.js. בסיום, הקובץ ייראה כך:{ "name": "hello-service", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "start": "node index.js", "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "express": "^4.17.1" } }
אם אתם מתכננים להמשיך לפתח את השירות הזה מעבר להדרכה המיידית, כדאי למלא את התיאור, את שם המחבר ולבדוק את הרישיון. פרטים נוספים זמינים במסמכי התיעוד בנושא package.json.
Python
יצירת ספרייה חדשה ב-
hello-service:mkdir hello-service cd hello-serviceיוצרים קובץ requirements.txt ומעתיקים אליו את התלות:
המשך
יוצרים ספרייה בשם
hello-service:mkdir hello-service cd hello-serviceיוצרים פרויקט Go על ידי הפעלה של מודול Go חדש:
go mod init <var>my-domain</var>.com/hello-service
אפשר לעדכן את השם הספציפי איך שרוצים: צריך לעדכן את השם אם הקוד מתפרסם במאגר המקורות של הקוד שאפשר לגשת אליו דרך האינטרנט.
Java
יוצרים פרויקט Maven:
mvn archetype:generate \ -DgroupId=com.example \ -DartifactId=hello-service \ -DarchetypeArtifactId=maven-archetype-quickstart \ -DinteractiveMode=falseמעתיקים את יחסי התלות לרשימת יחסי התלות
pom.xml(בין רכיבי<dependencies>):מעתיקים את הגדרת ה-build אל
pom.xml(מתחת לרכיבי<dependencies>):
יוצרים שירות HTTP לטיפול בבקשות נכנסות:
Node.js
Python
המשך
Java
יוצרים
Dockerfileכדי להגדיר את קובץ האימג' של הקונטיינר שמשמש לפריסת השירות:
שליחת הקוד
תהליך העברת הקוד כולל שלושה שלבים: יצירת קובץ אימג' של קונטיינר באמצעות Cloud Build, העלאת קובץ האימג' של הקונטיינר ל-Container Registry ופריסת קובץ האימג' של הקונטיינר ל-Knative serving.
כדי לשלוח את הקוד:
יוצרים את הקונטיינר ומפרסמים אותו ב-Container Registry:
Node.js
gcloud builds submit --tag gcr.io/PROJECT_ID/hello-service
כאשר PROJECT_ID הוא מזהה הפרויקט. Google Cloud אפשר לבדוק את מזהה הפרויקט הנוכחי באמצעות
gcloud config get-value project.אם הפעולה תצליח, תופיע הודעת SUCCESS עם המזהה, זמן היצירה ושם התמונה. התמונה מאוחסנת ב-Container Registry ואפשר לעשות בה שימוש חוזר אם רוצים.
Python
gcloud builds submit --tag gcr.io/PROJECT_ID/hello-service
כאשר PROJECT_ID הוא מזהה הפרויקט. Google Cloud אפשר לבדוק את מזהה הפרויקט הנוכחי באמצעות
gcloud config get-value project.אם הפעולה תצליח, תופיע הודעת SUCCESS עם המזהה, זמן היצירה ושם התמונה. התמונה מאוחסנת ב-Container Registry ואפשר לעשות בה שימוש חוזר אם רוצים.
המשך
gcloud builds submit --tag gcr.io/PROJECT_ID/hello-service
כאשר PROJECT_ID הוא מזהה הפרויקט. Google Cloud אפשר לבדוק את מזהה הפרויקט הנוכחי באמצעות
gcloud config get-value project.אם הפעולה תצליח, תופיע הודעת SUCCESS עם המזהה, זמן היצירה ושם התמונה. התמונה מאוחסנת ב-Container Registry ואפשר לעשות בה שימוש חוזר אם רוצים.
Java
mvn compile jib:build -Dimage=gcr.io/PROJECT_ID/hello-service
כאשר PROJECT_ID הוא מזהה הפרויקט. Google Cloud אפשר לבדוק את מזהה הפרויקט הנוכחי באמצעות
gcloud config get-value project.אם הפעולה תצליח, תוצג ההודעה BUILD SUCCESS. התמונה מאוחסנת ב-Container Registry ואפשר להשתמש בה שוב אם רוצים.
מריצים את הפקודה הבאה כדי לפרוס את האפליקציה:
gcloud run deploy hello-service --image gcr.io/PROJECT_ID/hello-service
מחליפים את PROJECT_ID במזהה הפרויקט ב- Google Cloud .
hello-serviceהוא גם השם של קובץ האימג' בקונטיינר וגם השם של שירות Knative Serving. שימו לב שקובץ אימג' של קונטיינר נפרס בשירות ובאשכול שהגדרתם קודם בקטע הגדרת gcloud.מחכים עד שהפריסה תושלם. התהליך הזה יכול להימשך כחצי דקה. אם הפעולה בוצעה ללא שגיאות, כתובת ה-URL של השירות מוצגת בשורת הפקודה.
אני רוצה לנסות
כדאי לנסות את השירות כדי לוודא שהפריסה בוצעה בהצלחה. הבקשות צריכות להיכשל עם שגיאת HTTP 500 או 503 (שגיאות ששייכות לסיווג 5xx שגיאות שרת). במדריך מוסבר איך לפתור את הבעיה שמופיעה בתגובה לשגיאה.
אם האשכול שלכם מוגדר עם דומיין ברירת מחדל שניתן לניתוב, אפשר לדלג על השלבים שלמעלה ולהעתיק את כתובת ה-URL לדפדפן האינטרנט.
אם לא משתמשים באישורי TLS אוטומטיים ובמיפוי דומיינים, לא מקבלים כתובת URL שניתן לנווט אליה בשביל השירות.
במקום זאת, משתמשים בכתובת ה-URL שסופקה ובכתובת ה-IP של שער הכניסה של השירות כדי ליצור פקודת curl שיכולה לשלוח בקשות לשירות:
-
כדי לקבל את כתובת ה-IP החיצונית של מאזן העומסים, מריצים את הפקודה הבאה:
kubectl get svc istio-ingressgateway -n ASM-INGRESS-NAMESPACE
מחליפים את ASM-INGRESS-NAMESPACE במרחב השמות שבו נמצאת הכניסה של Cloud Service Mesh. מציינים
istio-systemאם התקנתם את Cloud Service Mesh באמצעות הגדרת ברירת המחדל שלו.הפלט שיתקבל ייראה כך:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) istio-ingressgateway LoadBalancer XX.XX.XXX.XX pending 80:32380/TCP,443:32390/TCP,32400:32400/TCP
כאשר הערך EXTERNAL-IP הוא כתובת ה-IP החיצונית של מאזן העומסים.
מריצים פקודה
curlבאמצעות כתובתGATEWAY_IPהזו בכתובת ה-URL.curl -G -H "Host: SERVICE-DOMAIN" https://EXTERNAL-IP/
מחליפים את SERVICE-DOMAIN בדומיין שמוקצה כברירת מחדל לשירות. כדי לקבל את כתובת ה-URL הזו, לוקחים את כתובת ה-URL שמוגדרת כברירת מחדל ומסירים את הפרוטוקול
http://.מופיעה הודעת השגיאה HTTP 500 או HTTP 503.
בדיקת הבעיה
תארו לעצמכם ששגיאת HTTP 5xx שנתקלתם בה למעלה בקטע Trying it out התרחשה כשגיאת זמן ריצה בייצור. במדריך הזה מוסבר תהליך רשמי לטיפול בבעיה. תהליכי פתרון שגיאות בהפקה משתנים מאוד, אבל במדריך הזה מוצגת רצף מסוים של שלבים כדי להראות את השימוש בכלים ובטכניקות שימושיים.
כדי לחקור את הבעיה הזו, צריך לעבור את השלבים הבאים:
- כדאי לאסוף פרטים נוספים על השגיאה שדווחה כדי לתמוך בחקירה נוספת ולהגדיר אסטרטגיית צמצום סיכונים.
- כדי להקטין את ההשפעה על המשתמשים, אפשר להמשיך בתיקון או לחזור לגרסה תקינה מוכרת.
- לשחזר את השגיאה כדי לוודא שהפרטים הנכונים נאספו ושהשגיאה היא לא תקלה חד-פעמית
- מבצעים ניתוח של שורש הבעיה כדי למצוא את הקוד, ההגדרה או התהליך שיצרו את השגיאה הזו.
בתחילת הבדיקה יש לכם כתובת URL, חותמת זמן וההודעה Internal Server Error (שגיאת שרת פנימית).
איסוף פרטים נוספים
כדאי לאסוף מידע נוסף על הבעיה כדי להבין מה קרה ולקבוע מה השלבים הבאים.
משתמשים בכלים הזמינים כדי לאסוף פרטים נוספים:
פרטים נוספים זמינים ביומנים.
אפשר להשתמש ב-Cloud Logging כדי לבדוק את רצף הפעולות שהובילו לבעיה, כולל הודעות השגיאה.
חזרה לגרסה תקינה
אם יש לכם גרסה שאתם יודעים שהיא פעלה, אתם יכולים לבצע החזרה למצב קודם של השירות כדי להשתמש בגרסה הזו. לדוגמה, לא תוכלו לבצע חזרה לגרסה קודמת בשירות החדש hello-service שפרסתם במדריך הזה, כי הוא מכיל רק גרסה אחת.
כדי לאתר גרסה ולבטל את השינויים בשירות:
שחזור השגיאה
בעזרת הפרטים שקיבלתם קודם, ודאו שהבעיה מתרחשת באופן עקבי בתנאי בדיקה.
שולחים את אותה בקשת HTTP על ידי ניסיון חוזר, ובודקים אם מדווחת אותה שגיאה עם אותם פרטים. יכול להיות שיעבור זמן מה עד שפרטי השגיאה יופיעו.
מכיוון שהשירות לדוגמה במדריך הזה הוא לקריאה בלבד ולא מפעיל תופעות לוואי מסובכות, אפשר לשחזר שגיאות בייצור בצורה בטוחה. עם זאת, במקרים רבים של שירותים אמיתיים, זה לא יקרה: יכול להיות שתצטרכו לשחזר שגיאות בסביבת בדיקה או להגביל את השלב הזה לבדיקה מקומית.
שחזור השגיאה יוצר את ההקשר להמשך העבודה. לדוגמה, אם המפתחים לא מצליחים לשחזר את השגיאה, יכול להיות שיידרש מחקר נוסף כדי להוסיף מכשור לשירות.
ביצוע ניתוח שורש הבעיה
ניתוח הגורם המרכזי הוא שלב חשוב בפתרון בעיות יעיל, כדי לוודא שאתם פותרים את הבעיה ולא רק את הסימפטום.
בשלב מוקדם יותר במדריך הזה, שיחזרתם את הבעיה ב-Knative serving, מה שמאשר שהבעיה פעילה כשהשירות מתארח ב-Knative serving. עכשיו צריך לשחזר את הבעיה באופן מקומי כדי לקבוע אם הבעיה מוגבלת לקוד או שהיא מופיעה רק באירוח בסביבת הייצור.
אם לא השתמשתם ב-Docker CLI באופן מקומי עם Container Registry, צריך לאמת אותו באמצעות gcloud:
gcloud auth configure-docker
אפשר למצוא גישות חלופיות במאמר שיטות אימות ב-Container Registry.
אם השם של קובץ אימג' של קונטיינר שהיה בשימוש לאחרונה לא זמין, בתיאור השירות מופיע המידע של קובץ אימג' של קונטיינר שהופעל לאחרונה:
gcloud run services describe hello-service
מחפשים את השם של קובץ אימג' של קונטיינר בתוך האובייקט
spec. אפשר להשתמש בפקודה ממוקדת יותר כדי לאחזר אותו ישירות:gcloud run services describe hello-service \ --format="value(spec.template.spec.containers.image)"
הפקודה הזו חושפת את השם של קובץ אימג' של קונטיינר, כמו
gcr.io/PROJECT_ID/hello-service.מושכים את קובץ אימג' של קונטיינר מ-Container Registry לסביבה שלכם. השלב הזה עשוי להימשך כמה דקות כי קובץ אימג' של קונטיינר יורד:
docker pull gcr.io/PROJECT_ID/hello-service
אפשר לאחזר עדכונים מאוחרים יותר של קובץ אימג' של קונטיינר שנעשה בהם שימוש חוזר בשם הזה באמצעות אותה פקודה. אם מדלגים על השלב הזה, הפקודה
docker runשבהמשך מושכת קובץ אימג' של קונטיינר אם הוא לא קיים במחשב המקומי.מריצים באופן מקומי כדי לוודא שהבעיה לא ייחודית ל-Knative serving:
PORT=8080 && docker run --rm -e PORT=$PORT -p 9000:$PORT \ gcr.io/PROJECT_ID/hello-service
פירוט הרכיבים של הפקודה שלמעלה:
- משתנה הסביבה
PORTמשמש את השירות כדי לקבוע את היציאה להאזנה בתוך הקונטיינר. - הפקודה
runמפעילה את הקונטיינר, ומוגדרת כברירת מחדל לפקודת נקודת הכניסה שמוגדרת בקובץ Dockerfile או בקובץ אימג' של קונטיינר של אב. - הדגל
--rmמוחק את מופע הקונטיינר ביציאה. - הדגל
-eמקצה ערך למשתנה סביבה. -e PORT=$PORTמעביר את המשתנהPORTמהמערכת המקומית למאגר התגים עם אותו שם משתנה. - הדגל
-pמפרסם את מאגר התגים כשירות שזמין ב-localhost ביציאה 9000. בקשות אל localhost:9000 ינותבו אל הקונטיינר ביציאה 8080. המשמעות היא שהפלט מהשירות לגבי מספר היציאה שבשימוש לא יהיה זהה לדרך שבה ניגשים לשירות. - הארגומנט האחרון
gcr.io/PROJECT_ID/hello-serviceהוא נתיב למאגר שמצביע על הגרסה האחרונה של תמונת הקונטיינר. אם התמונה לא זמינה באופן מקומי, Docker מנסה לאחזר אותה ממאגר מרוחק.
פותחים את הכתובת http://localhost:9000 בדפדפן. בודקים את הפלט של הטרמינל כדי לראות אם יש הודעות שגיאה שדומות לאלה שמופיעות ב-Google Cloud Observability.
אם הבעיה לא ניתנת לשחזור באופן מקומי, יכול להיות שהיא ייחודית לסביבת Knative serving. כדאי לעיין במדריך לפתרון בעיות ב-Knative serving כדי לדעת באילו תחומים ספציפיים כדאי לבדוק.
במקרה כזה, השגיאה משוכפלת באופן מקומי.
- משתנה הסביבה
עכשיו, אחרי שאישרנו פעמיים שהשגיאה נמשכת ושהיא נגרמת על ידי קוד השירות ולא על ידי פלטפורמת האירוח, הגיע הזמן לבדוק את הקוד בצורה מדוקדקת יותר.
לצורך המדריך הזה, אפשר להניח שהקוד בתוך מאגר התגים והקוד במערכת המקומית זהים.
Node.js
מחפשים את המקור של הודעת השגיאה בקובץindex.js סביב מספר השורה שמופיע בדוח קריסות שמוצגים ביומנים:
Python
מחפשים את המקור של הודעת השגיאה בקובץmain.py סביב מספר השורה שמופיע בדוח קריסות שמוצגים ביומנים:
המשך
מחפשים את המקור של הודעת השגיאה בקובץ main.go סביב מספר השורה שמופיע בדוח קריסות שמוצגים ביומנים:
Java
מחפשים את המקור של הודעת השגיאה בקובץ App.java סביב מספר השורה שמופיע בדוח קריסות שמוצג ביומנים:
בבדיקה של הקוד הזה, הפעולות הבאות מתבצעות כשמשתנה הסביבה NAME לא מוגדר:
- שגיאה נרשמת ביומן ב-Google Cloud Observability
- נשלחת תגובת שגיאה של HTTP
הבעיה נגרמת בגלל משתנה חסר, אבל סיבת השורש ספציפית יותר: שינוי הקוד שמוסיף את התלות הקשיחה במשתנה סביבה לא כולל שינויים קשורים בסקריפטים של הפריסה ובמסמכי הדרישות של זמן הריצה.
תיקון שורש הבעיה
אחרי שאספנו את הקוד וזיהינו את שורש הבעיה האפשרי, אנחנו יכולים לנקוט צעדים לפתרון הבעיה.
בודקים אם השירות פועל באופן מקומי עם סביבת
NAMEשזמינה במקום:מריצים את הקונטיינר באופן מקומי עם משתנה הסביבה שנוסף:
PORT=8080 && docker run --rm -e PORT=$PORT -p 9000:$PORT \ -e NAME="Local World!" \ gcr.io/PROJECT_ID/hello-service
בדפדפן, עוברים לכתובת http://localhost:9000
הטקסט 'Hello Local World!' מופיע בדף
משנים את סביבת השירות הפועל של Knative serving כך שתכלול את המשתנה הזה:
מריצים את פקודת עדכון השירותים עם הפרמטר
--update-env-varsכדי להוסיף משתנה סביבה:gcloud run services update hello-service \ --update-env-vars NAME=Overrideמחכים כמה שניות בזמן ש-Knative serving יוצר גרסה חדשה על סמך הגרסה הקודמת עם משתנה הסביבה החדש שנוסף.
מוודאים שהשירות תוקן:
- בדפדפן, עוברים לכתובת ה-URL של שירות Knative.
- הטקסט 'Hello Override!' יופיע בדף.
- מוודאים שלא מופיעות הודעות או שגיאות לא צפויות ב-Cloud Logging.
שיפור מהירות פתרון הבעיות בעתיד
בדוגמה הזו של בעיה בייצור, השגיאה קשורה להגדרות התפעוליות. יש שינויים בקוד שיצמצמו את ההשפעה של הבעיה הזו בעתיד.
- לשפר את יומן השגיאות כך שיכלול פרטים ספציפיים יותר.
- במקום להחזיר שגיאה, השירות יחזור לברירת מחדל בטוחה. אם שימוש בערך ברירת מחדל מייצג שינוי בפונקציונליות הרגילה, צריך להשתמש בהודעת אזהרה למטרות מעקב.
נראה איך מסירים את משתנה הסביבה NAME כתלות מחייבת.
מסירים את הקוד הקיים לטיפול ב-
NAME:Node.js
Python
המשך
Java
מוסיפים קוד חדש שמגדיר ערך ברירת מחדל:
Node.js
Python
המשך
Java
כדי לבדוק באופן מקומי, צריך לבנות מחדש את הקונטיינר ולהפעיל אותו באמצעות תרחישי ההגדרות המושפעים:
Node.js
docker build --tag gcr.io/PROJECT_ID/hello-service .
Python
docker build --tag gcr.io/PROJECT_ID/hello-service .
Go
docker build --tag gcr.io/PROJECT_ID/hello-service .
Java
mvn compile jib:build
מוודאים שמשתנה הסביבה
NAMEעדיין פועל:PORT=8080 && docker run --rm -e $PORT -p 9000:$PORT \ -e NAME="Robust World" \ gcr.io/PROJECT_ID/hello-service
מוודאים שהשירות פועל ללא המשתנה
NAME:PORT=8080 && docker run --rm -e $PORT -p 9000:$PORT \ gcr.io/PROJECT_ID/hello-service
אם השירות לא מחזיר תוצאה, צריך לוודא שהסרת הקוד בשלב הראשון לא הסירה שורות נוספות, כמו אלה שמשמשות לכתיבת התגובה.
כדי להטמיע את הקוד, חוזרים לקטע הטמעת הקוד.
כל פריסה לשירות יוצרת גרסה חדשה ומתחילה להציג תנועה באופן אוטומטי כשהיא מוכנה.
כדי למחוק את משתני הסביבה שהוגדרו קודם:
gcloud run services update hello-service --clear-env-vars
מוסיפים את הפונקציונליות החדשה של ערך ברירת המחדל לכיסוי הבדיקות האוטומטיות של השירות.
חיפוש בעיות אחרות ביומנים
יכול להיות שיופיעו בעיות אחרות בכלי Log Viewer בשירות הזה. לדוגמה, קריאת מערכת לא נתמכת תופיע ביומנים כ-Container Sandbox Limitation (הגבלה של ארגז חול של קונטיינר).
לדוגמה, לפעמים השירותים של Node.js יוצרים את הודעת היומן הבאה:
Container Sandbox Limitation: Unsupported syscall statx(0xffffff9c,0x3e1ba8e86d88,0x0,0xfff,0x3e1ba8e86970,0x3e1ba8e86a90). Please, refer to https://gvisor.dev/c/linux/amd64/statx for more information.
במקרה הזה, חוסר התמיכה לא משפיע על שירות הדוגמה hello-service.
הסרת המשאבים
כדי להימנע מחיובים, אפשר למחוק את המשאבים שנוצרו במסגרת המדריך הזה.
מחיקת משאבי הדרכה
מוחקים את שירות מילוי הבקשות מסוג Knative שפרסתם במדריך הזה:
gcloud run services delete SERVICE-NAME
כאשר SERVICE-NAME הוא שם השירות שבחרתם.
אפשר גם למחוק שירותי Knative serving מהמסוף:Google Cloud
מסירים את הגדרות ברירת המחדל של gcloud שהוספתם במהלך ההגדרה של המדריך:
gcloud config unset run/platform gcloud config unset run/cluster gcloud config unset run/cluster_locationמסירים את הגדרות הפרויקט:
gcloud config unset projectמחיקת משאבים אחרים Google Cloud שנוצרו במדריך הזה:
- מוחקים את קובץ אימג' של קונטיינר בשם
gcr.io/<var>PROJECT_ID</var>/hello-serviceמ-Container Registry. - אם יצרתם אשכול בשביל המדריך הזה, צריך למחוק את האשכול.
- מוחקים את קובץ אימג' של קונטיינר בשם
המאמרים הבאים
- מידע נוסף על השימוש ב-Cloud Logging כדי לקבל תובנות לגבי התנהגות בסביבת הייצור.
- מידע נוסף על פתרון בעיות במילוי בקשות מסוג Knative
- כדאי להעמיק את הקריאה ולהכיר דוגמאות לארכיטקטורות, תרשימים ושיטות מומלצות בנושאי Google Cloud. כל אלה זמינים במרכז הארכיטקטורה של Cloud.