أحمد حايس
الرئيسيةمن أناالدوراتالمدونةالعروض
أحمد حايس

دورات عربية متخصصة في التقنية والبرمجة والذكاء الاصطناعي.

المنصة مبنية على الوضوح، التطبيق، والنتيجة النافعة: شرح مرتب يساعدك تفهم الأدوات، تكتب كودًا أفضل، وتستخدم الذكاء الاصطناعي بوعي داخل العمل الحقيقي.

تعلم أسرعوصول مباشر للدورات والمسارات من الموبايل.
تنقل أوضحالروابط الأساسية والدعم في مكان واحد بدون تشتيت.

المنصة

  • الرئيسية
  • من أنا
  • الدورات
  • العروض
  • المدونة

الدعم

  • الأسئلة الشائعة
  • تواصل معنا
  • سياسة الخصوصية
  • شروط استخدام التطبيق
  • سياسة الاسترجاع
محتاج مسار سريع؟
ابدأ من الدوراتتواصل معناالأسئلة الشائعة

© 2026 أحمد حايس. جميع الحقوق محفوظة.

الرئيسيةالدوراتالعروضالمدونةالدخول

Docker BuildKit Cache: قلل زمن الـ CI Build للنصف

📅 ٢٤ أبريل ٢٠٢٦⏱ 4 دقائق قراءة
Docker BuildKit Cache: قلل زمن الـ CI Build للنصف

مستوى القارئ: متوسط

Docker BuildKit Cache: قلل زمن الـ CI Build للنصف

هتخرج من المقال بإعداد عملي يقلل Docker build في CI من حوالي 6 دقائق إلى 2 أو 3 دقائق في مشاريع Node أو Python المتوسطة.

المشكلة باختصار

الطريقة الشائعة هي إنك تكتب Dockerfile شغال وخلاص. الطريقة دي بتفشل لمّا كل تعديل صغير في source file يخلي CI ينزل التبعيات من الأول. اللي بيحصل فعلاً إن ترتيب الطبقات والـ cache scope بيكسروا الاستفادة من BuildKit.

الافتراض إن عندك تطبيق ويب بحجم متوسط: 300 إلى 900 dependency، وCI runner مؤقت بيتبني من الصفر في كل Pull Request. في الحالة دي build مدته 6:20 دقيقة ممكن ينزل إلى 2:10 دقيقة بعد تفعيل cache mounts وregistry cache. الرقم تقديري، لكنه قريب من اللي بتشوفه في pipelines بتثبت npm أو pip كل مرة.

مخطط بصري يوضح استخدام Docker BuildKit cache mounts وregistry cache لتقليل زمن بناء الصور في CI

المفهوم: الكاش مش نوع واحد

ركز في الفرق ده. Docker layer cache بيشتغل لما التعليمة والملفات المرتبطة بها لم تتغير. لو كتبت COPY . . قبل RUN npm ci، أي تعديل في ملف JavaScript عادي ممكن يكسر طبقة تثبيت التبعيات. Docker نفسه يشرح إن ترتيب الـ layers وتقليل build context من أهم طرق تحسين الكاش.

BuildKit cache mounts مختلفة. هي مكان ثابت لتخزين cache مدير الحزم، مثل /root/.npm أو /root/.cache/pip. حتى لو طبقة RUN اتبنت من جديد، الحزم القديمة تفضل موجودة ويتنزّل الجديد فقط. Docker Docs تذكر إن cache mounts مفيدة تحديدًا لخطوات package managers لأنها تراكمية عبر builds.

إعداد عملي لـ Node.js

أفضل طريقة تبدأ بها هي إعادة ترتيب Dockerfile قبل إضافة أي أداة جديدة. بتكسب cache hit أعلى، وبتخسر بس شوية وضوح لو الفريق مش متعود على تقسيم COPY.

مقارنة مبسطة بين Dockerfile يكرر تنزيل التبعيات بعد كل تغيير وترتيب آخر يقلل كسر الكاش
Dockerfile
# syntax=docker/dockerfile:1.7
FROM node:22-alpine AS deps
WORKDIR /app

COPY package.json package-lock.json ./
RUN --mount=type=cache,target=/root/.npm \
    npm ci

FROM node:22-alpine AS build
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build

FROM node:22-alpine AS runtime
WORKDIR /app
ENV NODE_ENV=production
COPY --from=build /app/dist ./dist
COPY package.json ./
CMD ["node", "dist/server.js"]

المهم هنا إن package-lock.json هو المفتاح. لو اتغير، طبيعي npm ci يتعاد. لو عدلت src/user.controller.ts فقط، المفروض التبعيات لا تتنزل من الصفر.

إعداد CI مع registry cache

لو runner مؤقت، local cache لوحده مش كفاية. استخدم registry cache عشان BuildKit يسحب cache من build سابق. Docker Docs توضح إن external cache شبه أساسي في CI/CD لأن بيئات البناء غالبًا قليلة أو معدومة الاستمرارية.

YAML
name: docker-build
on: [push, pull_request]

jobs:
  image:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: docker/setup-buildx-action@v3
      - uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - uses: docker/build-push-action@v6
        with:
          context: .
          push: false
          tags: ghcr.io/org/app:pr-${{ github.sha }}
          cache-from: type=registry,ref=ghcr.io/org/app:buildcache
          cache-to: type=registry,ref=ghcr.io/org/app:buildcache,mode=max

الـ trade-off هنا واضح. بتكسب build أسرع بين PRs، وبتخسر مساحة تخزين في registry واحتمال تعقيد بسيط في صلاحيات الدفع. لو عندك 20 PR يوميًا وكل build بيوفر 3 دقائق، فأنت وفرت حوالي ساعة runner يوميًا. لو الدقيقة بتكلف 0.008 دولار، التوفير مش ضخم ماليًا، لكنه مؤثر في سرعة مراجعة الكود.

قياس النتيجة بدل الإحساس

متقيسش بالانطباع. شغّل build مرتين. الأولى باردة، والثانية بعد تعديل ملف لا يغير dependencies. شوف زمن خطوة npm ci وزمن الـ build الكلي.

Bash
docker buildx build --progress=plain -t app:test .
# عدل ملف داخل src فقط
Measure-Command { docker buildx build --progress=plain -t app:test . }

لو npm ci لسه بياخد نفس الزمن، غالبًا cache mount مش شغال أو ترتيب COPY غلط. لو الفرق ظهر محليًا ومظهرش في CI، راجع cache-from وcache-to وصلاحيات registry.

متى لا تستخدم هذه الطريقة

لا تستخدم registry cache لو المشروع صغير جدًا وbuild أقل من 45 ثانية. وقت سحب ورفع الكاش ممكن يبقى أكبر من المكسب. كمان لا تستخدم mode=max لو مساحة registry عندك محدودة جدًا أو عندك سياسة تنظيف aggressive. في monorepo كبير، ابدأ بخدمة واحدة بدل ما تطبق الكاش على كل الصور مرة واحدة.

المصادر

  • Docker Docs: Optimize cache usage in builds
  • Docker Docs: Cache storage backends
  • Docker Docs: Multi-stage builds

الخطوة التالية

افتح Dockerfile في أكثر خدمة build عندك، وانقل تثبيت التبعيات قبل نسخ باقي الملفات. بعدها أضف cache mount، وقارن زمن build قبل وبعد في رقم واحد واضح.

هل استفدت من المقال؟

اطّلع على المزيد من المقالات والدروس المجانية من نفس المسار المعرفي.

تصفّح المدونة