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

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

למה נתיב ברירת המחדל נוחת על הרשת הלא נכונה

כל רשת ששירות מצטרף אליה יכולה להציע שער משלה, והמכולה בכל זאת נשארת עם נתיב ברירת מחדל אחד בלבד. לפני Compose 2.33.1 הוכרע השוויון על ידי מיון שמות הרשתות, כך שתווית כמו control שבאה לפני office קבעה לאן התעבורה הולכת. שום דבר בתוך המכולה לא רושם שההחלטה הייתה שרירותית, ולכן היא שורדת סקירת קוד ומופיעה מאוחר יותר כנתיב מוזר. הצבת מדיניות בקובץ ה-compose היא הדרך היחידה להפוך את הבחירה לניתנת לבדיקה.

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

קבעו את השער עם gw_priority

Compose חושף gw_priority בכל חיבור שירות-לרשת מאז גרסה 2.33.1, והמספר הגבוה ביותר מנצח. אין מפתח שער לכל שירות, ולכן הערך שייך לבלוק ה-networks של השירות. הדוגמה שלמטה מעניקה את נתיב ברירת המחדל ל-control ומשאירה את office נגישה עבור ה-LAN המחובר ישירות שלה.

services:
  vpn:
    networks:
      control:
        gw_priority: 1
      office:
        gw_priority: 0

networks:
  control:
    driver: bridge
    ipam:
      config:
        - subnet: 172.30.50.0/24
  office:
    driver: macvlan
    driver_opts:
      parent: eno1.120
      macvlan_mode: bridge
    ipam:
      config:
        - subnet: 192.168.120.0/24
          ip_range: 192.168.120.192/27
          gateway: 192.168.120.1

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

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

אמתו איזו רשת באמת נושאת את נתיב ברירת המחדל

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

docker compose config --quiet
docker exec vpn ip -4 route show default
docker exec vpn cat /proc/net/route

תוצאה נכונה מציינת את תקן הגשר ואת 172.30.50.1; תוצאה שגויה מציינת את 192.168.120.1 ואת תקן ה-macvlan. אם התמונה אינה כוללת את חבילת iproute2, קובץ ה-/proc עדיין מדווח על נתיב ברירת המחדל, עם יעד 00000000 ובתי השער בסדר הפוך. השוו את עמודת הממשק ל-docker inspect כששמות ההתקנים אינם ברורים.

Macvlan הוא פורט פיזי, לא שיבוט של גשר

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

ההגדרה macvlan_mode: bridge היא מצב של מנהל ההתקן macvlan, לא גשר התוכנה של Docker, ו-passthru הוא מצב מתמחה נפרד ולא ברירת מחדל. לינוקס גם מונע ממכולת macvlan להגיע למארח של עצמה דרך אותו הורה, וזו הסיבה להשאיר את גשר הבקרה במקום לצפות שחיבור אחד יעשה את שתי העבודות.

תנו שם להורה ה-VLAN לפני ש-Compose רואה אותו

Docker מתייחס להורה עם נקודה כמו eno1.120 כממשק משנה 802.1Q ויוצר בעצמו את תקן ה-VLAN. לנוחות הזו יש גבולות: השם הנגזר תלוי בשם הממשק הפיזי, ושמות ארוכים עלולים לדחוף את התוצאה מעבר למה שהכלים שסביב מצפים לו. יצירת ממשק VLAN בעל שם בתצורת הרשת של המארח והצבעת parent אליו שומרת על שני הקצוות כצפויים.

זכרו שהמפתח תחת networks הוא שם Compose, לא התקן לינוקס. חיפוש במארח אחר ממשק בשם office ייכשל, כי הליבה רואה רק את ממשק ההורה ואת צמד ה-veth שמאחורי המכולה.

פנו מקום ל-VPN מעל

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

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

מאמרים קשורים