فرقی نمی‌کنه که با شنیدن واژه کانتینر به Docker ،Kubernetes ،Silverblue ،CoreOS یا Flatpak فکر کنیم، واضحه که این روزها اپلیکیشن‌های تازه برای راحتی، امنیت و مقیاس پذیری از کانتینرها استفاده می‌کنن.

کانتینرها شاید مفهوم پیچیده و گیج کننده‌ای باشن و هرچقدر مطالعه بیشتری در این زمینه انجام می‌دیم، بدون شک سوالات بیشتری برای ما به وجود میاد. مثلاً اینکه یک اپلیکیشن توی کانتینر اجرا می‌شه، دقیقاً به چه معناست؟ یا اینکه چطور پراسس‌های یک کانتینر با بخش‌های دیگه‌ی کامپیوتر تعامل دارند؟ از اونجایی که من از پیدا کردن جواب این سوال‌ها لذت می‌برم، بنابراین در ادامه این پست به طور خلاصه پشت پرده‌ی تکنولوژی کانتینرها را توضیح می‌دم.

Cgroup و Namespace واقعاً چه هستند؟

Cgroups یا Control Groups، مکانیزم کرنل لینوکس برای محدود کردن و اندازه‌گیری کل منابع در حال استفاده، توسط گروهی از پراسس‌های اجرایی روی سیستم هست. برای مثال با استفاده از cgroup می‌تونید منابع لینوکس خودتون مثل RAM ،CPU یا IO رو کنترل کنید. Cgroups در ابتدا توسط Paul Menage و Rohit Seth توی گوگل ساخته شد و اولین قابلیت‌های اون در کرنل لینوکس نسخه‌ی ۲.۶.۲۴ ادغام شد.

از طرف دیگه Namespaces مکانیزم دیگه‌ای توی کرنل برای محدود کردن دیدِ گروهی از پراسس‌ها، نسبت به بقیه سیستم است. برای مثال می‌شه یک یا چند پراسس رو محدود کرد تا امکان دیدن و تعامل با بقیه پراسس‌های در حال اجرا روی سیستم یا مثلاً امکان دسترسی به فایل سیستم‌های مانت شده را نداشته باشن.

Namespaceها در ابتدا توسط Eric Biederman توسعه پیدا کردن و توی کرنل لینوکس ۳.۸ ادغام شدند.

کانتینرها چطور از cgroup و Namespace استفاده می‌کنن؟

همونطوری که گفتم، با استفاده از Cgroup و Namespace می‌شه روی هر پراسس اجرایی در سیستم عامل لینوکس محدودیت‌های زیادی اعمال کرد و این محدودیت‌ها می‌تونه با جزئیات زیادی اعمال بشه. Cgroup به شما قابلیت‌های خیلی بیشتری از دستور nice برای تعیین محدودیت استفاده از CPU روی یک پراسس می‌ده.

زمانی که از Cgroupها و Namespaceها در کنار همدیگه استفاده کنیم، در نهایت گروهی از پراسس‌های لینوکس را در یک محیط کاملاً ایزوله شده خواهیم داشت. این دقیقاً همون چیزیه که بهش یک کانتینر لینوکسی می‌گیم. کانتینرها در لینوکس با مجموعه کاملی از Namespaceها محدود شدن به طوری که فقط می‌تونن دایرکتوری که از اون بوت شدن، پراسس‌های مربوط به خودشون، User IDهای خودشون و هرگونه رابط شبکه‌ای که اجازه دسترسی به اون‌ها دارن، مشاهده کنن. به همین ترتیب، کانتینرها برای کنترل استفاده از RAM ،CPU پهنای باند و IO با مجموعه کاملی از Cgroupها محدود هستن. بنابراین، با اعمال تمام این محدودیت‌ها پراسس‌های در حال اجرا در یک کانتینر لینوکسی نمی‌توانند هیچ کدوم از بخش‌های دیگر سیستم رو ببینن و بنابراین طوری رفتار می‌کنن که انگار توی یک کامپیوتر یا سرور جداگانه در حال اجرا هستن.

