تفاوت Deployment و StatefulSet در کوبرنتیس

برای پیاده سازی اپلیکیشن در محیط کوبرنتیس گزینه های مختلفی وجود دارد اما استفاده از Deployment و StatefulSet بسیار پرکاربرد تر از سایر گزینه ها است. گاهی اوقات تصمیم گیری در رابطه با اینکه چه زمانی باید از Deployment یا StatefulSet استفاده کرد، دشوار است. در این مقاله سعی داریم تا با بررسی ویژگی های این دو آبجکت تفاوت آن ها را استخراج کنیم تا برای پیاده سازی اپلیکیشن از بهترین گزینه استفاده کنیم.

یک آبجکت سطح بالا برای پیاده سازی و به روز رسانی اپلیکیشن Deployment است. زمانی که Deploymentساخته می شود یک آبجکت دیگر با نام ReplicaSet در پشت صحنه ساخته می شود. این آبجکت مسئول کنترل پادهای تحت مدیریت یک Deployment است. پس توجه به این نکته ضروری است که پادهای یک Deployment مستقیم توسط آن مدیریت و کنترل نمی شوند بلکه از طریق ReplicaSet این کار انجام می شود. در شکل 1 ارتباط بین Deployment و پاد های آن نشان داده شده است که توسط ReplicaSet کنترل می شوند.

شکل 1- ارتباط بین Deployment و پادها که توسط یک آبجکت میانی به نام ReplicaSet مدیریت می شوند
شکل 1- ارتباط بین Deployment و پادها که توسط یک آبجکت میانی به نام ReplicaSet مدیریت می شوند

بنابراین برای اینکه تفاوت Deployment با StatefulSet را متوجه شویم باید نحوه عملکرد ReplicaSet را با StatefulSet مقایسه کرد. ذکر این نکته ضروری است که ما هیچگاه اقدام به ساخت ReplicaSet به صورت مجزا نمی کنیم بلکه با ساخت Deployment یک ReplicaSet ساخته می شود.

در زمان تعریف Deployment بخشی با عنوان templateوجود دارد که با استفاده از آن ReplicaSetپادهای یکسان می سازد. به عبارت دیگر در زمان ساخت پاد از این تمپلیت استفاده می شود تا مشخصات آن تعیین شود بنابراین این پادها به جز در اسم و آدرس IP تفاوتی با یکدیگر ندارند. اگر در بخش template یک volume مشخص شده باشد که به یک PersistentVolumeClaim اشاره کند، تمامی پادهای ساخته شده از روی template به این فضای ذخیره سازی دسترسی خواهند داشت در واقع این فضای ذخیره سازی بین چندین پاد تحت مدیریت یک ReplicaSet به اشتراک گذاشته می شود. در شکل2 این موضوع نشان داده شده است.

شکل 2- تمام پادهای مرتبط با یک ReplicaSet از یک PersistentVolumeClaim استفاده می کنند
شکل 2- تمام پادهای مرتبط با یک ReplicaSet از یک PersistentVolumeClaim استفاده می کنند

در حالتی که از ReplicaSet استفاده شود و لازم باشد که هر پاد به یک فضای ذخیره سازی مجزا متصل باشد راهی جز ساختن ReplicaSet های مجزا با template های مختلف نیست، واضح است که این template ها فقط در بخش volumeمتفاوت هستند. در شکل3 نحوه اتصال هر پاد به فضاهای ذخیره سازی مجزا با استفاده از ReplicaSet نشان داده شده است.

شکل 3- نحوه اتصال هر پاد به فضاهای ذخیره سازی مجزا با استفاده از ReplicaSet
شکل 3- نحوه اتصال هر پاد به فضاهای ذخیره سازی مجزا با استفاده از ReplicaSet

همانطور که می دانید برای اتصال به پادهای یک Deployment یا ReplicaSet از مفهومی به نام سرویس استفاده می شود، زمانی که درخواست به یک سرویس وارد می شود، سرویس این درخواست را بین پادهایی توزیع می کند که به عنوان endpoint آن سرویس تعریف شده اند. حال سناریو شکل 3 را در نظر بگیرید که هر پاد فضای ذخیره سازی مجزایی داشته بنابراین پاسخ هایی که از جانب هر پاد داده می شوند، متفاوت خواهد بود. پس برای اینکه بتوان به طور مجزا به هر پاد متصل شد باید به ازای هر پاد یک سرویس مجزا تعریف کرد و تنها یک پاد را endpoint آن سرویس قرار داد. شکل 4 نحوه اتصال به هر پاد یک ReplicaSet که از فضای ذخیره سازی مجزا استفاده می کند را نشان می دهد. در این شکل سرویس A دارای سه endpoint هست اما سرویس های A1، A2 و A3 تنها دارای یک endpoint مجزا هستند.

