یکی از اصطلاحاتی که موقع سر و کله زدن با کانتینرها زیاد میشویم عبارت Container Runtime ها هستن که برای افراد مختلف، معنی های مختلفی دارن. میری در مورد یه کانتینر Runtime میخونی میبینی توش یه چیز دیگه وجود داره با نام کانتینر Runtime بهش اشاره میشه. اگه اون اولی کانتینر Runtime هست پس این دومی چیه و یا بالعکس. امروز میخوایم با هم یه مقدار این اصطلاح مبهم رو بررسی و شفاف کنیم.
به صورت پیشفرض برای یه برنامه نویس، Runtime میتونه به معنی فاز زمانی اجرای یک نرم افزار Program Runtime یا Implementation ی که امکان اجرای نرم افزار رو فراهم میکنه باشه مثل JRE یا Dot Net Runtime
اما وظیفه Container Runtime در واقع اجرای تمام مراحل مورد نیاز برای اجرای یک کانتینر هست و هیچ کاری با اجرای خود نرم افزار درون کانتینر نداره.
اما چی شد که Container Runtime معانی مختلفی پیدا کرد؟
داکر سال ۲۰۱۳ با معرفی نرم افزار و پلتفورم خودش خیلی از مشکلاتی رو که برنامه نویسی برای اجرای کانتینر ها و مدیریت چرخه عمر کانتینر ها داشتن رو حل کرد که شامل ویژگی های زیر بود:
- فرمت Image مناسب کارنتینر
- روش و ابزاری برای ساخت Image ها (Dockerfile, Docker Build)
- ابزار و روش مدیریت Image ها (Docker Images, Docker rm, ..)
- روش و ابزار مدیریت کانتینرها (Docker ps, Docker rm, …)
- روش و ابزار اشتراک گذاری کانتینرها (Docker push, Docker pull)
- روش و ابزار مناسب برای اجرای کانتینرها (Docker Run)
سال ۲۰۱۳ داکر یک نرم افزار مونولیث بود ولی در واقع هیچ بخشی وابسته به بخش دیگه ای نبود و محدودیت برای شکستن این نرم افزار مونولیث به تیکه های کوچیک تر وجود نداشت. به همین دلیل توی سال ۲۰۱۵ داکر با همراهی گوگل و Core OS سازمان OCI رو پایه گذاری کرد و یه تیکه از نرم افزارشو به نام runc به صورت یک لایبرری به عنوان مرجع پیاده سازی Container Runtime به OCI اهدا کرد.
اوایل چیزی که داکر به OCI اهدا کرد یه مقدار گیج کننده بود چرا که فقط و فقط یک لایبرری و مرجعی برای اجرای یک کانتینر بود نه چیز دیگه ای در صورتی که برای اجرای کانتینر، شما به یک فرمت استاندارد و ابزاری برای دریافت Image هم نیاز دارین و در واقع زمانی که شما با داکر یه کانتینر رو اجرا میکنید قدم هایی که برداشته میشه شامل دانلود Image، باز کردن یا همون Unpacking Image و تبدیل اون به یک باندل و اجرای کانتینر از اون باندل رو شامل میشه.
چیزی که داکر استاندارد سازی کرده بود فقط مرحله سوم یعنی اجرای کانتینر با استفاده از باندل Unpack شده بود.
تا زمانی که داکر اقدام به شفاف سازی نکرد (هر چند هنوزم خیلی شفاف نیست و این ابهام هنوز برای خیلیا وجود داره) که چیزی که داکر منظورش بوده فقط اجرای کانتینر بوده این ابهام خیلی گسترده ادامه داشت.
این دلیلی بود که بحث Container Runtime هم هنوز مبهم هست و میخوایم امروز بررسیش کنیم.
کانتینر runtime های سطح بالا و سطح پایین
وقتی افراد مشغول توی صنعت توسعه نرم افزار و عملیات اقدام به جستجوی Container runtime میکنند اغلب با مواردی مثل LXC, runc, imctfy, docker (Containerd), rkt, cri-o , … برخورد میکنن. هر کدوم از این container runtime ها برای موقعیت های متفاوت توسعه داده شدن و فیچر های متفاوتی دارن.بعضی از این کانتینر Runtime ها مثل Containerd & CRI-O در واقع از runc برای اجرای کانتینر ها استفاده میکنن اما فیچر هایی مثل مدیریت Image ها و API های اشتراک گذاری رو روی اون Implement کردن.
شما میتونید این ویژگی ها یعنی انتقال Image و unpacking و مدیریت اون و همچنین API هارو در مقایسه با ویژگی های runc، ویژگی های سطح بالا قلمداد کنید.
با توجه به این مثال میبینید که فضای کانتینر Runtime ها تقریبا پیچیده هست و هر کدوم طیفی از ویژگی های سطح پایین تا سطح بالا رو پشتیبانی میکنند که میتونید توی تصویر زیر ببینید:
بنابراین برای توصیف بهتر؛ به Runtime هایی که تخصصی فقط اجرای کانتینر ها را به عهده دارند و در واقع کارهای سطح پایین مانند ساختن namespace و cgroups و اجرای کامند های مورد نیاز داخل اون namespace و بهره گیری از این فیچر های کرنل سیستم عامل رو به عهده دارن رو Low Level Container Runtime مثل runc و crun و به runtime هایی که فیچر های سطح بالاتری مثل ابزار های مدیریت image و همچنین gRPC و web API دارند رو high level container runtime مثل Containerd و CRI-O میگیم.
نکته: توجه به این نکته مهمه که در واقع runtime های سطح پایین و سطح بالا ابزار های متفاوتی هستند که مشکلات متفاوتی رو حل میکنن و مقایسه اونا خیلی کار درستی نیست و بهتره بیشتر تلاش کنیم بشناسیمشون و تفاوت هاشونو درک کنیم.
معمولا برنامه نویسا برای اجرای کانتینر برنامه هایی که مینویسن به چیزی بیشتر از یه runtime سطح پایین نیاز دارن و معمولا به جز مرحله اجرای کانتینر به مدیریت Image ها و دریافت اونها و unpack کردنشونم نیاز دارن که این ویژگی ها توسط runtime های سطح بالا در اختیار ما قرا میگیره و معمولا runtime های سطح پایین خیلی به درد استفاده روز مره نمیخورن.
به همین دلیل معمولا کسایی از runtime های سطح پایین استفاده میکنند که بخوان یه runtime سطح بالا بنویسن.
مهندسایی که runtime های سطح پایین توسعه میدن معمولا این دیدگاه رو دارند که runtime هایی مثل Containerd و CRI-O در واقع runtime نیستند و بخش اجرای کانتینر رو به runc محول میکنن اما از دید کاربران عام و البته اکثریت کاربران این runtime ها در واقع ابزارها یکپارچه هستن که به اونها این امکان رو میدن که کانتیرها رو اجرا کنن و تا زمانی که مطابق استاندارد های OCI توسعه داده شده باشند میشه یه runtime رو با یکی دیگه عوض کرد و هیچ مشکلی پیش نیاد.
اشاره به این نکته هم کم اهمیت نیست اگر عنوان کنیم که شاید Containerd و CRI-O هر دو در سطح پایین دارند از runc بهره میبرند ولی فقط runc تنها نقطه مشترکشون هست و در واقع هر کدوم کاربرد ها و ویژگی های خاص خودشون رو دارند اما مطابق استاندارد OCI پیاده سازی شدند.
امیدوارم این مطلب براتون مفید واقع شده باشه.
با تشکر از Ian Matthew Lewis
دیدگاه خود را بنویسید