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

שתי בעיות שונות, שני מתגים שונים

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

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

FreeBind: המאזין קיים לפני הכתובת

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

[Socket]
ListenStream=
ListenStream=10.8.0.1:8443
FreeBind=yes

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

המדריך ל-socket של systemd מתעד את התנהגות IPv4 ו-IPv6 שמאחורי האפשרות, והפרט החשוב הוא שהיא חלה על הקישור ולא על הניתוב. דבר בו אינו מקצה כתובת או מפעיל VPN. FreeBind הוא הרשאה שניתנת למאזין, לא תחליף לממשק.

After= ו-Wants=: סדר אינו מוכנות

סדר ודרישה הם צירים נפרדים, וערבוב ביניהם יוצר יחידות שעולות בסדר הנכון ובכל זאת נכשלות. After=vpn-client.service פירושו רק שאם שתי המשימות מופעלות, זו ממתינה לזו השנייה שתופעל. הוא אינו מושך את ה-VPN, והוא אינו ממתין שה-VPN יסיים להתחבר.

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

בדקו מה היחידה מצהירה בפועל עם systemctl cat ו-systemctl show -p After -p Wants -p Requires. קבצי drop-in משלושה מדריכים שונים יכולים להוסיף הוראות שלא כתבתם מעולם, ו-systemd קורא רק את היחידה האפקטיבית.

מה network-online.target אינו עושה

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

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

בדקו את מחזור החיים שבחרתם בפועל

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

systemd-analyze verify myapp.socket
systemctl cat myapp.socket
ss -ltn "sport = :8443"

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

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

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