يجب أن يكون بناء Docker في الإنتاج سريعًا لأنه يعيد استخدام عمل آمن، لا لأنه يعيد استخدام مدخلات مجهولة بصمت. التصميم الموثوق يفصل أربع طبقات: مدخلات مثبتة أو قابلة للمراجعة، وBuildKit Cache قابل للحذف، وSecret Mounts مؤقتة، وRuntime Image صغيرة يُنشر Digest الخاص بها مع إقرارات SBOM وProvenance. هكذا تحصل CI على السرعة من دون تحويل الـCache إلى حقيقة الإصدار أو دفن Credential داخل Layer.
يعتمد هذا الدليل على وثائق Docker الرسمية لـBuildKit وDockerfile التي جرى التحقق منها في 5 أكتوبر 2026. توثق Docker الآليات؛ أما حدود الثقة وسياسة الإطلاق وبوابات CI أدناه فهي توصيات هندسية. هذا شرح عملي وليس إعلانًا عن إصدار جديد من Docker.
افصل أنواع إعادة الاستخدام الثلاثة
تسمي فرق كثيرة كل شيء “Docker Cache”، لكن BuildKit يعيد استخدام العمل بثلاث آليات مختلفة. يعيد Layer Cache العادي نتيجة تعليمة Dockerfile عندما تبقى مدخلاتها مطابقة. ويمنح Cache Mount مدير الحزم مجلد عمل مستمرًا مع بقاء تعليمة RUN قيد التنفيذ. أما External Cache فيصدّر سجلات البناء القابلة لإعادة الاستخدام إلى Registry أوBackend مدعوم كي يستوردها CI Worker مؤقت في تشغيل لاحق.
هذه الآليات للتسريع وليست دليلًا على أمان Artifact. تعني Cache Hit أن BuildKit وجد سجلًا مطابقًا وفق قواعده؛ ولا تعني أن Base Image روجعت حديثًا أوأن Lockfile معتمدة أوأن الصورة اجتازت سياسة الأمن الحالية. اجعل قرار الإصدار بعد البناء لا داخله.
يوصي دليل Docker لتحسين Cache بترتيب Layers بعناية وتصغير Build Context واستخدام Cache Mounts لتنزيلات مديري الحزم. استخدم ذلك لتجنب الشبكة والترجمة المتكررة، لكن لا تجعل النشر يعتمد على بقاء Cache Entry معينة؛ يجب أن تنتج Builder نظيفة صورة صحيحة أيضًا.
اجعل مدخلات البناء قابلة للمراجعة
ابدأ من Base Image. وسوم Docker متغيرة؛ يستطيع الناشر توجيه Tag إلى صورة أحدث. يوضح دليل أفضل ممارسات البناء أن تثبيت الصورة بالـDigest يختار المحتوى نفسه، لكنه يمنع وصول إصلاحات الأمن تلقائيًا. عامل الـDigest كاعتمادية خضعت للمراجعة وحدّثها بتغيير ظاهر يمر بالبناء والاختبار.
طبّق النموذج نفسه على اعتماديات التطبيق. خزّن Lockfile، واستخدم وضع التثبيت النظيف أوالمجمّد، وافشل إذا اختلف Manifest عن Lockfile. وللملفات البعيدة استخدم مصدرًا محدد الإصدار مع Checksum موثقة؛ يدعم Dockerfile التحقق من Checksum لمدخلات ADD البعيدة. الرابط الذي يعيد “latest” دائمًا ليس مدخلًا قابلًا للتكرار لمجرد أن Docker خزّنه مرة.
قلّص Build Context بواسطة .dockerignore. استبعد Credentials المحلية وقواعد بيانات التطوير ونواتج الاختبار وبيانات VCS والملفات غير المرتبطة. السياق الأصغر يحسن النقل ودقة الـCache، لكن الفائدة الأمنية أهم: الملف الذي لا يصل إلى Builder لا يمكن أن تنسخه تعليمة COPY واسعة لاحقًا بالخطأ.
رتّب Dockerfile بحسب حدود الإبطال
ضع الخطوات المستقرة والمكلفة قبل Source الذي يتغير كثيرًا. في خدمة Node انسخ package.json وLockfile، وثبّت الاعتماديات، ثم انسخ التطبيق. إذا نسخت المصدر قبل التثبيت فكل تعديل برمجي يبطل Dependency Layer المكلفة ولو لم تتغير شجرة الاعتماديات.
هذا لا يعني إخفاء التغييرات الحقيقية عن Cache. يجب أن تعتمد خطوة التثبيت على كل ملف يتحكم بالحل: Manifest وLockfile وإعدادات مدير الحزم وPlatform Args ذات الصلة. وإذا غيّر Build Script أوGenerated Client الناتج المثبت، فأدخل مدخله قبل الخطوة أوانقل التوليد إلى Stage صريحة.
استخدم أسماء للمراحل واجعل Production Stage الأخيرة هي الافتراضية. تشرح وثائق Multi-stage builds كيف تنسخ مرحلة متأخرة Artifacts مختارة فقط من Builder. وتبقى الأسماء صحيحة بعد إعادة ترتيب Dockerfile، كما تسمح لـCI باستهداف Test أوDebug Stage من دون شحنها.
استخدم Cache Mount كوسيلة تسريع قابلة للحذف
يسمح Package Cache Mount لـnpm أوpnpm أوapt أوpip بالاحتفاظ بالملفات المنزلة بين عمليات البناء من دون نسخ هذا الـCache إلى Image. تبقى تعليمة RUN قيد التنفيذ ويبقى مدير الحزم مسؤولًا عن التحقق. يختلف ذلك عن Cached Layer حيث يمكن إعادة نتيجة التعليمة كاملة.
اختر Target خاصًا بمدير الحزم وحدد Sharing Mode يطابق نموذج التزامن. تستخدم أمثلة Docker sharing=locked للأدوات التي تحتاج وصولًا حصريًا. وفي CI متعدد العملاء لا تسمح لمستودعات غير موثوقة بمشاركة Writable Cache Namespace. اعزل External Cache حسب المستودع ومستوى الثقة، وافصل Protected Branches عن فروع غير موثوقة.
لا تنقل محتوى Cache Mount إلى Runtime Image. انسخ Output المثبت والموثّق من Build Stage. قد يُحذف Cache أويمتلئ جزئيًا أوينشئه إصدار أقدم من الأداة؛ يجب أن تأتي الصحة من Package Manager وLockfile، لا من استمرار Bytes في الـCache.
أبقِ الأسرار خارج Layers وMetadata وCache Keys
تحتاج Private Package Registries ومستودعات المصدر إلى Credentials وقت البناء. لا تمررها عبر ARG أوENV ولا تنسخ ملف Credential إلى Stage ثم “تحذفه”. تقول وثائق Build Secrets إن ARG وENV غير مناسبتين لأن القيم الحساسة قد تبقى في Final Image أوMetadata. استخدم BuildKit Secret Mount أوSSH Mount لتعليمة RUN الوحيدة التي تحتاجها.
Secret Mount مؤقتة. يرسل Build Client السر بواسطة --secret وتستهلكه Dockerfile عبر RUN --mount=type=secret. يتوفر الملف خلال التعليمة ولا يدخل Layer الناتجة. لكن افترض أن الأمر يستطيع تسريبه: لا تطبعه ولا تضعه في Artifact يُنسخ لاحقًا ولا تدخله في Logs مفصلة ولا تجعل مدير الحزم يكتبه داخل Persistent Cache.
هناك قاعدة دقيقة: تغيير قيمة السر لا يبطل Cached RUN تلقائيًا. توثق قواعد Cache Invalidation أن Secret ID وخصائص Mount تدخل المطابقة، بينما محتوى السر نفسه لا يدخل. إذا كان Output غير سري يعتمد فعلًا على تدوير Credential فغيّر قيمة Cache-bust صريحة وغير حساسة. وغالبًا العقد الأفضل هو أن Credential تسمح بالوصول، بينما Lockfile وArtifact Digest تحددان المحتوى.
اجعل Runtime Stage مملة عمدًا
يجب أن تحتوي Final Image على Runtime واعتماديات الإنتاج والناتج المترجم والملفات اللازمة لبدء العملية فقط. اترك Compilers وCredentials ومديري الحزم وBuild Cache وأدوات الاختبار وSource Maps التي تكشف كودًا خاصًا في مراحل سابقة، إلا إذا كانت عمليات الإنتاج تحتاجها بعقد صريح.
شغّل الخدمة كمستخدم Non-root عندما لا تحتاج Privileges. عيّن الملكية أثناء COPY باستخدام --chown بدل إنشاء Layer كبيرة من chown متكرر. حدد WORKDIR وCMD وUID/GID ثابتين عندما تعتمد المنصة على ملكية رقمية. توثق Docker سلوك USER وCOPY، لكن يجب اختبار التطبيق فعليًا بالهوية المقيدة.
الصغر لا يساوي الأمان تلقائيًا. Minimal Image بـRuntime غير محدثة تبقى معرضة، وقد تحذف Ultra-minimal Image شهادات أوTimezone Data أوإشارات تشخيص يحتاجها التطبيق. اختر أصغر Runtime تحقق عقد التشغيل ثم أعد بناءها دوريًا بعد مراجعة تحديثات Base Image.
صدّر Cache بحسب حدود الثقة
تفقد CI Workers المؤقتة حالة BuildKit المحلية، لذلك يفيد External Cache. تدعم وثائق Cache Backends الاستيراد بـ--cache-from والتصدير بـ--cache-to. Registry Cache ملائمة لأنها تعبر نفس حدود Registry الموثقة، مع بقائها Reference منفصلة عن Image.
لا تجعل كل الفروع تكتب إلى المرجع نفسه؛ تحذر Docker من أن الكتابة مرتين إلى الموقع نفسه تستبدل بيانات Cache السابقة. سياسة عملية تستورد Protected Main Cache وCache الفرع الحالي، ثم تصدّر إلى مرجع الفرع فقط. وبعد الدمج يجدد Workflow موثوق Cache الخاصة بـmain.
عامل صلاحية كتابة Cache بحساسية أعلى من القراءة. لا تسمح لـPull Request غير موثوق بالنشر إلى Namespace ستستهلكه Production Builds لاحقًا. حتى مع تحقق BuildKit من السجلات، يجعل العزل Provenance والتحقيق في الحوادث أوضح ويمنع Job منخفضة الثقة من التحكم بحالة التسريع المشتركة.
أرفق الدليل بالصورة المرفوعة
يستطيع BuildKit إنشاء إقرارات SBOM وProvenance. توضح وثائق Build Attestations أن SBOM تسرد Software Artifacts، بينما تسجل Provenance كيف بُنيت الصورة. ترتبط الإقرارات بـImage Index ويمكن فحصها من Registry من دون سحب الصورة كاملة.
أنشئ الإقرارات للـArtifact التي ترفعها، لا لـLocal Test Build فقط. يجب أن ينتقل Registry Digest وSBOM وProvenance معًا خلال Promotion. عندها تستطيع Deployment Policy اشتراط Builder Identity مسموحة وSource Revision مراجعة ومستودع متوقع ونتيجة اعتماديات مقبولة قبل قبول الـDigest.
الإقرارات دليل وليست حكمًا. قد تكون SBOM ناقصة لبعض Ecosystems، ولا تثبت Provenance صحة المصدر. اربطها بفحص الاعتماديات وسياسة توقيع أوهوية واختبارات وضوابط Runtime. وتحقق من دعم Builder: تقول Docker إن حفظ Attestations يحتاج مسار Image Store وExporter يحافظ على Image Index؛ يحتفظ --push بها بينما قد لا يحتفظ بها Classic Local Image Store.
Dockerfile موجهة للإنتاج
يفصل النمط التالي حل الاعتماديات والترجمة واعتماديات الإنتاج والتشغيل. استبدل Placeholder Digest بقيمة راجعتها وعدّل المسارات لتناسب التطبيق. تحتاج npm Secret Mount فقط عند استخدام Private Registry.
# syntax=docker/dockerfile:1
ARG NODE_IMAGE=node:24-alpine@sha256:<reviewed-digest>
FROM ${NODE_IMAGE} AS dependencies
WORKDIR /app
COPY package.json package-lock.json ./
RUN --mount=type=cache,target=/root/.npm,sharing=locked \
--mount=type=secret,id=npmrc,target=/root/.npmrc \
npm ci
FROM dependencies AS build
COPY . .
RUN npm test && npm run build
FROM ${NODE_IMAGE} AS production-dependencies
WORKDIR /app
COPY package.json package-lock.json ./
RUN --mount=type=cache,target=/root/.npm,sharing=locked \
--mount=type=secret,id=npmrc,target=/root/.npmrc \
npm ci --omit=dev
FROM ${NODE_IMAGE} AS runtime
ENV NODE_ENV=production
WORKDIR /app
COPY --from=production-dependencies --chown=node:node /app/node_modules ./node_modules
COPY --from=build --chown=node:node /app/dist ./dist
COPY --chown=node:node package.json ./package.json
USER node
CMD ["node", "dist/main.js"]لا تنسخ المثال حرفيًا. تحتاج بعض Frameworks إلى Generated Assets أوNative Libraries أوCA Bundles أوProcess Init. وتحقق أن Production Dependencies تحتوي Binaries أصلية مناسبة لكل Target Architecture. إذا كان postinstall يترجم Native Module فيجب أن تتوافق libc والمعمارية بين Build وRuntime.
حوّل CI Build إلى عقد
ابدأ بفحوص Docker الساكنة. تدعم وثائق Build Checks الأمر docker build --check وتسمح بتحويل Warnings إلى Errors. تكشف هذه المرحلة أسرارًا موضوعة في ARG أوENV وأسماء مراحل غير صحيحة ومشاكل Dockerfile قبل صرف ميزانية البناء كاملة.
بعد ذلك ابنِ واختبر وارفع حسب Revision غير متغير. استورد Cache من الفرع الحالي وmain المحمي، وصدّر إلى نطاق الفرع، واربط Secrets من CI Secret Store، واطلب Attestations. أمر تمثيلي:
docker build --check .
docker buildx build \
--secret id=npmrc,src="$NPMRC_PATH" \
--cache-from type=registry,ref=registry.example.com/app:cache-main \
--cache-from type=registry,ref=registry.example.com/app:cache-$BRANCH_SLUG \
--cache-to type=registry,ref=registry.example.com/app:cache-$BRANCH_SLUG,mode=max \
--platform linux/amd64,linux/arm64 \
--sbom=true --provenance=mode=max \
--tag registry.example.com/app:$GIT_SHA \
--push .بعد الرفع سجل Resolved Digest وتحقق من Platform Manifests والإقرارات المرفقة. انشر بالـDigest لا Release Tag متغيرة. شغّل Container بالمستخدم النهائي ومع Read-only Filesystem عندما يدعم التطبيق ذلك، واختبر Health وShutdown، وافحص الـDigest المرفوعة نفسها لا Local Rebuild تشبهها.
نفذ Clean Rebuilds مجدولة بمدخلات حديثة ومراجعة. يثبت Warm-cache Build المسار السريع، ويثبت Clean Build دوري أن Dockerfile مكتملة. إذا فشل البناء النظيف فالـCache كانت تخفي Undeclared Dependency.
اعرف متى لا تطارد Cache Hits
لا تحافظ على Dependency Layer عندما يكون الهدف اكتشاف حزم مصلحة أمنيًا. يجب أن يحدّث Security Refresh الـBase المثبتة أومدخلات الاعتماديات ويبطل الخطوات المتأثرة عمدًا. يجبر --no-cache التعليمات على التنفيذ، لكنه لا يسحب Base أحدث تلقائيًا؛ توثق Docker أن --pull و--no-cache تحكمان سلوكين مختلفين.
تجنب Shared External Cache لمستودعات غير موثوقة وغير مترابطة. وتجنب Artifacts مولدة تعتمد على Secret Contents ما لم تملك هوية غير سرية دقيقة ويمكن التحقق منها مستقلًا. ولا تعتبر Multi-platform Emulation دليلًا على صحة Runtime الأصلية؛ اختبر الكود الحساس للمعمارية على Native Runners أوبيئات ممثلة.
في خدمة صغيرة تُبنى نادرًا قد تكون Remote-cache Topology أعقد من فائدتها. ابدأ بترتيب Layers وسياق ضيق وMulti-stage Output. أضف Cache Mount عندما تهيمن تنزيلات الحزم. وأضف External Cache عندما تكون CI Workers مؤقتة وBuild Time مؤثرة فعليًا.
قرار الإنتاج
هدف التحسين الآمن ليس “أعلى Cache Hit Rate”، بل “أقل عمل متكرر مع بقاء كل إصدار قابلًا للتفسير”. ثبّت المدخلات أوراجعها، واجعل Cache قابلة للحذف، واربط Secret بالتعليمة التي تحتاجها فقط، وانسخ Runtime Artifacts وحدها إلى Final Stage، وارفع الصورة مع SBOM وProvenance.
يناسب هذا التصميم CI/CD التي تبني كثيرًا أوتستخدم Private Dependencies أوتستهدف معماريات متعددة. قد يكون مبالغة لـPrototype محلي مؤقت، لكن حدود الأسرار وMinimal Runtime تظلان مهمتين. ولجانب التشغيل اربطه مع هندسة السحابة والنشر وضبط موارد Kubernetes وعقود Rollout الآمنة.
المراجع الرسمية
تدعم هذه المراجع سلوك الأدوات المذكورة. الأمثلة وقرارات التصميم توضيحية، ويجب تكييفها مع متطلبات المشروع وإصداراته.
إعداد: Noor Yasser
تعمل على تحدٍ تقني مشابه؟
أساعد الفرق على تحويل القرار المعماري إلى نطاق واضح وتنفيذ يمكن تشغيله ومراجعته بثقة.




