word image 15692 1

چرا Docker Build کند است؟ ۸ علت و راهکار افزایش سرعت Build

اگر ساخت ایمیج Docker در پروژه شما چند دقیقه طول می‌کشد، باید بدانید که این مشکل همیشه به Dockerfile یا چند خط کد داخل آن محدود نمی‌شود. کند بودن Docker Build می‌تواند از عوامل مختلفی مانند ترتیب نادرست لایه‌ها، ارسال حجم زیادی از فایل‌های غیرضروری، مدیریت نامناسب کش، محدودیت منابع سخت‌افزاری یا حتی زیرساخت CI/CD ناشی شود. به همین دلیل، قبل از اینکه Dockerfile را بارها بازنویسی کنید، بهتر است علت واقعی این کندی را شناسایی کنید.

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

word image 15692 2

Docker Build چگونه کار می‌کند؟

قبل از اینکه سراغ دلایل کندی Docker Build برویم، بهتر است بدانیم هنگام اجرای دستور docker build در پشت صحنه چه اتفاقی رخ می‌دهد. آشنایی با این فرایند باعث می‌شود بهتر درک کنید که چرا گاهی با کوچک‌ترین تغییر در پروژه، زمان ساخت ایمیج به‌طور محسوسی افزایش پیدا می‌کند.

داکر ابتدا پوشه پروژه یا همان Build Context را بررسی می‌کند و فایل‌های موردنیاز را در اختیار موتور Build قرار می‌دهد. سپس Dockerfile را از اولین دستور تا آخرین خط به‌ترتیب اجرا می‌کند. هر دستور مانند FROM، COPY یا RUN یک لایه (Layer) جدید می‌سازد و نتیجه اجرای آن را به‌عنوان بخشی از ایمیج ذخیره می‌کند. پس از پایان اجرای همه دستورات، این لایه‌ها روی یکدیگر قرار می‌گیرند و در نهایت ایمیج Docker ساخته می‌شود.

نکته مهم این است که داکر برای جلوگیری از اجرای دوباره مراحل تکراری، لایه‌های ساخته‌شده را در حافظه کش (Layer Cache) نگه می‌دارد. بنابراین اگر در Build بعدی تغییری در یک لایه ایجاد نشده باشد، داکر همان لایه را از کش می‌خواند و بدون اجرای مجدد از آن استفاده می‌کند. اما اگر یکی از لایه‌ها تغییر کند، تمام لایه‌هایی که بعد از آن قرار دارند نیز باید دوباره ساخته شوند. به همین دلیل، ترتیب دستورات داخل Dockerfile و نحوه مدیریت کش، تأثیر مستقیمی بر سرعت ساخت ایمیج دارند.

چرا باید کند بودن Docker Build را سریع درست کرد؟

شاید در نگاه اول چند دقیقه انتظار برای ساخت یک ایمیج چندان مهم به نظر نرسد، اما وقتی این تأخیر در طول روز بارها تکرار شود، هزینه واقعی آن مشخص می‌شود. تصور کنید یک تیم ۱۰ نفره توسعه نرم‌افزار، هر روز به‌طور متوسط ۵ بار Docker Build اجرا می‌کند و هر Build حدود ۱۵ دقیقه زمان می‌برد. در چنین شرایطی، سالانه بیش از ۳۰۰۰ ساعت از زمان کاری تیم صرف انتظار برای پایان Build می‌شود؛ زمانی که تقریباً معادل کار یک و نیم نیروی تمام‌وقت است.

البته هزینه این موضوع فقط به اتلاف زمان محدود نمی‌شود. انتظار برای پایان Build معمولاً باعث پدیده‌ای به نام Context Switching یا جابه‌جایی ذهنی می‌شود. در این فاصله، توسعه‌دهنده به سراغ بررسی ایمیل‌ها، پاسخ دادن به پیام‌ها یا انجام کارهای دیگر می‌رود و تمرکز خود را روی مسئله اصلی از دست می‌دهد. بازگشت دوباره به همان سطح از تمرکز نیز به زمان نیاز دارد و در آخر، سرعت توسعه پروژه و بهره‌وری کل تیم کاهش پیدا می‌کند.

word image 15692 3

مهم‌ترین دلایل کند بودن Docker Build را بشناسید!

