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

נתקלתי בזה בצומת Debian שהריץ תמונת OpenVPN שהותקנה דרך chart, והמנהרה הייתה החלק הקל. הלקוח קיבל חכירה של 10.8.0.x, ‏10.8.0.1 ענה, ו-10.96.0.10, שירות ה-DNS של האשכול, פג בזמן. שום דבר ביומן השרת לא נראה חולה, וזו בדיוק הסיבה שאנשים מתחילים לשכתב כללי iptables שמעולם לא היו צריכים לגעת בהם.

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

למה הלקוח יכול להגיע ולמה לא

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

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

קראו את ההגדרה בתוך מרחב השמות

כל פוד מקבל מרחב שמות רשת משלו, ו-net.ipv4.ip_forward הוא sysctl לכל מרחב שמות. שינוי שלו בצומת לא אומר לכם דבר על הקונטיינר, וזו דרך אמינה לבלות אחר צהריים במכונה הלא נכונה.

kubectl exec -it deploy/openvpn -- sysctl net.ipv4.ip_forward
# net.ipv4.ip_forward = 0

אפס מאשר את האבחון. הערך גם לא עובר בירושה מהתצורה בזמן ריצה של הצומת: הוא מתחיל מברירת המחדל של התמונה בכל פעם שקונטיינר נוצר. לכן תיקון שהוחל ביד עם kubectl exec ... sysctl -w נעלם באתחול הבא וחוזר כתקלה שנראית לסירוגין.

להפעיל כך שהמניפסט ישמור על זה

האפשרות העמידה היא קונטיינר init שרץ באותו pod sandbox וכותב את הערך לפני שקונטיינר ה-VPN מתחיל. קונטיינרים בפוד חולקים מרחב שמות רשת, כך שההגדרה עוברת לקונטיינר הראשי.

initContainers:
- name: enable-forwarding
  image: busybox:1.36
  command: ["sysctl", "-w", "net.ipv4.ip_forward=1"]
  securityContext:
    privileged: true

בדיוק privileged: true הוא השורה שהסוקרים מתנגדים לה, ובצדק. כתיבת sysctl דורשת הרשאה או יכולת מוגבלת, ואשכול שמריץ את תקן Pod Security המוגבל עשוי לסרב לחלוטין לקונטיינר init מיוחס. אם admission דוחה את הפוד, אתם לומדים זאת בזמן היצירה, וזה לפחות כן וקל לקריאה.

החלופה הנקייה יותר היא רשימת securityContext.sysctls ברמת הפוד, שמאפשרת ל-kubelet להחיל sysctls עם מרחב שמות בלי לתת הרשאה לאף קונטיינר. היא מכסה רק שמות ברשימת ההיתר של האשכול. אם net.ipv4.ip_forward נמצא ברשימה תלוי באופן שבו הוגדר ה-kubelet, ופוד שמבקש sysctl מחוצה לה נדחה ב-admission או נתקע ב-CreateContainerConfigError בזמן שה-sandbox מנוסה שוב. בדקו את רשימת ההיתר לפני שאתם מניחים שהשדה שבור.

לפני שאתם בונים ידנית כל אחת מהגישות, בדקו אם ה-chart כבר חושף את המתג, לעתים כמשהו כמו ipForwardInitContainer: true. שימוש בערך של ה-chart שומר על קובץ העקיפה שלכם קטן ושורד את השדרוג הבא, מה שעריכות Deployment שתוקנו ביד לא עושות.

המחצית השנייה: נתיב חזור ומדיניות

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

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

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

לבודד את הקפיצה הכושלת מהלקוח

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

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

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