رفتن به محتوای اصلی

Pedram Sarani

یادداشت‌های SRE و DevOps

بازگشت به فهرست درس‌ها

بخش چهارم: مسیر Pod to Pod؛ سفر واقعی یک پکت

در این بخش مسیر واقعی یک پکت را در ارتباط مستقیم Pod-to-Pod دنبال می‌کنیم؛ از same-node و cross-node تا مسیر برگشت، source IP، connection tracking و تفاوت dataplaneها.

مسیر Pod to Pod؛ سفر واقعی یک پکت

در بخش اول، وقتی درباره «ارتباط مستقیم Pod به Pod» حرف زدیم، فقط یک تصویر ذهنی ساختیم. گفتیم اگر مقصد روی همان نود باشد، پکت لوکال جلو می‌رود؛ اگر روی نود دیگری باشد، CNI باید route یا tunnel لازم را آماده کرده باشد. در بخش سوم هم همین ایده را بیشتر باز کردیم، اما تمرکز آن بخش روی ساختن شبکه Pod بود: network namespace، veth، CNI، IPAM، و دو نگاه کلی overlay و underlay.

اینجا بحث را یک پله عملی‌تر می‌کنیم. دیگر نمی‌خواهیم فقط بگوییم شبکه چطور ساخته شده؛ می‌خواهیم یک پکت واقعی را برداریم و ببینیم دقیقاً از کجا رد می‌شود. فرض ما این است که پاد A از قبل ای پی پاد B را می‌داند و مستقیماً به همان آدرس وصل می‌شود.

چرا این مسیر برای فهم پایه‌ای networking این‌قدر مهم است؟ چون اینجا کمترین لایه اضافی را داریم. Service وسط نیست.

یعنی:

  • DNS درگیر نمی‌شود؛ آدرس را از قبل داریم و نیازی به resolve کردن نام نیست.
  • Service VIP یا ClusterIP مقصد این connection نیست.
  • مسیر Service load-balancing و انتخاب backend وارد این flow نمی‌شود.
  • DNAT مربوط به ClusterIP هم نداریم؛ مقصد از همان ابتدا ای‌پی پاد واقعی است.

به همین دلیل، این مسیر بهترین جا برای دیدن سه چیز است، بدون اینکه Service NAT شلوغش کند: پکت چطور از پاد A به پاد B می‌رسد، برگشت جواب از چه راهی انجام می‌شود، و سورس ای‌پی در این رفت‌وبرگشت چه سرنوشتی دارد. وقتی این حالت ساده را تمیز ببینیم، در بخش‌های بعدی که Service و NAT وارد می‌شوند، خیلی راحت‌تر می‌فهمیم هرکدام دقیقاً چه چیزی را تغییر می‌دهند.

یک connection دقیقاً یعنی چه؟ مدل ۵-تایی

قبل از اینکه دنبال مسیر برویم، باید روشن کنیم اصلاً داریم چه چیزی را دنبال می‌کنیم. برای flowهای TCP و UDP، معمولاً از یک ۵-تایی یا 5-tuple حرف می‌زنیم:

(protocol, source IP, source port, destination IP, destination port)

وقتی اپلیکیشن داخل پاد A یک کانکشن به پاد B باز می‌کند:

  • destination IP همان پاد مقصد است؛ مثلاً 10.244.2.8.
  • destination port پورتی است که اپلیکیشن مقصد روی آن گوش می‌دهد؛ مثلاً 8080.
  • source IP آدرس پاد A است؛ مثلاً 10.244.1.5.
  • source port یک پورت موقت یا همان ephemeral پورت است؛ اگر اپلیکیشن خودش آن را مشخص نکرده باشد، kernel سمت مبدا یک پورت آزاد از بازه ephemeral پورت انتخاب می‌کند.

این ۵-تایی هویت همان flow در لایه ۳ و ۴ است. dataplane می‌تواند برای forwarding، policy یا connection tracking از همین مشخصات استفاده کند، اما مکانیزم دقیقش بین پیاده‌سازی‌ها یکسان نیست.

نکته اصلی این بخش این است که در مدل استاندارد Pod-to-Pod کوبرنتیز، آدرس مبدأ و مقصد اصلی برای ارتباط مستقیم بین دو پاد نباید NAT شوند. نبود Service هم یعنی Service DNAT یا انتخاب بک‌اند چیزی به این مسیر اضافه نمی‌کند. بنابراین در سناریوی پایه‌ای که در این فصل دنبال می‌کنیم، ۵-تایی جریان اصلی شامل IP مبدأ، IP مقصد، پورت مبدأ، پورت مقصد و پروتکل، از مبدأ تا مقصد حفظ می‌شود.