تا اینجا با نحوه عملکرد Docker Build آشنا شدیم و دیدیم که فرآیند ساخت ایمیج چگونه انجام می‌شود. حالا نوبت آن است که مهم‌ترین عواملی را بررسی کنیم که باعث افزایش زمان Build می‌شوند. بعضی از این مشکلات به نحوه نوشتن Dockerfile مربوط هستند و برخی دیگر به زیرساخت، منابع سخت‌افزاری یا تنظیمات محیط توسعه ارتباط دارند. اگر علت اصلی را به‌درستی شناسایی کنید، رفع مشکل نیز بسیار ساده‌تر خواهد بود.

۱. Build Context بیش از حد بزرگ است

اولین دلیل کند بودن Docker Build، بزرگ بودن Build Context است. Build Context همان پوشه پروژه‌ای است که هنگام اجرای دستور docker build برای موتور Build ارسال می‌شود. هرچه این پوشه فایل‌ها و پوشه‌های بیشتری داشته باشد، زمان بیشتری نیز صرف انتقال و پردازش آن خواهد شد.

قبل از شروع Build، داکر کل پوشه پروژه را بررسی می‌کند. اگر فایل‌ها و پوشه‌های غیرضروری مانند node_modules، .git، dist، coverage، فایل‌های Log یا حتی فایل‌های موقت داخل پروژه وجود داشته باشند، در هر بار Build دوباره بررسی و ارسال می‌شوند؛ در نتیجه، حتی قبل از اجرای اولین دستور Dockerfile نیز بخشی از زمان Build هدر می‌رود.

بهترین راه‌حل برای این مشکل، استفاده از فایل .dockerignore است. این فایل عملکردی مشابه .gitignore دارد و به داکر اعلام می‌کند کدام فایل‌ها و پوشه‌ها نباید وارد Build Context شوند. با حذف فایل‌های غیرضروری، حجم داده‌های ارسالی کاهش پیدا می‌کند و زمان Build نیز به‌طور محسوسی کمتر خواهد شد.

۲. Layer Cache دائماً از بین می‌رود

دومین عاملی که باعث کند شدن Docker Build می‌شود، از بین رفتن مداوم Layer Cache است. همان‌طور که گفته شد، داکر نتیجه اجرای هر دستور Dockerfile را به‌صورت یک لایه ذخیره می‌کند تا در Buildهای بعدی دوباره از آن استفاده کند. اما اگر این کش بی‌دلیل باطل شود، داکر مجبور خواهد شد تمام مراحل بعدی را دوباره اجرا کند.

برای مثال اگر در ابتدای Dockerfile کد زیر را قرار دهید:

COPY . .

RUN npm install

با کوچک‌ترین تغییری در پروژه، حتی اگر فقط فایل README.md را ویرایش کرده باشید، کش از بین می‌رود و دستور npm install دوباره اجرا خواهد شد. این موضوع در پروژه‌هایی که تعداد زیادی وابستگی دارند، می‌تواند چندین دقیقه به زمان Build اضافه کند.

برای جلوگیری از این مشکل، بهتر است ابتدا فایل‌های مربوط به وابستگی‌ها را کپی کنید و سپس عملیات نصب را انجام دهید.

COPY package*.json ./

RUN npm ci

COPY . .

در این حالت تا زمانی که فایل‌های package.json یا package-lock.json تغییر نکنند، مرحله نصب وابستگی‌ها از کش خوانده می‌شود و دیگر نیازی به اجرای مجدد آن نخواهد بود.

۳. وابستگی‌ها در هر Build دوباره نصب می‌شوند

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

برای پروژه‌های Node.js بهتر است به‌جای npm install از دستور npm ci استفاده کنید. این دستور بر اساس فایل package-lock.json وابستگی‌ها را به‌صورت سریع‌تر و قابل پیش‌بینی نصب می‌کند و گزینه مناسب‌تری برای محیط‌های CI/CD محسوب می‌شود. همچنین اگر از BuildKit استفاده می‌کنید، می‌توانید با قابلیت Cache Mount کش دانلود پکیج‌ها را بین Buildهای مختلف حفظ کنید تا نیاز به دانلود مجدد آن‌ها نباشد.

۴. ترتیب لایه‌های Dockerfile مناسب نیست

همان‌طور که پیش‌تر نیز اشاره کردیم، ترتیب دستورات داخل Dockerfile تأثیر مستقیمی بر عملکرد Layer Cache دارد. اگر فایل‌هایی که مرتب تغییر می‌کنند در ابتدای Dockerfile قرار بگیرند، با هر تغییر کوچک، تمام مراحل بعدی دوباره اجرا خواهند شد و زمان Build افزایش پیدا می‌کند.

