اگر چند سالی برنامهنویسی کرده باشید، احتمالاً حداقل یک بار با این وضعیت روبهرو شدید: پروژه روی سیستم خودتان بدون مشکل اجرا میشود، اما همین که روی سیستم یکی از همتیمیها یا روی سرور بالا میآید، یکدفعه همهچیز به هم میریزد.
یک جا نسخه Node.js فرق دارد، جای دیگر نسخه دیتابیس متفاوت است، یک Dependency روی سرور نصب نشده یا تنظیمات Environment با محیط توسعه فرق میکند. آخرش هم معمولاً همان جمله معروف را میشنویم:
«ولی روی سیستم من کار میکرد!»
Docker تا حد زیادی برای حل همین جنس مشکلات ساخته شده است. ایده اصلی آن این است که به جای وابسته بودن اجرای برنامه به تنظیمات یک سیستم مشخص، محیط اجرای نرمافزار را هم همراه پروژه تعریف کنیم.
Docker دقیقاً چه مشکلی را حل میکند؟
فرض کنید روی یک پروژه وب کار میکنیم که از Angular برای Frontend، یک API با Node.js یا .NET، دیتابیس PostgreSQL و Redis استفاده میکند.
برای اجرای این پروژه روی یک سیستم جدید، در حالت عادی باید نسخه مناسب تمام این ابزارها نصب شود. بعد Environment Variableها تنظیم شوند، دیتابیس ساخته شود، پورتها بررسی شوند و سرویسهای مختلف هم به ترتیب اجرا شوند.
در یک تیم چندنفره خیلی زود مشکلات شروع میشوند.
ممکن است پروژه با Node.js 22 نوشته شده باشد اما یکی از توسعهدهندگان Node.js 20 داشته باشد. ممکن است نسخه PostgreSQL روی سیستم توسعه با سرور Production متفاوت باشد یا یک کتابخانه Native روی یک سیستم نصب شده باشد ولی روی سیستم دیگر وجود نداشته باشد.
Docker تلاش میکند این وابستگی به سیستم میزبان را کمتر کند.
به جای اینکه بگوییم:
- Node.js 22 نصب کن
- PostgreSQL نصب کن
- Redis را راهاندازی کن
- این Dependencyها را نصب کن
- این تنظیمات را انجام بده
محیط موردنیاز برنامه را تعریف میکنیم و Docker آن محیط را برای ما ایجاد میکند.

Docker چیست؟
Docker یک پلتفرم برای ساخت و اجرای نرمافزار داخل محیطهایی به نام Container است.
Container را میتوان یک محیط ایزوله برای اجرای برنامه در نظر گرفت. برنامه داخل این محیط Runtime، Dependencyها و تنظیمات موردنیاز خودش را دارد و تا حد زیادی از محیط اصلی سیستم جدا است.
فرض کنید Backend پروژه ما برای اجرا به موارد زیر نیاز دارد:
Node.js 22
npm packages
Environment Variables
Port 3000
به جای نصب و تنظیم دستی این موارد روی هر سیستم، آنها را داخل تنظیمات Docker مشخص میکنیم.
در نتیجه هر کسی که Docker داشته باشد میتواند تقریباً همان محیط را روی سیستم خودش ایجاد کند.
این همان بخشی است که Docker را برای تیمهای توسعه جذاب میکند؛ محیط اجرای پروژه دیگر فقط در لپتاپ توسعهدهنده وجود ندارد، بلکه میتوان آن را تعریف و بازتولید کرد.
Dockerfile چیست؟
برای مشخص کردن نحوه ساخت محیط برنامه معمولاً از فایلی به نام Dockerfile استفاده میکنیم.
برای مثال یک Dockerfile ساده برای Backend نوشتهشده با Node.js میتواند چیزی شبیه این باشد:
FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
EXPOSE 3000
CMD ["npm", "start"]
در خط اول:
FROM node:22-alpine
مشخص میکنیم محیط پایه ما Node.js نسخه 22 باشد.
سپس با:
WORKDIR /app
دایرکتوری کاری برنامه را داخل Container مشخص میکنیم.
این قسمت Dependencyهای پروژه را نصب میکند:
COPY package*.json ./
RUN npm ci
و در نهایت مشخص میکنیم هنگام اجرای Container چه دستوری اجرا شود:
CMD ["npm", "start"]
بعد از آماده شدن Dockerfile میتوانیم از آن یک Image بسازیم:
docker build -t my-api .
و بعد برنامه را اجرا کنیم:
docker run -p 3000:3000 my-api
در این مرحله Backend ما داخل یک Container اجرا شده است.
تفاوت Image و Container
دو اصطلاحی که هنگام شروع Docker زیاد با آنها برخورد میکنیم Image و Container هستند.
Image را میتوان یک قالب آماده برای اجرای نرمافزار در نظر گرفت.
برای مثال:
node:22-alpine
postgres:17
redis:alpine
nginx:alpine
همگی Docker Image هستند.
اما Container نسخه در حال اجرای یک Image است.
اگر بخواهیم با مفاهیم برنامهنویسی مقایسه کنیم، میتوانیم بگوییم Image شبیه Class و Container شبیه Instance آن است.
از یک Image میتوان چند Container جداگانه ایجاد کرد.

