Multi-Tenancy ב-Kubernetes: איך משתפים cluster אחד בין כמה צוותים או לקוחות בלי שהם ידרכו אחד על השני

מאת צוות מדיה דיל · 04.08.2026 · DevOps · 7 דק'

מדריך מעמיק לדגמי Multi-Tenancy ב-Kubernetes - namespace isolation, virtual clusters ו-node isolation - וכיצד לבחור את רמת הבידוד הנכונה בין עלות לביטחון.

חברת SaaS B2B שמארחת עשרות לקוחות ארגוניים על אותה תשתית נתקלה בתקרית שהפכה לשיעור יקר: workload של לקוח אחד, שדרש עומס CPU חריג בגלל תהליך batch כבד, הרעיב את כל שאר הלקוחות שרצו על אותו cluster וגרם להשבתה חלקית שנמשכה שעתיים. הסיבה: כל הלקוחות שיתפו את אותם namespaces בלי resource quotas, בלי network policies שמפרידות ביניהם, ובלי אסטרטגיית בידוד ברורה. Multi-Tenancy ב-Kubernetes היא אחת הבעיות הארכיטקטוניות המורכבות והפחות מובנות בתחום - כי Kubernetes לא נבנה מלכתחילה כפלטפורמה multi-tenant אמיתית, וכל רמת בידוד דורשת בחירה מודעת ומורכבות תפעולית נלווית.

שלוש רמות של Multi-Tenancy: מה באמת ההבדל

הספרות המקצועית מבחינה בין שלושה מודלים עיקריים. Soft Multi-Tenancy מניח שכל הדיירים (tenants) אמינים - למשל צוותים שונים בתוך אותו ארגון - והבידוד נועד למנוע טעויות בשוגג, לא תקיפה מכוונת. כאן מספיק namespace isolation עם RBAC ו-resource quotas. Hard Multi-Tenancy מניח שהדיירים לא אמינים זה לזה כלל - למשל לקוחות SaaS חיצוניים - ודורש בידוד ברמת האבטחה שמונע מדייר אחד לגשת בכלל למידע או משאבים של דייר אחר, גם אם הוא מנסה בכוונה. בין השניים יש רצף שלם של פתרונות עם רמות סיכון ועלות תפעולית שונות.

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

Namespace Isolation: הבסיס שכולם מתחילים ממנו

namespace הוא חלוקה לוגית בתוך אותו cluster - כל דייר מקבל namespace משלו, עם RBAC שמגביל אילו משתמשים יכולים לגשת אליו, ו-ResourceQuota שמגביל את סך המשאבים (CPU, memory, מספר pods) שהdייר יכול לצרוך. זה קל להטמעה אבל הבידוד חלש משמעותית: כברירת מחדל pods בnamespaces שונים עדיין רצים על אותם נודים פיזיים, חולקים את אותו kernel, ויכולים לתקשר ביניהם ברשת אלא אם מוגדרת Network Policy מפורשת שחוסמת זאת.

הבעיה המרכזית: namespace isolation לא מונעת noisy neighbor ברמת הנוד אם לא הוגדרו resource limits מדויקים, ולא מונעת container escape - מצב שבו קוד זדוני בתוך קונטיינר מנצל חולשה כדי לצאת מהבידוד של הקונטיינר ולגשת ישירות ל-kernel של הנוד המארח, וממנו לכל workload אחר שרץ עליו, ללא קשר ל-namespace.

Network Policies: לסגור את הדלת שפתוחה כברירת מחדל

כפי שצוין, ברירת המחדל ב-Kubernetes היא שכל pod יכול לתקשר עם כל pod אחר בכל namespace. במערכת multi-tenant זו נקודת פרצה קריטית: דייר A יכול תיאורטית לנסות לגשת ישירות ל-service של דייר B אם הוא יודע (או מנחש) את הכתובת הפנימית שלו. הפתרון הוא הגדרת NetworkPolicy שאוכפת default-deny - כל תעבורה חסומה כברירת מחדל, ומאפשרים במפורש רק את מה שצריך. הטמעה זו דורשת CNI plugin שתומך ב-Network Policies (Calico, Cilium) - לא כל plugin תומך, ובחירה לא נכונה של CNI מוקדם בפרויקט יכולה לחייב מעבר יקר בהמשך.

Virtual Clusters: בידוד חזק בלי עלות של cluster נפרד