بهترین ترتیب برای بیشتر پروژه‌ها به شکل زیر است:

  1. کپی فایل‌های وابستگی
  2. نصب وابستگی‌ها
  3. کپی کد پروژه
  4. Build برنامه

هرچه فایل‌های کم‌تغییرتر در ابتدای Dockerfile قرار بگیرند، احتمال استفاده از Cache بیشتر خواهد بود.

۵. از BuildKit استفاده نمی‌کنید

یکی دیگر از دلایل رایج کند بودن Docker Build، استفاده نکردن از BuildKit است. بسیاری از توسعه‌دهندگان هنوز از موتور قدیمی Build استفاده می‌کنند یا حتی از وجود BuildKit اطلاع ندارند؛ در حالی که این قابلیت در نسخه‌های جدید Docker امکانات متعددی برای افزایش سرعت ساخت ایمیج در اختیار شما قرار می‌دهد.

BuildKit با اجرای هم‌زمان مراحل مستقل، مدیریت هوشمندتر کش، پشتیبانی از Cache Mount و بهینه‌سازی فرآیند Build، می‌تواند زمان ساخت ایمیج را به میزان قابل توجهی کاهش دهد.

برای فعال کردن آن کافی است متغیر محیطی زیر را تنظیم کنید:

export DOCKER_BUILDKIT=1

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

۶. Base Image بسیار بزرگ است

یکی دیگر از عواملی که روی سرعت Docker Build تأثیر منفی می‌گذارد، انتخاب Base Image نامناسب است. هرچه حجم ایمیج پایه بیشتر باشد، زمان دانلود، Build و حتی Push کردن ایمیج نیز افزایش پیدا می‌کند. علاوه بر این، ایمیج‌های حجیم فضای ذخیره‌سازی بیشتری اشغال می‌کنند و انتقال آن‌ها در محیط‌های CI/CD زمان‌برتر خواهد بود.

جدول زیر مقایسه‌ای بین چند Image رایج را نشان می‌دهد.

Image

حجم تقریبی

پیشنهاد

node

زیاد

node:slim

متوسط

node:alpine

کم

python

زیاد

python:slim

کمتر

البته همیشه کوچک‌ترین Image بهترین انتخاب نیست. برای مثال، نسخه‌های Alpine اگرچه حجم بسیار کمی دارند، اما ممکن است با برخی کتابخانه‌ها یا وابستگی‌های بومی سازگار نباشند. بنابراین، هنگام انتخاب Base Image باید علاوه بر حجم، سازگاری و نیازهای پروژه را نیز در نظر بگیرید.

۷. محدودیت منابع سخت‌افزاری

گاهی اوقات اصلاً مشکل از Dockerfile یا تنظیمات Build نیست، بلکه سیستم یا سروری که Build روی آن اجرا می‌شود، منابع کافی در اختیار ندارد. کمبود CPU، حافظه RAM، سرعت پایین Disk I/O یا استفاده از هاردهای HDD به‌جای SSD، همگی می‌توانند زمان ساخت ایمیج را افزایش دهند.

این موضوع در محیط‌های CI/CD بیشتر به چشم می‌خورد؛ زیرا بسیاری از تیم‌ها از Shared Runner استفاده می‌کنند و منابع سخت‌افزاری بین چندین پروژه تقسیم می‌شود. اگر بعد از بهینه‌سازی Dockerfile همچنان زمان Build زیاد است، بهتر است زیرساخت اجرای Build را نیز بررسی کنید.

اگر نمی‌خواهید زمان و هزینه زیادی برای مدیریت این زیرساخت صرف کنید، استفاده از یک پلتفرم ابری (PaaS) که فرآیند Build و Deploy را روی زیرساخت بهینه انجام می‌دهد، می‌تواند انتخاب مناسبی باشد. برای مثال، در چابکان Build و استقرار پروژه روی زیرساخت مدیریت‌شده انجام می‌شود و دیگر نیازی نیست نگران محدودیت منابع، مدیریت Runnerها یا تنظیمات پیچیده زیرساخت باشید.

  • اگر با مفهوم PaaS آشنا نیستید، پیشنهاد می‌کنیم ابتدا این مقاله را مطالعه کنید.

۸. کش در CI/CD حفظ نمی‌شود

آخرین عامل مهمی که معمولاً نادیده گرفته می‌شود، حفظ نشدن کش در خط لوله CI/CD است. اگر در هر بار اجرای Pipeline تمام مراحل Build از ابتدا اجرا شوند، زمان ساخت به‌مرور افزایش پیدا می‌کند؛ به‌خصوص در پروژه‌هایی که وابستگی‌های زیادی دارند.

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

word image 15692 4

راهکارهای افزایش سرعت Docker Build

جدول زیر خلاصه‌ای از مهم‌ترین روش‌های بهینه‌سازی را نشان می‌دهد.

راهکار

در چه موقع و چگونه کمک می‌کند؟

استفاده از فایل نادیده‌گیری داکر (.dockerignore)

زمانی که پوشه پروژه فایل‌های اضافی دارد؛ با حذف آن‌ها از زمینه ساخت (Build Context)، زمان Build کاهش می‌یابد.

رعایت ترتیب صحیح لایه‌ها (Layer Ordering)

زمانی که فایل‌های پروژه مرتب تغییر می‌کنند؛ باعث می‌شود حافظه نهان لایه‌ها (Layer Cache) کمتر از بین برود.

فعال‌سازی بیلدکیت (BuildKit)

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

استفاده از ساخت چندمرحله‌ای (Multi-stage Build)

زمانی که حجم ایمیج زیاد است؛ فایل‌های غیرضروری را از ایمیج نهایی حذف می‌کند.

استفاده از کش موقت (Cache Mount)

زمانی که وابستگی‌ها در هر Build دوباره دانلود می‌شوند؛ از دانلود مجدد جلوگیری می‌کند.

انتخاب ایمیج پایه سبک (Lightweight Base Image)

زمانی که دانلود یا انتقال ایمیج زمان‌بر است؛ حجم ایمیج را کاهش می‌دهد.

ترکیب دستورهای اجرا (RUN)

زمانی که Dockerfile لایه‌های زیادی ایجاد می‌کند؛ تعداد لایه‌ها و حجم نهایی را کمتر می‌کند.

اشتباهات رایج توسعه‌دهندگان

برخی اشتباهات حتی در پروژه‌های حرفه‌ای نیز دیده می‌شوند:

  • استفاده از COPY . . در ابتدای Dockerfile
  • استفاده از Imageهای بسیار بزرگ
  • نداشتن فایل .dockerignore
  • اجرای چندین دستور RUN به‌صورت جداگانه
  • استفاده نکردن از Multi-stage Build
  • مشخص نکردن نسخه وابستگی‌ها (Pinned Versions)
  • دانلود فایل‌ها از اینترنت در هر Build

اجتناب از همین اشتباهات می‌تواند زمان ساخت را به شکل محسوسی کاهش دهد.

word image 15692 5

آیا مشکل همیشه از Dockerfile است؟

در بسیاری از پروژه‌ها، Dockerfile کاملاً بهینه است اما Build همچنان با سرعت پایینی اجرا می‌شود. این موضوع نشان می‌دهد که همیشه نباید مشکل را در Dockerfile یا کد پروژه جستجو کرد. گاهی گلوگاه اصلی، زیرساختی است که Build روی آن اجرا می‌شود.

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

در چنین شرایطی باید عواملی مانند منابع پردازشی (CPU)، حافظه (RAM)، سرعت ورودی و خروجی دیسک (Disk I/O)، شبکه، حافظه کش (Cache) و حتی خط لوله CI/CD را بررسی کنید. این مشکلات معمولاً در سرورهای اشتراکی، Shared Runnerها یا زیرساخت‌هایی با منابع محدود بیشتر دیده می‌شوند و می‌توانند زمان Build را حتی با وجود یک Dockerfile بهینه، افزایش دهند.

اگر نمی‌خواهید با چنین محدودیت‌هایی روبه‌رو شوید، بهتر است از یک زیرساخت ابری استفاده کنید که متناسب با نیاز پروژه، منابع پردازشی و زیرساخت Build را در اختیارتان قرار دهد. در این حالت، تیم توسعه به‌جای درگیر شدن با مدیریت سرور، بهینه‌سازی زیرساخت و رفع مشکلات Build، می‌تواند روی توسعه قابلیت‌های جدید و بهبود محصول تمرکز کند.

ما در چابکان این زیرساخت را به‌صورت مدیریت‌شده در اختیار تیم‌های توسعه قرار داده‌ایم تا بتوانند Build و Deploy پروژه‌های خود را سریع‌تر، ساده‌تر و بدون دغدغه مدیریت زیرساخت انجام دهند. بنابراین اگر رشد پروژه باعث شده محدودیت‌های زیرساختی به یکی از گلوگاه‌های توسعه تبدیل شود، استفاده از یک پلتفرم ابری (PaaS) مانند چابکان می‌تواند راهکاری مناسب برای رفع این چالش باشد.