برای مثال ممکن است یک Image از Backend داشته باشیم و سه Container از روی آن اجرا کنیم تا درخواستهای کاربران بین آنها تقسیم شود.
Docker با Virtual Machine چه فرقی دارد؟
ممکن است این سؤال پیش بیاید که اگر Virtual Machine داریم، چرا باید از Docker استفاده کنیم؟
در یک Virtual Machine معمولاً هر ماشین مجازی سیستمعامل خودش را دارد. یعنی اگر چند VM روی یک سرور اجرا کنیم، هرکدام بخشی از منابع را برای سیستمعامل مستقل خودشان مصرف میکنند.
ساختار ساده یک VM چیزی شبیه این است:
Hardware
↓
Host OS
↓
Hypervisor
↓
Guest OS
↓
Application
Containerها روش متفاوتی دارند.
آنها معمولاً Kernel سیستم میزبان را به اشتراک میگذارند و نیازی نیست هر Container یک سیستمعامل کامل مستقل داشته باشد.
Hardware
↓
Host OS
↓
Docker
↓
Containers
به همین دلیل Containerها معمولاً بسیار سریعتر ساخته و اجرا میشوند و منابع کمتری نسبت به یک VM کامل مصرف میکنند.
البته Docker جای Virtual Machine را کاملاً نمیگیرد.
در بسیاری از زیرساختهای واقعی حتی خود Docker داخل یک VM اجرا میشود. بنابراین این دو تکنولوژی بیشتر مکمل یکدیگر هستند تا رقیب مستقیم.

Docker Compose؛ وقتی پروژه چند سرویس دارد
در یک پروژه واقعی معمولاً فقط یک Container نداریم.
ممکن است پروژه ما از سرویسهای زیر تشکیل شده باشد:
- Frontend
- Backend API
- PostgreSQL
- Redis
- Nginx
میتوان هرکدام از آنها را با دستور docker run اجرا کرد، اما وقتی تعداد سرویسها زیاد شود مدیریت آنها سخت میشود.
اینجاست که Docker Compose وارد میشود.
با Docker Compose میتوانیم سرویسهای پروژه را داخل یک فایل تعریف کنیم.
برای مثال:
services:
api:
build: ./backend
ports:
- "3000:3000"
depends_on:
- database
- redis
database:
image: postgres:17
environment:
POSTGRES_DB: myapp
POSTGRES_USER: admin
POSTGRES_PASSWORD: password
volumes:
- postgres-data:/var/lib/postgresql/data
redis:
image: redis:alpine
volumes:
postgres-data:
بعد برای اجرای کل محیط پروژه کافی است بنویسیم:
docker compose up -d
و برای متوقف کردن آن:
docker compose down
به جای اجرای دستی PostgreSQL، Redis و Backend، کل محیط با یک دستور بالا میآید.
این موضوع مخصوصاً وقتی توسعهدهنده جدیدی وارد تیم میشود خیلی کاربردی است. به جای ارسال یک فایل چندصفحهای برای نصب و تنظیم سرویسها، بخش بزرگی از محیط پروژه در Docker تعریف شده است.
Volume چیست و چرا به آن نیاز داریم؟
فرض کنید PostgreSQL داخل یک Container اجرا میشود.
اگر Container را حذف کنیم، قطعاً نمیخواهیم دیتابیس کاربران هم همراه آن حذف شود.
برای حل این مسئله Docker مفهومی به نام Volume دارد.
Volume محلی برای نگهداری دادههای Persistent است که مستقل از عمر Container باقی میماند.
برای مثال:
volumes:
- postgres-data:/var/lib/postgresql/data
در این حالت اطلاعات PostgreSQL داخل Volume نگهداری میشود.
حالا حتی اگر Container دیتابیس را حذف کنیم و دوباره بسازیم، دادههای اصلی همچنان وجود دارند.
Volumeها معمولاً برای مواردی مثل دیتابیس، فایلهای آپلودشده یا اطلاعاتی که نباید با حذف Container از بین بروند استفاده میشوند.
Containerها چطور با هم ارتباط برقرار میکنند؟
یکی دیگر از مفاهیم مهم Docker، Network است.
فرض کنید Backend ما باید به PostgreSQL متصل شود.
اگر هر دو سرویس داخل Docker Compose تعریف شده باشند، Docker یک Network داخلی بین آنها ایجاد میکند.
مثلاً اگر سرویس دیتابیس این نام را داشته باشد:
database:
image: postgres:17
Backend میتواند به جای استفاده از IPهای دستی، مستقیماً با این آدرس به آن متصل شود:
database:5432
در واقع نام سرویس به Hostname آن تبدیل میشود.
این قابلیت باعث میشود سرویسهای مختلف پروژه بدون وابستگی به IP سیستم میزبان با یکدیگر ارتباط داشته باشند.
یک پروژه وب واقعی با Docker
فرض کنیم پروژه ما ساختاری شبیه این داشته باشد:
my-project/
│
├── frontend/
│ └── Angular
│
├── backend/
│ └── Node.js
│
├── nginx/
│ └── nginx.conf
│
└── docker-compose.yml
در این پروژه میتوانیم برای Frontend و Backend Image جداگانه داشته باشیم.
PostgreSQL و Redis هم در Containerهای مستقل اجرا شوند و Nginx درخواستهای ورودی کاربران را مدیریت کند.
ساختار کلی سیستم میتواند چیزی شبیه این باشد:

