کانتینر (Container) و مفهوم و کاربرد این تکنولوژی — به زبان ساده
شما چه یک دانشآموز، چه توسعهدهندهای در یک شرکت و یا فردی علاقهمند به نرمافزار باشید، در هر حال این احتمال وجود دارد که تاکنون با عبارت «کانتینر» مواجه شده باشید. همچنین ممکن است شنیده باشید که کانتینرها ماشینهای مجازی سبکی هستند؛ اما مفهوم کانتینر دقیقاً چیست، کانتینرها دقیقاً چگونه کار میکنند و چرا تا این حد مهم هستند؟
در این نوشته قصد داریم به بررسی کانتینرها، ایدههای اصلی فنی تشکیل دهنده و کاربردهای آنها بپردازیم. ما انتظار نداریم شما در این زمینه هیچ دانش قبلی به جز درکی کلی از علوم رایانه داشته باشید.
کرنل و سیستم عامل
لپتاپ شما و هر رایانه دیگری بر مبنای قطعات مختلفی از سختافزار مانند سیپییو، حافظه دائمی (هارددیسک یا SSD)، حافظه، کارت شبکه و غیره ساخته شده است.
برای تعامل با این سختافزار به نرمافزاری به نام سیستم عامل نیاز داریم. بخشی از سیستم عامل که با سختافزاری تعامل دارد و به عنوان پلی بین سختافزار و بقیه سیستم عمل میکند، کرنل (kernel) نام دارد. کرنل مسئولیت زمانبندی پردازشها (برنامهها) برای اجرا، مدیریت دستگاهها (نوشتن و خواندن آدرسها روی دیسک و حافظه) و مواردی از این دست را بر عهده دارد.
بخشهای دیگر سیستم عامل عملکرد روشن شدن رایانه و ارائه محیط کاربری را بر عهده دارند که در آنجا کاربران برنامهها را اجرا میکنند و به طور مداوم با کرنل تعامل دارند.
ماشین مجازی
فرض کنید یک سیستم دارید که سیستم عامل آن MacOS است و اپلیکیشنی نیز دارید که برای اجرا روی اوبونتو نوشته شده است. در این حالت یکی از راهحلهای مشکل، بوت کردن یک ماشین مجازی روی رایانه مک است که سیستم عامل اوبونتو را اجرا میکند و بدین ترتیب میتوانید برنامه خود را روی ماشین مجازی اجرا کنید.
ماشین مجازی (virtual machine) از چند سطح از سختافزار و مجازیسازی کرنل تشکیل یافته است که یک سیستم عامل میهمان را اجرا میکند. بخشی از نرمافزار که hypervisor نامیده میشود، سختافزار مجازیسازی را ایجاد میکند که شامل دیسک مجازی، کارت شبکه مجازی، CPU مجازی و مواد دیگر است. ماشینهای مجازی شامل کرنل میهمان هستند که میتواند با سختافزار مجازی ارتباط بگیرد.
هایپرویزور میتواند میزبانی شود، یعنی برخی نرمافزارهای آن متعلق به سیستم عامل میزبان (در این مثال MacOS) باشند. همچنین میتواند مستقیماً روی سختافزار ماشین میزبان اجرا شود و جایگزین سیستم عامل شود. در هر حالت استفاده از هایپرویزور رویکرد سنگینی است، چون نیازمند مجازیسازی چندین بخش و در برخی موارد همه سختافزار و کرنل است.
زمانی که به چندین گروه مجازی روی یک ماشین منفرد نیاز داشته باشیم برای هر یک از آن گروهها، یک ماشین مجازی اجرا میکنیم که رویکرد سنگینی محسوب میشود و درواقع اتلاف منابع است.
ماشینهای مجازی نیازمند مجازیسازی سختافزار برای ایزوله سازی سطح ماشین است؛ در حالی که کانتینرها بر مبنای ایزولاسیون درون یک سیستم عامل عمل میکنند. تفاوت سربار با افزایش تعداد فضاهای ایزوله کاملاً متفاوت خواهد بود. چرا که یک لپتاپ معمولی میتواند دهها کانتینر را اجرا کند؛ اما در صورت اجرای تنها یک ماشین مجازی ممکن است به زحمت بیفتد.
Cgroups
مهندسان گوگل در سال 2006 مفهوم «گروههای کنترل» (control groups) را در لینوکس ابداع کردند که به اختصار Cgroups نامیده میشوند. این یک ویژگی کرنل لینوکس است که استفاده از منابع برای پردازشهای کاربر را ایزوله و کنترل میکند.
این پردازشها میتوانند در فضاهای نام (namespaces) و به طور خاص در مجموعه پردازشهایی که محدودیتهای منابع مشترکی دارند قرار گیرند. هر رایانهای میتواند چندین فضای نام داشته باشد که هر یک مشخصات منابع الزام شده از سوی کنترل را داشته باشند.
تخصیص منابع در هر فضای نام میتواند جهت محدودسازی مقدار CPU، RAM و موارد دیگر که از سوی یک دسته پردازشها استفاده میشوند، مورد بهره برداری قرار گیرند. برای نمونه یک اپلیکیشن گردآوری گزارشها که در پسزمینه کار میکند، احتمالاً باید محدودیتهایی در منابع خود داشته باشد تا به طور تصادفی سروری که مشغول تهیه گزارش از آن است را به دلیل بلعیدن منابع از کار نیندازد.
با این که Cgroups یکی از ویژگیهای اصلی لینوکس محسوب نمیشود؛ اما در نهایت طوری بازنویسی شده تا شامل یک ویژگی به نام «ایزولاسیون فضای نام» (namespace isolation) باشد. ایده ایزولاسیون فضای نام خود، مفهوم جدیدی محسوب نمیشود و پیشتر انواع مختلفی ایزولاسیون فضای نام در لینوکس وجود داشته است. یک نمونه مشترک ایزولاسیون پردازش است که هر پردازش منفرد را از دیگران جدا میکند تا از اتفاقاتی مانند اشتراک حافظه جلوگیری کند.
ایزولاسیون Cgroup سطح بالایی از جداسازی است که در آن مطمئن میشویم پردازشهای درون فضای نام Cgroup مستقل از پردازشها در فضاهای نام دیگر هستند. چند ویژگی مهم ایزولاسیون فضای نام در ادامه توضیح داده شدهاند و بدین ترتیب بنیانی برای سطحی از ایزولاسیون که از کانتینرها انتظار داریم ارائه میشود:
- فضاهای نام PID که اختصاری برای «شناسه پردازش» (Process Identifier) است: این ایزولاسیون تضمین میکند که پردازشهای درون یک فضای نام از پردازشهای موجود در فضاهای نام دیگر اطلاعی ندارند.
- فضاهای نام شبکه: ایزولاسیون کنترلر رابط شبکه، iptables، جدولهای مسیریابی، و دیگر سطوح پایین از ابزارهای شبکه.
- فضاهای نام Mount: در این سطح سیستمهای فایل mount میشوند به طوری که گویی حیطه سیستم فایل تنها محدود به دایرکتوریهایی است که روی آنها اجرا شده است.
- فضاهای نام کاربر: کاربران درون فضاهای نام مخصوص خود محدود میشوند و از تداخل ID کاربر در میان فضاهای نام مختلف جلوگیری میشود.
به بیان سادهتر هر فضای نام از نظر پردازشهایی که درونش قرار دارند یک رایانه مستقل محسوب میشود.
کانتینرهای لینوکس
مفهوم cgroups در لینوکس مسیری برای یک فناوری به نام «کانتینرهای لینوکس» (LXC) آماده کرد. LXC عملاً نخستین پیادهسازی عمده از آن چیزی است که امروزه به نام کانتینر میشناسیم و با بهرهگیری از مزیت cgroups و ایزولاسیون فضاهای نام، اقدام به ایجاد محیطهای مجازی با فضای پردازش و شبکهبندی مجزا کرد.
این وضعیت امکان ایجاد فضاهای کاربری مستقل و جدا از هم را فراهم ساخت. ایده کانتینرها به طور مستقیم از LXC ناشی میشود. در واقع نسخههای اولیه داکر (Docker) مستقیماً بر مبنای LXC ساخته شدهاند.
داکر
داکر پرکاربردترین فناوری مورد استفاده در زمینه کانتینرها است و در واقع وقتی اغلب افراد به کانتینر اشاره میکنند منظورشان داکر است.
با این که فناوریهای کانتینری اوپنسورس دیگری مانند rkt از CoreOS نیز وجود دارند و شرکت های بزرگ موتورهای کانتینر خاص خود (مانند lmctfy از سوی گوگل) را ساختهاند؛ اما داکر به یک استاندارد در زمینه کانتینریزاسیون تبدیل شده است. داکر نیز بر مبنای cgroups و فضای نام ارائه شده از سوی کرنل لینوکس و اخیراً از سوی ویندوز ساخته شده است.
هر کانتینر داکر از سه لایه به نامهای تصویر (images) تشکیل یافته است که فایلهای باینری هستند که مجموعاً به صورت یک بسته منفرد گردآوری شدهاند. تصویر پایه شامل سیستم عامل کانتینر است که میتواند متفاوت از سیستم عامل میزبان باشد.
سیستم عامل کانتینر به شکل یک تصویر است. البته این تصویر یک سیستم عامل کامل نیست؛ بلکه تنها شامل سیستم فایل و فایلهای باینری سیستم عامی است؛ در حالی که یک سیستم عامل کامل شامل سیستم فایل، باینریها و کرنل است.
سپس بر روی این تصویر مبنا چندین تصویر ایجاد شدهاند که هر یک بخشی از کانتینر را تشکیل می دهند. برای نمونه ممکن است روی تصویر مبنا تصویری باشد که شامل وابستگیهای apt-get باشد. در روی این لایه نیز ممکن است تصویری باشد که شامل فایلهای باینری اپلیکیشن و مواردی از این دست باشد.
نکته جالب این است که اگر دو کانتینر با لایههای تصویر a، b، c و a، b، d وجود داشته باشند، در این صورت تنها کافی است یک کپی از هر لایه تصویر a, b, c, d به صورت محلی در این ریپازیتوری ذخیره کنید. این همان مفهوم «سیستم فایل متحد» (union file system) داکر است.
هر تصویر به وسیله یک هش (hash) مشخص میشود که تنها یکی از لایههای ممکن تصاویری است که کانتینر را تشکیل میدهند. با این وجود هر کانتینر تنها بر اساس تصویر لایه فوقانیاش شناسایی میشود که به تصاویر والد ارجاع میکند. دو تصویر لایههای فوقانی (تصویر 1 و تصویر 2) که در نمودار فوق نمایش یافتهاند دارای سه لایه اولیه مشترک هستند. تصویر 2 دو لایه مرتبط با پیکربندی اضافی دارد؛ اما دارای همان تصویر والد مربوط به تصویر 1 است.
زمانی که یک کانتینر بوت میشود، تصویر والد آن از ریپو دانلود میشود، فضاهای نام و cgroup ایجاد میشود و تصویر برای ایجاد یک محیط مجازی مورد استفاده قرار میگیرد. فایلهای باینری ذکر شده در تصویر از منظر درونی این کانتینر، تنها فایلهایی هستند که روی رایانه وجود دارند. در این حالت پردازش اصلی کانتینر آغاز میشود و کانتینر زنده تلقی میشود.
داکر ویژگیهای بسیار جالب دیگری نیز دارد که شامل کپی در هنگام نوشتن، مفهوم volume ها (یعنی سیستمهای فایل مشترک بین کانتینرها)، daemon داکر (که اقدام به مدیریت کانتینرها روی رایانه میکند)، ریپازیتوری های با کنترل نسخه (مانند گیتهاب برای کانتینرها) و موارد دیگر میشود.
چرا باید از کانتینرها استفاده کرد؟
کانتینرها علاوه بر ایزولاسیون پردازش، مزیتهای بسیار دیگری هم دارند.
کانتینر به عنوان یک واحد مجزا ارائه میشود که میتواند روی هر چیزی که از آن پشتیبانی کند اجرا شود و در مورد هر یک از این وهلهها، کانتینر دقیقاً یکسان خواهد بود. مهم نیست که سیستم عامل میزبان CentOS, Ubuntu, MacOS و یا یک چیز غیر یونیکسی مانند ویندوز باشد. چون از روی هر کدام از اینها کانتینر میتواند اجرا شود. از این رو میتوان مطمئن بود که کانتینری که روی لپتاپ ساخته میشود، روی سرورهای شرکت نیز عملکردی دقیقاً به همان گونه خواهد داشت.
کانتینر همچنین به عنوان یک واحد استاندارد شده کاری یا محاسباتی عمل میکند. یک پارادایم رایج برای هر کانتینر این است که یک وبسرور منفرد، یک shrad منفرد از پایگاه داده، یا یک Spark worker منفرد را اجرا میکند. در این حالت برای مقیاسبندی اپلیکیشن کافی است تعداد کانتینرها افزایش یابند.
در این پارادایم، هر کانتینر دارای پیکربندی منابع ثابت (CPU, RAM، تعداد threads و غیره) است و مقیاسبندی اپلیکیشن صرفاً به افزایش تعداد کانتینرها وابسته است و نیازی به بررسی تک تک منابع ندارد. بدین ترتیب لایه انتزاعی بسیار سادهای برای مهندسانی فراهم میشود که میتوانند مقیاسبندی یک اپلیکیشن را به آسانی افزایش یا کاهش بدهند.
همچنین کانتینرها ابزاری عالی برای پیادهسازی معماری میکروسرویس محسوب میشوند که در آن هر میکروسرویس تنها دستهای از کانتینرهای همکار هم است. برای نمونه میکروسرویس Redis میتواند با یک کانتینر master منفرد و چند کانتینر slave پیادهسازی شود.
این معماری مبتنی بر (میکرو) سرویس مشخصات بسیار مهمی دارد که ایجاد و انتشار اپلیکیشنها را برای تیمهای مهندسی آسانتر میکند.
هماهنگی
از زمان معرفی کانتینرهای لینوکس، کاربران در برخی موارد تلاش میکنند که اپلیکیشنهای بزرگ مقیاس را روی ماشینهای مجازی زیادی که در آنها هر پردازش روی کانتینر خود اجرا میشود انتشار دهند. این کار نیازمند وجود امکان انتشار دهها تا هزاران کانتینرها روی صدها ماشین مجازی و ادغام شبکهبندی، سیستمهای فایل، منابع و موارد دیگر آنها است. امروزه داکر این کار را اندکی سادهتر ساخته است، چون از مفهوم «هماهنگی» (Orchestration) برای تعریف شبکهبندی کانتینرها، volume ها برای سیستم فایل، پیکربندی منابع و غیره استفاده میکند.
با این حال همچنان برای موارد زیر نیازمند یک ابزار هستیم:
- دریافت مشخصات و انتساب کانتینرها به ماشینها (زمانبندی)
- بوت کردن کانتینرهای مشخص روی ماشینها از طریق داکر
- پرداختن به ارتقا و rollback ها برای ماهیت دائماً در حال تغییر سیستم
- پاسخدهی به موارد شکست مانند کرش کردن کانتینرها
- و ایجاد منابع کلاستر مانند کشف سرویس، شبکهبندی درون ماشین مجازی، ingress/egress کلاستر و غیره.
این مجموعه مسائل به هماهنگی سیستم توزیع یافته مربوط است که بر مبنای مجموعهای از کانتینرها ساخته شدهاند و افراد مختلف به این منظور سیستمهای واقعاً مناسبی برای حل این مشکلها ارائه کردهاند. برای آشنا شدن با این ابزارها پیشنهاد میکنیم به نوشته «زمانبندی و هماهنگی (Orchestration) در اکوسیستم داکر» مراجعه کنید.
اگر این مطلب برایتان مفید بوده است، آموزشهای زیر نیز به شما پیشنهاد میشوند:
- مجموعه آموزشهای ابزارهای مهندسی کامپیوتر
- آموزش داکر (Docker) برای توسعه دهندگان
- مجموعه آموزشهای دروس مهندسی کامپیوتر
- اکوسیستم داکر (Docker) — کامپوننتهای رایج
- شبکه بندی و ارتباط ها در اکوسیستم داکر — راهنمای جامع
- مجموعه آموزشهای علوم کامپیوتر
==