برای ملموس‌تر شدن، یک کانکشن از نوع TCP را تصور کنیم. سه پکت اول، یعنی همان three-way handshake، همین flow را می‌سازند: SYN از پاد A به پاد B می‌رود، SYN-ACK از پاد B با ۵-تایی معکوس برمی‌گردد، و ACK دوباره از پاد A راه می‌افتد. source port هم تا پایان همان کانکشن ثابت می‌ماند. پس وقتی در این بخش از «مسیر» حرف می‌زنیم، منظور فقط یک پکت تک‌جهتی نیست؛ یک flow دوطرفه را دنبال می‌کنیم.

Kubernetes Pod-to-Pod packet journey showing the original 5-tuple across same-node and cross-node paths
این تصویر نمای کلی مسیر مستقیم Pod-to-Pod را نشان می‌دهد؛ بدون تغییر آدرس‌ها و پورت‌های اصلی جریان تا دو مسیر same-node و cross-node، بدون Service DNAT یا NAT بین پادها در سناریوی پایه.

مسیر same-node؛ و چرا همیشه یک‌شکل نیست

آسان‌ترین حالت این است که پاد A و پاد B هر دو روی یک نود باشند. اما همین حالت ساده هم یک دام دارد که خیلی وقت‌ها در توضیح‌ها نادیده گرفته می‌شود: رفتار same-node به CNI و dataplane بستگی دارد. برای ساختن مدل ذهنی، دو پیاده‌سازی رایج را جدا می‌کنیم.

مدل اول: bridge و لایه ۲

در مدل‌های bridge‌محور، مثل ترکیب رایج Flannel با CNI bridge plugin، پادهای یک نود به یک بریج مجازی روی همان نود وصل می‌شوند؛ چیزی مثل cni0. پادهای آن subnet لوکال در یک broadcast domain قرار می‌گیرند و در IPv4 می‌توانند با ARP آدرس MAC یکدیگر را پیدا کنند. در این مدل، ارتباط same-node عمدتاً به‌صورت forwarding در لایه ۲ انجام می‌شود.

  • پاد A می‌خواهد به پاد B، مثلاً 10.244.1.6، وصل شود و می‌بیند مقصد داخل همان subnet است.
  • اگر هنوز neighbor entry نداشته باشد، باید MAC مقصد را پیدا کند. یک ARP request می‌فرستد: «چه کسی 10.244.1.6 است؟»
  • ARP از veth بیرون می‌آید و به bridge می‌رسد. bridge آن را در broadcast domain پخش می‌کند، پاد B جواب می‌دهد و MAC خودش را اعلام می‌کند.
  • بعد پاد A فریم را با MAC مقصد می‌سازد و bridge آن را مثل یک switch به پورت مربوط به پاد B می‌فرستد.

در این مدل، برای همین ارتباط لوکال بین دو endpoint داخل همان subnet، فورواردینگ اصلی در لایه ۲ انجام می‌شود.

مدل دوم: routing مستقیم و لایه ۳؛ نمونه Calico

در dataplane استاندارد لینوکسی Calico، پادها پشت bridge مشترک قرار نمی‌گیرند. هر workload هم route خودش را دارد و host مثل router بین endpointها عمل می‌کند. داخل یک پاد IPv4 معمولاً چیزی شبیه این می‌بینیم:

default via 169.254.1.1 dev eth0
169.254.1.1 dev eth0 scope link
  • پاد ترافیک را به gateway آدرس 169.254.1.1 تحویل می‌دهد. این آدرس convention خود Calico است و استاندارد عمومی همه routed CNIها نیست.
  • Calico لازم نیست این ای‌پی را واقعاً روی host-side interface بنشاند. روی interface مربوط به workload، proxy_arp باعث می‌شود host برای آن gateway جواب ARP بدهد.
  • host برای workloadهای محلی route دارد. پس وقتی پکت از پاد A وارد host می‌شود، FIB lookup مقصد پاد B را پیدا می‌کند و پکت به اینترفیس درست فرستاده می‌شود.

پس در این مدل، حتی اگر دو پاد روی یک نود باشند، forwarding از مسیر لایه ۳ هاست جلو می‌رود، نه از یک bridge مشترک.

