برای تعریف سیستم کوبرنتیز در قالب یک جملهی کوتاه میتوان گفت کوبرنتیز در حال حاضر معروفترین و پرکاربردترین container orchestrator است.
از آن جایی که این سیستم کاربردهای زیادی دارد و افراد بسیار زیادی با آن آشنا هستند، در این مقاله از تعریف کوبرنتیز گذشته و به بررسی مزایا و برتریهای آن نسبت به سیستمهای مشابه خواهیم پرداخت.
کوبرنتیز طراحی بسیار گسترده و رویکردی متفاوت دارد. در ادامه برای توضیح بهتر طراحی این سیستم از یک مثال استفاده میکنیم.
طرح یک مسئلهی ساده:
یکی از چالشهایی که ممکن است اکثر افراد با آن روبهرو باشند، جواب دادن به پیامهای تلگرام است. البته نمیتوان این موضوع را یک چالش همیشگی دانست اما در برخی موارد ممکن است باعث ایجاد نارضایتی در مخاطب شود.
ممکن است برای این که بدانیم لازم است جوابی را برای یک یا چند پیام دریافتی ارسال کنیم رویکردهای مختلفی داشته باشیم:
رویکرد اول: اگر اعلانی (notification) دریافت شود پیام را پاسخ دهیم. مشکل این است که گاهی اوقات به دلایل مختلفی اعلان نمایش داده نمیشود (وجود مشکل در اتصال اینترنت، اشکال در vpn، حالت PowerSaving).
رویکرد دوم: پس از گذشت یک بازهی زمانی مشخص مثلا هر ۵ دقیقه یک بار پیامرسان تلگرام را باز کرده و به آن فرصت بهروزرسانی بدهیم. پس از بهروزرسانی پیامهای جدید را خواهیم دید. اما این راهحل هم مشکلاتی را به همراه دارد. ممکن است آخرین باری که در صفحهی پیام با یک مخاطب بودهایم، آخرین پیام را ندیده باشیم. حتی ممکن است پیام را دیده ولی فراموش کرده باشیم که پاسخ را ارسال کنیم یا اینکه پاسخ را در ذهن داشته ولی به صورت پیام آن را ارسال نکردهایم.
رویکرد سوم: شاید آخرین راهحلی که به ذهن میرسد این باشد که پس از گذشت یک بازهی زمانی مثلا هر ۲۰ دقیقه یک بار، همهی صفحههای پیام با مخاطبان مختلف را باز کرده و از پاسخ به همهی پیامها اطمینان حاصل کنیم. این کار بسیار زمانبر است و قطعا امکان انجام آن به صورت همیشگی وجود ندارد.
همانطور که میبینید هرچه رویکردهای بیشتری ارائه شد، هزینهی انجام کار هم بالاتر رفت. در عین حال میزان اطمینان از پاسخگویی درست و کامل به پیامهای دریافتی هم افزایش یافت. نکتهی مهم این است که هر رویکرد میتواند برای بهینه شدن (optimize)، رویکردهای قبلی را هم در خود داشته باشد. به عنوان مثال، اگر رویکرد سوم را برای پاسخ دادن به پیامها داریم، میتوانیم در صورت دریافت اعلان در بازهی زمانی ۲۰ دقیقه هم، پیام را پاسخ بدهیم. یا اینکه هر ۵ دقیقه یک بار فقط پیامرسان تلگرام را باز کرده و از پیامهای جدید مطلع شویم.
اگر از دید فنی به این مسئله و رویکردهای آن نگاه کنیم:
رویکرد اول Interrupt است. به این معنی که فرد در حال انجام کارهای دیگری است و کار جدیدی به او push میشود. در این صورت کارهای قبلی را رها کرده و به دنبال انجام کار push شده خواهد رفت.
رویکرد دوم polling است. به این معنی که فرد پس از یک مدت مشخص بررسی کند که اگر اتفاق جدیدی رخ داده بر اساس آن یک کار را انجام دهد.
این دو رویکرد event triggered هستند. یعنی فردی در یک شرایطی قرار دارد و به نحوی از یک رویداد (event) بیرونی آگاه میشود. ممکن است خود فرد دربارهی رویداد بپرسد یا اینکه دیگران رویداد را به او اطلاع دهند. این فرد پس از آگاهی از رویداد، عملیاتی را بر اساس همان رویداد انجام میدهد. نکتهی مهم این است که در این رویکرد در عین بهینه بودن، ممکن است رویدادی از دست داده شود. و گاهی اگر رویدادی از دست رود امکان مشاهدهی مجدد آن وجود ندارد.
رویکرد سوم level triggered است. در این رویکرد رویداد وجود ندارد و حالت (state) حائز اهمیت است. یعنی در مسئلهی مطرح شده، زمان دریافت پیام یا اعلان و یا هر رویداد دیگری اهمیتی ندارد. بلکه مستقل از هر رویدادی میدانیم که در این لحظه پیامهایی وجود دارند و باید به آنها پاسخ داده شود.
در این رویکرد، هدف این است که current state یا وضعیت فعلی را به desired state یا وضعیت دلخواه برسانیم.