چک‌لیست عیب‌یابی Docker Build Slow

قبل از هر تغییر، این موارد را بررسی کنید:

☐ فایل .dockerignore ایجاد شده است.

☐ ترتیب Layerها بر اساس میزان تغییر تنظیم شده است.

☐ از BuildKit استفاده می‌کنید.

☐ وابستگی‌ها با Cache Mount مدیریت می‌شوند.

☐ از Multi-stage Build استفاده شده است.

☐ Base Image مناسب انتخاب شده است.

☐ کش CI/CD حفظ می‌شود.

☐ منابع سخت‌افزاری سیستم کافی هستند.

word image 15692 6

جمع‌بندی

کند بودن Docker Build همیشه به Dockerfile مربوط نمی‌شود. هرچند با استفاده از تکنیک‌هایی مانند فایل نادیده‌گیری داکر (.dockerignore)، ساخت چندمرحله‌ای (Multi-stage Build) و کش موقت (Cache Mount) می‌توانید زمان Build را به‌طور قابل توجهی کاهش دهید، اما اگر مشکل همچنان ادامه داشت، بهتر است زیرساخت CI/CD، منابع سخت‌افزاری، سرعت ورودی و خروجی دیسک (Disk I/O)، شبکه و مدیریت کش را نیز بررسی کنید؛ زیرا در بسیاری از پروژه‌ها، گلوگاه اصلی در زیرساخت قرار دارد، نه در Dockerfile.

اگر می‌خواهید توسعه‌دهندگان به‌جای درگیر شدن با مشکلات زیرساخت، تمام تمرکز خود را روی توسعه محصول بگذارند، چابکان می‌تواند این مسیر را ساده‌تر کند. چابکان به‌عنوان یک پلتفرم ابری (PaaS)، با فراهم کردن زیرساخت مدیریت‌شده برای Build و Deploy و با بیش از ۷۵ هزار استقرار موفق، به تیم‌های نرم‌افزاری کمک می‌کند تا سریع‌تر و بدون پیچیدگی‌های رایج، پروژه‌های خود را منتشر کنند.

با شروع رایگان، می‌توانید امکانات چابکان را از نزدیک تجربه کنید و ببینید چگونه مدیریت Build، Deploy و زیرساخت پروژه‌ها را ساده‌تر و سریع‌تر می‌کند.

سوالات متداول

1. چرا Docker Build هر بار از ابتدا شروع می‌شود؟

معمولاً به دلیل از بین رفتن Layer Cache، تغییر Build Context یا تغییر ترتیب دستورات Dockerfile است.

2. BuildKit چه مزیتی نسبت به Build قدیمی دارد؟

BuildKit از کش هوشمند، اجرای موازی، Cache Mount و قابلیت‌های بهینه‌سازی پیشرفته پشتیبانی می‌کند و سرعت Build را افزایش می‌دهد.

3. آیا استفاده از Multi-stage Build همیشه ضروری است؟

برای اکثر پروژه‌های Production بله. این روش حجم Image نهایی را کاهش می‌دهد و باعث افزایش سرعت انتقال، استقرار و اجرای کانتینر می‌شود.

4. آیا استفاده از Alpine همیشه بهترین انتخاب است؟

خیر. اگرچه Alpine حجم بسیار کمی دارد، اما ممکن است با برخی کتابخانه‌ها یا ابزارهای بومی سازگاری کامل نداشته باشد. در بسیاری از پروژه‌ها، نسخه‌های slim تعادل بهتری بین حجم، سازگاری و عملکرد ایجاد می‌کنند.

5. اگر Dockerfile بهینه باشد اما Build همچنان کند باشد، چه باید کرد؟

در این حالت باید گلوگاه‌های خارج از Dockerfile را بررسی کنید؛ از جمله منابع CPU و RAM، سرعت Disk I/O، وضعیت شبکه، رجیستری Docker، تنظیمات BuildKit و کش CI/CD. در پروژه‌های بزرگ، این عوامل تأثیر بیشتری از خود Dockerfile دارند.

 

نوشتن ته مزه ای از خلق کردن داره

دیدگاه خود را بنویسید:

آدرس ایمیل شما نمایش داده نخواهد شد.

فوتر سایت