
בדיקת liveness שגויה עלולה להפיל אשכול — כך מפרידים שלוש בדיקות

לפי תיעוד הבדיקות של Kubernetes, שלוש הבדיקות מכוונות לפעולות שונות: startup נותנת ליישום זמן להשלים את האתחול, readiness עוצרת תעבורה אל Pod שאינו מסוגל לשרת בקשות, ו־liveness מפעילה מחדש מכולה שנתקעה במצב שהפעלה מחדש עשויה לתקן. הגדרה שגויה של liveness עלולה ליצור כשלים מתגלגלים: מכולות מופעלות מחדש תחת עומס, בקשות נכשלות והעבודה עוברת ל־Pods שנותרו.
ההבחנה המעשית היא בין חוסר זמינות זמני לבין תקלה מקומית שאינה צפויה לחלוף. תיעוד מחזור החיים של Pod מתאר כיצד כשל readiness מסיר את כתובת ה־Pod מ־EndpointSlices של Services מתאימים, בעוד המכולה ממשיכה לפעול. אם התהליך עדיין מסוגל להתאושש, הפעלה מחדש עלולה להוסיף עבודת אתחול דווקא כשהשירות מתקשה לשאת את העומס.
ממפים את הסימפטום לפעולה
התחילו בשאלה מה ה־kubelet אמור לעשות בעקבות הכשל, ורק אחר כך בחרו נתיב HTTP או פקודת בדיקה. אותה תשובת שגיאה אינה מתאימה אוטומטית לכל הבדיקות, משום שלכל אחת תוצאה תפעולית אחרת.
- אם המכולה עדיין טוענת נתונים, בונה מטמון או מבצעת הכנה ראשונית, השתמשו ב־startup. עד להצלחתה, בדיקות readiness ו־liveness אינן מתחילות. אם היא נכשלת מעבר לסף שהוגדר, המכולה נהרגת וכפופה למדיניות ההפעלה מחדש של ה־Pod.
- אם היישום פועל אך אינו יכול לטפל כעת בבקשות, השתמשו ב־readiness. היא נבדקת לאורך חיי המכולה, ולכן יכולה להוציא Pod ממסלול התעבורה בזמן עומס או תקלה זמנית ולהחזירו כשהוא מוכן שוב, בלי להפעיל את המכולה מחדש.
- אם היישום תקוע כך שהמשך ההמתנה לא צפוי לעזור, השתמשו ב־liveness. דוגמה היא deadlock שבו התהליך עדיין פועל אך אינו מתקדם. בחרו אות שמעיד על מצב התהליך עצמו, משום שכישלונות רצופים של הבדיקה מובילים להפעלה מחדש.
מונעים מתלות חיצונית להפוך להפעלה מחדש
בדיקת liveness צריכה לענות על שאלה צרה: האם המכולה המקומית מסוגלת להתקדם. בדיקה שפונה בכל פעם למסד נתונים, לשירות צד שלישי או למערכת תורים עשויה להיכשל גם כשהמכולה עצמה תקינה. במקרה כזה הפעלה מחדש אינה מתקנת את התלות החיצונית, אך היא קוטעת בקשות ומוסיפה עבודת אתחול.
אם השירות אינו מסוגל להשיב כראוי ללא תלות חיצונית מסוימת, אפשר לשקף זאת ב־readiness ולמנוע ניתוב בקשות ל־Pods שאינם כשירים. כאשר כל ה־Pods חולקים את אותה תלות, כשל משותף עשוי להוציא את כולם מתעבורה. לכן הגדירו כשל readiness רק כשהשירות באמת אינו יכול לתת תשובה שימושית; אם הוא מסוגל לספק תפקוד חלקי, נקודת הבדיקה צריכה לשקף את היכולת הזאת.
גם בדיקה מקומית צריכה להיות זולה. נתיב health שמבצע עבודה כבדה בכל קריאה עלול להוסיף עומס דווקא כשהשירות איטי. העדיפו תגובה קצרה שמבוססת על מצב שכבר ידוע לתהליך, והפרידו בין ״האתחול הושלם״, ״אפשר לקבל תעבורה״ ו״התהליך מתקדם״ כאשר המשמעויות האלה שונות ביישום שלכם.
מחשבים את חלון הכשל לפני שקובעים ספים
ב־startup, המכפלה failureThreshold × periodSeconds משמשת לתכנון חלון שיכסה גם את זמן האתחול האיטי שאתם מצפים לו. הוראות ההגדרה של Kubernetes משתמשות בחישוב הזה: בדוגמה שלהן 30 כישלונות במרווח של 10 שניות נותנים 300 שניות, כלומר חמש דקות. אל תקבעו את הסף לפי זמן האתחול הממוצע אם טעינת נתונים או התאוששות עשויות להימשך יותר.
failureThreshold סופר כישלונות רצופים; timeoutSeconds קובע מתי ניסיון יחיד נחשב לכישלון. בדוגמה מותנית לשירות אחר, readiness עם מרווח של 5 שניות ושני כישלונות רצופים יכולה להפסיק תעבורה מהר יחסית, ואילו liveness עם מרווח של 10 שניות ושישה כישלונות רצופים סובלנית יותר להאטה חולפת. אלה ערכי פתיחה להמחשה, לא ספים בטוחים לכל שירות: משך הבדיקה ותזמון הניסיונות משפיעים על רגע שינוי המצב בפועל.
מדדו בנפרד כמה זמן נמשך אתחול בתנאי עומס, כמה זמן נמשכת האטה זמנית לפני התאוששות וכמה זמן סביר להשאיר תהליך תקוע. אם timeoutSeconds קצר מזמן התגובה הרגיל של נקודת הבדיקה תחת עומס צפוי, הגדלת failureThreshold בלבד עלולה רק לדחות הפעלה מחדש שגויה. תחילה פשטו את הבדיקה או התאימו את ה־timeout למציאות התפעולית.
תבנית YAML לשירות שמתחיל לאט
להלן דוגמה מותנית לקטע תחת spec של Pod. כתיב ה־YAML הוא בתצורת flow בשורה אחת; החליפו את כתובת התמונה והטמיעו ביישום את נתיבי ה־health לפני פריסה. הנתיב started צריך להצליח כשהאתחול הושלם, ready כשהשירות יכול לקבל תעבורה, ו־live כשהתהליך המקומי מסוגל להתקדם בלי לבדוק תלות חיצונית.
containers: [{name: app, image: registry.example.com/app:replace-me, ports: [{containerPort: 8080}], startupProbe: {httpGet: {path: /health/started, port: 8080}, periodSeconds: 10, timeoutSeconds: 2, failureThreshold: 30}, readinessProbe: {httpGet: {path: /health/ready, port: 8080}, periodSeconds: 5, timeoutSeconds: 2, failureThreshold: 2}, livenessProbe: {httpGet: {path: /health/live, port: 8080}, periodSeconds: 10, timeoutSeconds: 2, failureThreshold: 6}}]
אין צורך להוסיף initialDelaySeconds ל־liveness כדי להמתין לאתחול בתבנית הזאת: startup מונעת את תחילת שתי הבדיקות האחרות עד להצלחתה. לאחר מכן readiness ו־liveness פועלות לפי הספים שלהן, בלי להמתין זו לזו. לכן מעבר מוקדם מדי של started מקצר בפועל את ההגנה שנועדה לשירות האיטי.
רשימת בדיקה לפני פריסה
- אמתו שכל נתיב מחזיר הצלחה רק עבור המצב שהוא מייצג. בפרט, נתקו את live מקריאות רשת לשירותים אחרים ובדקו ש־started אינו מצליח לפני שההכנה המקומית הסתיימה.
- השוו את חלון startup למשך האתחול האיטי הצפוי, לרבות טעינת נתונים והתאוששות אחרי הפעלה מחדש. בדקו ש־timeoutSeconds ארוך מספיק עבור נקודת הבדיקה עצמה גם כשמשאבי ה־Pod תחת עומס.
- בחנו כשל זמני בתלות חיצונית: האם ready משתנה לפי יכולתו האמיתית של השירות להשיב, והאם live נשארת תקינה כשהתהליך המקומי בריא? אם כל ה־Pods יוצאים מתעבורה יחד, בחנו אם התלות הכרחית לכל הבקשות.
- בפריסה מדורגת עקבו אחר שינויי Ready, אירועי probe ומספר ההפעלות מחדש. אם יש עלייה בהפעלות מחדש בזמן עומס, בדקו מה הכשיל את liveness לפני שינוי הספים או הגדלת מספר ההעתקים.
קראו גם:
כתבות קשורות


Live Nation מקימה את Creator Nation — ומחפשת נכסים מעבר לאלגוריתם

Instagram הופכת שידור חי למודעה — הקידום פועל רק בזמן השידור

Docker או Podman: הביצועים כמעט זהים, ההרשאות לא

DMARC עם p=none רק צופה בהתחזות — כך עוברים לחסימה בלי לשבור דואר

Promptfoo או DeepEval: בדיקות תקינות אינן תחליף לתקיפה
הירשמו לניוזלטר שלנו
קבלו את החדשות האחרונות על Web3, AI וקריפטו ישירות לתיבת הדואר.