در Calico معمولاً اینترفیس سمت نودِ workload آدرس IP ندارد و ممکن است MACهایی مثل ee:ee:ee:ee:ee:ee هم ببینیم. این‌ها جزئیات پیاده‌سازی خود Calico هستند و جزو الزامات عمومی معماری CNI نیستند.

Same-node Kubernetes Pod-to-Pod traffic comparing an L2 bridge dataplane with a Calico L3 routed dataplane
این تصویر دو مدل رایج برای ارتباط same-node بین دو پاد را مقایسه می‌کند؛ در مدل bridge‌محور، فورواردینگ عمدتاً با ARP، MAC learning و FDB در لایه ۲ انجام می‌شود، اما در مدل routed کالیکو، نود با routeهای workload و FIB lookup پکت را در لایه ۳ به پاد مقصد می‌رساند.

وجه مشترک این مدل‌ها این است که چون مقصد روی همان نود است، پکت لازم نیست از شبکه بین nodeها عبور کند. overlay بین نودها، encapsulation cross-node و MTU آن مسیر بیرونی وارد بازی نمی‌شوند. به همین خاطر same-node معمولاً مسیر ساده‌تری نسبت به cross-node دارد.

یک نکته IPv6 و dual-stack

تا اینجا برای ساده نگه‌داشتن، فرض کردیم همه‌چیز IPv4 است. در کلاستر dual-stack، پاد می‌تواند IPv4 و IPv6 داشته باشد و flow هر خانواده با آدرس‌های همان خانواده جلو می‌رود.

فرق مهم در neighbor discovery است. IPv4 از ARP استفاده می‌کند، اما IPv6 چیزی به اسم ARP ندارد؛ این کار با Neighbor Discovery روی ICMPv6 انجام می‌شود. در یک مدل لایه ۲، به‌جای ARP request می‌توان Neighbor Solicitation دید. جزئیات gateway و neighbor handling در مدل‌های routed باز هم به CNI وابسته است؛ بنابراین نباید آدرس یا مکانیزم کالیکو IPv4 را خودکار به IPv6 یا CNIهای دیگر تعمیم داد.

مسیر cross-node؛ سفر واقعی پکت

حالا برسیم به حالت قشنگ‌تر: پاد B روی نود دیگری است. پکت را از لحظه خروج از پاد A تا رسیدن به پاد B دنبال کنیم.

  • اپلیکیشن داخل پاد A پکت را با destination واقعی پاد B می‌سازد.
  • پکت از اینترفیس پاد وارد dataplane نود مبدأ می‌شود؛ در setupهای veth معمولی از eth0 پاد و host-side veth عبور می‌کند، ولی این جزئیات در همه dataplaneها الزاماً veth نیست.
  • نود مبدأ برای مقصد تصمیم forwarding می‌گیرد. مقصد لوکال این نود نیست و باید به نود دیگری برسد.
  • بسته به CNI، پکت اصلی ممکن است داخل تونلی مثل VXLAN، Geneve یا IP-in-IP حمل شود. در حالت دیگر، اگر شبکه زیرین مسیر IP پادها را بشناسد، همان پکت با مسیریابی مستقیم تا نود مقصد می‌رسد.
  • روی نود مقصد، اگر encapsulation داشته باشیم outer header برداشته می‌شود و inner پکت دوباره دیده می‌شود.
  • حالا dataplane نود مقصد پکت را به endpoint محلی پاد B تحویل می‌دهد. در مدل bridge-based، این مرحله می‌تواند بعد از host routing به bridge با یک hop لایه ۲ تمام شود؛ در مدل routed، روت مستقیم endpoint را پیدا می‌کند؛ و در dataplaneهای دیگر ممکن است مسیر متفاوت باشد.
Cross-node Kubernetes Pod-to-Pod traffic comparing overlay encapsulation with native routing and showing the return path
این تصویر مسیر cross-node بین دو پاد را نشان می‌دهد؛ پکت اصلی یا داخل یک تونل مثل VXLAN، Geneve یا IP-in-IP بین نودها حمل می‌شود، یا بدون encapsulation و با native routing از شبکه زیرین عبور می‌کند. مسیر برگشت نیز routing lookup مستقل خودش را دارد.