دو عبارت edge و level در طراحی سیستمهای دیجیتال مطرح میشوند. کنترلرهای مدارها عملیات را هنگام عوض شدن سیگنال یا روی مقدار خاصی از سیگنال انجام میدهند. مثلا وقتی سیگنال x از ۰ به ۱ تغییر میکند حالت edge و وقتی سیگنال مقدار ۱ دارد حالت level است.

کوبرنتیز هم بر اساس رویکرد level trigerred طراحی شده و به این الگوی طراحی controller pattern میگویند. لازم به ذکر است که API کوبرنتیز از نوع declarative است. در چنین سیستمهایی تنها هدف مورد نظر را به سیستم اعلام کرده و نحوهی انجام آن تا رسیدن به نتیجهی مورد نظر بر عهدهی خود سیستم است.
در کوبرنتیز بخشی با عنوان kube-apiserver وجود دارد که desired stateها در آن ذخیره میشوند. مفهوم دیگری هم با عنوان manifest وجود دارد. Manifest یک فایل به همراه اطلاعاتی دربارهی محتویات آن است که desired stateها را در خود نگه میدارد. به عنوان مثال یک فایل manifest داریم که در آن نوشته شده که یک pod میخواهد یک nginx container روی آن باشد و ۲ هستهی cpu و حافظهی ۴GB داشته باشد. ایجاد این manifest تنها نشاندهندهی ثبت سفارش است و به این معنی نیست که هدف مورد نظر در حال حاضر محقق شده است. پس از هر رویداد یا تغییری status یا وضعیت در manifest ثبت میشود که نشان دهد pod در چه فازی قرار دارد.
به برنامههای کاربردی که بر اساس manifest (که desired state)و state فعلی عملیاتی را انجام میدهند تا به شرایط هدف برسند، «کنترلر» گفته میشود. یک فرایند کلی برای کنترلرها تعریف میشود که پس از دریافت manifest بتوانند شرایط فعلی را به شرایط هدف یا دلخواه برسانند. این فرایند همیشه و حتی در حالتی که رویدادی هم در سیستم پیش نیاید اجرا میشود. چرا که مطلع نشدن از یک رویداد، الزاما به معنی عدم وجود آن نیست.
کنترلرها همواره شرایط cluster را با manifestها همگام (sync) میکنند. به عملیات همگامسازی تکرار شونده reconcilation میگویند. کنترلرها علاوه بر reconcilation کل manifestها در فاصلههای زمانی (interval)، تغییرات manifestها را watch کرده و reconcile آنها را در همان لحظه اجرا میکنند. مثل اینکه در رویکرد سوم مسئلهی مثال برای بهینه شدن عملیات، علاوه بر چک کردن پیامها در هر ۲۰ دقیقه، در صورت دریافت اعلان در همان لحظه به پیام پاسخ دهیم.

رویکرد طراحی کوبرنتیز چه کمکی به کاربران میکند؟
از این رو به طراحی سیستم کوبرنتیز، self-healing میگویند. یعنی اگر مشکلی در سیستم ایجاد شود حتما آن را رفع خواهد کرد.
چالشهای طراحی
چالشی که این نوع از طراحی ایجاد میکند لزوم idempotent بودن عملیات reconcilation در کنترلر است. به این معنی که تعداد دفعات اجرای یک عملیات اهمیتی ندارد. برای مثال اگر دستور update یکی از attributeهای یک رکورد پایگاهداده را چندین بار اجرا کنیم، با یک بار اجرای این دستور تفاوتی نخواهد داشت. پس این عملیات idempotent است. اما اگر یک دستور عدد موجود در یک رکورد را به علاوهی ۱ کند idempotent نخواهد بود. چرا که در نهایت عدد به اندازهی تعداد دفعات اجرای دستور، افزایش یافته است.
اهمیت وجود این ویژگی در کنترلر این است که یک manifest باید در دفعات بسیار زیادی reconcile شود. بدیهی است که در صورت قرار داشتن در شرایط درست نیازی به ایجاد تغییر در شرایط نخواهد بود.
در واقع در منطق کنترلر فقط وجود یا عدم وجود یک پارامتر، همگامسازی شده و چیزی ایجاد یا حذف نمیشود. در واقع برای انجام یک عملیات ابتدا بررسی میکند که محتوا همان محتوای مورد نیاز هست یا نه. اگر با محتوای مورد نیاز متفاوت بود آن را بهروزرسانی میکند، در غیر این صورت تغییری ایجاد نخواهد کرد.

در نهایت میتوان گفت که این رویکرد ممکن است کمی با رویکردهای دیگر متفاوت باشد و سختیهایی را به طراح و توسعهدهنده تحمیل کند، اما در نهایت منجر به ایجاد سیستمی خواهد شد که توانسته برخی از چالشها را از بین ببرد و reliability بیشتری داشته باشد.
در صورت نیاز و علاقه به مطالعهی بیشتر دربارهی controller pattern به لینکهای زیر مراجعه کنید: