در بخش اول این مقاله ارتباط اجزای مختلف کوبرنتیز به صورت داخل کلاستر رو بررسی کردیم. در بخش دوم درباره نحوهی ارتباط پادها و سرویسها با دنیای خارج و اینترنت صحبت میکنیم.
تاحالا بررسی کردیم که ترافیک به چه شکل داخل کلاستر کوبرنتیز منتقل میشه. اما اگر قرار باشه سرویسمون رو برای جهان خارج هم دسترس پذیر کنیم چه اتفاقی میوفته؟
دو حالت ممکنه: Ingress و Egress. Egress یعنی چه جوری ترافیک رو برای اینترنت بفرستیم؛ و Ingress یعنی چه جوری ترافیک اینترنت رو به داخل کلاستر منتقل کنیم.
اینکه ترافیک به چه شکل به اینترنت منتقل میشه کاملا بستگی به شبکهای که ازش استفاده میکنیم داره. از اونجایی که کوبرنتیز بیشتر داخل محیطهای ابری استفاده میشه در اینجا برای مثال از AWS VPC استفاده میکنیم. VPC همون شبکهی خصوصی برای هر کاربر هست.
در AWS کوبرنتیز داخل یک VPC اجرا میشه و هر نود یک آدرس IP خصوصی داره که توسط کلاستر کوبرنتیز قابل دسترسیه. برای اینکه بتونیم ترافیک رو از خارج از کلاستر به داخل کلاستر هدایت کنیم نیاز به یک Internet Gateway داریم. Internet Gateway چه کاری انجام میده؟ ارتباط با جهان خارج رو با استفاده از مکانیزم NAT ممکن میکنه. بنابراین با استفاده از یک IG نودها میتونن با اینترنت ارتباط برقرار کنن. اما یک مشکل وجود داره: آدرس IP پادها با آدرس نودها فرق میکنه، و عمل ترجمهی آدرس که در IG اجرا میشه هیچ ایدهای در مورد اینکه کدوم پادها روی کدوم نودها دارن اجرا میشه نداره. کوبرنتیز به چه شکل این مشکل رو برطرف میکنه؟ دوباره با استفاده از iptables.
در شکل پایین، بسته در پاد ۱ ایجاد میشه و از طریق اینترفیسهای eth0 و veth1 به root namespace میرسد. بعد از رسیدن به root namespace از اونجایی که آدرس مقصد به هیچکدام از زیرشبکههای bridge تعلق نداره، بسته برای اینترفیس نود یا همون eth0 ارسال میشه. اما قبل از اینکه بسته به eth0 برسه iptables آدرس مبدا بسته رو عوض میکنه و آدرس نود رو به جای اون قرار میده. چرا؟ چون اگه این اتفاق نیوفته اگه بسته به IG برسه drop میشه. به خاطر اینکه IG فقط آدرس نودهایی که به اون متصل هستند رو NAT میکنه. بنابراین iptables کاری میکنه که انگار بسته از طرف خود نود (و نه از پاد ۱) داره ارسال میشه. به این ترتیب در نهایت بسته از طریق اینترفیس نود به IG میرسه. حالا IG هم یکبار دیگه عمل NAT رو انجام میده و آدرس مبدا بسته رو به جای آدرس نود آدرس IP خودش قرار میده، و برای اینترنت میفرسته.
انتقال ترافیک به داخل کلاستر کوبرنتیز عمل پیچیدهتریه. جزئیات این انتقال کاملا به بستگی به مدل شبکهی پیادهسازی شده داره. اما معمولا به دو روش قابل پیادهسازیه:
وقتی که یک سرویس داخل کوبرنتیز درست میکنیم برای expose کردن اون سرویس به خارج چند روش وجود داره. یکی از روشهایی که در محیطهای رایانش ابری استفاده میشه LoadBalancer هست. ارتباط بین کوبرنتیز و این LoadBalancer به وسیلهی cloud-controller انجام میشه. یعنی زمانی که سرویس ایجاد شد، آدرسش رو برای LoadBalancer میفرسته. LoadBalancer هم ترافیک رو بین همهی نودهای کلاستر پخش میکنه. وقتی که ترافیک به یک نود برسه، به وسیلهی iptables به پادهای مربوط به اون سرویس میرسه.
هنگامی که یک سرویس ایجاد کردیم، یک LoadBalancer هم به وسیلهی ابر (مثلا AWS) ایجاد میشه. LoadBalancer از پادها خبری نداره، یعنی نمیدونه کدوم پاد روی کدوم ماشین قرار داره؛ بنابراین ترافیک رو بین تمام نودهای کلاستر پخش میکنه. اما این وظیفهی iptables هست که ترافیک رو به سمت پاد مناسب هدایت کنه.
این فرآیند در شکل زیر نشون داده شده: ترافیک به LoadBalancer میرسه، و LB یک نود رو به صورت تصادفی انتخاب میکنه. فرض کنیم ترافیک برای VM2 ارسال بشه. اما پاد ۳ در این ماشین وجود نداره. پس ترافیک چگونه به نود ۳ و پاد ۳ منتقل میشه؟ iptables. در واقع ruleهای iptables که روی ماشین قرار داره بسته رو به سمت پاد درست هدایت میکنه. اما این قوانین iptables که میتونه ترافیک رو داخل کلاستر به درستی منتقل کنه از کجا ایجاد شده؟ همونطور که قبلا هم بررسی کردیم این وظیفه رو kube-proxy به عهده داره.
توزیع بار در لایهی کاربرد (لایه هفت) بر مبنای پروتکل HTTP/HTTPS کار میکنه؛ و در کوبرنتیز یک لایه بالاتر از سرویسها ایجاد شده. قدم اول برای ایجاد ingress استفاده از مدل NodePort در سرویسهای کوبرنتیزه. وقتی که type یک سرویس در کوبرنتیز NodePort قرار بگیره، نودهای مستر کوبرنتیز یک پورت رو روی همهی نودهای کلاستر باز میکنن؛ و هر ترافیکی که برای اون پورت ارسال بشه، با استفاده از قوانین iptables برای سرویس مورد نظر فرستاده میشه.
حالا اگه بخوایم این NodePort رو روی اینترنت expose کنیم، معمولا از Ingress استفاده میکنیم. Ingress دقیقا چیه؟ Ingress یک HTTP Load Balancer هست که درخواستهای HTTP رو به سمت سرویسهای کوبرنتیز میفرسته. ALB Ingress Controller توی محیط AWS نقش ingress رو برای کوبرنتیز بازی میکنه.
اما سناریوی واقعی که معمولا اتفاق میوفته اینه که ALB رو جوری کانفیگ میکنیم که تمام ترافیک رو برای یک Ingress دیگه که داخل خود کلاستر وجود داره میفرسته. این Ingress میتونه مثلا Nginx یا Ambassador یا هر ابزار دیگهای باشه. بعدا داخل این Ingress بر اساس Hostname تصمیم گرفته میشه که ترافیک برای چه سرویسی ارسال بشه.
برای اطلاعات بیشتر میتونید به مقالههای مختلفی که توی این زمنیه وجود داره، مثلا این مقاله مراجعه کنید.
این فرآیند خیلی شبیه به فرآیند قبلی هست. تفاوت اصلی در اینجاست که Ingress نسبت به URL Path آگاهی داره. یعنی میتونه ترافیک رو بر اساس مسیر برای سرویسهای مختلف route کنه.
هنگامی که شما یک سرویس جدید رو روی کلاستر دیپلوی میکنید، یک Ingress Load Balancer توسط ابر برای شما ایجاد میشه. در اینجا هم دوباره Load Balancer خبری از پادها نداره. بنابراین ترافیک رو برای یکی از ماشینهای کلاستر میفرسته. سپس ترافیک بر اساس قوانینی که در iptables تعریف شده، برای پاد درست فرستاده میشه. پاسخی که از طرف پاد برای کلاینت ارسال میشه با آدرس مبدا پاد برمیگرده. اما کلاینت با Load Balancer صحبت میکنه. پس از iptables و conntrack برای تغییر دادن آدرس بستهها استفاده میشه.
مقالهی جالبی در همین باره با جزئیات بیشتر در این لینک وجود داره که پیشنهاد میکنم بخونید. خوشحال میشم اگر نکتهای به ذهنتون میرسه رو کامنت کنید.