خطمشیهای شبکه انتزاع درستی نیستند (برای توسعهدهندگان)

شما یک مهندس پلتفرم هستید که روی ساخت یک پلتفرم مبتنی بر Kubernetes کار میکنید که اعتماد صفر را بین پادها به دست میآورد. توسعه دهندگان باید بتوانند کار را به سرعت انجام دهند، به این معنی که در کنار اعتماد صفر، اولویت بالایی برای تجربه توسعه دهندگان قائل هستید.
آیا سیاست های شبکه Kubernetes به اندازه کافی خوب هستند؟ من فکر می کنم چندین نقص وجود دارد که از سیاست های شبکه جلوگیری می کند، به تنهایی، از یک راه حل موثر برای یک مورد استفاده در دنیای واقعی است.
قبل از اشاره به مشکلات، میخواهم منظورم را وقتی میگویم اعتماد صفر، و همچنین چند جزئیات در مورد نحوه عملکرد خطمشیهای شبکه را توضیح دهم.
صفر اعتماد به معنای جلوگیری از دسترسی از منابع ناشناس یا غیرمجاز است
خط مشی های شبکه می توانند از ترافیک ورودی به یک مقصد (سرور) جلوگیری کنند یا از ترافیک خروجی از یک منبع (یک کلاینت) جلوگیری کنند.
اعتماد صفر ذاتاً به این معنی است که شما به هیچ یک از منابع اعتماد ندارید فقط به این دلیل که آنها در محیط شبکه شما هستند، بنابراین تنها مسدود کردن مربوط به دستیابی به اعتماد صفر، مسدود کردن ترافیک ورودی (“ورود”) از منابع غیرمجاز است.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: my-policy
spec:
ingress:
- {} # ingress rules
policyTypes:
- Ingress # policy refers to ingress, but it could also have egress
بیایید در مورد سیاست های شبکه صحبت کنیم
آنها منابع فضای نامی هستند و بر اساس برچسب به غلاف ها اشاره می کنند
خطمشیهای شبکه منابعی با فضای نام هستند و بر اساس برچسب به پادها اشاره میکنند. منطقاً، آنها باید در کنار پادهایی که روی آنها اعمال میشوند زندگی کنند – در مورد ما، از آنجایی که ما از سیاستهای ورودی استفاده میکنیم، به این معنی است که در کنار سرورهایی که محافظت میکنند.
آنها به طور مستقیم به غلاف های خاصی اشاره نمی کنند، البته، زیرا غلاف ها زودگذر هستند، اما به طور منطقی به غلاف با برچسب اشاره می کنند. این در Kubernetes رایج است، اما مشکلاتی را برای سیاست های شبکه ایجاد می کند. این جزئیات را در نظر داشته باشید زیرا بعداً به آن خواهیم پرداخت.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: protect-backend
spec:
podSelector:
matchLabels:
app: my-backend # policy will apply to pods labeled app=my-backend, in the same namespace as the policy
ingress:
- from:
- podSelector:
matchLabels:
app: my-client # and allow ingress access from pods labeled app=my-client
policyTypes:
- Ingress
آنها اطلاعاتی در مورد چندین مجموعه غلاف دارند
محتویات خط مشی های شبکه در واقع یک لیست مجاز است که مشخص می کند کدام پادهای دیگر می توانند به پادهایی که خط مشی محافظت می کند دسترسی داشته باشند. اما یک مشکل بزرگ وجود دارد: در حالی که خط مشی شبکه باید با پادهای محافظت شده زندگی کند، و به عنوان بخشی از چرخه حیات پادهای محافظت شده به روز می شود، به طور طبیعی به عنوان بخشی از چرخه عمر غلاف های مشتری که به پادهای محافظت شده دسترسی دارند، به روز نمی شود. .
فعال کردن دسترسی بین دو پاد
هر زمان که یک توسعهدهنده برای پاد مشتری نیاز به دسترسی به سرور داشته باشد، باید پاد کلاینت خود را وارد خطمشی شبکه سرور کند تا اجازه تماس با سرور را داشته باشد. توسعهدهنده اغلب نمیتواند خودش آن خطمشی شبکه را مدیریت کند، زیرا معمولاً در فضای نامی وجود دارد که مسئولیت آن را ندارند و با سرویسی که مالک آن نیست مستقر میشود.
نتیجه این است که توسعهدهنده کلاینت برای دسترسیهایی که باید سلفسرویس میشد، به تیم سرور وابسته است، و تیم سرور اکنون حواسش پرت میشود و توسعهدهنده کلاینت را قادر میسازد، حتی اگر واقعاً هیچ چیز از دیدگاه تیم سرور تغییر نکرده باشد. یک کلاینت جدید در حال اتصال به سرور خود است، همین! برای فعال کردن یک کلاینت دیگر نباید تغییرات سمت سرور مورد نیاز باشد.
اگر بخواهید سرور را به عقب برگردانید چه؟
همچنین تعداد بیشماری از مشکلات درجه دوم وجود دارد که تیم مونزو از طریق حل این مشکل در مورد آنها یاد گرفته بود. (این یک پست وبلاگ فوق العاده خوب نوشته شده است؛ توصیه می کنم مطالعه کنید)، مانند این که بازگرداندن سرور بر روی اتصال کلاینت ها تأثیر می گذارد، زیرا خط مشی شبکه خود را عقب انداخته است.
هنگامی که یک سرور به دلیل یک مشکل نامرتبط به عقب بازگردانده می شود، سیاست شبکه آن نیز ممکن است در صورتی که بخشی از همان استقرار باشد (مثلاً بخشی از همان نمودار Helm) بازگردانده شود و کلاینت هایی را که به آن نسخه از شبکه متکی هستند شکسته شود. خط مشی! این بازتابی از وابستگی ناسالم بین تیم مشتری و سرور است: در حالی که منطقی است که یک تغییر سمت سرور که عملکرد را به هم میزند، روی کلاینت تأثیر بگذارد، معقول نیست که بازگشت نامرتبط و غیرقابل شکست سرور روی کلاینت تاثیر می گذارد.
چگونه می دانید سیاست درست است؟
از آنجایی که خطمشیهای شبکه به برچسبهای غلاف اشاره میکنند، اعتبارسنجی استاتیکی آنها دشوار است. پادها معمولاً مستقیماً ایجاد نمیشوند، بلکه توسط منابع دیگری مانند Deployments ایجاد میشوند.
آیا می توانید بگویید که آیا یک خط مشی شبکه اجازه دسترسی به سرویس شما را بدون استقرار و آزمایش آن می دهد؟ در واقع، فقط با پرسیدن این سوال که “کدام خدمات به سرویس A دسترسی موثر دارند؟” فوق العاده سخت می شود
توسعهدهندگان خدمات را بهعنوان برچسبهای غلاف در نظر نمیگیرند، اما معمولاً نامی مناسب برای توسعهدهندگان دارند. به عنوان مثال، checkoutservice یک نام دوستانه است، در حالی که checkoutservice-dj3847-e120 نامی است. این ممکن است در واقع ارزش برخی از برچسب ها باشد، اما هیچ راه استانداردی برای کشف این نام وجود ندارد.
بنابراین، چگونه میتوان مفهوم یک سرویس را با نام مناسب توسعهدهندهاش در نظر گرفت و آن را به برچسبهایی که توسط خطمشیهای شبکه و مثلاً استقرار آن به آن اشاره میشود، نگاشت تا بتوانید بررسی کنید که آیا آن را دارد یا خیر. پس از استقرار برچسبهای جدید آن دسترسی داشته باشید؟ شما می توانید به صورت دستی این کار را انجام دهید، به عنوان یک توسعه دهنده در یک تیم واحد که همه قسمت های متحرک را درک می کند. با این حال، این بسیار مستعد خطا است، و البته، برای راه حلی که مهندس پلتفرم میتواند به کار گیرد، صدق نمیکند: بهعنوان یک مهندس پلتفرم، به چیزی خودکار نیاز دارید که بتوانید آن را در اختیار همه توسعهدهندگان سازمان خود قرار دهید.
این مشکلی است که تیم مونزو سخت روی آن کار کرد. توصیه می کنم آن وبلاگ را مطالعه کنید زیرا بسیار خوب نوشته شده است و همچنین سایر عوامل مشکل را پوشش می دهد.
چگونه به پادها در خط مشی های شبکه اشاره می کنید؟
قبلاً اشاره کردم که خطمشیهای شبکه مستقیماً به پادها اشاره نمیکنند، زیرا زودگذر هستند، بلکه با برچسب به آنها اشاره میکنند. این عمل در Kubernetes رایج است. با این حال، خطمشیهای شبکه از این جهت منحصربهفرد هستند که از برچسبها برای اشاره به دو (یا چند) مجموعه از pods استفاده میکنند که اغلب متعلق به تیمهای مختلف در سازمان هستند.
این چالشهای منحصربهفردی را ایجاد میکند، زیرا برای عملکرد خطمشی شبکه، برچسبهای ارجاعشده توسط خطمشی و برچسبهای متصل به پادها باید با هم هماهنگ باشند و در صورت عدم انجام این کار، پیامدهای مخربی به همراه خواهد داشت – ارتباطات مسدود خواهد شد! برچسبهای پاد برای پادهای سرویس گیرنده توسط تیم مشتری مدیریت میشوند، در حالی که خطمشی شبکه که به آنها اشاره میکند توسط تیم سرور مدیریت میشود، بنابراین میتوانید ببینید کجا همه چیز میتواند از همگامسازی خارج شود.
خط مشی های شبکه به طور موثر متعلق به چندین تیم است
این به این معنی است که شما نیاز به هماهنگی بین تیمها دارید، نه تنها زمانی که خطمشی شبکه برای اولین بار اجرا میشود، بلکه در طول زمان با تکامل کلاینتها و سرورها نیز نیاز دارید.
اگر خط مشی شبکه ای داشته باشید که به چندین مشتری اجازه می دهد به یک سرور متصل شوند چه؟ اکنون شما تیم سرور را دارید که با 2 تیم هماهنگ می کند.
برای هر تغییری که یک تیم کلاینت پیشنهاد می کند، تیم سرور نه تنها باید قوانین خط مشی شبکه مربوط به آن کلاینت را تغییر دهد، بلکه باید مطمئن شود که آنها به طور ناخواسته روی مشتریان دیگر تأثیر نمی گذارند. این میتواند از نظر شناختی یک کار دشوار باشد، زیرا اعضای تیم سرور معمولاً به برچسبهای pod متعلق به تیمهای دیگر اشاره نمیکنند، بنابراین ممکن است بلافاصله مشخص نباشد که کدام برچسبها متعلق به کدام تیم هستند.
این امر توانایی تیم ها برای تعیین استانداردهای داخلی و کار مستقل را کاهش می دهد و سرعت توسعه را کاهش می دهد. اگر این را به درستی دریافت نکنید، ممکن است نقاط دردناکی در چرخه توسعه وجود داشته باشد که در آن تغییرات شکننده هستند و سرعت آنها تا حد خزیدن کند می شود. این درد ممکن است منجر به پخش دوچرخه و سیاست های بین تیمی شود، زیرا تیم ها در مورد نحوه انجام کارها بحث می کنند و ناامیدی فزاینده به دلیل تاخیر در استقرار مشتری در نتیجه عدم به روز رسانی خط مشی های شبکه سرور.
آیا همه افراد سازمان شما به نحوه عملکرد سیاست های شبکه مسلط هستند؟
در بسیاری از سازمان ها اینطور نیست. خطمشیهای شبکه در حال حاضر مستعد خطا هستند و حتی برای اشتباهات کوچک نیز پیامدهای مخربی دارند. درخواست از هر توسعهدهندهای که سرویسش با سرویس دیگری تماس میگیرد برای آشنایی با خطمشیهای شبکه ممکن است کار دشواری باشد، با پتانسیل برای استقرار ناموفق یا تماسهای ناموفق که اشکالزدایی آنها سخت است.
یک راه حل خوب برای اعتماد صفر باید برای آن نتیجه خاص بهینه شود، در حالی که خط مشی های شبکه کمی یک چاقوی ارتش سوئیس هستند: آنها فقط برای ترافیک پاد به پاد نیستند، بنابراین برای این مورد استفاده بهینه نیستند.
3 ویژگی زیر کلیدی برای یک انتزاع با اعتماد صفر خوب است که در واقع پذیرفته می شود:
- مالکیت تک تیمی: هر منبع فقط باید توسط یک تیم مدیریت شود تا تیم های مشتری بتوانند به طور مستقل به آن دسترسی داشته باشند، و اگر نیازی به تغییر در پایان آنها نباشد، نیازی به دخالت تیم های سرور نیست.
- تجزیه و تحلیل استاتیک باید امکان پذیر باشد: باید بتوان به صورت ایستا بررسی کرد که آیا سرویسی بدون استفاده از آن دسترسی دارد یا خیر.
- هویت خدمات جهانی: سرویسها باید به جای برچسبهای غلاف، به استفاده از نام استانداردی نزدیک یا یکسان با نامهای مناسب توسعهدهندهشان ارجاع داده شوند.
اهداف مشتری را وارد کنید
در Otterize، ما معتقدیم که اهداف مشتری این الزامات را برآورده می کند. اجازه دهید به طور خلاصه توضیح دهم که آنها چیستند و سپس بررسی کنیم که آیا آنها ویژگی های فوق را برآورده می کنند یا خیر.
یک فایل intents کلاینت به سادگی فهرستی از تماسها با سرورهایی است که یک کلاینت داده شده است قصد دارد ساختن. همراه با مکانیزمی برای حل نام سرویسها، فهرست مقاصد مشتری میتواند به مکانیسمهای مختلف مجوز، مانند سیاستهای شبکه ترجمه شود.
به عبارت دیگر، توسعه دهندگان خدمات خود را اعلام می کنند قصد دارد برای دسترسی، و سپس می توان آن را به یک خط مشی شبکه و مجموعه ای از برچسب های غلاف مرتبط تبدیل کرد.
در اینجا نمونه ای از فایل intents مشتری (به عنوان یک منبع سفارشی Kubernetes YAML) برای سرویسی به نام آمده است. مشتری تماس با سرویس دیگری به نام سرور:
apiVersion: k8s.otterize.com/v1alpha2
kind: ClientIntents
metadata:
name: client-intents
spec:
service:
name: client
calls:
- name: server
بیایید ببینیم آیا این یک انتزاع خوب است یا خیر
حالا بیایید به عقب برگردیم و معیارهای خود را برای یک انتزاع با اعتماد صفر خوب مرور کنیم:
آیا یک تیم مالک تمام و تنها منابعی است که باید مدیریت کند؟
فایلهای هدف مشتری همراه با مشتری مستقر و مدیریت میشوند، بنابراین فقط تیم مشتری مالک آنها است. شما را مستقر خواهید کرد ClientIntents برای این مشتری همراه با مشتری، به عنوان مثال در کنار آن گسترش منبع
آیا دسترسی به صورت ایستا قابل بررسی است؟
از آنجایی که سرویس ها هویت های درجه یک در مقاصد مشتری هستند (به جای اینکه به طور غیرمستقیم توسط برچسب های pod نشان داده شوند)، به طور پیش پا افتاده ای امکان پرس و جو وجود دارد که کدام کلاینت ها به یک سرور دسترسی دارند و آیا یک کلاینت خاص به سرور دسترسی دارد یا خیر. به عنوان یک امتیاز اضافی، تمام اطلاعات برای یک کلاینت در یک منبع واحد در یک فضای نام جمعآوری میشود، بهجای اینکه در فضای نامهای متعددی که سرورها مستقر هستند، تقسیم شوند.
آیا هویت خدمات جهانی و طبیعی است؟
نامهای سرویس در کل سازمان به یک شکل حل میشوند و به راحتی میتوان در مورد اینکه آیا یک سرویس خاص دارای نام خاصی است، استدلال کرد.
اپراتور Kubernetes که این اهداف را مدیریت می کند چگونه کار می کند؟
هنگامی که Intent برای یک کلاینت ایجاد میشود، اپراتور intent باید به طور خودکار خطمشیهای شبکه را ایجاد، بهروزرسانی و حذف کند، و بهطور خودکار پادهای کلاینت و سرور را برچسبگذاری کند تا دقیقاً تماسهای کلاینت به سرور اعلام شده در فایلهای هدف مشتری را منعکس کند. یک خط مشی شبکه واحد برای هر سرور ایجاد میشود و برچسبهای پاد به صورت پویا برای مشتریان بهروزرسانی میشوند.
نام سرویسها با بهدستآوردن بازگشتی مالک یک pod تا زمانی که مالک اصلی پیدا شود، معمولاً یک Deployment، StatefulSet یا منابع دیگری از این قبیل حل میشود. از نام آن منبع استفاده میشود، مگر اینکه پاد دارای یک حاشیهنویسی نام سرویس باشد که نام را لغو کند، در این صورت به جای آن از مقدار آن حاشیهنویسی استفاده میشود.
عملگر intent را امتحان کنید!
شما را شگفت زده نمی کند که ما در واقع چنین پیاده سازی منبع باز ایجاد کرده ایم، و به آن عملگر Otterize intents می گویند. به آن ضربه بزنید و ببینید که آیا مدیریت خط مشی های شبکه را برای شما آسان تر می کند یا خیر 🙂