شکل 4- نحوه اتصال به هر پاد یک ReplicaSet که از فضای ذخیره سازی مجزا استفاده می کند
شکل 4- نحوه اتصال به هر پاد یک ReplicaSet که از فضای ذخیره سازی مجزا استفاده می کند

واضح است که در شرایط ذکر شده استفاده از ReplicaSet یا همان Deployment کار راحتی نیست و دارای پیچیدگی های زیادی است که امکان بروز اشتباه از سمت کاربر را افزایش می دهد. اکنون که با نحوه عملکرد Deployment یا ReplicaSet آشنا شدیم به مقایسه آن با StatefulSet پرداخته می شود.

از تفاوت اصلی ReplicaSet و StatefulSet نام گذاری پادهای ساخته شده از template است. نام گذاری پادها در Replicasetدارای فرمتی به شکل ReplicaSetName-RandomID است در صورتی که در StatefulSet به صورت StatefulSetName-ordinaIndex است. شکل 5 تفاوت نام گذاری پادها را نمایش می دهد.

شکل 5- تفاوت نام گذاری پادها در ReplicaSet و StatefulSet
شکل 5- تفاوت نام گذاری پادها در ReplicaSet و StatefulSet

در صورتی که یک پاد از بین برود در هر دو حالت یک پاد جایگزین ساخته خواهد شد با این تفاوت که در ReplicaSet نام پاد جدید با پاد از دست رفته متفاوت خواهد بود اما در StatefulSet نام پاد جدید با پاد از دست رفته دقیقا یکسان است که در شکل 6 این مورد قابل مشاهده است.

شکل 6- تفاوت نام گذاری پادها در ReplicaSet و StatefulSet
شکل 6- تفاوت نام گذاری پادها در ReplicaSet و StatefulSet

همانطور که در شکل 7 آمده است StatefulSet در کنار مشخص کردن template برای پادها قابلیت تعریف templateبرای فضای ذخیره سازی هم فراهم می کند که با نام volumeClaimTemplates مشخص می شود. استفاده از volumeClaimTemplates این قابلیت را فراهم می کند تا هر کدام از پادهای مرتبط با یک StatefulSet به یک فضای ذخیره سازی مجزا متصل شود. از طرف دیگر از آنجایی که هر پاد نام مشخص خود را دارد با تعریف یک سرویس خاص با نوع headless می توان به طور مستقیم به هرکدام از پادها متصل شد. این کار از طریق آدرس دهی با فرمت PodName.HeadlessService انجام می شود.

شکل 7- نحوه اتصال فضای ذخیره سازی مجزا به هر پاد در StatefulSet
شکل 7- نحوه اتصال فضای ذخیره سازی مجزا به هر پاد در StatefulSet

در صورتی که بخواهیم تعداد پاد های یک StaefulSet را افزایش یا کاهش دهیم با سناریو شکل 8 مواجه می شویم. در این سناریو در صورتی که تعداد پاد کاهش پیدا کند، آن پاد از مدار خارج می شود ولی فضای ذخیره سازی حذف نمی شود (مگر اینکه کاربر به صورت دستی این کار را انجام بدهد) و در صورت افزایش تعداد پاد در صورتی که از قبل یک فضای ذخیره سازی برای این پاد وجود داشته باشد، آن را به پاد متصل می کند و در صورتی که وجود نداشته باشد یک فضای ذخیره سازی از روی volumeClaimTemplates مشخص شده می سازد و آن را به پاد متصل می کند.

شکل 8- نحوه اتصال فضای ذخیره سازی به هر پاد در زمان کاهش یا افزایش تعداد پادهای تحت کنترل StatefulSet
شکل 8- نحوه اتصال فضای ذخیره سازی به هر پاد در زمان کاهش یا افزایش تعداد پادهای تحت کنترل StatefulSet

به طور خلاصه تفاوت بین Deployment و StatefulSet را می توان به این صورت تشریح کرد، پاد تحت کنترل StatefulSet شناسه یکتا خواهد داشت که با استفاده از سرویس headless می توان مستقیما به هر پاد متصل شد، از طرف دیگر قابلیت اختصاص دیسک مجزا به هر پاد نیز در این حالت وجود دارد. پاد تحت کنترل Deployment شناسه تصادفی خواهد داشت و از طریق سرویس داخلی درخواست بین پاد های مختلف آن توزیع می شود، از طرف دیگر امکان اختصاص دیسک مجزا به هر پاد وجود ندارد و یک دیسک بین تمامی پاد ها به اشتراک گذاشته می شود.

برای پیاده سازی اپلیکیشن در صورتی که نمی دانید از Deployment یا StatefulSet استفاده کنید، پیشنهاد می شود کار خود را با Deployment شروع کنید و اگر با محدودیت های ذکر شده Deployment مواجه شدید، پیاده سازی اپلیکیشن خود را به StatefulSet تغییر دهید.

منبع

Marko Luksa - Kubernetes in Action-Manning Publications (2018)