הגדרת Docker Networks: בידוד וסגמנטציה של קונטיינרים

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

היכולות שלנו:

שאלות נפוצות

העבודות האחרונות

  • פיתוח אפליקציית ווב עבור FEEDME
    פיתוח אפליקציית ווב עבור FEEDME
    1359
  • פיתוח חנות מקוונת לחברת FURNORO
    פיתוח חנות מקוונת לחברת FURNORO
    1330
  • עיצוב לוגו לחברת B2B Advance
    עיצוב לוגו לחברת B2B Advance
    776
  • פיתוח אפליקציית ווב עבור Enviok
    פיתוח אפליקציית ווב עבור Enviok
    1077
  • פיתוח לוגו חברת AIDER
    פיתוח לוגו חברת AIDER
    1022
  • פיתוח CRM עבור Chasseurs
    פיתוח CRM עבור Chasseurs
    1113

קונטיינרים רואים זה את זה: היכן נשבר בידוד Docker networks

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

אבל בידוד Docker networks במקרה הזה לא מוגדר כלל — רשת קונטיינרים שטוחה הופכת כל שירות שנפרץ לנקודת כניסה לכל שאר התשתית.

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

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

תפקידים ובדיקות הרשאות מתארים מה מותר לשירות לעשות עם הנתונים, אבל לא מונעים ממנו להתחבר לפורט של מישהו אחר ולקרוא את מה שפתוח שם.

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

מה נותנת הסגמנטציה: פחות נקודות כניסה ותעבורה צפויה

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

ב-Docker רשת ברירת המחדל מאחדת את כל ה-stack, לכן הצעד הראשון הוא להפריד תפקידים לפי ייעוד. מה בודקים אחרי ההפרדה:

  • משטח התקיפה. מהקונטיינר שאליו חדר קוד זר נראים רק שכנים ברשת: במקום עשרות שמות ופורטים נשארים שניים-שלושה כתובות. החוצה מפרסמת פורטים נקודת כניסה יחידה.
  • תעבורה צפויה. הקשרים מתוארים במפורש: השירות פונה למסד הנתונים לפי שם קבוע, ולא «לאן שהצליח». את סכמת התקשורת קוראים מהקונפיגורציה ולא משחזרים מהלוגים.
  • הפרדת סביבות. סביבת הפיתוח והסביבה הייצורית לא חופפות: קונטיינר בדיקה לא יראה את מסד הנתונים הייצורי גם אם יש שגיאה במשתני הסביבה.
  • גבולות אמון בין שירותים. רכיבים עם דרישות גישה שונות כבר לא שוכבים באותו מישור — הממשק האדמיניסטרטיבי אינו נגיש מהמעגל הציבורי.
  • ניתוח אירועים. האנומליה מאותרת לפי הרשת: רואים איזה זוג שירותים החל לתקשר באופן חריג, והחיפוש מצטמצם לרכיב אחד או שניים.

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

השוואת מצבים: רשת סטנדרטית, מותאמת אישית, host ו-overlay

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

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

מתי המצב מזיק

host על צומת עם כמה אפליקציות מביא לקונפליקט פורטים ומבטל את הסגמנטציה. overlay עבור צומת אחת נותן רק תקורה של אנקפסולציה בלי רווח בבידוד.

כמה רשתות לשירות

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

סדר העבודה: מאינוונטר שירותים ועד מסירת סכמות

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

  1. אינוונטר שירותים וקשרים. אוספים רשימה של קונטיינרים, פורטים שפורסמו החוצה ופניות של «מי פונה למי». מקורות — קבצי הרצה, יומנים, מפת תלויות מהמפתחים. בפלט — טבלת קשרים עם ציון הפורט והכיוון.

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

  3. הגדרת רשתות הקונטיינרים. מרימים רשת נפרדת לכל סגמנט, ומחברים את השירות רק לרשתות שבאמת נחוצות לו. פרסום פורטים — נקודתי, דרך פרוקסי הפוך, ולא החוצה מכולם בבת אחת.

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

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

  6. העלאה למעגל הייצור ובקרה. מעבירים את הסכמה שלב-שלב, עם בדיקה אחרי כל שלב, כדי לא לתפוס כשל שירות באמצע. רשתות מנותקות וחיבורים מיותרים מוחקים.

  7. מסירת תיעוד ותקנות. מוסרים סכמת רשתות, מפת קשרים, סדר חיבור שירות חדש ופקודות אבחון בעת תקלות.

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

מה נשאר אצל הצוות: סכמות רשתות, מדיניויות, תקנות

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

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

  • סכמת רשתות וקשרים — אילו רשתות נוצרו, אילו שירותים נכללים בהן, מה פורסם החוצה ומה נסגר בכוונה. הסכמה הותאמה למצב בפועל, ולא לכוונה הראשונית.
  • קבצי קונפיגורציה של רשתות — תיאור דקלרטיבי של רשתות, אליאסים וחיבורים, שממנו הסביבה עולה בפקודה אחת על מכונה נקייה.
  • מדיניויות גישה — טבלה מסוג «שירות → שירות → מותר או אסור», צמודה לשמות הרשתות: החוק משתנה במקום אחד ולא מתפשט בין המכונות.
  • תיאור התשתית — צמתים, נקודות כניסה, כתובות חיצוניות, פרוקסים הפוכים ומה שקריטי לעמידות כל מעגל.
  • תקנת רשתות — מי מאשר שינוי, באיזה שלב הוא נבדק בסביבת הבדיקות, וכיצד מתבטל במקרה של כישלון.
  • סדר הוספת שירות חדש — רשימה שלב-שלב: לאיזו רשת לחבר, אילו שמות לתת, אילו בדיקות לעבור לפני שחרור.
  • תזכיר לאבחון — תקלות אופייניות כמו שם שלא נפתר או פורט תפוס, למה להסתכל קודם וכיצד להבדיל בין שגיאת קונפיגורציה לתקלת שירות.

כל מסמך מתעדכן יחד עם השינוי, אחרת מאבד את משמעותו: נסכם מי בצוות שלכם שומר אותם מעודכנים.

בידוד שירותים בייצור: מקרה עם מטריקות לפני ואחרי

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

הפרידו את התעבורה לרשתות מותאמות אישית נפרדות: אחת — רק לפרוקסי ולפרונטאנד, שנייה — ל-API ולמעבדים, שלישית — למסד הנתונים ולמטמון, שאליה מחוברת רק שכבת האפליקציה. במקום כתובות — אליאסים של רשת, במקום רשת ברירת מחדל משותפת — רשימה מפורשת של חיבורים לכל שירות.

מה הראו המדידות לפני ואחרי

מדד לפני אחרי
שיעור האירועים בגלל קישוריות רשת מיותרת 4 מתוך 10 1 מתוך 10
זמן איתור מקור התקלה 3–4 שעות 40–60 דקות
זמן שחזור השירות לאחר ביטול 25–30 דקות 8–10 דקות
שירותים ברשת אחת 14 3

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

מה לעשות אם הקונטיינרים כבר עובדים ברשת שטוחה אחת?

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

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

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

החלפת הכתובות של השירותים היא המקור העיקרי לכשלים. אם כתובת של שכן מוגדרת בקשיחות בקונפיגורציה, אחרי המעבר הפנייה יוצאת לשומקום, ונופל דווקא לא השירות שהועבר.

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

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

ספקות טכניים שכיחים: שמות שירותים, פורטים, השהיות

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

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

להלן מה שבדרך כלל מבררים לפני ההתחלה: מהתשובות תלויות קונפיגורציית הרשתות וכללי הגישה.

כיצד ימצאו השירותים זה את זה אם הכתובות משתנות בהפעלה מחדש?

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

מה לפרסם החוצה ומה להשאיר בפנים?

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

האם הבידוד יאט את התעבורה בין השירותים?

לא. בידוד הוא חוקי ניתוב על ה-host, ולא קטע רשת מיותר. ההשהיה גדלה בחלקיקי מילישנייה ואובדת על רקע הפנייה למסד הנתונים; ההבדל נראה רק במדידות סינתטיות.

כיצד לבדוק שהבידוד באמת פועל?

בבדיקה הפוכה: מרימים קונטיינר זמני ברשת אחת ומנסים להגיע לשירות מרשת אחרת — החיבור לא אמור להיות מוקם. משווים את docker network inspect ואת רשימת הרשתות של הקונטיינר לסכמה המתוכננת.

נדון בסכמת הרשת שלכם: מה לשלוח להערכה ולתוכנית

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

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

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