این جداسازی same-node و cross-node برای troubleshooting واقعاً ارزشمند است. اگر یک جفت پاد روی همان نود می‌توانند مستقیم با هم حرف بزنند ولی همان تست بین دو نود fail می‌شود، تمرکز اول روی لایه cross-node می‌رود: routing، encapsulation، MTU و firewall بین نود‌ها. این نتیجه درباره همان تست مشخص است؛ نه اینکه هر مسیر Pod-to-Pod دیگری در کلاستر را سالم فرض کنیم.

مسیر برگشت؛ routing کجا تصمیم می‌گیرد و connection state چه نقشی دارد؟

کانکشن قاعدتا فقط رفت نیست؛ جواب هم باید برگردد. اما یک تفکیک مهم اینجا داریم: routing مسیر برگشت را انتخاب می‌کند، نه conntrack.

وقتی Pod B جواب می‌دهد، پکت برگشت source و destination معکوس دارد. همان‌طور که پکت رفت در هر hop تصمیم مسیریابی یا forwarding خودش را داشت، پکت برگشت هم از سمت B یک lookup مستقل دارد. لازم نیست مسیر فیزیکی برگشت دقیقاً همان hopهای مسیر رفت را برعکس طی کند. به این حالت asymmetric routing می‌گوییم؛ یعنی مسیر رفت و برگشت یک connection می‌توانند از مسیرهای متفاوتی عبور کنند. در شبکه‌هایی با ECMP، BGP یا چند مسیر، چنین رفتاری می‌تواند کاملاً معتبر باشد.

مشکل وقتی شروع می‌شود که یکی از اجزای مسیر با این asymmetry کنار نیاید؛ مثلاً reverse-path filtering سخت‌گیرانه، firewall stateful یا یک طراحی tunnel که انتظار دیگری دارد. آن وقت ممکن است SYN برسد ولی SYN-ACK در مسیر دیگری drop شود. پس چیزی که لازم داریم reachability دوطرفه و سازگاری dataplane است، نه الزام به یک مسیر رفت‌وبرگشت کاملاً متقارن.

connection tracking بدون NAT

connection tracking و NAT یک چیز نیستند. در dataplaneهایی که بر پایه netfilter لینوکس کار می‌کنند، conntrack می‌تواند flow را حتی وقتی هیچ NATی وجود ندارد track کند. اما این رفتار را نباید به همه dataplaneها تعمیم داد. پکت‌هایی که از connection tracking مستثنا شده‌اند، یا dataplaneهایی که مسیر netfilter روی هاست را دور می‌زنند، ممکن است در nf_conntrack دیده نشوند.

برای مثال، dataplane استاندارد Calico از conntrack لینوکس استفاده می‌کند، اما dataplane مبتنی بر eBPF خود Calico وضعیت connection را داخل mapهای BPF نگه می‌دارد. Cilium هم در بعضی حالت‌ها مسیر netfilter یا connection tracking مبتنی بر iptables را برای ترافیک پاد دور می‌زند و وضعیت connection را در BPF نگه می‌دارد.

NetworkPolicy هم در سطح API به conntrack لینوکس وابسته نیست. مشخصات کوبرنتیز می‌گوید ترافیک پاسخ برای یک connection مجاز باید به‌صورت ضمنی اجازه عبور داشته باشد، اما اینکه پلاگین شبکه این وضعیت را دقیقاً با چه مکانیزمی نگه می‌دارد، به پیاده‌سازی آن بستگی دارد. حتی رفتار connectionهای موجود بعد از تغییر policy هم می‌تواند بین پیاده‌سازی‌های مختلف متفاوت باشد.

source IP در این مسیر چه می‌شود؟

در مدل شبکه کوبرنتیز، ارتباط مستقیم بین پادها باید بدون NAT باشد. یعنی وقتی پاد A مستقیم به پاد B وصل می‌شود، پاد B باید source را همان ای‌پی واقعی پاد A ببیند. این ویژگی از مدل Pod network می‌آید؛ نه از این فرض که «هر چیزی داخل کلاستر است پس هیچ rule دیگری نمی‌تواند آن را تغییر دهد».

Kubernetes Pod-to-Pod source IP preservation, egress SNAT behavior, and unexpected intra-cluster SNAT
این تصویر رفتار source IP را در مسیر مستقیم Pod-to-Pod و هنگام خروج از شبکه پادها مقایسه می‌کند؛ در ارتباط مستقیم، IP واقعی پاد مبدأ حفظ می‌شود، اما در ترافیک خروجی ممکن است بسته به قابلیت مسیریابی شبکه و تنظیمات dataplane، SNAT یا masquerade انجام شود.

