Docker چیست و چه کاربردی دارد؟ راهنمای ساده و کاربردی داکر
مبینا اسبقی
1405/06/23
Docker چیست و چه کاربردی دارد؟ از مفهوم Container تا کاربرد در پروژه واقعی
فرض کن یه برنامه روی کامپیوترت داری که خیلی خوب کار میکنه. همهچیز رو نصب کردی، تنظیماتش رو انجام دادی و بدون مشکل اجرا میشه.
حالا میخوای همین برنامه رو روی یه کامپیوتر دیگه اجرا کنی.
فایلهای پروژه رو منتقل میکنی و برنامه رو اجرا میکنی، ولی یه مشکلی پیش میاد.
برنامه اجرا نمیشه.
یه چیزی کم داره.
شاید یه نرمافزار باید نصب باشه، شاید نسخه یکی از ابزارها فرق داره، شاید یه تنظیم خاص روی سیستم اول وجود داشته که روی سیستم دوم نیست.
شروع میکنی یکییکی این موارد رو بررسی کردن تا بفهمی مشکل از کجاست.
حالا همین اتفاق رو بزرگتر کن.
وقتی چند نفر روی یک پروژه کار میکنن، یا قراره یک برنامه روی چند سیستم مختلف اجرا بشه، این تفاوتها خیلی راحت تبدیل به دردسر میشن. هرکس ممکنه یه سیستم با تنظیمات متفاوت داشته باشه و پروژه روی یک سیستم درست کار کنه ولی روی سیستم دیگه نه.
اینجا یه سؤال مهم پیش میاد:
چطور میتونیم محیطی که برنامه برای اجرا شدن لازم داره رو هم همراه خود برنامه داشته باشیم؟
ایده اصلی Docker دقیقاً از همینجا شروع میشه.
Docker کمک میکنه برنامه رو به همراه چیزهایی که برای اجرا شدن لازم داره، داخل یک محیط جدا و قابلتکرار قرار بدیم؛ محیطی که میتونیم روی سیستمهای مختلف ایجاد و اجراش کنیم.
برای اینکه این موضوع ملموستر بشه، در ادامه همین ایده رو روی یک پروژه واقعی بررسی میکنیم؛ یک ASP.NET Core Web API که به SQL Server وصل میشه.
در این مسیر با مفاهیمی مثل Container، Dockerfile و Image آشنا میشیم و میبینیم Docker دقیقاً چه مشکلی رو حل میکنه و چرا اصلاً بهش نیاز داریم.
آخر مقاله هم میرسیم به یه سؤال مهمتر:
اصلاً پروژه من به Docker نیاز داره؟
چرا Docker به وجود آمد؟
برگردیم به همون پروژه خودمون.
Developer A پروژه رو ساخته و روی سیستم خودش همهچی آمادهست:
نسخه مناسب .NET نصبه، SQL Server در دسترسه و Configuration موردنیاز پروژه هم تنظیم شده.
Developer B همون کد رو میگیره، ولی سیستمش دقیقاً همین شرایط رو نداره.
شاید نسخه Runtime فرق داشته باشه. شاید تنظیمات دیتابیس متفاوت باشه. شاید برای بالا آوردن پروژه چند مرحله Setup لازم باشه که اصلاً جایی درست ثبت نشده.
هرکدوم از این مشکلات بهتنهایی قابل حلن. دردسر اصلی وقتی شروع میشه که هر نفر جدیدی که وارد تیم میشه، مجبور باشه دوباره حدس بزنه پروژه دقیقاً توی چه شرایطی اجرا میشده.
چون چیزی که برای اجرای پروژه لازم داریم فقط این نیست:
Source Code
بیشتر شبیه اینه:
Source Code + Runtime + Dependencies + Configuration + Services
توی یه پروژه کوچیک شاید این قضیه اصلاً اذیتت نکنه. ولی هرچی تیم بزرگتر بشه یا تعداد سرویسها و تنظیمات بالا بره، تفاوت Environmentها زودتر خودش رو نشون میده.
پس مسئله Docker فقط این نیست که «نصب نرمافزار سخته».
مسئله اصلی اینه:
چطور شرایط اجرای پروژه رو طوری تعریف کنیم که ساختن دوباره همون Environment روی یه سیستم دیگه راحتتر باشه؟
یعنی بهجای اینکه Developer B بشینه سیستمش رو قدمبهقدم شبیه سیستم Developer A کنه، بخشی از Environment موردنیاز پروژه رو همراه خود پروژه تعریف کنیم.
اینجاست که ایده Docker به درد میخوره.
Docker چیست و چه مشکلی را حل میکند؟
اگه بخوایم خیلی ساده بگیم، Docker ابزاریه برای ساخت و اجرای Applicationها داخل Container.
ولی چیزی که مهمتره، ایده پشتشه.
وقتی Source Code پروژه رو برای یه نفر دیگه میفرستی، فقط کد رو جابهجا کردی. هنوز معلوم نیست محیط اجرای اون برنامه روی سیستم نفر بعدی چه شکلیه.
Docker کمک میکنه بخش مهمی از این شرایط اجرا رو هم تعریف کنی.
توی پروژه ما یعنی Developer B قرار نیست تکتک جزئیات سیستم Developer A رو حدس بزنه. API میتونه توی محیطی اجرا بشه که نحوه ساخت و اجرای اون از قبل مشخص شده.
البته Docker قرار نیست یهدفعه همه مشکلات رو جادویی حل کنه.
اگه API باگ داشته باشه، Docker درستش نمیکنه. اگه Connection String اشتباه باشه، مقدار درست رو حدس نمیزنه. حتی قرار نیست تضمین کنه برنامه تحت هر شرایطی روی هر سیستمی دقیقاً یه رفتار داشته باشه.
کاری که Docker برامون بهتر میکنه اینه که محیط اجرای Application قابل تعریفتر و قابل تکرارتر میشه.
Docker این کار رو با مفهومی به اسم Container انجام میده؛ محیطی نسبتاً ایزوله که Application و فایلها و نیازمندیهای اجرای خودش رو داره. (Docker Docs)
Docker Engine چه کار میکند؟
وسط این بحث ممکنه اسم Docker Engine رو هم زیاد ببینی.
فعلاً همینقدر بدون که Docker Engine بخشی از ماجراست که کارهایی مثل ساخت Image و ایجاد و اجرای Containerها رو مدیریت میکنه.
لازم نیست برای فهم Docker همین اول وارد معماری داخلیش بشیم.
چیزی که الان بیشتر به درد ما میخوره این سؤاله:
Docker از کجا میفهمه API ما باید چطور ساخته و اجرا بشه؟
برای جوابش باید سه مفهوم رو کنار هم ببینیم:
Dockerfile → Image → Container
Dockerfile، Image و Container چه ارتباطی دارند؟
اگه Dockerfile، Image و Container رو سه تعریف جدا حفظ کنی، احتمالاً خیلی زود دوباره با هم قاطیشون میکنی.
بهتره از همون اول این سهتا رو یه مسیر ببینی:
Dockerfile
↓
ساخت Image
↓
Image
↓
اجرای Image
↓
Container
حالا همین مسیر رو روی ASP.NET Core API خودمون جلو ببریم.
Dockerfile چیست؟
Developer B کد API رو گرفته، ولی هنوز یه چیز مشخص نیست:
این API دقیقاً باید با چه شرایطی ساخته بشه؟
اینجاست که Dockerfile وارد ماجرا میشه.
Dockerfile در اصل به Docker میگه برای ساخت Image باید چه مراحلی رو انجام بده.
مثلاً میتونه مشخص کنه:
از چه .NET Imageای شروع کن، کد پروژه رو کجا بذار، برنامه رو چطور Publish کن و در آخر چه چیزی باید اجرا بشه.
پس اگه بخوام خیلی کوتاه جمعش کنم:
Dockerfile = دستورالعمل ساخت Image
خود Dockerfile برنامه در حال اجرا نیست. فقط داره مشخص میکنه چیزی که قراره بعداً اجرا بشه، چطور ساخته بشه.
Image چیست؟
خب، Dockerfile رو داریم. حالا Docker اون رو میخونه و Build رو انجام میده.
خروجی این Build میشه Image.
توی سناریوی ما، Image نسخه آمادهای از ASP.NET Core APIه که فایلها و چیزهایی که برای اجرا لازم داره داخلش آماده شده.
پس Developer B دیگه فقط Source Code نداره. میتونه یه خروجی مشخص از API داشته باشه که برای اجرا آماده شده.
ولی یه نکته خیلی مهم:
Image هنوز برنامه در حال اجرا نیست.
تا اینجا داریم:
Dockerfile → Build → Image
Container چیست؟
خب، Image رو ساختیم. ولی هنوز API اجرا نشده.
وقتی Image رو Run میکنیم، Docker از روی اون یه Container میسازه.
اینجاست که API واقعاً بالا میاد و شروع به کار میکنه.
پس این سهتا رو اینطوری از هم جدا کن:
Dockerfile = دستورالعمل ساخت Image
Image = نسخه آماده برای اجرا
Container = نمونه در حال اجرای Image
حتی میشه از یه Image چند Container جدا بالا آورد.
مثلاً اگه Image پروژه SampleApi رو داشته باشیم، میتونیم چند Instance جدا از همون API رو از روی همون Image اجرا کنیم.
Docker هم Container رو یک runnable instance of an image تعریف میکنه؛ یعنی یه نمونه قابل اجرای Image. (Docker Docs)
پس اگه فقط یه چیز از این بخش یادت بمونه، همین باشه:
Dockerfile → Build → Image → Run → Container
این رابطه رو که بگیری، بخش بزرگی از ابهام Docker برات حل میشه.
Docker چه تفاوتی با Virtual Machine دارد؟
Docker و VM هر دو میتونن یه محیط جدا برای اجرای Application بهت بدن، ولی روش کارشون یکی نیست.
توی یه Virtual Machine معمولی، ماشین مجازی معمولاً Guest OS خودش رو داره.
اگه خیلی سادهش کنیم:
Hardware → Host OS → Virtual Machine → Guest OS → Application
Container مدل متفاوتی داره.
توی مدل رایج Linux Containerها، چند Container از یه Linux Kernel مشترک استفاده میکنن و هر Container بیشتر Application، فایلها و Dependencyهای خودش رو جدا نگه میداره.
اگه بخوایم مدل ذهنیش رو ساده کنیم:
Host OS → Container Runtime → Containers
به همین خاطره که Containerها معمولاً نسبت به بالا آوردن یه سیستمعامل کامل برای هر VM، سبکتر اجرا میشن.
ولی یه اشتباه رایج رو همینجا کنار بذاریم:
Docker قرار نیست جای VM رو توی همه سناریوها بگیره.
این دوتا مسئلههای متفاوتی رو حل میکنن و حتی خیلی جاها کنار هم استفاده میشن. مثلاً ممکنه Docker Containerهای تو روی یه Virtual Machine اجرا بشن.
چیزی که برای این مقاله باید یادت بمونه اینه:
Container یه Virtual Machine کوچیکشده نیست.
توی مدل رایج Linux containers، Container Guest OS کامل جداگانهای مثل VM نداره و مدل اجرای متفاوتی داره.
یک ASP.NET Core API را داخل Container اجرا کنیم
قرار نیست اینجا یه Tutorial کامل Docker راه بندازیم.
فقط میخوایم این زنجیرهای که تا الان دربارهش حرف زدیم، یه بار جلوی چشممون اتفاق بیفته:
Dockerfile → Image → Container → Running API
فرض میکنیم:
- Docker از قبل نصب است.
- یک ASP.NET Core Web API سالم داریم.
- نام Assembly پروژه ما SampleApi.dll است.
۱. Dockerfile پروژه
یک Dockerfile ساده میتواند شبیه این باشد:
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src
COPY . .
RUN dotnet publish -c Release -o /app/publish
FROM mcr.microsoft.com/dotnet/aspnet:10.0
WORKDIR /app
COPY --from=build /app/publish .
ENTRYPOINT ["dotnet", "SampleApi.dll"]
اینجا از Imageهای رسمی .NET 10 SDK و ASP.NET Core Runtime 10 استفاده کردیم؛ تگهای 10.0 هم توی Registry رسمی Microsoft وجود دارن. (Microsoft Container Registry)
ممکنه AS build و COPY --from=build توی نگاه اول یه مقدار عجیب به نظر برسن.
این Dockerfile دو مرحله داره، ولی فعلاً لازم نیست وارد بحث Multi-stage Build بشی.
همینقدر بدون که مرحله اول برنامه رو Build و Publish میکنه و مرحله دوم خروجی نهایی رو داخل Imageای میذاره که قراره API رو اجرا کنه.
برای چیزی که الان میخوایم بفهمیم، همین مقدار کاملاً کافیه.
۲. Image را بسازیم
حالا توی پوشهای که Dockerfile قرار داره این دستور رو اجرا میکنیم:
docker build -t sample-api .
وقتی این دستور رو اجرا میکنی، Docker میره سراغ Dockerfile و از روی دستورهایی که داخلش نوشته شده، Imageای با اسم sample-api میسازه.
پس الان داریم:
Dockerfile → Build → Image
۳. Container را اجرا کنیم
حالا که Image آماده شده، میتونیم اجراش کنیم:
docker run --rm -p 8000:8080 --name sample-api sample-api
اینجا عدد سمت چپ یعنی پورتی که روی سیستم خودمون استفاده میکنیم و عدد سمت راست پورتیه که Application داخل Container روی اون گوش میده.
توی Image رسمی ASP.NET Core برای .NET 10، پورت HTTP پیشفرض Container 8080 هست. (Microsoft Learn)
الان Docker از روی Image یه Container ساخته و API داخل اون داره اجرا میشه.
Image → Run → Container
۴. API را ببینیم
حالا یکی از Endpointهای واقعی API خودمون رو از طریق پورت 8000 صدا میزنیم؛ مثلاً:
http://localhost:8000/<your-endpoint>
اگه Endpoint جواب بده، همون زنجیرهای که تا الان دربارهش حرف میزدیم، جلوی چشممون اجرا شده:
Dockerfile → Image → Container → Running API
اگه فقط بخوای ببینی چه Containerهایی الان در حال اجرا هستن، میتونی این دستور رو بزنی:
docker ps
همین.
نمیخوایم این بخش رو تبدیل کنیم به آموزش Docker CLI یا Debugging.
چیزی که لازم بود ببینیم اتفاق افتاد:
Dockerfile مشخص کرد Image چطور ساخته بشه، Image ساخته شد و وقتی اجراش کردیم، Container بالا اومد و API شروع به کار کرد.
ولی پروژه ما هنوز یه تکه مهم کم داره.
SQL Server چی؟
Docker در پروژه ASP.NET Core + SQL Server چگونه استفاده میشود؟
برگردیم به همون پروژه خودمون.
تا اینجا ASP.NET Core API رو داخل Container اجرا کردیم.
ولی API برای کار کردن به SQL Server هم نیاز داره.
شاید اولین چیزی که به ذهنت برسه این باشه که SQL Server رو هم بندازیم توی همون Container.
لازم نیست.
API و SQL Server دو سرویس با مسئولیت متفاوتن و میتونن Containerهای جدا داشته باشن:
ASP.NET Core API
↓
API Container
SQL Server
↓
Database Container
خب، پروژه واقعیتر شد.
ولی حالا سه سؤال تازه داریم:
- API چطور Database رو پیدا کنه؟
- دادههای SQL Server کجا بمونن؟
- این چند Container رو چطور با هم مدیریت کنیم؟
همین سؤالهاست که Network، Volume و Compose رو وارد داستان میکنه.
Network؛ API چطور SQL Server را پیدا میکند؟
API Container باید بتونه با SQL Server Container حرف بزنه.
وقتی سرویسها رو با Docker Compose اجرا میکنیم، Compose بهصورت پیشفرض برای پروژه Network میسازه و سرویسهای داخل همون Network میتونن همدیگه رو با نام Service پیدا کنن. (Docker Docs)
مثلاً اگه سرویس SQL Server توی Compose اسم db داشته باشه، API میتونه برای ارتباط داخلی از همین اسم استفاده کنه.
یعنی لازم نیست IP یه Container رو حفظ کنیم و امیدوار باشیم همیشه همون بمونه.
برای این مقاله همین مدل ذهنی کافیه:
Network = راه ارتباط Containerهای پروژه با هم
فعلاً لازم نیست وارد انواع Docker Network بشیم.
Volume؛ اگر Container دیتابیس حذف شود چه؟
اینجا شرایط API و Database یه کم با هم فرق داره.
اگه API Container رو حذف کنی، معمولاً میتونی دوباره از روی Image بسازیش و بالا بیاری.
ولی دیتابیس داده داره.
حالا فرض کن SQL Server Container رو حذف کردی و دوباره ساختیش. تکلیف اطلاعاتت چی میشه؟
اینجاست که Volume به درد میخوره.
Volume کمک میکنه دادهها به عمر خود Container وابسته نباشن. یعنی میتونی Container رو حذف یا دوباره ایجاد کنی، ولی دادهای که توی Volume نگه داشته شده، مستقل از اون Container باقی بمونه. (Docker Docs)
پس توی پروژه ما:
SQL Server Container
↓
Volume
↓
Database Data
فقط یه نکته رو قاطی نکنیم:
Volume بهتنهایی Backup یا Security داده رو تضمین نمیکنه.
کاری که اینجا برامون انجام میده اینه که داده رو از Lifecycle خود Container جدا میکنه.
Docker Compose؛ سرویسها را چطور کنار هم نگه داریم؟
حالا پروژه حداقل دو سرویس داره:
- API
- SQL Server
تازه Port، Environment Variable، Network و Volume هم داریم.
میتونیم همه اینها رو با دستورهای جدا جدا مدیریت کنیم، ولی خیلی زود کار شلوغ و دردسرساز میشه.
اینجاست که Docker Compose وارد میشه.
Compose بهت اجازه میده سرویسها، Networkها، Volumeها و Configuration اصلی Application رو توی یه فایل YAML تعریف کنی و کل Stack رو کنار هم مدیریت کنی. (Docker Docs)
پس این دوتا رو با هم قاطی نکن:
Dockerfile میگه Image API چطور ساخته بشه.
Compose میگه سرویسهای پروژه چطور کنار هم اجرا بشن.
توی پروژه ما، تصویر کلی این شکلیه:
ASP.NET Core API
↓
Container
SQL Server
↓
Container
Compose
↓
هماهنگکردن سرویسها
Network
↓
ارتباط API و Database
Volume
↓
نگهداری داده Database مستقل از عمر Container
Configuration چه میشود؟
یه بخش دیگه از مشکل اولیهمون Configuration بود.
مثلاً Connection String یا تنظیماتی که بین Development و Environmentهای دیگه فرق دارن.
قرار نیست این چیزها رو بیدلیل داخل Source Code ثابت کنیم.
توی یه پروژه Containerized میتونیم Configuration موردنیاز هر Environment رو از بیرون Application به Container بدیم؛ مثلاً با Environment Variableها.
برای این مقاله همین اصل رو نگه دار:
کد Application و تنظیمات Environment رو تا جای ممکن از هم جدا نگه دار.
Secret Management و تنظیمات Production خودش یه بحث جداست و فعلاً نمیخوایم واردش بشیم.
Docker در پروژه واقعی چه ارزشی ایجاد میکند؟
برگردیم به اول داستان.
Developer B فقط Source Code رو گرفته بود و باید خودش میفهمید چه Runtime، Configuration و سرویسهایی برای بالا آوردن پروژه لازمه.
حالا بخش مهمی از این اطلاعات همراه خود پروژه تعریف شده.
API یه Dockerfile داره.
Image مشخصی از API ساخته میشه.
SQL Server سرویس خودش رو داره.
Network و Volume مشخصن.
Compose هم میتونه تعریف کل Stack رو کنار هم نگه داره.
Docker همه اختلافهای Environment رو جادویی از بین نبرده، ولی شرایط اجرای پروژه قابل پیشبینیتر و قابل تکرارتر شده.
راهاندازی پروژه برای عضو جدید تیم سادهتر میشود
وقتی یه نفر جدید وارد تیم میشه، لازم نیست نصف روز دنبال این باشه که پروژه دقیقاً با چه تنظیماتی روی سیستم نفر قبلی اجرا میشده.
بخش مهمی از Setup، دیگه فقط توی ذهن Developer A نیست؛ همراه پروژه تعریف شده.
تفاوت Environmentها کمتر دردسر ایجاد میکند
وقتی اعضای تیم از Image و Configuration تعریفشده استفاده میکنن، بخشی از تفاوتهای اتفاقی بین سیستمها کمتر میشه.
نه اینکه همه سیستمها کاملاً یکی بشن؛ ولی وابستگی به Setup دستی کمتر میشه.
اجرای چند سرویس قابل مدیریتتر میشود
وقتی پروژه فقط یه API نیست و Database یا سرویسهای دیگه هم کنارش دارن اجرا میشن، مدیریت تکتکشون بهصورت جدا خیلی زود شلوغ میشه.
Compose کمک میکنه تعریف این Stack یه جای مشخص داشته باشه.
محیطها تکرارپذیرتر میشوند
میتونی همون تعریف Application رو دوباره برای Development، Testing یا Environmentهای دیگه استفاده کنی؛ هرچند Configuration هر Environment ممکنه فرق داشته باشه.
هدف این نیست که بگیم «همهجا صددرصد دقیقاً یکسان میشه».
هدف اینه که اجرای پروژه کمتر به تنظیمات دستی یه Machine خاص وابسته باشه.
Image را میتوان منتقل کرد
Image ساختهشده لازم نیست فقط روی سیستم Developer A بمونه.
میتونی اون رو داخل یه Container Registry ذخیره کنی و بعد روی یه سیستم یا Environment دیگه دریافت و اجراش کنی.
Docker Hub هم یکی از Registryهای شناختهشده برای همین کاره.
فعلاً لازم نیست وارد Push، Authentication یا مدیریت Registry بشیم.
همین مدل ذهنی رو نگه دار:
Image میتونه بهعنوان یه خروجی قابل توزیع بین Environmentهای مختلف جابهجا بشه.
تا اینجا کلی مزیت دیدیم.
ولی فقط دیدن مزایا کافی نیست، چون Docker خودش هم یه مقدار پیچیدگی وارد پروژه میکنه.
پس یه سؤال مهمتر داریم.
آیا Docker برای پروژه من مناسب است؟
یه نکته مهم رو همین اول بگیم:
Docker قرار نیست توی همه پروژهها لازم باشه.
اینکه توی خیلی از پروژههای حرفهای Docker میبینی، دلیل نمیشه هر پروژه کوچیکی رو هم حتماً Dockerize کنی.
اول باید ببینی چه مشکلی قرار هست برات حل بشه.
Docker احتمالاً ارزش بیشتری دارد اگر...
چند Developer روی پروژه کار میکنن و Environmentهاشون با هم فرق داره.
پروژه چند سرویس داره؛ مثلاً API و Database.
بالا آوردن پروژه برای یه نفر جدید زمان میبره.
Development یا Testing Environment رو مرتب باید دوباره آماده کنی.
میخوای Build و اجرای Application قابل تکرارتر باشه.
یا Dependencyهای اجرای پروژه خیلی به تنظیمات دستی سیستم افراد وابسته شده.
اینجور وقتها Docker داره یه Pain مشخص رو حل میکنه.
Docker ممکن است فعلاً ارزش اضافهشدن نداشته باشد اگر...
پروژه خیلی کوچیکه.
فقط خودت روش کار میکنی.
Application وابستگی محیطی خاصی نداره.
Setup پروژه چند دقیقه بیشتر طول نمیکشه.
و تفاوت Environment هم تا الان مشکلی برات درست نکرده.
اینجور وقتها ممکنه Docker بیشتر از اینکه کمکت کنه، یه مقدار پیچیدگی اضافه وارد پروژه کنه.
چون از این به بعد باید چیزهایی مثل Image، Container، Port، Network، Volume و Compose رو هم مدیریت کنی.
پس سؤال درست این نیست:
«Docker خوبه یا بد؟»
سؤال بهتر اینه:
«مشکلی که Docker توی پروژه من حل میکنه، ارزش پیچیدگی اضافهای که وارد میکنه رو داره؟»
این تصمیم خیلی مهمتر از اینه که صرفاً برای حرفهایتر به نظر رسیدن پروژه، Docker هم بهش اضافه کنیم.
بعد از فهم Docker چه چیزی را یاد بگیریم؟
اگه تا اینجا مقاله رو دنبال کرده باشی، Docker دیگه یه مشت اسم نامفهوم نیست.
الان میدونی Dockerfile کجای کاره.
Image چیه.
Container چه زمانی ساخته میشه.
Compose چرا وقتی چند سرویس داریم به درد میخوره.
Network و Volume هرکدوم چه مشکلی رو حل میکنن.
از اینجا به بعد لازم نیست یهدفعه بری سراغ Kubernetes و دهها ابزار DevOps.
مسیر منطقی میتونه همین باشه:
Dockerfile پایه
↓
Build و Run
↓
Image و Container
↓
Docker Compose
↓
Network و Volume
↓
تمرین روی یک پروژه واقعی
بهترین قدم بعدی اینه که این مفاهیم رو روی یه پروژه واقعی امتحان کنی.
اگه مسیر اصلیت ASP.NET Coreه، تمرین عملی Docker و Docker Compose در پروژههای ASP.NET Core میتونه ادامه طبیعی همین مسیر باشه؛ جایی که دیگه فقط تعریفها رو نمیخونی و میبینی Docker توی خود پروژه کجا به کارت میاد.
سؤالات متداول Docker
Container چیست؟
Container نمونه در حال اجرای یه Imageه. وقتی Docker Image رو Run میکنی، Container ساخته میشه و Application داخلش اجرا میشه. Container محیط نسبتاً ایزوله خودش رو داره، ولی توی مدل رایج Linux containers مثل یه VM سیستمعامل کامل جداگانه نداره.
تفاوت Image و Container چیست؟
Image نسخه آماده اجرای Applicationه؛ Container همون Imageیه که الان داره اجرا میشه. از یه Image میتونی یک یا چند Container بسازی. پس سادهترین رابطه اینه: Image رو Run میکنیم و Container ساخته میشه.
Dockerfile چه ارتباطی با Image دارد؟
Dockerfile به Docker میگه برای ساخت Image چه مراحلی رو انجام بده. Docker اون رو میخونه، Build رو انجام میده و Image میسازه. پس رابطه اصلی اینه: Dockerfile → Build → Image.
تفاوت Docker و Virtual Machine چیست؟
VM معمولاً Guest OS کامل خودش رو داره. Containerها توی مدل رایج Linux از یه Linux Kernel مشترک استفاده میکنن و Application و Dependencyهای خودشون رو توی محیط جدا اجرا میکنن. به همین دلیل مدل اجرای Container معمولاً سبکتره، ولی Docker و VM جایگزین کامل هم نیستن.
Docker Compose چیست و چه زمانی استفاده میشود؟
وقتی پروژه چند سرویس داره، مثلاً API و SQL Server، Docker Compose کمک میکنه سرویسها، Network، Volume و Configuration اصلی اونها رو توی یه فایل تعریف کنی و کنار هم مدیریت کنی.
آیا Docker برای پروژههای کوچک لازم است؟
نه. اگه پروژه ساده و تکنفرهست و مشکل خاصی هم با Environment یا Setup نداری، Docker ممکنه فقط پیچیدگی اضافه وارد پروژه کنه. بهتره اول ببینی Containerization چه مسئلهای رو قراره برات حل کنه.
Docker برای کار تیمی چه کمکی میکند؟
Docker کمک میکنه بخش مهمی از نحوه ساخت و اجرای پروژه تعریفشده و قابل تکرار باشه. اینطوری نفر جدید تیم کمتر مجبور میشه دنبال Setupها و تنظیماتی بگرده که فقط روی سیستم یکی از اعضای قبلی وجود داشتن.
جمعبندی
ما داستان رو با یه مشکل آشنا شروع کردیم:
ASP.NET Core API روی سیستم Developer A بدون دردسر کار میکرد، ولی وقتی Developer B همون Source Code رو گرفت، Environmentها دقیقاً مثل هم نبودن.
Docker از همینجا وارد ماجرا شد.
بعد قدمبهقدم رسیدیم به این مسیر:
Problem → Docker → Dockerfile → Image → Container
وقتی SQL Server رو هم وارد پروژه کردیم، چند نیاز جدید به وجود اومد:
- Compose برای تعریف سرویسها،
- Network برای ارتباط API و Database،
- و Volume برای اینکه داده Database به عمر خود Container وابسته نباشه.
ولی شاید مهمترین نتیجه مقاله این باشه که Docker قرار نیست به زور وارد همه پروژهها بشه.
اگه چند Developer داری، پروژه چند سرویس داره، Setup پیچیده شده یا برات مهمه Environment رو راحتتر دوباره بسازی، Docker میتونه ارزش زیادی داشته باشه.
ولی اگه پروژه سادهست و Containerization هیچ مشکل مشخصی رو برات حل نمیکنه، اضافهکردن Docker لزوماً پروژه رو حرفهایتر نمیکنه.
پس اگه بخوایم جواب «Docker چیست و چه کاربردی دارد؟» رو خیلی جمعوجور بگیم:
Docker کمک میکنه Application و بخش مهمی از محیط اجرای اون رو بهشکل تعریفشدهتر و قابل تکرارتری بسازیم و اجرا کنیم؛ تا پروژه کمتر به Setup دستی یه سیستم خاص وابسته باشه.
Docker وقتی جذابتر میشه که یه پروژه واقعی پشتش باشه!!
فهمیدن Docker، Image و Container یه قدم مهمه؛ ولی وقتی این مفاهیم واقعاً جا میافتن که پروژهای داشته باشی که API، Database، Environment و اجرای واقعی بخشی از مسئلهاش باشن.
اگه میخوای از «فهمیدن ابزارها» یه قدم جلوتر بری، ساختن پروژههای واقعی با ASP.NET Core MVC و Web API میتونه ادامه منطقی مسیرت باشه. اونجاست که مفاهیمی مثل ساختار پروژه، Backend، Database و آمادهکردن Application برای اجرا، دیگه فقط چند اصطلاح جدا از هم نیستن و توی یک پروژه کنار هم قرار میگیرن.