גישה שהתפתחה בשנים האחרונות היא Virtual Clusters (כמו הפרויקט vcluster) - כל דייר מקבל control plane וירטואלי משלו (API Server ו-etcd משלו) שרץ בתוך namespace על ה-host cluster, אבל מבחינת הדייר זה נראה ומתנהג בדיוק כמו cluster עצמאי משלו. היתרון: בידוד חזק משמעותית מ-namespace isolation פשוט, כולל אפשרות לדייר להתקין CRDs משלו בלי להשפיע על דיירים אחרים, בלי לשלם את מחיר התפעול המלא של cluster נפרד לגמרי (כל control plane וירטואלי משתף בפועל את משאבי החישוב של ה-host cluster, כך שאין overhead של נודי control plane נפרדים לכל דייר).

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

Node Isolation: הבידוד הפיזי הכי חזק בתוך cluster אחד

כשבידוד ברמת הרשת וה-namespace לא מספיק - למשל בגלל דרישות רגולטוריות שאוסרות שיתוף חומרה בין לקוחות - האפשרות הבאה היא node isolation: הקצאת נודים ייעודיים לכל דייר, באמצעות taints ו-tolerations שמונעים מ-pods של דיירים אחרים להתזמן על אותם נודים. זה מבטל את בעיית ה-noisy neighbor ברמה הפיזית וגם מצמצם משמעותית את משטח התקיפה של container escape - גם אם קוד זדוני יוצא מהקונטיינר, הוא נמצא בנוד שמוקצה רק לאותו דייר.

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

Cluster-per-Tenant: הפתרון הכי בטוח והכי יקר

הרמה הקיצונית ביותר של בידוד היא פשוט להריץ cluster נפרד לגמרי לכל דייר - עם control plane משלו, נודים משלו, ורשת משלו. זה מבטל כמעט כל וקטור לדליפה בין דיירים, אבל מגיע עם מחיר תפעולי גבוה: ניהול, שדרוג ותצפית על עשרות או מאות clusters נפרדים דורש כלים ותהליכים ייעודיים (Cluster API, GitOps מרכזי לניהול הצי כולו), ואי אפשר לנצל שיתוף משאבים בין דיירים בכלל, מה שמייקר את התשתית בסקייל גדול. גישה זו נפוצה בעיקר בהקשרים עם דרישות רגולטוריות קשיחות (למשל בריאות, פיננסים) שבהם עלות הבידוד המקסימלי מוצדקת.

Resource Quotas ו-LimitRanges: המנגנון שמונע ניצול יתר

גם ברמת בידוד גבוהה, חייבים ResourceQuota ברמת namespace שמגביל את סך המשאבים שדייר יכול לצרוך, ו-LimitRange שמגדיר ברירות מחדל וגבולות לכל container בודד בתוך ה-namespace, כדי למנוע מקרה שבו pod בודד מנסה לצרוך את כל המשאבים המוקצים לדייר כולו. בלי ResourceQuota, אפילו בידוד רשת מלא לא מונע מדייר אחד להריץ כמות בלתי מוגבלת של pods ולצרוך את כל קיבולת ה-cluster המשותפת, מה שפוגע בכל שאר הדיירים בעקיפין דרך cluster autoscaler שמנסה לפצות ומעלה עלויות בצורה בלתי צפויה.

אבטחת ה-Control Plane המשותף

גם כשמשתמשים ב-namespace isolation, ה-API Server, etcd וה-control plane כולו משותפים לכל הדיירים. זו נקודת כשל קריטית: RBAC לא מוגדר נכון יכול לאפשר לדייר אחד לקרוא Secrets של namespace אחר, או גרוע מכך - לקבל הרשאות cluster-wide בטעות. חשוב להימנע מ-ClusterRoleBindings רחבים מדי, ולהעדיף Roles מוגבלים ל-namespace ספציפי בכל מקום שאפשר. כמו כן, יש להקפיד שאף דייר לא מקבל הרשאה ליצור אובייקטים ברמת cluster (כמו Nodes, PersistentVolumes או CustomResourceDefinitions) - הרשאות שצריכות להישאר בלעדית לצוות התשתית.

נקודה שרבים מפספסים: גם admission controllers כמו OPA Gatekeeper או Kyverno צריכים להיות מוגדרים ברמת cluster כדי לאכוף מדיניות אחידה על כל הדיירים - למשל חסימת יצירת pods שרצים כ-root, או אכיפת תיוג חובה לכל משאב. בלי אכיפה מרכזית כזו, המדיניות תלויה בכל דייר לנהוג יפה מרצונו הטוב, מה שלא עומד במבחן מציאות אמיתית בסביבת multi-tenant.

