تفاوت داکر و ماشین مجازی در لایه جداسازی است: ماشین مجازی سختافزار را مجازی میکند و سیستمعامل و هسته کامل خودش را دارد، اما کانتینر Docker یک پردازه جداشده روی همان هسته لینوکس میزبان است. برای اپلیکیشن لینوکسی که مرتب بهروز میشود، Docker سبکتر و سریعتر است. اگر ویندوز، هسته متفاوت، جداسازی قوی بین مشتریها یا نرمافزار قدیمی دارید، ماشین مجازی مناسبتر است. در بیشتر محیطهای عملیاتی هم این دو کنار هم به کار میروند و Docker داخل ماشین مجازی اجرا میشود.
مفاهیم هایپروایزر و انواع مجازیسازی در مجازیسازی چیست و چگونه کار میکند توضیح داده شده است. تمرکز این راهنما روی انتخاب برای یک سرویس مشخص است و دستورها بر اساس مستندات Docker و Proxmox تا شهریور ۱۴۰۵ نوشته شدهاند.
تفاوت داکر و ماشین مجازی در معماری
در ماشین مجازی، هایپروایزری مثل KVM، ESXi یا Hyper-V برای هر ماشین CPU، حافظه، دیسک و کارت شبکه مجازی میسازد. سیستمعامل مهمان مثل یک سرور فیزیکی بوت میشود و هسته خودش را دارد؛ به همین دلیل روی میزبان لینوکسی میتوانید ماشین ویندوزی اجرا کنید.
کانتینر از قابلیتهای هسته لینوکس استفاده میکند. Namespaceها به هر کانتینر نمای جداگانهای از پردازهها، شبکه و فایلسیستم میدهند و cgroupها مصرف CPU و حافظه را محدود میکنند. ایمیج Docker از لایههای فقطخواندنی ساخته میشود و کانتینر یک لایه نوشتنی روی آن اضافه میکند. بوتی در کار نیست و کانتینر در حد اجرای یک پردازه راه میافتد. این آزمایش ساده نشان میدهد کانتینر هسته جداگانه ندارد:
# on the Linux host
uname -r
# inside a container: prints the same kernel version as the host
docker run --rm alpine uname -rDocker Desktop روی ویندوز و macOS برای اجرای کانتینرهای لینوکسی پشت صحنه یک ماشین مجازی لینوکسی سبک اجرا میکند، چون این کانتینرها به هسته لینوکس نیاز دارند.
مقایسه Docker و ماشین مجازی در یک جدول
| موضوع | ماشین مجازی | کانتینر Docker |
|---|---|---|
| واحد جداسازی | سختافزار مجازی و سیستمعامل کامل | پردازه جداشده با Namespace و cgroup |
| هسته سیستمعامل | هسته مستقل برای هر ماشین | هسته مشترک با میزبان |
| سیستمعامل قابل اجرا | هر سیستمعاملی که هایپروایزر پشتیبانی کند | کانتینر لینوکسی روی هسته لینوکس |
| زمان راهاندازی | بوت کامل سیستمعامل | در حد اجرای یک پردازه |
| سربار منابع | حافظه و دیسک برای هر سیستمعامل مهمان | کم؛ فقط خود اپلیکیشن و وابستگیهایش |
| داده ماندگار | روی دیسک ماشین | باید در Volume یا Bind Mount باشد؛ لایه نوشتنی با حذف کانتینر پاک میشود |
| جابهجایی زنده | Live Migration در هایپروایزر | کانتینر روی سرور دیگر دوباره ساخته میشود |
| بکاپ | Snapshot یا بکاپ کل ماشین | ایمیج در Registry، بکاپ Volume و دیتابیس |
| وصله امنیتی | بهروزرسانی سیستمعامل هر ماشین | ساخت دوباره ایمیج و بهروزرسانی هسته میزبان |
امنیت: هسته مشترک یعنی مرز نازکتر
همه کانتینرهای یک سرور از یک هسته استفاده میکنند. آسیبپذیری هسته که فرار از کانتینر را ممکن کند، به همه کانتینرهای آن میزبان میرسد؛ در ماشین مجازی مهاجم باید از مرز هایپروایزر هم عبور کند. مستندات Proxmox هم برای کاربردهایی که بیشترین جداسازی و امکان Live Migration را لازم دارند، اجرای کانتینرها داخل ماشین مجازی را توصیه میکند.
بیشتر مشکلات امنیتی Docker در عمل از پیکربندی نادرست میآید. این موارد را در هر سرور بررسی کنید:
- گزینه –privileged تقریباً همه محدودیتهای کانتینر را برمیدارد و فقط در موارد خاص و مستند لازم است.
- Mount کردن /var/run/docker.sock داخل کانتینر به آن دسترسی معادل root روی میزبان میدهد.
- پورتهایی که با -p منتشر میشوند، مستقیم در قواعد iptables ثبت میشوند و ممکن است از قواعد UFW عبور کنند؛ سرویسهای داخلی را به 127.0.0.1 ببندید.
- اجرای پردازه با کاربر غیر root داخل ایمیج و استفاده از Rootless Mode دامنه خسارت را کمتر میکند.
امنسازی سیستمعامل میزبان، بهروزرسانی هسته و بستن پورتهای غیرضروری جداگانه لازم است؛ این بخش در خدمات امنسازی سرور پوشش داده میشود.
چه زمانی Docker انتخاب مناسبتری است؟
- وباپلیکیشن و API که چند بار در هفته نسخه جدید میگیرد و باید سریع به نسخه قبل برگردد.
- چند سرویس کوچک که هر کدام وابستگیها و نسخه زبان برنامهنویسی خودش را دارد، مثلاً دو نسخه متفاوت PHP روی یک سرور.
- یکسان بودن محیط توسعه، تست و عملیات، تا خطای «روی سیستم من کار میکرد» تکرار نشود.
- Runnerهای CI و ساخت و تست خودکار نسخهها در پایپلاین CI/CD.
یک فایل Compose ساده برای اپلیکیشن و دیتابیس این شکل را دارد. داده دیتابیس در Volume نامدار میماند و پورت اپلیکیشن فقط روی localhost باز است تا پشت Reverse Proxy قرار بگیرد:
services:
app:
image: registry.example.local/shop/app:1.4.2
env_file: .env
depends_on:
- db
ports:
- "127.0.0.1:8080:8080"
restart: unless-stopped
db:
image: postgres:16
volumes:
- db-data:/var/lib/postgresql/data
restart: unless-stopped
volumes:
db-data:چه زمانی ماشین مجازی لازم است؟
- ویندوز سرور، Active Directory و نرمافزارهای ویندوزی.
- نرمافزاری که نسخه خاصی از هسته یا ماژول هسته اختصاصی میخواهد.
- اپلیکیشن قدیمی یکپارچه که چند سرویس systemd، Cron و تنظیمات پراکنده در سیستمعامل دارد و بازنویسی آن صرفه ندارد.
- جداسازی قوی بین مشتریها یا تیمهایی که نباید به هیچ منبع مشترکی دسترسی داشته باشند.
- تجهیزات نرمافزاری مثل فایروال یا Mail Gateway که سازنده فقط بهصورت ISO یا OVA عرضه میکند.
سرور مجازی که از دیتاسنتر اجاره میکنید هم یک ماشین مجازی است؛ تفاوت آن با هاست و سرور اختصاصی در سرور مجازی چیست توضیح داده شده است.
ترکیب رایج: Docker داخل ماشین مجازی
در بیشتر سازمانها لایهها اینطور چیده میشوند: کلاستر هایپروایزر، چند ماشین مجازی برای هر محیط یا تیم، و Docker داخل همان ماشینها. Snapshot، بکاپ و Live Migration از لایه مجازیسازی میآید و سرعت استقرار و بازگشت نسخه از Docker. در Proxmox VE برای Docker یک ماشین مجازی بسازید و آن را داخل کانتینر LXC اجرا نکنید؛ ساخت ماشین و شبکه آن در آموزش کانفیگ سرور Proxmox VE آمده است.
وقتی تعداد سرویسها و سرورها زیاد میشود و استقرار، مقیاسپذیری و جایگزینی خودکار کانتینرها روی چند سرور لازم است، مدیریت دستی Docker جواب نمیدهد و به یک Orchestrator مثل Kubernetes نیاز پیدا میکنید.
محدودیت Docker Hub در ایران و راهحل سازمانی
Docker Hub درخواستهای IPهای ایران را مسدود میکند و دستور docker pull روی سرورهای داخلی با خطای 403 متوقف میشود. برای محیط عملیاتی دو راه منطقی وجود دارد: تعریف Registry Mirror در تنظیمات Docker، یا راهاندازی Registry داخلی مثل Harbor که ایمیجهای عمومی را Cache کند و ایمیجهای خود سازمان را هم نگه دارد. طبق مستندات Docker، گزینه registry-mirrors فقط برای Docker Hub کار میکند و Registryهای دیگر را Mirror نمیکند.
پس از آماده شدن Mirror، آدرس آن را در فایل /etc/docker/daemon.json قرار دهید و Docker را دوباره راهاندازی کنید:
{
"registry-mirrors": ["https://mirror.registry.example.local"]
}sudo systemctl restart docker
docker info | grep -A1 "Registry Mirrors"کانفیگ سرور مشکل دسترسی به سرویسهای تحریمشده را حل میکند. راهاندازی Harbor با Proxy Cache، Mirror و انتقال سرویسها به کانتینر در خدمات راهاندازی Docker و Registry داخلی توضیح داده شده است.
چکلیست انتقال سرویس از ماشین مجازی به کانتینر
- تنظیمات قابل تغییر مثل آدرس دیتابیس و کلیدها را از کد جدا و به متغیر محیطی یا فایل تنظیمات منتقل کنید.
- همه مسیرهایی که داده ماندگار مینویسند را پیدا کنید و برایشان Volume تعریف کنید.
- لاگها را به stdout و stderr بفرستید تا با docker logs یا سامانه جمعآوری لاگ خوانده شوند.
- برای هر کانتینر یک پردازه اصلی در نظر بگیرید و Health Check تعریف کنید.
- از برچسب نسخه مشخص ایمیج استفاده کنید و latest را در محیط عملیاتی به کار نبرید.
- بکاپ Volumeها و دیتابیس و بازگشت به نسخه قبلی ایمیج را پیش از انتقال تست کنید.
اشتباهات رایج در انتخاب بین Docker و ماشین مجازی
- انتقال یک سرور کامل با همه سرویسهایش به یک کانتینر بزرگ؛ نتیجه ایمیجی سنگین است که سرعت استقرار Docker را ندارد و مشکلات نگهداری ماشین مجازی را هم با خود میآورد.
- نگه داشتن داده دیتابیس یا فایلهای آپلودشده در لایه نوشتنی کانتینر؛ با اولین docker rm یا بهروزرسانی ایمیج، این دادهها پاک میشوند.
- اجرای کانتینرهای چند مشتری روی یک میزبان مشترک، وقتی بین آنها جداسازی قوی لازم است؛ در این حالت برای هر مشتری ماشین مجازی جدا بسازید.
- رها کردن بکاپ به این دلیل که ایمیج در Registry هست؛ ایمیج فقط کد و وابستگیها را دارد و Volumeها و دیتابیس بکاپ جداگانه میخواهند.
- بهروز نکردن هسته میزبان با این فرض که کانتینرها ایمیج جدید دارند؛ آسیبپذیری هسته به همه کانتینرهای آن سرور میرسد.
- ساختن ماشین مجازی جدا برای هر سرویس کوچک فقط به این دلیل که تیم با Docker آشنا نیست؛ وصله و نگهداری دهها سیستمعامل مهمان بار عملیاتی زیادی میسازد.
سوالات متداول
آیا داکر نوعی ماشین مجازی است؟
خیر. کانتینر Docker پردازهای جداشده روی هسته سیستمعامل میزبان است و سختافزار مجازی یا هسته مستقل ندارد. فقط Docker Desktop روی ویندوز و macOS برای اجرای کانتینرهای لینوکسی از یک ماشین مجازی سبک استفاده میکند.
آیا میتوان ویندوز را داخل Docker اجرا کرد؟
کانتینرهای ویندوزی وجود دارند، اما فقط روی میزبان ویندوزی اجرا میشوند و یک دسکتاپ یا سرور کامل ویندوز نیستند. برای ویندوز سرور کامل روی میزبان لینوکسی، ماشین مجازی لازم است.
دیتابیس را داخل Docker اجرا کنیم یا روی ماشین مجازی؟
هر دو شدنی است. در Docker داده باید روی Volume با استوریج قابل اعتماد باشد، محدودیت منابع تعیین شود و بکاپ با ابزار خود دیتابیس گرفته شود. برای دیتابیسهای بزرگ و حساس، بسیاری از تیمها ماشین مجازی اختصاصی را برای تنظیم دقیقتر منابع و جداسازی ترجیح میدهند.
Docker را داخل کانتینر LXC در Proxmox اجرا کنیم؟
مستندات Proxmox برای بیشترین جداسازی و امکان Live Migration، اجرای کانتینرها داخل ماشین مجازی QEMU را توصیه میکند. LXC هسته میزبان را به اشتراک میگذارد و Docker داخل آن یک لایه هسته مشترک دیگر اضافه میکند.





