תעבורת מכולות Docker עוקפת את ה-VPN של המארח: כיצד לבדוק
VPN של המארח מכסה רק את מרחב השמות של המארח. השתמשו בבדיקות האלה כדי לגלות אם תעבורת מכולות על גשר נכנסת למנהרה או יוצאת ישירות.
הדפדפן שלכם במארח מציג את כתובת היציאה של ה-VPN, המכולה מדווחת על החיבור הביתי שלכם, ומישהו קורא לזה דליפה. שום דבר לא דלף. מנהרת מארח היא צרור של ממשקים, נתיבים וכללים ששייכים למרחב השמות של רשת המארח, ומכולה על גשר היא מרחב שמות אחר עם נתיב ברירת המחדל שלו. ישבתי על מחסנית Compose שבה לקוח ה-VPN היה מחובר שבועות ואף מנות מכולה אחת לא נכנסה אליו אי פעם.
בדקו את מרחב השמות לפני סמל המגש
מרחבי שמות הם כל הטיעון. כאשר Docker מפעיל מכולה ברשת גשר, הוא יוצר מרחב שמות של רשת, מחבר קצה אחד של זוג veth לתוכו, ונותן למרחב השמות הזה כתובת ונתיב ברירת מחדל. ממשק המנהרה, איך שלא ייקרא, חי במרחב השמות של המארח. תעבורה בתוך המכולה לא יכולה לראות אותו, ושום הגדרה של הלקוח לא משנה זאת מבחוץ.
שתי תנועות נתמכות מוציאות אתכם מהבידוד. --network host מציב את המכולה בתוך מרחב השמות של המארח, כך שהיא יורשת את הנתיבים של המארח ולכן את המנהרה. --network container:vpn חולק את מרחב השמות של מכולה אחרת, וכך רוב עיצובי ה-sidecar שולחים עומס עבודה דרך מכולת VPN. שתיהן בחירות מפורשות; בדרך כלל רק אחת מהן היא מה שהאדם שמפרס התכוון אליו.
מצב מארח אינו שדרוג חינם. המכולה מפסיקה להיות בעלת כתובת משלה, פרסום פורטים מפסיק לחול, ותהליך שמחזיק NET_ADMIN שם יכול לשכתב את הניתוב של המארח. לקבל זאת יכול להיות ההחלטה הנכונה. להניח שזה כבר דלוק זה איך שאנשים מבלים ערב בניפוי מנהרה שמעולם לא הייתה בנתיב.
עקבו אחרי המנות מחוץ לגשר
מכולה על גשר שולחת את המנות שלה לשער ברירת המחדל שלה, שהוא ממשק הגשר במארח. המארח מעביר אז את המנות, ובתצורת ברירת המחדל מתרגם את כתובת המקור לשלו לפני שהמנות יוצאת. שלב התרגום הזה הוא מה שמביס את המדיניות בשקט.
עד שהמנות מגיעה לנקודת הקצה של המנהרה היא נושאת את כתובת המארח. כל כלל, נתיב מדיניות או החלטת מנהרה מפוצלת שמבוססים על הכתובת המקורית של המכולה מפסיקים להתאים, ושתי מכולות שאמורות לצאת דרך יציאות שונות לא ניתנות להבחנה רק לפי המקור. אם אתם צריכים ניתוב לכל מכולה, ההחלטה חייבת להתקבל לפני התרגום או בתוך מרחב שמות שאתם שולטים בו.
Docker מתחזק את הכללים האלה בעצמו, דרך אותו backend של חומת אש שאיתו הוגדר הדמון. כללים שנכתבו ביד מחוץ לווי התמיכה לתעבורה מועברת, DOCKER-USER, עלולים להיות מסודרים מחדש או להימחק כשהדמון מופעל מחדש או כשהמארח משודרג. התיעוד של Docker על סינון מנות מציג את סדר השרשראות; הנקודה המעשית היא שכל כלל צריך בעלים ונתיב טעינה מחדש שבאמת בדקתם.
בדקו את שתי המערכות בנפרד
ראיות ממרחב שמות אחד לא אומרות דבר על האחר. בקשה שרצה בתוך מכולת ה-VPN מוכיחה שהמנהרה עובדת עבור אותה מכולה. זו אינה ראיה לגבי המארח, ואותה פקודה שרצה ממכולת --network host אינה ראיה לגבי הגשר.
# host namespace
ip route get 1.1.1.1
ip -brief addr show
# a fresh container on the same bridge network
docker run --rm --network appnet alpine sh -c 'ip route; cat /etc/resolv.conf; ip -6 route'
אחר כך חזרו על הבדיקה בתוך מכולת היישום האמיתית ולא בתמונה דומה. היישום עשוי לשאת נתיב נוסף, משתנה סביבה של פרוקסי או פותר אחר, וכל אחד מאלה משנה את התשובה. בדקו את פתרון השמות ואת משפחת הכתובות השנייה בכל פעם: מכולות על גשרים שהוגדרו על ידי המשתמש נפתרות דרך הפותר המובנה של Docker בכתובת 127.0.0.11, ונתיב ברירת מחדל של IPv6 על הגשר יכול להוציא תעבורה החוצה בזמן שאתם עסוקים בבדיקת מנהרה של IPv4 בלבד.
קראו את הדפוס לפני שאתם נוגעים בהרשאות
כשהמארח עובד והמכולה לא, הסיבה כמעט תמיד מבנית, והחלפת מפתחות או התקנה מחדש של הלקוח מבזבזות אחר צהריים. מיינו קודם את התסמין והתיקון בדרך כלל נותן לעצמו שם.
| What you see | Usual cause | First check |
|---|---|---|
| Host exits through the VPN, container shows the ISP address | The container never entered the tunnel | Default route inside the container |
| Container works until the daemon restarts, then stops | Rules outside the supported hook, or a changed backend | Daemon's reported firewall backend and DOCKER-USER |
| Container loses internal hosts after the tunnel comes up | VPN prefix overlaps the Docker bridge subnet | ip route on the host, then docker network inspect |
| Small replies arrive, large ones hang | Tunnel MTU or missing MSS clamping | Link MTU on both ends of the tunnel |
| Container falls back to the ISP address when the tunnel drops | Nothing enforces the kill switch for forwarded traffic | Stop the tunnel with a request in flight |
שורת החפיפה ראויה למשפט משלה. פרופיל VPN שדוחף נתיב ל-172.17.0.0/16, או ל-10.0.0.0/8 שבמקרה מכיל את קידומת הגשר שלכם, גורם למנהרה לתבוע את תת-הרשת של המכולות, והתשובות לכתובות מתורגמות ייסעו לכיוון הלא נכון או ייעלמו. מספור מחדש של רשת Docker בדרך כלל נקי יותר מאשר הצטברות חריגים.
הפכו את הכיסוי למפורש, ואז שברו אותו בכוונה
שני עיצובים מחזיקים מעמד בבדיקה. חלקו את מרחב השמות של מכולת ה-VPN וכל עומס עבודה מכוסה משתמש במנהרה אחת עם גבול הפעלה מחדש אחד, וזה פשוט עד ששירות אחד צריך יציאה אחרת או נתיב DNS משלו. או נתבו את רשת המכולות לשער VPN במארח: העברה מופעלת, קידומת הגשר מופנית למנהרה, תעבורת החזור מטופלת במפורש. זה קונה שליטה לכל רשת ועולה לכם בסט כללים לתחזק לאורך שדרוגי הדמון והלקוח.
כך או כך, הבדיקה שחשובה היא מקרה הכשל. עצרו את המנהרה כשבקשה של מכולה באוויר ותראו לאן המנות הולכת. אם היא נופלת חזרה לנתיב הישיר, הכיסוי מעולם לא נאכף, כי kill switch של לקוח שולט בתעבורה של הלקוח עצמו ולא במנות מועברות מגשר. הפעילו מחדש את הדמון ואת המארח ואחר כך אשרו את התוצאה פעם שנייה; זה הרגע שבו כללים שנכתבו ביד נעלמים.
לפני שאתם קוראים לזה גמור, אשרו ארבעה דברים: ממשק המנהרה נמצא באותו מרחב שמות כמו התעבורה, בדיקת המכולה רצה בתוך המכולה האמיתית, פתרון השמות ושתי משפחות הכתובות נבדקו, ובדיקת כשל המנהרה עדיין נכשלת סגור. אחר כך רשמו את ה-backend של חומת האש, את גרסת הלקוח ואת הבעלים של כל כלל. הרשומה הזו היא מה שמונע מהשדרוג הבא להשאיר תערובת לא מתועדת של הנחות ישנות.