حالا اگر توسعهدهنده جدیدی Repository را Clone کند، به جای نصب دستی تمام ابزارها، در یک سناریوی ایدهآل فقط Environment موردنیاز را تنظیم میکند و سپس اجرا میکند:
docker compose up -d
بعد از چند لحظه Frontend، Backend، Database و Redis آماده کار هستند.
اینجا مزیت Docker خیلی ملموستر میشود.
Docker فقط برای پروژههای وب نیست
اگرچه مثالهای Docker معمولاً حول Backend و Database هستند، استفاده از Container محدود به پروژههای وب نیست.
یکی از مثالهای خوب، پروژههای هوش مصنوعی و Machine Learning است.
در این پروژهها معمولاً با مجموعهای از Dependencyهای حساس به نسخه روبهرو هستیم:
Python
PyTorch
CUDA
cuDNN
Transformers
NumPy
گاهی تغییر کوچک نسخه یکی از این موارد باعث میشود پروژه دیگر اجرا نشود.
Docker کمک میکند یک محیط مشخص برای اجرای پروژه AI بسازیم و همان محیط را روی سیستم توسعه، سرور یا ماشین دارای GPU اجرا کنیم.
به همین دلیل بسیاری از پروژهها و ابزارهای حوزه AI هم Docker Image آماده ارائه میکنند.
Docker همه مشکلات Deployment را حل نمیکند
گاهی Docker طوری معرفی میشود که انگار با Container کردن پروژه دیگر Deployment هیچ پیچیدگیای ندارد.
اما Docker فقط بخشی از مسئله را حل میکند.
هنوز موارد زیادی وجود دارند که باید برای آنها راهحل جداگانه داشته باشیم:
- مدیریت Secretها
- Security
- Monitoring
- Logging
- Backup
- Load Balancing
- مدیریت سرورها
- استراتژی Deployment
همچنین در پروژههای بزرگ ممکن است با ابزارهایی مثل Kubernetes روبهرو شویم.
Docker و Kubernetes هم یک چیز نیستند.
Docker بیشتر روی ساخت و اجرای Containerها تمرکز دارد، در حالی که Kubernetes برای مدیریت تعداد زیادی Container و سرویس روی چندین سرور استفاده میشود.
چند دستور کاربردی Docker
برای مشاهده Containerهای در حال اجرا:
docker ps
برای مشاهده تمام Containerها:
docker ps -a
برای مشاهده Imageهای موجود:
docker images
برای دیدن Log یک Container:
docker logs <container-name>
برای ورود به Shell یک Container:
docker exec -it <container-name> sh
برای اجرای سرویسهای Docker Compose:
docker compose up -d
برای مشاهده Log سرویسها:
docker compose logs -f
و برای متوقف کردن کل پروژه:
docker compose down
برای شروع کار با Docker همین چند دستور بخش زیادی از کارهای روزمره را پوشش میدهند.
نتیجهگیری
مهمترین مزیت Docker فقط این نیست که برنامه را داخل یک Container اجرا میکند.
موضوع اصلی این است که محیط اجرای نرمافزار هم تبدیل به بخشی قابل تعریف از پروژه میشود.
میتوان مشخص کرد برنامه با چه Runtimeای اجرا شود، چه Dependencyهایی نیاز دارد، چه سرویسهایی باید کنار آن باشند و ارتباط بین این سرویسها چگونه انجام شود.
این موضوع باعث میشود فاصله بین محیط Development، Testing و Production کمتر شود و راهاندازی پروژه روی سیستمهای مختلف قابل پیشبینیتر باشد.
در یک پروژه کوچک شاید مزیت Docker خیلی محسوس نباشد، اما وقتی Database، Cache، Backend، Frontend، Worker و سرویسهای دیگر وارد پروژه شوند، ارزش آن خیلی سریع مشخص میشود.
Docker تمام مشکلات توسعه و Deployment را حل نمیکند، اما یکی از دردسرهای قدیمی برنامهنویسی را تا حد زیادی کاهش میدهد:
اینکه نرمافزار فقط روی سیستم کسی که آن را نوشته درست اجرا شود.
💙 اگر این مقاله براتون مفید بود، خوشحال میشم با لایک کردن و بهاشتراکگذاری اون با بقیه، حمایت کنید.
