במדריך הזה מפורטות שיטות מומלצות לתכנון, להטמעה, לבדיקה ולפריסה של שירות Knative serving. טיפים נוספים זמינים במאמר העברת שירות קיים.
כתיבת שירותים אפקטיביים
בקטע הזה מתוארות שיטות מומלצות כלליות לתכנון וליישום של שירות Knative Serving.
הימנעות מפעילויות ברקע
כשאפליקציה שפועלת ב-Knative serving מסיימת לטפל בבקשה, הגישה של מופע הקונטיינר למעבד מושבתת או מוגבלת מאוד. לכן, לא מומלץ להפעיל שרשורים או שגרות ברקע שפועלים מחוץ להיקף של מטפלי הבקשות.
הפעלת שרשורים ברקע עלולה לגרום להתנהגות בלתי צפויה, כי כל בקשה עוקבת לאותו מופע של מאגר התגים מפעילה מחדש כל פעילות ברקע שהושעתה.
פעילות ברקע היא כל פעילות שמתרחשת אחרי שהתגובה של HTTP נמסרת. בודקים את הקוד כדי לוודא שכל הפעולות האסינכרוניות מסתיימות לפני ששולחים את התגובה.
אם אתם חושדים שיש פעילות ברקע בשירות שלכם שלא ברורה מאליה, אתם יכולים לבדוק את היומנים: חפשו כל מה שמתועד אחרי הרשומה של בקשת ה-HTTP.
מחיקת קבצים זמניים
בסביבת Cloud Run, אחסון הדיסק הוא מערכת קבצים בזיכרון. קבצים שנכתבים לדיסק צורכים זיכרון שזמין לשירות, והם יכולים להישמר בין הפעלות. אם לא תמחקו את הקבצים האלה, בסופו של דבר תופיע שגיאת אין זיכרון פנוי (OOM), ולאחר מכן יתבצע הפעלה במצב התחלתי (cold start).
אופטימיזציה של הביצועים
בקטע הזה מתוארות שיטות מומלצות לאופטימיזציה של הביצועים.
הפעלה מהירה של שירותים
מכיוון שמתבצעת התאמה של גודל המופעים של הקונטיינר לפי הצורך, שיטה טיפוסית היא לאתחל את סביבת ההפעלה באופן מלא. סוג כזה של אתחול נקרא "הפעלה במצב התחלתי (cold start)". אם בקשת לקוח מפעילה הפעלה מההתחלה (cold start), הפעלת מופע המאגר גורמת לזמן אחזור נוסף.
תרחיש ההפעלה כולל:
- הפעלת השירות
- הפעלת הקונטיינר
- מריצים את הפקודה entrypoint כדי להפעיל את השרת.
- בדיקה של יציאת השירות הפתוחה.
אופטימיזציה של מהירות הפעלת השירות מצמצמת את זמן האחזור שגורם לעיכוב בהגשת בקשות על ידי מופע של קונטיינר.
שימוש חכם בתלות
אם אתם משתמשים בשפה דינמית עם ספריות תלויות, כמו ייבוא מודולים ב-Node.js, זמן הטעינה של המודולים האלה מוסיף חביון במהלך הפעלה במצב התחלתי (cold start). כדי לקצר את זמן האחזור של ההפעלה:
- כדי ליצור שירות יעיל, מומלץ לצמצם את מספר התלויות ואת הגודל שלהן.
- אם השפה תומכת בכך, כדאי להשתמש בטעינה מדורגת של קוד שלא נמצא בשימוש לעיתים קרובות.
- משתמשים באופטימיזציות של טעינת קוד, כמו composer autoloader optimization של PHP.
שימוש במשתנים גלובליים
ב-Knative serving, אי אפשר להניח שמצב השירות נשמר בין בקשות. עם זאת, Knative serving עושה שימוש חוזר במופעי קונטיינר בודדים כדי להציג תנועה שוטפת, כך שאפשר להצהיר על משתנה בהיקף גלובלי כדי לאפשר שימוש חוזר בערך שלו בהפעלות הבאות. אי אפשר לדעת מראש אם בקשה ספציפית תהנה מהשימוש החוזר הזה.
אפשר גם לשמור במטמון אובייקטים בזיכרון אם יקר ליצור אותם מחדש בכל בקשת שירות. העברת הפונקציה הזו מהלוגיקה של הבקשה להיקף גלובלי משפרת את הביצועים.
Node.js
Python
Go
Java
ביצוע אתחול עצלני של משתנים גלובליים
האתחול של משתנים גלובליים תמיד מתרחש במהלך ההפעלה, מה שמגדיל את זמן ההפעלה במצב התחלתי (cold start). כדאי להשתמש באתחול עצל כדי לדחות את עלות הזמן ולקצר את זמני ההפעלה במצב התחלתי (cold start) של אובייקטים שלא משתמשים בהם לעיתים קרובות.
Node.js
Python
Go
Java
אופטימיזציה של בו-זמניות (concurrency)
מופעי Knative serving יכולים לטפל בכמה בקשות בו-זמנית, עד מקסימום מקבילות שניתן להגדרה.
ההגדרה הזו שונה מפונקציות Cloud Run, שבהן נעשה שימוש ב-concurrency = 1.
מומלץ להשאיר את הגדרת ברירת המחדל של מספר ההפעלות המקסימלי בו-זמנית, אלא אם לקוד שלכם יש דרישות ספציפיות לגבי מספר ההפעלות בו-זמנית.
התאמת מספר החיבורים בו-זמנית בשירות
מספר הבקשות בו-זמניות שכל מופע של קונטיינר יכול לטפל בהן יכול להיות מוגבל על ידי חבילת הטכנולוגיות והשימוש במשאבים משותפים כמו משתנים וחיבורים למסד נתונים.
כדי לבצע אופטימיזציה של השירות כך שיוכל לתמוך במספר מקסימלי של משתמשים בו-זמנית:
- אופטימיזציה של ביצועי השירות.
- מגדירים את רמת התמיכה הצפויה בריבוי משימות בו-זמנית בכל הגדרה של ריבוי משימות בו-זמנית ברמת הקוד. לא בכל מחסנית טכנולוגיות נדרשת הגדרה כזו.
- פורסים את השירות.
- מגדירים את רמת המקביליות של Knative Serving לשירות כך שתהיה שווה או נמוכה מכל הגדרה ברמת הקוד. אם אין הגדרה ברמת הקוד, משתמשים בערך המקביל הצפוי.
- משתמשים בכלים של בדיקת עומס שתומכים בהגדרה של מספר חיבורים בו-זמניים. צריך לוודא שהשירות שלכם נשאר יציב תחת העומס והבו-זמניות הצפויים.
- אם השירות לא פועל בצורה טובה, עוברים לשלב 1 כדי לשפר את השירות או לשלב 2 כדי לצמצם את מספר הבקשות בו-זמנית. אם השירות פועל בצורה טובה, חוזרים לשלב 2 ומגדילים את מספר הבקשות המקבילות.
ממשיכים לחזור על התהליך עד שמגיעים למקסימום של יציבות במקביל.
התאמת הזיכרון לשימוש בו-זמני
כל בקשה שהשירות מטפל בה דורשת כמות מסוימת של זיכרון נוסף. לכן, כשמגדילים או מקטינים את מספר הבקשות המקבילות, חשוב להגדיל או להקטין גם את מגבלת הזיכרון.
הימנעות ממצב גלובלי שניתן לשינוי
אם רוצים להשתמש במצב גלובלי שניתן לשינוי בהקשר של פעולות בו-זמניות, צריך לבצע פעולות נוספות בקוד כדי לוודא שהפעולה מתבצעת בצורה בטוחה. כדי לצמצם את התחרות על משאבים, מגבילים את המשתנים הגלובליים לאתחול חד-פעמי ולשימוש חוזר, כמו שמתואר למעלה בקטע ביצועים.
אם משתמשים במשתנים גלובליים שניתנים לשינוי בשירות שמטפל בכמה בקשות בו-זמנית, חשוב להשתמש בנעילות או ב-mutex כדי למנוע תנאי מירוץ.
Container Security
שיטות רבות לאבטחת תוכנה למטרות כלליות חלות על אפליקציות בקונטיינרים. יש כמה שיטות עבודה שספציפיות למאגרי תגים או שתואמות לפילוסופיה ולארכיטקטורה של מאגרי תגים.
כדי לשפר את אבטחת הקונטיינר:
מומלץ להשתמש בתמונות בסיסיות מאובטחות שמתעדכנות באופן שוטף, כמו תמונות בסיסיות של Google או תמונות רשמיות של Docker Hub.
כדי להחיל עדכוני אבטחה על השירותים, צריך לבנות מחדש באופן קבוע תמונות של קונטיינרים ולפרוס מחדש את השירותים.
כוללים במאגר רק את מה שנדרש להפעלת השירות. קוד, חבילות וכלים נוספים הם פרצות אבטחה פוטנציאליות. למעלה מופיע מידע על ההשפעה על הביצועים.
הטמעה של תהליך build דטרמיניסטי שכולל גרסאות ספציפיות של תוכנה וספרייה. כך לא ייכלל קוד לא מאומת במאגר התגים.
מגדירים את מאגר התגים כך שיפעל כמשתמש שאינו
rootבאמצעות ההצהרה DockerfileUSER. יכול להיות שחלק מתמונות המאגר כבר כוללות משתמש ספציפי שהוגדר.
אוטומציה של סריקות אבטחה
הפעלת סריקת נקודות חולשה כדי לבצע סריקת אבטחה של תמונות קונטיינרים שמאוחסנות ב-Artifact Registry.
אפשר גם להשתמש ב-Binary Authorization כדי לוודא שרק קובצי אימג' מאובטחים של קונטיינרים נפרסים.
פיתוח קובצי אימג' מינימליים של קונטיינרים
תמונות גדולות של קונטיינרים עלולות להגדיל את נקודות החולשה באבטחה, כי הן מכילות יותר ממה שהקוד צריך.
ב-Knative serving, הגודל של קובץ אימג' של קונטיינר לא משפיע על זמן ההפעלה הקרה או על זמן עיבוד הבקשה, והוא לא נכלל בזיכרון הזמין של הקונטיינר.
כדי ליצור קונטיינר מינימלי, כדאי לעבוד עם קובץ אימג' בסיסי רזה כמו:
Ubuntu גדול יותר, אבל הוא קובץ אימג' בסיסי שנמצא בשימוש נפוץ עם סביבת שרת שלמה יותר.
אם תהליך הבנייה של השירות שלכם כולל שימוש רב בכלים, כדאי להשתמש בבנייה רב-שלבית כדי שהקונטיינר יהיה קל בזמן הריצה.
במקורות המידע הבאים אפשר לקרוא מידע נוסף על יצירת קובצי אימג' של קונטיינרים יעילים:
- שיטות מומלצות ל-Kubernetes: איך ולמה כדאי ליצור קובצי אימג' קטנים של קונטיינרים
- 7 שיטות מומלצות ליצירת קונטיינרים