بناء Docker لا يصل إلى تبعية خاصة: راجع هذه النقاط
قد تفشل حزمة خاصة يستطيع المضيف جلبها داخل البناء. حدِّد الباني وأثبت المسار ثم اربط الرمز كسرّ بناء.
قد تفشل حزمة خاصة تُحلّ بلا مشكلة على جهازك داخل البناء بخطأ 404 أو بانتهاء المهلة، ونادرًا ما يكون ملف Dockerfile هو السبب. فخطوة البناء تعمل في نطاق شبكة مختلف، وبرؤية DNS مختلفة ومخزن بيانات اعتماد مختلف عن الصدفة التي اختبرت فيها. راجع هذه الفحوص بالترتيب وتوقّف عند أول فحص يفشل، لأن كل فحص لاحق يفترض نجاح الفحص السابق. كل خطوة تسمّي الأمر الذي يحسم المسألة.
ابدأ بتسمية الباني لا بملف Dockerfile
قد يكون BuildKit محليًا أو داخل حاوية أو على جهاز آخر، ولكل من ذلك شبكته الافتراضية. شغّل docker buildx ls واقرأ العقدة المعلّمة بنجمة قبل أن تعدّل أي شيء. فأي docker-container أو باني سحابي لا يشارك المسار الخاص على حاسوبك المحمول لمجرد أنك كتبت الأمر هناك. وإذا كان الباني النشط بعيدًا، فعلى كل فحص متبقٍ أن يُنفَّذ على ذلك المضيف بدلًا من محطة عملك.
يحمل الباني أيضًا إعدادات المُحلِّل ومتغيرات الوسيطالخاصة به. ويُقرأ كلاهما وقت البناء ولا يُورَّث من الطرفية التي بدأت البناء.
أثبت مسار الشبكة من داخل خطوة بناء
اكتب مرحلة مؤقتة تُحلّ مضيف التبعية وتفتح اتصالًا به. هذا هو الاختبار الوحيد الذي يجيب عن السؤال لصالح الباني لا لصالح الصدفة عندك.
FROM alpine:3.20
RUN apk add --no-cache curl bind-tools && getent hosts registry.example.internal && curl -sS -o /dev/null -w "%{http_code}
" https://registry.example.internal/simple/
ابنِ ذلك الملف بالباني نفسه ووضع الشبكة نفسه وتركيبات الأسرار نفسها التي يستخدمها بناؤك الحقيقي: docker buildx build --builder remote0 -f Dockerfile.probe --progress=plain .. إذا لم getent يطبع شيئًا، فالخلل في تحليل الأسماء ولن يصلحه أي بيانات اعتماد. وإذا حُلّ الاسم لكن curl أبلغ عن انتهاء المهلة، فالعائق هو المسار أو سياسة الخروج أمام السجل.
احذف أداة الفحص بمجرد أن تجيب. فهي مرحلة تشخيصية، وليست شيئًا ينبغي أن يُوسم أو يُدفع أبدًا.
اربط بيانات الاعتماد بدلًا من نسخها
بعد أن يعمل المسار، تصبح المصادقة هي الفشل التالي في الطابور. فتركيب سرّ BuildKit يعرّض ملفًا لخطوة RUN واحدة دون كتابته في طبقة، وهذا ما تحتاجه أداة التبعيات وما يجب ألا تحتفظ به الصورة.
RUN --mount=type=secret,id=npmrc,target=/root/.npmrc npm ci --omit=dev
يجب توريد السر من خارج Dockerfile: docker buildx build --secret id=npmrc,src=/home/me/.npmrc .. يبقى الملف على العميل ولا يدخل سجل الصورة أبدًا. أما ARG أو ENV يحملان الرمز نفسه فلا يؤديان هذه المهمة، لأن كليهما يُسجَّل في تكوين الصورة.
الصورة غير الجذرية تحتاج مسار هدف خاصًا بها، مثل /home/app/.npmrc أو الملف المكافئ لـ pip أو Maven أو Cargo. ويجب أن يطابق هدف التركيب المستخدم الذي يشغّل الأمر، وإلا أبلغت الأداة عن ملف تكوين مفقود وهو موجود فعلًا.
دقّق فيما تتركه أداة التبعيات في الصورة
التركيب المؤقت يبقي بيانات الاعتماد خارج الطبقة، لكنه لا يمنع الأداة من كتابة شيء آخر. فمديرو الحزم يتركون ملفات القفل وأدلة الذاكرة المؤقتة وأحيانًا عنوان السجل المحلول.
اقرأ نظام الملفات النهائي بدلًا من الثقة بملف Dockerfile. docker history --no-trunc image:tag يسرد كل أمر طبقة، و docker run --rm image:tag sh -c "ls -a /root" يُظهر ما نجا إلى الحاوية العاملة. وحتى لو كان الملف مركّبًا فقط، فإن رمزًا يُكتب في سطر سجل أثناء npm ci يبقى تسريبًا.
اقرأ سجل البناء أيضًا، لأن --progress=plain يطبع مخرجات الأوامر حرفيًا. وإذا ظهر الرمز هناك، فبدّله قبل أي شيء آخر ومرّره عبر ملف تقرأه الأداة بهدوء.
تأكد أن صورة التشغيل لم تعد تحتاج المسار الخاص
البناء والتطبيق العامل مستهلكان مختلفان للتبعية نفسها، وأولهما فقط يحتاج المسار الخاص. فالصورة المكتملة ينبغي أن تبدأ وتحلّ تبعيات التشغيل وتخدم الحركة دون بيانات اعتماد وقت البناء.
اختبره حيث يكون السجل الخاص غير قابل للوصول، أو ابدأ الحاوية ببساطة بـ --network none وتأكد من أنها تقلع دون السر المركّب. فالحاوية التي لا تبدأ إلا بوجود سر البناء ما زالت مقترنة ببيئة البناء.
وإذا كانت الحاوية تحتاج السجل فعلًا وقت التشغيل، فهذا قرار وصول منفصل، ومكانه مخزن أسرار المنسّق لا البناء. وثّق المسارين منفصلين كي لا يحاول أحد إصلاح سحب وقت التشغيل بعلم بناء. وعندما تنجح الفحوص الخمسة كلها، تصبح للعرض الأصلي علّة مسمّاة في كل طبقة بدلًا من تخمين حول شبكة Docker.