Dev Container לא מגיע למארח הזמין רק דרך VPN: היכן לחפש
לדפדפן ולקונטיינר יש הקשרי resolver, proxy ומסלול שונים. גלו איזה מהם משתמש התהליך שנכשל לפני שתשנו הגדרת VPN כלשהי.
ה-API הפרטי נפתח בדפדפן שולחן העבודה ונכשל בקונטיינר הפיתוח. זו אינה סתירה, ולעיתים רחוקות ה-VPN עצמו הוא האשם. בקשת הדפדפן והבקשה שנכשלת בוצעו על ידי תהליכים שונים, עם resolvers, פרוקסי ומסלולים שונים, ולעיתים קרובות ממרחבי שמות רשת שונים לחלוטין. «על המחשב הנייד שלי» יכול להיות המארח Windows, הפצת WSL, המכונה הווירטואלית של Docker Desktop וקונטיינר בתוך אותה VM — ארבעה הקשרים שכל אחד מהם יכול לענות אחרת לאותו שם מארח. גלו איזה מהם משתמש התהליך שנכשל לפני שתיגעו בהגדרה אחת.
אתרו את התהליך לפני שתשנו הגדרה
התחילו במנוע הקונטיינרים ולא בלקוח ה-VPN. שאלו עם איזה הקשר מדבר שורת הפקודה ועל איזו מערכת הפעלה מנוע זה רץ, כי קונטיינר Linux שמנוהל על ידי VM שולחני הולך במסלול שונה מזה שמנוהל על ידי daemon מקומי:
docker context ls
docker info --format '{{.OperatingSystem}} / {{.Name}}'
docker run --rm alpine ip route
ב-Windows, wsl -l -v אומר לכם אם ההפצה רצה תחת WSL 2, מה שמציב אותה מאחורי מתג וירטואלי משלה. הפרט הזה קובע אם הקונטיינר חולק את טבלת הניתוב של המארח או יושב מאחורי NAT שזקוק לפורט מועבר או לשם מארח כדי להגיע למארח.
השאירו בקשה אחת קבועה והשוו
בחרו נקודת קצה לא מזיקה במארח הפרטי והשתמשו בה לכל השוואה: מהדפדפן, מטרמינל של המארח, מהפצת WSL ומתוך הקונטיינר. רשמו ארבעה דברים לכל ניסיון: הכתובת שנפתרה, אם נעשה שימוש בפרוקסי, סוג הכשל והזמן שחלף. חיפוש שם, כינון חיבור, אימות TLS וסטטוס HTTP הם ארבע בעיות שונות, וערבובן לתוך «זה לא עובד» מבזבז בוקר שלם.
הריצו את ההשוואה בתוך הקונטיינר שנכשל, עם timeout כדי שחומת אש שקטה לא תחזיק את הטרמינל בדקות. קונטיינר חדש משחזר את הקשר הרשת של המנוע, אבל לא את מרחב השמות, משתני הפרוקסי או ה-resolver של קונטיינר היישום, ולכן docker exec לתוך הקונטיינר האמיתי הוא המבחן המוסמך, וקונטיינר צדדי הוא רק דרך לבודד אם ההבדל במנוע או בקונטיינר:
docker exec -it app /bin/sh -c "getent hosts api.internal; curl -v --max-time 8 https://api.internal/ 2>&1 | tail -20"
docker run --rm --network container:app curlimages/curl:latest -sv --max-time 8 https://api.internal/ 2>&1 | tail -20
תמונת הבסיס alpine מכילה busybox ולא curl, וזה בדיוק סוג הפרט שגורם לבלוק אבחון מועתק להיכשל: בחרו תמונה עם הלקוח, או הוסיפו אותו באותה הרצה. השוואה לאתרים ציבוריים לא קשורים לא מבודדת דבר. אם https://example.com עובד מהקונטיינר, למדתם שלקונטיינר יש גישה לאינטרנט, ושום דבר על האם הוא מגיע לכתובת פרטית דרך המנהרה. באותה מידה, פתיחת טרמינל חדש מוכיחה רק שהטרמינל החדש עובד, לא שהוא חולק סביבת הרצה עם היישום שנכשל.
Docker Desktop יכול לעבוד עם VPN
התיעוד של Docker עצמו על VPN וקישוריות למארח מתאר זאת כהגדרה נתמכת, והסיכום הכנה הוא שזה עובד ולא שבור אוטומטית. אל תניחו שה-VM השולחני עוקף את המנהרה של המארח מעצם התכנון; בהגדרות רבות התעבורה עוקבת נכון אחרי המנהרה של המארח, ולכן האגדה «Docker מתעלם מה-VPN» מייצרת עצות בטוחות ושגויות.
מה שעדיין חשוב הוא ה-backend שבו משתמשים, מדיניות ה-split tunnel של הלקוח ותצורת ה-resolver שה-VM קיבל. לקוח VPN שמתקין מסלולים אבל לא DNS, או שדוחף שרת DNS שה-VM לא יכול להגיע אליו, מייצר כשל בחיפוש שם בתוך הקונטיינר בעוד המארח עובד כי יש לו resolver נוסף או תשובה במטמון. זו בעיית resolver בתחפושת קונטיינר. היא שורדת כל חיבור מחדש של VPN שתנסו, כי המנהרה כבר נושאת את התעבורה שביקשתם ממנה לשאת.
חפיפות כתובות ו-MTU הם כשלים שונים
שני כשלים ראויים לאבחון משלהם כי לעיתים קרובות טועים לחשוב שהם מדיניות גישה. הראשון הוא חפיפת כתובות: אם ה-VPN דוחף טווח שמתנגש בתת-הרשת של הגשר המוגדר כברירת מחדל של רשת קונטיינרים, המסלול של הקונטיינר לטווח הזה מצביע על הגשר המקומי ולעולם לא מגיע למנהרה. בדקו את תת-הרשתות בפועל במקום לנחש:
docker network inspect bridge --format '{{range .IPAM.Config}}{{.Subnet}}{{end}}'
ip route get 10.20.30.40
השני הוא בעיית MTU. אם החיבור נוצר ו-TLS מושלם אבל תגובות גדולות יותר נתקעות, יש לכם בעיית גודל מנה, לא בעיית הרשאה, והחלפת רשומות DNS לעולם לא תתקן אותה. בדקו עם בקשה קטנה ובקשה גדולה לפני שתשנו משהו, ורשמו את שתי התוצאות.
הפתרון לחפיפה הוא תת-רשת קונטיינר אחרת או מסלול מוגבל, שנבחר על ידי מי שמחזיק בתכנית הכתובות. הפתרון לתקיעת MTU הוא הידוק או הקטנה של ה-MTU של המנהרה או הממשק לערך ששורד את המסלול, מיושם בשכבה שאתם שולטים בה.
תצורת פרוקסי היא לפי תהליך, לא לפי מכונה
בתוך קונטיינר, localhost מציין את הקשר הרשת של אותו קונטיינר, ולכן פרוקסי שרץ על המארח אינו נגיש שם בשם הזה. Docker Desktop מספק host.docker.internal לגישה למארח, וב-Linux מוסיפים אותו במפורש עם --add-host=host.docker.internal:host-gateway. כך או כך, השם הזה נותן לכם מסלול למארח; הוא לא יוצר שירות פרוקסי ולא מאשר לכם להשתמש באחד.
השתמשו בכתובת ובפורט הפרוקסי שסופקו עבור הסביבה בפועל, ובדקו מי קורא אותם. משתנים שמיוצאים ב-shell אינטראקטיבי אינם מגדירים אוטומטית כל הרחבת עורך, שרת שפה, כלי build ו-daemon ברקע. התהליך שחשוב הוא זה שיצר את הבקשה שנכשלה, לכן בדקו את הסביבה שלו ולא את זו של הטרמינל שלכם.
לבסוף, תנו לתיקון להסביר את עצמו. פתרון מועיל נוקב בגבול שהיה שגוי, בהגדרה ששינתה אותו ובקבוצת התהליכים שהוא משפיע עליהם כעת. הפעלה מחדש של ה-VPN, העורך והמנוע ברצף עשויה לשנות את הסימפטום, אבל היא לא משאירה דבר שהאדם הבא יוכל להשתמש בו.