کانتینرها (Docker) و کوبرنیتیز

آشنایی با مفاهیم کانتینرها، داکر، کوبرنیتیز و بررسی تفاوت‌های آن‌ها با ماشین‌های مجازی در معماری مدرن زیرساخت.

تاریخچه

در گذشته، یکی از بزرگترین چالش‌های توسعه نرم‌افزار این بود که کدهای نوشته‌شده در سیستم توسعه‌دهنده (لپ‌تاپ) به درستی کار می‌کردند، اما پس از انتقال به سرور اصلی به دلیل تفاوت در نسخه‌های نرم‌افزاری و تنظیمات محیطی، دچار اختلال می‌شدند. برای حل این مشکل، مهندسان از ماشین‌های مجازی (Virtual Machine یا VM) استفاده کردند تا برنامه‌ها را در محیط‌هایی ایزوله اجرا کنند. با این حال، ماشین‌های مجازی به دلیل نیاز به سیستم‌عامل کامل و مجزا برای هر برنامه، بسیار سنگین بودند و منابع زیادی را مصرف می‌کردند. این محدودیت‌ها نیاز به یک راهکار بسیار سبک‌تر و سریع‌تر را ایجاد کرد.

درک مفاهیم با تمثیل

برای درک بهتر، می‌توان صنعت حمل‌ونقل را مثال زد. در گذشته، بارها به شکل‌های نامنظم (بشکه، گونی، جعبه) در کشتی چیده می‌شدند که بارگیری را دشوار می‌کرد و خطر آسیب به محموله را افزایش می‌داد. اختراع «کانتینر باری استاندارد» این صنعت را متحول کرد؛ دیگر برای جرثقیل یا کشتی اهمیتی نداشت که داخل جعبه چیست، بلکه تنها جابه‌جایی یک کانتینر فلزی استاندارد مطرح بود. Docker در دنیای نرم‌افزار دقیقاً همین کانتینرهای استاندارد را تولید می‌کند.

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

مفاهیم تخصصی

  • کانتینر (Container): یک بسته نرم‌افزاری بسیار سبک، ایزوله و مستقل است که تمامی نیازمندی‌های یک برنامه برای اجرا (شامل کدها، کتابخانه‌ها، فایل‌های کمکی و تنظیمات) را درون خود بسته‌بندی کرده است.

  • داکر (Docker): شناخته‌شده‌ترین پلتفرم نرم‌افزاری است که امکان ساخت، استقرار و اجرای کانتینرهای نرم‌افزاری را به صورت استاندارد فراهم می‌کند.

  • کوبرنیتیز (Kubernetes یا K8s): یک سیستم هماهنگ‌کننده و مدیریت کانتینر (Orchestrator) است که وظایف پیچیده‌ای نظیر مقیاس‌پذیری (افزایش و کاهش خودکار تعداد کانتینرها بر اساس ترافیک) و خودترمیمی سرویس‌ها را در مقیاس وسیع بر عهده دارد.

برای ایجاد یک کانتینر، از یک فایل متنی ساده و ساختاریافته به نام Dockerfile استفاده می‌شود که حاوی دستورالعمل‌های ساخت است. در ادامه نمونه‌ای از این پیکربندی بررسی شده است:

# ابتدا یک سیستم‌عامل پایه و بسیار سبک (مثل اوبونتو) را به عنوان بستر کار مشخص می‌کنیم
FROM ubuntu:20.04
 
# کدهای برنامه را از محیط محلی به داخل پوشه app در کانتینر منتقل می‌کنیم
COPY my-app /app
 
# ابزارهای مورد نیاز برنامه (مانند زبان برنامه‌نویسی پایتون) را نصب می‌کنیم
RUN apt-get update && apt-get install -y python3
 
# دستور نهایی: به کانتینر می‌گوییم در زمان اجرای اولیه، این برنامه را اجرا کند
CMD ["python3", "/app/main.py"]

با اجرای این فایل، یک ایمیج استاندارد ساخته می‌شود. این کانتینر پس از استقرار در هر سرور یا محیط Cloud در سراسر جهان، رفتاری کاملاً یکسان و قابل پیش‌بینی خواهد داشت، زیرا تمامی پیش‌نیازهای اجرایی خود را به همراه دارد.

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

در معماری قابلیت اطمینان سایت (SRE)، یک اصل طلایی وجود دارد: کانتینرها ماهیتی Ephemeral (فانی و یک‌بارمصرف) دارند. Kubernetes ممکن است به دلایل مختلف (از جمله بروزرسانی یا خرابی سخت‌افزار سرور)، هر لحظه کانتینر فعلی را حذف کرده و جایگزین جدیدی برای آن ایجاد کند. بنابراین، داده‌های مهم باید همواره در فضاهای ذخیره‌سازی مانا و مستقل از چرخه عمر کانتینر ذخیره شوند.

یکی از چالش‌های کلاسیک و همیشگی در تیم‌های توسعه نرم‌افزار، مواجهه با جمله معروف «روی سیستم من به درستی کار می‌کند!» است. فرض کنید کدی در لپ‌تاپ توسعه‌دهنده به خوبی اجرا می‌شود، اما روی سرور اصلی به دلیل فقدان یک فایل پیکربندی یا مغایرت نسخه برنامه‌ها از کار می‌افتد.

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