وقتی ترافیک از پاد نتورک به مقصد دیگری می‌رود، داستان به محیط بستگی دارد. اگر شبکه مقصد route برگشت به پاد CIDR نداشته باشد، egress SNAT یا masquerade یکی از راه‌های رایج برای قابل برگشت کردن ترافیک است؛ راه دیگر می‌تواند فراهم کردن routing واقعی برای ای‌پی پادها باشد. بنابراین SNAT رفتار عمومی و اجباری کوبرنتیز نیست و در یک شبکه native-routed یا VPC-native ممکن است اصلاً لازم نباشد.

خود مکانیزم masquerade هم بین محیط‌ها فرق می‌کند. ip-masq-agent یکی از گزینه‌هاست و با nonMasqueradeCIDRs کار می‌کند. Calico می‌تواند با natOutgoing روی IPPool ترافیک بیرون از poolها را SNAT کند. Cilium هم masquerading و native-routing CIDR خودش را دارد. بنابراین موقع تی شوت اول باید بدانیم چه کامپوننتی در همان کلاستر مسئول SNAT است.

یک دردسر عملی همین‌جاست: اگر rule سفارشی یا تنظیمات NAT و egress اشتباه باشند، ممکن است حتی در ارتباطی که باید مستقیم Pod-to-Pod باشد، پاد مقصد source IP دیگری ببیند. در چنین حالتی اول باید پیدا کنیم SNAT کجا و توسط کدام بخش از dataplane اعمال شده است.

این تغییر می‌تواند روی NetworkPolicy هم اثر بگذارد، اما رفتار دقیق آن به پیاده‌سازی شبکه بستگی دارد. به‌خصوص policyهایی مثل ipBlock که مستقیماً با IP سروکار دارند، ممکن است رفتاری متفاوت از policyهای مبتنی بر selector داشته باشند؛ چون ترتیب اعمال NAT و policy enforcement بین پیاده‌سازی‌های مختلف یکسان نیست.

این مسیر در عمل کجا استفاده می‌شود؟

شاید سوال پیش بیاید وقتی معمولاً از Service استفاده می‌کنیم، اصلاً چه زمانی کسی مستقیم به ای پی پاد وصل می‌شود؟ در عمل چند سناریوی مهم به همین مسیر می‌رسند:

  • StatefulSetها و peer discovery: یک headless Service می‌تواند DNS را به endpointهای واقعی برساند. هویت پایدار StatefulSet از نام و DNS پایدار می‌آید؛ خود ای‌پی پاد الزاماً برای همیشه ثابت نیست و بعد از recreate می‌تواند عوض شود.
  • operatorها و control planeهای داخلی: که برای کاری مشخص مستقیم با یک پاد خاص حرف می‌زنند.
  • بعضی الگوهای service mesh و sidecar: که در بخش‌هایی از dataplane با ای‌پی پادها سروکار دارند؛ البته مش می‌تواند مسیر را intercept یا تغییر دهد، پس دیگر لزوماً همان مسیر ساده این فصل نیست.
  • debugging و تست: که در آن عمداً مستقیم به ای پی وصل می‌شویم تا بخشی از مسیر Service را از آزمون حذف کنیم.

اگر ای‌پی پاد مستقیم از یک source مشخص به یک destination مشخص کار کند ولی همان درخواست از Service fail شود، یک چیز مهم می‌دانیم: همان مسیر مستقیم مشخص قابل دسترس است. هنوز نمی‌توانیم نتیجه بگیریم کل Pod-to-Pod کلاستر سالم است، چون Service ممکن است endpoint دیگری روی node دیگری انتخاب کند یا مشکل در خود Service dataplane باشد.

مسیر مستقیم در برابر ClusterIP؛ چه چیزی تغییر می‌کند؟

حالا که مسیر پایه را دیده‌ایم، قبل از رفتن به بخش بعدی یک قاب ذهنی بسازیم. این جدول درباره Service معمولی دارای ClusterIP است؛ headless Service داستان دیگری دارد و بعد از DNS، کلاینت می‌تواند مستقیم به Pod IP برسد.