מדידת עלות לכל דייר: Cost Allocation

אתגר נוסף שלעיתים קרובות נשכח בתכנון multi-tenancy הוא הקצאת עלות (cost allocation) - כשה-cluster משותף, איך יודעים כמה כל דייר עולה בפועל כדי לגבות ממנו נכון או לתקצב פנימית? כלים כמו OpenCost או Kubecost מודדים ניצול משאבים בפועל (CPU, memory, storage, ולעיתים גם תעבורת רשת) ברמת namespace או תיוג (label), ומאפשרים דוח עלות מדויק לכל דייר. בלי כלי כזה, ההקצאה נשארת בגדר הערכה גסה שמבוססת על ResourceQuota המוגדר ולא על השימוש בפועל - מה שיוצר עיוותים כשדייר אחד מוקצה quota גדול אבל בפועל משתמש רק בחלקו.

Pod Security Standards כשכבת הגנה נוספת

מעבר לבידוד רשת ומשאבים, סביבת multi-tenant חייבת להגביל גם מה pod יכול לעשות מבחינת הרשאות מערכת. Pod Security Standards (התחליף המודרני ל-PodSecurityPolicy שהוצא משימוש) מגדיר שלוש רמות - Privileged, Baseline ו-Restricted - ואוכף אותן ברמת namespace. ברמת Restricted, pods לא יכולים לרוץ כ-root, לא יכולים להשתמש ב-hostNetwork או hostPath, ומוגבלים ב-capabilities שהם יכולים לבקש מה-kernel. בסביבת multi-tenant עם דיירים לא אמינים, אכיפת Restricted כברירת מחדל על כל namespace של דייר היא לא אופציונלית - זו שכבת ההגנה האחרונה שמונעת מ-pod שנפרץ להשתלט על הנוד המארח כולו.

שילוב נכון בפרודקשן נראה כך: namespace isolation בסיסי לכל הדיירים, Network Policies עם default-deny, ResourceQuota ו-LimitRange מחמירים, Pod Security Standards ברמת Restricted, ו-RBAC מוגבל לnamespace בלבד - וכל זה עוד לפני שמדברים על Virtual Clusters או node isolation. ארגונים רבים מדלגים ישר לפתרונות היקרים (cluster-per-tenant) מבלי למצות קודם את השכבות הזולות והיעילות האלה, ומשלמים מחיר תפעולי מיותר על בידוד שהם יכלו להשיג בעלות נמוכה משמעותית.

מתי לבחור באיזו רמת בידוד

הכלל המעשי: להתחיל מ-namespace isolation עם Network Policies ו-ResourceQuotas מוגדרות היטב לכל תרחיש Soft Multi-Tenancy פנים-ארגוני. לעבור ל-Virtual Clusters או node isolation ברגע שיש דיירים חיצוניים או דרישת ציות (compliance) שדורשת בידוד מוגבר. ולשקול cluster-per-tenant רק כשיש דרישה רגולטורית מפורשת או כשמדובר בלקוחות Enterprise גדולים שמוכנים לשלם פרמיה משמעותית על בידוד מלא. במדיה דיל אנחנו רואים הרבה פעמים ניסיון להשיג בידוד hard-tenancy באמצעות namespace isolation בלבד - שילוב שלא באמת עומד במבחן תקיפה אמיתית, ולכן חשוב להתאים את רמת הבידוד לרמת האמון האמיתית בין הדיירים, לא לרמה הזולה ביותר שנראית 'מספיק טובה' בבדיקה שטחית. המפתח הוא לגשת לבידוד כרצף מדורג ולא כבחירה בינארית - להוסיף שכבת הגנה נוספת רק כשיש סיבה עסקית או רגולטורית ברורה לה, ולא 'כי אפשר'. הבנה הדרגתית הזו גם עוזרת בשיחה עם לקוחות Enterprise שדורשים 'בידוד מלא' - לעיתים קרובות אפשר להראות להם שרמת הבידוד הקיימת כבר עומדת בדרישות האבטחה שלהם בפועל, בלי הצורך לעבור לפתרון היקר ביותר.

תגיות: Kubernetes Multi-Tenancy · Namespace Isolation · Network Policy · Virtual Clusters · vcluster · RBAC · Resource Quota · Pod Security Standards

← חזרה לבלוג · צור קשר