תמונות מכולה יכולות לשאת כל קובץ בינארי וקובץ תצורה של OpenVPN שהן זקוקות לו ובכל זאת להיכשל בקריאת הרשת הראשונה. השגיאה מציינת את /dev/net/tun מפני שהאפליקציה ביקשה מהגרעין ממשק TUN ולמכולה לא היה לא צומת ההתקן ולא היכולת ליצור אחד. אלו שתי הרשאות נפרדות, ותיקון האחת משאיר את השנייה בדיוק במקום שבו הייתה.

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

צומת ההתקן והיכולת הם שני שערים

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

הגדרת devices של Docker ממפה את התקן המארח אל תוך המכולה, בעוד cap_add מתאים את קבוצת היכולות. bind mount של אותו נתיב מציג את הקובץ בלי להחיל את סמנטיקת הגישה להתקן.

שחזרו זאת מחוץ לקובץ Compose

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

ls -l /dev/net/tun
docker run --rm --cap-add NET_ADMIN --device /dev/net/tun:/dev/net/tun alpine sh -c 'apk add -q iproute2 && ip tuntap add dev tun9 mode tun && ip link show tun9'

היעדר צומת במארח פירושו שמודול tun אינו זמין, וזה תיקון בצד המארח ולא בצד המכולה. צומת שקיים אך אינו נפתח בתוך המכולה מצביע על גישה להתקן, וההודעה תאמר permission denied ולא no such file. הסדר של שתי הכשלות הללו הוא כל האבחון. רשמו איזו מהן ראיתם לפני שתשנו דגל.

השגיאות שאחרי TUN הן בעיות אחרות

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

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

אמתו את הממשק בתוך המכולה

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

ls -l /dev/net/tun
capsh --print | grep -i net_admin
ip link add dev tun9 type tun && ip link show tun9

יכולת שנמצאת ב-bounding set אך חסרה ב-effective set מתנהגת אחרת מיכולת שמעולם לא ניתנה, ו-capsh מציג את שתיהן. אם הצומת קיים והיכולת שם בעוד היצירה עדיין נכשלת, סביבת הריצה כופה משהו אחר, כמו פרופיל seccomp או מדיניות AppArmor שמגבילה את הפעולה. זהו גבול שלישי, שמתועד על ידי סביבת הריצה ולא על ידי האפליקציה.

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

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