جنبهمستقیم Pod-to-Podاز طریق Service دارای ClusterIP
مقصد اولیهPod IP واقعیClusterIP یا آدرس مجازی Service
Service proxy / load-balancingوارد flow نمی‌شودbackend را انتخاب می‌کند
data plane شبکه پاددرگیر استهمچنان درگیر است
تغییر destinationدر حالت پایه نداردمعمولاً translation به endpoint واقعی
۵-تایی inner flowدر حالت پایه حفظ می‌شودdestination و در بعضی مسیرها source می‌تواند تغییر کند
source IPدر حالت پایه حفظ می‌شودبه نوع Service و مسیر بستگی دارد

نگاه production؛ وقتی مسیر مستقیم Pod-to-Pod خراب می‌شود

موقع troubleshooting بهتر است ترتیب بررسی را از architecture واقعی همان کلاستر شروع کنیم:

  • اول CNI و dataplane مود را مشخص کنیم. Calico استاندارد، Calico eBPF، Cilium، Flannel یا چیز دیگری؟ قبل از اینکه دنبال cni0، cali* یا Linux conntrack بگردیم باید بدانیم اصلاً انتظار داریم وجود داشته باشند یا نه.
  • آیا پاد مقصد IP دارد و Running است؟ با kubectl get pod <pod> -o wide آدرس فعلی را چک کنیم.
  • مشکل همان source/destination روی same-node است یا cross-node؟ اگر same-node سالم و cross-node خراب است، routing، tunnel، MTU و firewall بین نود‌ها مظنون‌های جدی‌تری هستند.
  • در مدل‌های مبتنی بر bridge، وضعیت neighbor و جدول FDB بریج را بررسی می‌کنیم. در dataplane استاندارد کالیکو، routeهای مربوط به workload و proxy ARP برای آدرس 169.254.1.1 مهم هستند. البته باز هم بگم این الگو مخصوص همان پیاده‌سازی است و نباید آن را به همه CNIهای مبتنی بر routing تعمیم بدهیم.
  • آیا الگوی خطا شبیه MTU است؟ کانکشن کوچک کار می‌کند ولی payload بزرگ گیر می‌کند؟ آن وقت outer encapsulation و MTU مسیر cross-node را بررسی کنیم.
  • sourceی که destination می‌بیند چیست؟ اگر به‌جای ای‌پی پاد، ای‌پی نود یا آدرس دیگری دیده می‌شود، باید پیاده‌سازی SNAT همان کلاستر را پیدا کنیم؛ ممکن است این NAT را ip-masq-agent، تنظیم natOutgoing در Calico، قابلیت masquerading در Cilium یا حتی یک rule سفارشی ایجاد کرده باشد.
  • آیا NetworkPolicy درگیر است؟ اول مطمئن شویم CNI آن را enforce می‌کند و بعد مود همان دیتاپلین را بررسی کنیم. رفتار state و محل policy enforcement بین implementationها یکسان نیست.

چند ابزار پایه برای دیدن مسیر:

root@pedram:~# kubectl get pods -o wide

root@pedram:~# kubectl exec -it <pod> -- ip route
root@pedram:~# kubectl exec -it <pod> -- ip neigh

اگر ایمیج پاد iproute2 نداشته باشد، این دستورها طبیعتاً کار نمی‌کنند؛ در imageهای distroless این اتفاق عادی است. آنجا می‌توان از kubectl debug با یک ephemeral container مناسب یا ابزارهای node-side استفاده کرد.

روی نود، در dataplaneهای veth-based می‌توان اینترفیس سمت host را با tcpdump دید:

root@pedram:~# tcpdump -ni <host-veth-interface>

فقط جهت پکت را از دید همان اینترفیس بخوانیم؛ ingress/egress سمت host لزوماً همان چیزی نیست که از دید eth0 داخل Pod انتظار داریم.

اگر dataplane از Linux netfilter conntrack استفاده می‌کند و ابزار conntrack در دسترس است:

root@pedram:~# conntrack -L

اما این دستور منبع حقیقت همه CNIها نیست. برای نمونه، Calico eBPF جدول BPF خودش را با calico-node -bpf conntrack dump دارد و Cilium هم BPF connection-tracking map خودش را با ابزارهای cilium-dbg bpf ct list نشان می‌دهد.

نام interfaceها، routeها و ابزار مناسب بین CNIها و modeها فرق می‌کند. قبل از هر تست، اول dataplane واقعی همان cluster را مشخص کنیم و در محیط پروداکشن هم ابزارهای tracing و تغییر state را با احتیاط به‌کار ببریم.

