ساخت Image با Dockerfile و بهینهسازی لایهها
ماهیت یک Docker Image و مفهوم لایهها (Layers)
ایمیج یک قالب فقطخواندنی (Read-Only) شامل سیستمعامل پایه، وابستگیها، کد برنامه و تنظیمات پیشفرض است. کانتینر در حقیقت یک نمونهی در حال اجرا (Instance) از یک ایمیج است که داکر روی آن یک لایهی نازک و موقت برای خواندن و نوشتن (Read/Write Container Layer) قرار میدهد.
هر دستوری در فایل Dockerfile (مانند RUN، COPY، ADD) یک لایهی مجزا به ایمیج اضافه میکند. به لطف مکانیزم Copy-on-Write (CoW)، اگر دو یا چند کانتینر از یک ایمیج ساخته شوند، همهی آنها لایههای ایمیج را بهصورت مشترک میخوانند و هیچ فضای اضافهای مصرف نمیشود.
دستورهای اصلی در Dockerfile
یک Dockerfile فایلی متنی بدون پسوند است که گامهای ساخت یک ایمیج را به صورت خودکار تعریف میکند:
FROM: مشخص کردن ایمیج پایه (مثلاًpython:3.11-slimیاnode:20-alpine). همیشه اولین دستور غیراز کامنت یاARGاست.WORKDIR: تعیین دایرکتوری کاری درون کانتینر برای اجرای دستورات بعدی (بهجای استفادهی نامنظم از دایرکتوری روت/).COPY: کپی کردن فایلها یا دایرکتوریها از سیستم میزبان به داخل ایمیج.ADD: شبیهCOPY، اما توانایی اکسترکت خودکار آرشیوهایtarو دانلود از URL را دارد. در عمل برای جلوگیری از رفتارهای غیرمنتظره، معمولا استفاده ازCOPYتوصیه میشود.RUN: اجرای دستور در زمان ساخت ایمیج (مانند نصب پکیجها باapt-getیاnpm install).ENV: تعریف متغیرهای محیطی که هم در زمان ساخت و هم در زمان اجرای کانتینر در دسترس خواهند بود.ARG: متغیرهای موقتی که فقط در زمان ساخت ایمیج (docker build --build-arg) معتبرند و در ایمیج نهایی ذخیره نمیشوند.EXPOSE: صرفاً یک برچسب مستندسازی (Documentation) برای اعلام پورتی که برنامه روی آن گوش میدهد.CMDوENTRYPOINT: دستوری که هنگام استارت کانتینر اجرا میشود:- فرم استاندارد (Exec Form):
CMD ["python", "app.py"](توصیهشده، بدون ایجاد شل میانی). - فرم شل (Shell Form):
CMD python app.py(تحت پردازش/bin/sh -cاجرا میشود).
- فرم استاندارد (Exec Form):
فایل .dockerignore و Build Context
هنگام اجرای دستور docker build .، نقطهی پایانی (.) نشاندهندهی Build Context است. داکر کلاینت ابتدا تمام فایلهای این مسیر را بستهبندی کرده و برای دیمن داکر میفرستد.
اگر دایرکتوری شما شامل پوشههای حجیمی مانند .git/، node_modules/ یا فایلهای حساسی مانند .env باشد، حجم و زمان بیلد بسیار بالا میرود و احتمال نشت اطلاعات محرمانه وجود دارد.
همیشه در کنار Dockerfile یک فایل به نام .dockerignore بسازید:
بهینهسازی کش لایهها (Layer Caching)
داکر هنگام بیلد، اگر دستوری و فایلهای مرتبط با آن تغییر نکرده باشند، از کش بیلد قبلی استفاده میکند. ترتیب دستورات در Dockerfile بسیار تعیینکننده است:
روش غیراصولی:
در این حالت، با هر تغییر کوچک در کدهای برنامه، خط COPY . . بیلد کش را باطل میکند و دستور سنگین pip install باید هر بار از اول اجرا و دانلود شود!
روش اصولی و بهینه:
در این حالت، تا زمانی که فایل requirements.txt تغییر نکند، داکر مرحلهی نصب وابستگیها را از کش فوری میخواند و زمان بیلد به زیر چند ثانیه کاهش مییابد.
چندمرحلهای ساختن ایمیجها (Multi-stage Builds)
در زبانهای کامپایلری (مانند Go، Rust یا Java) یا برنامههای فرانتاند (React، Vue)، ابزارهای بیلد، کامپایلرها و کدهای سورس حجم بسیار بالایی (چند صد مگابایت یا گیگابایت) دارند، در حالی که در محیط Production فقط به فایل باینری کامپایلشده یا فایلهای خروجی HTML/JS نیاز داریم.
با Multi-stage Build میتوانید چند ایمیج مجزا در یک Dockerfile تعریف کنید و فقط خروجی تمیز را به ایمیج نهایی منتقل کنید:
نتیجه؟ حجم ایمیج نهایی بهجای ۶۰۰ مگابایت به کمتر از ۲۰ مگابایت کاهش مییابد و هیچ ابزار اضافی یا سورس کدی در محیط پروداکشن وجود ندارد که سطح حملات امنیتی را بالا ببرد.
ℹ️ نکته و راهنمای امنیتی: اجرای کانتینر با کاربر غیر روت (
USER)بهطور پیشفرض، کانتینرها با کاربر
rootاجرا میشوند. در محیطهای واقعی و استانداردهای امنیتی Production، اجرای کانتینر با دسترسی root بهدلیل خطرات امنیتی توصیه نمیشود؛ زیرا اگر مهاجم بتواند از برنامهی داخل کانتینر سوءاستفاده کند، ممکن است شانس بیشتری برای فرار از کانتینر (Container Escape) و نفوذ به سیستمعامل میزبان داشته باشد.برای اجرای امن با کاربر غیر روت در
Dockerfile:همچنین در توزیعهای مبتنی بر Alpine میتوانید از
adduserاستفاده کنید:توجه: به دلیل محدودیت زمان دورهی هفتگی و برای جلوگیری از درگیر شدن با خطاهای پیچیدهی دسترسی فایلها (
Permission Denied) در گامهای اولیه، استفاده از این تنظیم در تمرینهای این هفته اختیاری است، اما شناخت آن برای محیطهای واقعی سازمانی ضروری است.
آزمایش عملی: ساخت و اجرای ایمیج با docker build
بیایید یک پروژهی سادهی پایتونی ایجاد کنیم، برای آن Dockerfile بنویسیم، ایمیج را بسازیم و کانتینر آن را اجرا کنیم:
گام ۱: ایجاد دایرکتوری و فایل برنامهی پایتون
یک دایرکتوری به نام python-demo بسازید و وارد آن شوید:
یک اسکریپت پایتون ساده به نام app.py ایجاد کنید:
گام ۲: نوشتن فایل Dockerfile
در همان دایرکتوری، فایلی به نام Dockerfile بسازید:
گام ۳: ساخت ایمیج با دستور docker build
دستور زیر را در همان مسیر اجرا کنید (نقطهی انتهایی نشاندهندهی مسیر فعلی است):
برای مشاهدهی ایمیج ساختهشده در لیست ایمیجهای سیستم:
گام ۴: اجرای کانتینر از روی ایمیج ساختهشده
اکنون کانتینر را از روی ایمیج محلی خود اجرا کنید:
خروجی مشابه زیر در ترمینال چاپ میشود:
همچنین میتوانید با فلگ -e مقدار متغیر محیطی را تغییر دهید:
گام ۵: حذف ایمیج (در صورت عدم نیاز)
منابع یادگیری
ویدیو
- آشنایی و کارهای مقدماتی با داکر قسمت سه از سه — جادی — آموزش فارسی شامل ساخت ایمیج با Dockerfile و مباحث تکمیلی شبکه در داکر
مستندات و مقالات
- Best practices for writing Dockerfiles — الگوهای بهینهسازی لایهها، حجم و امنیت ایمیجها
- Multi-stage builds Guide — راهنمای رسمی پیادهسازی ایمیجهای چندمرحلهای