מדוע פודי GKE אינם מגיעים למארחים מקומיים דרך VPN
הצומת מגיע לרשת המקומית, הפוד לא. חריגי masquerade ב-GKE משאירים את כתובות הפודים ללא תרגום ליעדי 10.x.
ה-ping עובד מהצומת ונכשל מהפוד, ושום דבר לא מגיע לצד המקומי. המנהרה והמסלול תקינים; כתובת המקור על הכבל לא. מה שמבדיל בין שני המקרים הוא מה שהחבילה מצהירה שהיא כשהיא יוצאת מהאשכול, ול-GKE יש דעה בעניין. המנגנון הוא רשימת חריגי masquerade, וקריאתה דורשת פקודה אחת.
קראו את הרשימה התקפה לפני שמשנים משהו
GKE מספק סוכן שמחליט, לכל טווח יעד, אם תעבורת הפודים נכתבת מחדש לכתובת הצומת ביציאה. התצורה המסופקת שלו מפרטת את שלושת בלוקי RFC1918, 10.0.0.0/8, 172.16.0.0/12 ו-192.168.0.0/16, כיעדים פטורים. לכן כל מה שתשלחו מפוד למארח 10.x מקומי יוצא מהצומת כשכתובת הפוד עצמו עדיין מחוברת. התעבורה של הצומת עצמו אינה נכתבת מחדש, וזו בדיוק הסיבה שה-ping שלו עובד.
קראו את התצורה המיועדת ואת הכללים המותקנים, כי הם עלולים שלא להסכים. kubectl -n kube-system get configmap ip-masq-agent -o yaml מראה מה נאמר לסוכן, ו-kubectl -n kube-system get pods -l k8s-app=ip-masq-agent מראה אם משהו רץ כדי להחיל אותו. בצומת, iptables-save | grep -i masq מראה את הכללים שקיימים באמת בליבה. כשתצורת ConfigMap אומרת דבר אחד והכללים אומרים אחר, החשוד הוא הסוכן ולא הרשת.
אמתו את כתובת המקור באמצעות לכידה
בצעו לכידה לפני שתשנו רשימה. סינון ליעד אחד שומר על פלט קריא: tcpdump -ni any host 10.20.30.40.
השוו זאת למה שהצד השני מדווח. לכידה מקומית שמראה את כתובת הפוד ואין תגובה סוגרת את המעגל: רשימת החריגים מסבירה את חוסר הסימטריה בלי כל תקלת מנהרה. שתי תצפיות של אותה כתובת מקור מספיקות כדי להפסיק לנחש לגבי ה-CNI.
צמצמו את החריג ל-CIDR של הפודים
התיקון הנתמך מצמצם את הפטור במקום להסיר אותו: השאירו את ה-CIDR של הפודים פטור והשליכו את שאר מרחב 10.x. הרשימה הזו נמצאת ב-ConfigMap של הסוכן תחת nonMasqueradeCIDRs, ושינוי שלה הוא עריכה ואחריה פריסה. החליפו את הרשומה הרחבה בטווח הפודים האמיתי של האשכול, השאירו את שאר הבלוקים הפרטיים אם תעבורה בתוך האשכול עדיין זקוקה להם, והניחו ל-resyncInterval אלא אם יש לכם סיבה. החילו, אמתו שפודי הסוכן הופעלו מחדש ואמתו שכללי הליבה השתנו.
זהו שינוי בכל האשכול עם רדיוס השפעה אמיתי. לאחר שיוחל, תעבורה שקודם שמרה על מקור הפוד מגיעה כעת כתובה מחדש לצומת, ולכן כל מה שהסתמך על כתובות הפודים האלה רואה שולח אחר. הנפגעים הם היומנים, רשימות ההיתר וכללי חומת האש המקומיים שמציינים כתובות פודים, והם נכשלים בשקט. הכריזו על השינוי כשינוי התנהגות, לא כתיקון.
באשכול עם כמה מאגרי צמתים, בדקו שהסוכן מתוזמן על הצמתים שבהם הפודים המושפעים באמת רצים. מאגר בלי DaemonSet שומר על הכללים הישנים, ושום דבר ב-ConfigMap לא יראה זאת.
החלופה ומחירה
האפשרות האחרת שומרת על כתובות הפודים ללא שינוי ומלמדת את המסלול עליהן. ה-CIDR של הפודים נכנס לבוררי התעבורה של Cloud VPN, והצד המקומי צריך מסלול חזרה עבורו כדי שהתגובות ידעו לאן ללכת. זה משמר את זהות הפוד שחלק ממודלי האבטחה רוצים, ומרחיב גם את היקף הניתוב וגם את היקף חומת האש שהצד השני חייב לקבל.
העסקה היא קריאות מול היקף. תרגום גורם לצד המקומי לראות כתובת אחת לכל צומת, שקל להוסיף לרשימת היתר ומסתיר איזה פוד שלח מה. בלי תרגום כתובת הפוד נשמרת מקצה לקצה, שטוב יותר לייחוס וגרוע יותר לכל התקן במסלול שצריך ללמוד טווח חדש. אף אפשרות אינה פגם של Docker או CNI; שתיהן החלטות ניתוב עם חשבון תפעולי. בחרו בזו שהצוות שלכם יכול לשלם את חשבונה, וכתבו מדוע.
אמתו והחזירו
הריצו שוב את אותה לכידה. לכידה ברמת הצומת שמדפיסה עדיין את כתובת הפוד אחרי העריכה שלכם פירושה שהכללים מעולם לא השתנו, יהא אשר יאמר ConfigMap. הכבל הוא העובדה; כל השאר הסקה.
לאחר מכן בדקו את הכיוון ההפוך, כי מחצית מהשינויים האלה נבדקים רק ביציאה. אמתו שהתגובה מגיעה לצומת או לפוד ששלח את הבקשה, ואמתו שהיישום הסתיים ולא רק קיבל SYN. לכידה שמראה בקשה בלי תגובה היא בעיית ניתוב בצד השני, לא בעיית masquerade בצד הזה.
החזרה היא ה-ConfigMap הקודם, מיושם באותה דרך, עם אותה אמת מידה שהסוכן הופעל מחדש ושהכללים השתנו. שמרו את כתובת המקור לפני ואחרי עבור בקשה ידועה אחת ביומן השינויים, כי השורה האחת הזו היא שמוכיחה שהשינוי עשה את מה שאמרתם. המדריך של GKE לסוכן IP masquerade מתעד את ברירות המחדל ואת שדות ה-ConfigMap. אם כתובת המקור לא השתנתה אחרי הפריסה, הסוכן לא רץ על אותו צומת ושום עריכת YAML לא תתקן זאת.