نتیجه

مسیر مستقیم Pod-to-Pod، پایه‌ای‌ترین مسیر شبکه کوبرنتیز است؛ مسیری که Service proxy و Service DNAT را کنار می‌گذارد و خود pod network را جلوی چشم می‌آورد.

یادداشت فنی

این فصل مدل استاندارد Pod network را توضیح می‌دهد و برای جزئیات پیاده‌سازی از چند نمونه رایج استفاده می‌کند. bridge و Calico routed دو مدل آموزشی مفیدند، نه فهرست کامل dataplaneهای موجود. در کلاسترهای eBPF، cloud-native routing، service mesh یا تنظیمات سفارشی NAT ممکن است مسیر واقعی با این مثال‌ها فرق داشته باشد. معیار troubleshooting همیشه باید همان CNI، همان mode و همان نسخه‌ای باشد که روی cluster واقعی اجرا می‌شود.

هیچ‌وقت در محیط‌های عملیاتی این موارد را کورکورانه بررسی/استفاده نکنید.

منابع و مطالعهٔ بیشتر

  1. Kubernetes Docskubernetes.ioبازبینی: ۲۱ مرداد ۱۴۰۵

    مرجع رسمی مدل شبکه کوبرنتیز؛ شامل ارتباط مستقیم Pod-to-Pod بدون proxy و بدون NAT و نقش pod network در پیاده‌سازی این مدل.

  2. Network Policiesمستندات رسمی

    Kubernetes Docskubernetes.ioبازبینی: ۲۱ مرداد ۱۴۰۵

    مرجع رسمی NetworkPolicy؛ شامل مجاز بودن ضمنی reply traffic و وابسته بودن جزئیات enforcement و رفتار connectionهای موجود به پیاده‌سازی network plugin.

  3. Virtual IPs and Service Proxiesمستندات رسمی

    Kubernetes Docskubernetes.ioبازبینی: ۲۱ مرداد ۱۴۰۵

    مرجع رسمی مسیر Service، نقش kube-proxy یا جایگزین آن، sync شدن ruleها و DNAT ترافیک ClusterIP به endpoint واقعی.

  4. IP Masquerade Agent User Guideمستندات رسمی

    Kubernetes Docskubernetes.ioبازبینی: ۲۱ مرداد ۱۴۰۵

    مرجع رسمی ip-masq-agent و nonMasqueradeCIDRs؛ این agent فقط یکی از پیاده‌سازی‌های ممکن برای egress masquerading است.

  5. Frequently asked questionsمستندات رسمی

    Calico Docsdocs.tigera.ioبازبینی: ۲۱ مرداد ۱۴۰۵

    مرجع رسمی مدل routed کلاسیک Calico؛ شامل gateway آدرس 169.254.1.1، proxy ARP و MAC رایج cali interfaceها.

  6. About Calico eBPFمستندات رسمی

    Calico Docsdocs.tigera.ioبازبینی: ۲۱ مرداد ۱۴۰۵

    مقایسه dataplane استاندارد Calico با eBPF؛ از جمله Linux conntrack در dataplane استاندارد و BPF conntrack map در dataplane eBPF.

  7. IP poolمستندات رسمی

    Calico Docsdocs.tigera.ioبازبینی: ۲۱ مرداد ۱۴۰۵

    مرجع رسمی natOutgoing و رفتار masquerade برای ترافیک خارج از Calico IP pools.

  8. Tuning Guideمستندات رسمی

    Cilium Docsdocs.cilium.ioبازبینی: ۲۱ مرداد ۱۴۰۵

    مرجع رسمی eBPF host-routing، bypass شدن host netfilter در بعضی modeها، netkit و امکان bypass کردن iptables connection tracking برای Pod traffic.

  9. Masqueradingمستندات رسمی

    Cilium Docsdocs.cilium.ioبازبینی: ۲۱ مرداد ۱۴۰۵

    مرجع رسمی masquerading در Cilium و native-routing CIDR؛ نشان می‌دهد egress traffic در شبکه‌های routable الزاماً SNAT نمی‌شود.

  10. Flannel Troubleshootingمستندات رسمی

    Flannelgithub.comبازبینی: ۲۱ مرداد ۱۴۰۵

    مرجع رسمی troubleshooting فلنل؛ شامل VXLAN روی UDP/8472 و اثر MTU و firewall بر مسیر cross-node.