کانتینر (Container) در لینوکس به بیان ساده

کانتینر (Container) در لینوکس به بیان سادهفرض کنید می‌خواهیم پکیج و سرویس‌های مختلفی را روی یک سیستم‌عامل نصب کنیم که به آن‌ها اختصارا app می‌گوییم. طبیعی است که هر App کتابخانه‌ها و نیازمندی‌های متفاوتی دارد که به آن‌ها dependency گفته می‌شود. ممکن است app هایی داشته باشیم که به dependency با نام یکسان اما ورژن‌های متفاوت نیازمند باشند. همچنین این dependency ها ممکن است خودشان نیز dependency داشته باشند. این مورد در شکل زیر نشان داده شده است.وضعیت Dependency ها (البته شکل برای معماری میکروسرویس است)مدیریت پکیج‌ها در لینوکس نسبتا به خوبی صورت می‌گیرد اما dependency ها زمانی مشکل‌ساز می‌شوند که دو پکیج conflict (تداخل) بخورند یا اینکه یک کتابخانه برای اجرا نیاز به محیط یا سیستم‌عاملی دیگر داشته باشد، عبارت The following packages have unmet dependencies...عبارت نسبتا آشنایی برای افرادی است که با دبیان‌بیس‌ها کار کرده‌اند!شاید بتوان برای برخی از کامپوننت‌ها و سرویس‌ها، ماشین‌های مجازی (Virtual Machine یا VM) مجزایی را درنظر گرفت که تاحدی مشکلات Conflict و محیط اجرا را حل می‌کند، اما این سناریو یک ایراد بسیار بزرگ دارد: زمانی که محصول رشد می‌کند یا تعداد سرویس‌‌ها زیاد می‌شود، نیازمند VM های متعددی هستیم. طبیعی است که افزایش تعداد VM نه تنها منجر به افزایش هزینه و هدر-رفت منابع سخت‌افزاری می‌شود که مدیریت خود VM ها و سیستم‌عامل‌های نیز سخت خواهد شد.جدای از بحث dependency و نگه‌داری (Maintenance) از سویی دیگر، در محیط‌های عملیاتی (Production) چندمورد ضروری است:مصرف منابع (نظیر رم و سی‌پی‌یو) برای پراسس‌ها باید مدیریت شود.پراسس / سرویس‌های موجود را بتوان ایزوله کرد.بتوان سرویسی را Scale کرد، هرچند می‌توان از یک سرویس چندین پراسس ایجاد کرد، اما این پراسس‌ها باید ایزوله باشند.کانتینر (Container) وارد می‌شودمواردی که گفته شد، تقریباً بطور کامل با کانتینر حل می‌شود:استفاده از محیط‌های مختلفایزوله‌کردن پراسس‌هااجرای سرویس‌های متعدد و اجرای متعدد سرویس‌ها روی یک ماشینسربار بسیار پایین نسبت به VMمدیریت مصرف منابعمدیریت ساده‌تربجای استفاده از VM های متعدد برای حل این موارد، می‌توان از Linux Container Technology (LXC) بعنوان یکی از راه‌های پیاده‌سازی و مدیریت کانتینرها نام برد. LXD نیز یکی دیگر از راه‌های پیاده‌سازی کانتینرها است. کانتینر سربار بسیار بسیار کمی نسبت به VM دارد.زمانی که پراسس داخل کانتینر اجرا می‌شود، در کنار سایر پراسس‌ها و داخل یک سیستم‌عامل اجرا شده، با این تفاوت که نسبت به بقیه کاملاً ایزوله است و آن پراسس اجرای خود را داخل یک سیستم‌عامل و ماشین دیگر می‌بیند.تفاوت کانتینر با VMکانتینر نسبت به VM بسیار سبک است (Lightweight) و اجرای تعداد زیادی از کامپوننت‌ها روی یک سیستم‌عامل را امکان‌پذیر می‌کند. همچنین منابع سخت‌افزاری بسیار کمتری نیاز دارد، چرا که هر VM نیازمند منابع، سیستم‌عامل، کرنل و ... اختصاصی مربوط به خودش است. بطور کلی اگر بخواهیم کانتینر را تعریف کنیم شاید عبارت زیر مناسب باشد:کانتینر، یک یا چند پراسس ایزوله‌شده و بدون سربار اضافی است که منابع اختصاص‌داده شده به خودش را مصرف می‌کند. در‌واقع بجای ایزوله‌کردن در لایه‌ی hypervisor ، ایزوله‌سازی در سطح کرنل انجام می‌شود. بعبارت دیگر در کانتینر هزینه‌ی کرنل را نمی‌دهیم.شکل زیر تفاوت کانتینر و VM را بخوبی نشان می‌دهد:تفاوت کانتینر و ماشین مجازی (VM)همانطور که گفته شد و در تصویر بالا نیز مشاهده می‌شود، کانتینر از کرنل هاست اصلی استفاده می‌کند، بنابراین خروجی دستور زیر برای مشاهده ورژن و نام کرنل در هر کانتینر و هاست اصلی یکسان است:uname -srvmنتیجه:کانتینر از کرنل هاست اصلی استفاده می‌کنداما یک سوال را هنوز نمی‌توانم پاسخ دهم و خوب است که در مورد آن فکر کنیم:اصلا مقایسه‌ی کانتینر و VM کار درستی است؟کانتینر / Container و باربریکانتینر در باربری (از جمله باربری دریایی) تحولی را بوجود آورد. یعنی تولیدکننده بار خود را در یک ساختار مشخص (کانتینر) ریخته و ارسال می‌کند. داخل کانتینر هرچیزی می‌تواند باشد: عروسک، تلفن همراه، لپ‌تاپ، کفش و ... که ساختار و نحوه ارسال آن کاملا مستقل از جنس ارسالی است.کانتینر چگونه کار می‌کند؟همانطور که گفته شد کانتینر، پراسس‌ها را ایزوله می‌کند اما این سؤال مطرح می‌شود که چگونه پراسس در یک سیستم‌عامل مشترک از سایر پراسس‌های همان سیستم‌عامل ایزوله می‌شود؟ پاسخ به این سؤال در دو ویژگی لینوکس است:یک. Linux Namespacesدو. Linux Control Groups (cgroups)فضای‌نام لینوکس / Linux Namespacesدر لینوکس، Namespace ها باعث می‌شوند که هر پراسس نگاه (View) خودش را به سیستم داشته باشد، این «زاویه‌ی دید» شامل فایل‌ها، پردازنده، Hostname، اینترفیس شبکه و مواردی از این قبیل است.لینوکس بطور پیش‌فرض یک Namespace دارد که همه منابع سیستم مانند PID ها، UserID ها، اینترفیس‌های شبکه و … به آن Namespace تعلق دارند.می‌توان Namespace های مختلفی را ایجاد و منابع سیستم را برای آن‌ها مدیریت کرد. همچنین اجرای پراسس در آن Namespace ها امکان‌پذیر بوده، بگونه‌ای که پراسس تنها منابع مربوط به آن Namespace را مشاهده می‌کند.لازم به ذکر است انواع مختلفی از Namespace در لینوکس وجود داشته و پراسس لزوماً فقط به یک Namespace خاص تعلق ندارد. از انواع مختلف Namespace می‌توان به موارد زیر اشاره کرد:Mount (mnt)Process ID (pid)Network (net)Inter-process communication (ipc)UTSUser ID (user)هر نوعی از Namespace برای ایزوله‌کردن گروهی از منابع بکار می‌رود. بعنوان مثال UTS مشخص‌ می‌کند که پراسس کدام Hostname و دامنه (Domain Name) را ببیند؛ مثلا با دو Namespace متفاوت از نوع UTS می‌توان پراسس‌هایی داشت که دو Hostname مختلف را می‌بینند و بعبارت دیگر دو پراسس داریم که در دو ماشین مجزا اجرا شده‌اند.گروه‌های کنترلی / Linux Control Groups (cgroups)گروه‌های کنترلی یا Linux Control Groups (cgroups) دومین ویژگی‌ای است که لینوکس برای ایزوله‌کردن کانتینرها بکار می‌گیرد. Cgroup یکی از Feature های کرنل لینوکس بوده و محدودیت منابع مصرفی کانتینر و پراسس (یا گروهی از پراسس‌ها) را مشخص می‌کند. پراسس نمی‌تواند بیش از آنچه‌ که بدان اختصاص داده شده است را مصرف کند. این محدودیت منابع شامل پردازنده، رم، پهنای‌باند و مواردی از این دست است. همانطور که پراسس‌های دو سیستم مجزا نمی‌توانند منابع یکدیگر را مصرف کنند، این محدودیت منابع نیز باعث می‌شود که پراسس اجازه مصرف منابع سایر پراسس‌ها را نداشته باشد.رابطه داکر / Docker و کانتینر / Containerتا اینجا توضیحاتی در مورد کانتینر داده شد، اما رابطه کانتینر و داکر چیست؟ می‌توان گفت که داکر یک سرویس (یا پلتفرم) برای مدیریت کانتینرها است، در‌واقع داکر اولین سیستم مدیریت کانتینر بود که علاوه بر نقش مدیریت کانتینر، عملیات پکیج‌کردن و dependency ها را نیز به سادگی و در سیستم‌عامل‌های مختلف مدیریت می‌کند. یکی از ویژگی‌های بسیار عالی داکر، نیز همین مورد است؛ اجرای کانتینرهای مختلف روی سیستم‌عامل‌های مختلف.و اگر ساده‌تر بگوییم:داکر یک پکیج کاملاً Portable می‌سازد که علاوه بر اجرا بصورت کانتینر و مستقل از سیستم‌عامل، امکان مدیریت منابع را هم فراهم می‌کند. این پکیج‌ها همان Image های داکر هستند.مثالی را برای تقریب به ذهن می‌زنم:در مجازی‌سازی، ایمیج (مثلاً export فایل ovf) داریم که روی virtual-box (یا هر مجازی‌ساز دیگر مثل ESX) اجرا شده و VM شروع بکار می‌کند. برای داکر هم Image داریم که سرویس داکر آن‌ را اجرا کرده و کانتینر شروع بکار می‌کند، با این تفاوت که سربار اضافی نداریم و کرنل مشترک است.چند نکتهیکی از تفاوت‌های VM و داکر، علاوه بر سطح جداسازی، تفاوت لایه‌بندی ایمیج‌ها است، بدینصورت که در داکر اگر لایه‌ای از قبل موجود باشد نیازی به دانلود یا ساختن مجدد آن نیست.یکی از مواردی که مورد توجه قرار دارد، بحث امنیت است. همانطور که گفته شد ایزوله‌کردن کانتینر در سطح کرنل صورت گرفته و اگر در کرنل آسیب‌پذیری‌ای وجود داشته باشد امکان دورزدن cgroup و namespace بوجود می‌آید. البته این نگرانی در مورد مجازی‌سازی و Hypervisor هم وجود دارد، اگر آسیب‌پذیری‌ای در ESX وجود داشته باشد، دسترسی از یک VM به VM دیگر امکان‌پذیر است.کانتینر به خودی‌خود سربار چندانی ندارد، اما زمانی که پورت کانتینر پابلیش می‌شود (Port Mapping) به دلیل عملیات NAT کردن و قرارگرفتن پشت iptables یک سربار نسبتا کمی را ایجاد می‌کند. این Overhead ایجادشده در ازای مزایای کانتینر، کاملا ارزش هزینه‌-کرد را دارد.راه‌های مختلفی برای پیاده‌سازی میکروسرویس وجود دارد اما استفاده از کانتینر رایج بوده و عموما توصیه می‌شود.از rkt (بخوانید rock-it) می‌توان بعنوان دیگر پلتفرم مدیریت کانتینر و جایگزینی برای Docker نام برد.کوبرنتیز (Kubernetes) برای مدیریت، دپلوی و Scale کانتینرها در سطح چندین هاست است. داکر یکی از ابزارهایی است که کوبرنتیز توانایی کار با آن را دارد.در این نوشتار سعی شد تا حد ممکن بصورت ساده توضیحاتی داده شود و ایراداتی از نظر فنی دارد.برای این نوشته تا حد زیادی از کتاب Kubernetes in Action کمک گرفته شده است. همچنین تصاویر نیز از همین منبع است.