چطور می‌تونیم از Cgroup و Namespace استفاده کنیم؟

در اکثر اوقات منطقی نیست که یک مدیر سیستم مستقیم از Cgroup و Namespace استفاده کنه، چرا که ابزارهای ایجاد و مدیریت کانتینرها مثل Kubernetes ،Docker یا LXC خودشون این کار را برای شما انجام می‌دن. با این حال، می‌تونید برای درک بهتر چیزی که پشت پرده اتفاق می‌افته، این کار رو به صورت دستی انجام بدید.

کنترل Cgroupها در فایل سیستم /sys/fs/cgroup/ انجام میشه.

توی مثال زیر tar توی یک Cgroup با محدودیت RAM اجرا شده است:

mkdir -p /sys/fs/cgroup/test/
cat /sys/fs/cgroup/cpuset.cpus > /sys/fs/cgroup/test/cpuset.cpus
cat /sys/fs/cgroup/cpuset.mems > /sys/fs/cgroup/test/cpuset.mems
echo $((1<<26)) >/sys/fs/cgroup/test/memory.kmem.limit_in_bytes
echo $ > /sys/fs/cgroup/test/tasks
tar xfz linux-3.14.1.tar.gz

در چهار خط اول یک Cgroup با نام test ایجاد شده که امکان دسترسی به تمام سخت افزارهای فیزیکی را داره اما استفاده از RAM توی اون محدود شده. توی خط پنجم، bash و هر پراسسی که بعداً توی اون اجرا می‌شه توی Cgroup که قبلاً ایجاد کردیم، قرار گرفته و توی خط ششم، tar در حالت عادی اجرا می‌شه اما چون در Cgroup قرار گرفته بنابراین محدودیت RAM روی آن اعمال خواهد میشه.

محدودیت‌های متعددی وجود داره که می‌تونید با Cgroup اعمال کنید. داکیومنت مربوط به اون‌ها رو می‌تونید توی لینک‌های زیر مشاهده کنید:

https://www.kernel.org/doc/Documentation/cgroup-v1

https://www.kernel.org/doc/Documentation/cgroup-v2.txt

از طرف دیگه، Namespaceها با دستور unshare کنترل می‌شن. به عنوان مثال اگر دستورهای زیر را اجرا کنید:

unshare --mount /bin/bash
mount /dev/sda2 /mnt

bash رو توی یک Mount Namespace ایزوله شده اجرا می‌کنه. این یعنی فایل سیستمی که در خط بعدی مانت شده تنها از طریق همون پراسس bash (و پراسس‌هایی که توی اون اجرا می‌شن) که ازش استفاده می‌کنید، قابل مشاهده هستن، و بقیه سیستم امکان دیدن این فایل سیستم رو در محلی که مانت شده، ندارن. پیشنهاد می‌شه برای مشاهده بقیه Namespaceهایی که می‌شه از اون‌ها استفاده کرد دستور man unshare رو وارد کنید.

حرف آخر

همونطوری که می‌تونید تصور کنید، در صورتی که از مجموعه کاملی از Cgroupها و Namespaceها با هم استفاده کنیم، نتیجه‌ی اون ایزوله شدن نرم‌افزار محدود شده، از بقیه‌ی سیستم خواهد بود که در‌ واقع به اون یک کانتینر لینوکسی می‌گیم. فهمیدن نحوه‌ی عملکرد Cgroup و Namespace می‌تونه توی درک اینکه برنامه‌های کانتینر شده چطور و چرا چنین رفتاری دارن، کمک کنه. کانتینرها یکی از ویژگی‌های قدرتمند سیستم عامل لینوکس هستن و هر روز محبوبیت بیشتری پیدا می کنن. حالا که نسبتاً با نحوه‌ی عملکرد اون‌ها آشنا شدید، پیشنهاد می‌شه به تکنولوژی‌های دیگه مثل Silverblue ،LXC ،Docker ،Kubernetes یا Flatpak هم سری بزنید تا متوجه بشید که با نرم‌افزارهای کانتینر شده می‌تونید چه کارهایی انجام بدید.