2.1 · كتابة أول ملف Dockerfile (Dockerfile)

المستوى 2 · Dockerfile وبناء الصور

2.1كتابة أول ملف Dockerfile (Dockerfile)

الهدف: كتابة ملف Dockerfile مصغر يغلّف تطبيقا ويشغّله.
الوقت المقدّر: 14 دقيقة · قراءة ذاتية · إذا كان لديك 5 دقائق فقط: اقرأ «الأساسي في 30 ثانية» + المخطط.

الأساسي في 30 ثانية

  • 5 تعليمات = صورة قابلة للتشغيل : FROM وWORKDIR وCOPY وRUN وCMD — لكل واحدة دور مميز.
  • البناء يطهو، والتشغيل ينفّذ : البناء يجمّد الطبقات (Layer)، والتشغيل يطلق الحاوية — اقرأ الخطوة الأخيرة عند الفشل.
  • RUN يبني، وCMD يشغّل : ثبّت أثناء البناء، وأطلق أثناء التشغيل — أبدا الخادم داخل RUN.

حالة مستمرة — إدير والتطبيق الذي لم يسافر

إدير، مهندس devops مبتدئ في الجزائر، يجب أن يسلّم تطبيق Node الصغير لفريقه على جهاز آخر : « يعمل عندي » لم يعد كافيا. كتب أول ملف Dockerfile في جذر المشروع : قاعدة رسمية، ومجلد عمل، وإيداع الكود، والتثبيت أثناء البناء، وأمر التشغيل. بنى الصورة mon-app:1.0 ثم شغّلها مع نشر المنفذ : فاستجاب التطبيق على localhost:3000، على أي جهاز. هذا التطبيق « المغلف من إدير » يعود في 2.2 (بناء أسرع وصورة أنحف)، و2.3 (الوسم والنشر)، و2.4 (منفذ قابل للإعداد)، و2.5 (نسخة مقواة غير root).

الخيط الرابط للمستوى 2 : تطبيق إدير يعود في الدرس والمخطط والنص الجاهز وتحدي 48 ساعة — ويستمر في 2.2 و2.3 و2.4 و2.5.

1. التعليمات الخمس الحيوية

FROM تختار القاعدة (مثلا node:20-slim، صورة رسمية خفيفة)، وWORKDIR يثبّت مجلد العمل الداخلي (يُنشأ إن غاب)، وCOPY يودع الكود فيه من السياق، وRUN يثبّت أثناء البناء (كل RUN يجمّد طبقة)، وCMD يحدد أمر التشغيل للحاوية. خمسة أسطر تكفي لأول خدمة تعمل. كتبها إدير بهذا الترتيب : القاعدة، والمجلد، والكود، والتثبيت، والتشغيل.

2. البناء ثم التشغيل : زمنان

docker build -t mon-app:1.0 . يطهو الصورة : والنقطة الأخيرة تعني السياق، أي المجلد المرسل إلى المحرك لأجل البناء. وdocker run ينفّذها : فتبدأ الحاوية وتنشر منافذها. إذا فشل البناء، نقرأ آخر خطوة معروضة : فهي المتهمة (اعتمادية ناقصة، أو خطأ مطبعي، أو شبكة مقطوعة). سمّى إدير صورته اسم:إصدار منذ البناء ليهتدي إليها.

3. CMD مقابل RUN : لا تخلط بعد اليوم

RUN تُنفَّذ أثناء البناء (تثبيت، تجميع) وتجمّد طبقة في الصورة. وCMD تُنفَّذ عند بدء الحاوية (تشغيل الخادم)، مع كل run. وضع التشغيل داخل RUN يجمّد بناء لا يبدأ أبدا : وهو خطأ المبتدئ الكلاسيكي. نكتب CMD بالصيغة JSON (["node", "server.js"])، أمر تشغيل واحد. ثبّت إدير بـ RUN وشغّل بـ CMD : نبني ثم نشغّل، ولا عكس أبدا.

خطأ شائع في الفهم: « RUN وCMD شيء واحد : فكلاهما يشغّل أوامر ». لا. RUN تُنفَّذ أثناء البناء وتجمّد طبقة (تثبيت، تجميع) ؛ وCMD تُنفَّذ عند بدء الحاوية (تشغيل الخادم). وقاعدة إدير : كل ما يجهّز الصورة ← RUN ؛ وأمر التشغيل الذي يُحيي الحاوية ← CMD، بالصيغة JSON.
من الكود إلى تطبيق يعمل القاعدة، والكود، والتثبيت أثناء البناء، والتشغيل عند run FROM + COPY قاعدة رسميةوإيداع الكودRUN (أثناء البناء) تثبيت،وتجميد طبقةCMD (عند التشغيل) تشغيلالخادم عند البدء
القاعدة، والكود، والتثبيت أثناء البناء، والتشغيل عند run
نص المخطط (SEO / قارئات الشاشة / الترجمة): 1) يضع إدير القاعدة : FROM على صورة رسمية خفيفة وWORKDIR كمجلد عمل، ثم COPY لإيداع الكود من السياق. 2) يطهو : RUN يثبّت الاعتماديات أثناء البناء (طبقة مجمدة)، وdocker build -t mon-app:1.0 يجمّد الصورة. 3) يشغّل : CMD بالصيغة JSON يبدأ الخادم عند docker run، مع منفذ منشور. الدرس : RUN تبني، وCMD تشغّل — زمنان ودوران.

🔎 مثال ملموس — 🔎 مثال ملموس — تطبيق Node مغلف

تطبيق إدير، من الكود إلى صورة قابلة للتشغيل :

FROM node:20-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]

docker build -t mon-app:1.0 .
docker run -d --name app -p 3000:3000 mon-app:1.0

القراءة : الاعتماديات تُثبَّت أثناء البناء (RUN)، والخادم يبدأ عند التشغيل (CMD)، والمنفذ مُعلَن (EXPOSE) ومنشور (-p).

الدرس : نسخ package*.json أولا يمهّد مسبقا لتحسين الذاكرة المؤقتة (2.2).

مفردات القسم

FROM
الصورة القاعدة لملف Dockerfile، نقطة انطلاق كل الطبقات (ويُفضَّل صورة رسمية خفيفة).

مثال بسيط: انطلق إدير من node:20-slim لتطبيق Node الخاص به.

ما ليس كذلك: الأمر الذي يشغّل الحاوية.

رد فعل: قاعدة رسمية خفيفة أولا.

WORKDIR
مجلد العمل الداخلي للحاوية، يُنشأ تلقائيا إن غاب ؛ وكل التعليمات التالية تُنسب إليه.

مثال بسيط: ثبّت إدير WORKDIR /app قبل نسخ كوده.

ما ليس كذلك: مجلد يخزّن البيانات بثبات.

رد فعل: ثبّت المجلد قبل النسخ.

RUN
تنفيذ أمر أثناء البناء (تثبيت، تجميع) ؛ وكل RUN يجمّد طبقة في الصورة.

مثال بسيط: ثبّت إدير اعتمادياته عبر RUN npm ci.

ما ليس كذلك: أمر تشغيل الحاوية.

رد فعل: تجهيز الصورة = RUN.

CMD
أمر بدء الحاوية، يُنفَّذ عند كل docker run ؛ أمر واحد، ويُفضَّل بالصيغة JSON.

مثال بسيط: شغّل إدير عبر CMD ["node", "server.js"].

ما ليس كذلك: تثبيت مجمّد أثناء البناء.

رد فعل: إحياء الحاوية = CMD.

في التطبيق — عمليا — غلّف تطبيقا مصغرا

  1. أنشئ مجلدا فيه server.js يرد « OK » على المنفذ 3000.
  2. اكتب Dockerfile (FROM وWORKDIR وCOPY وRUN وEXPOSE وCMD) في جذر المشروع.
  3. ابنِ الصورة mon-app:1.0 واقرأ كل خطوة من البناء.
  4. شغّل عبر -p 3000:3000 وافتح localhost:3000.
تحوّل أي كود إلى صورة قابلة للتشغيل : بناء هنا، وتشغيل في كل مكان.

نص جاهز — اشرح Dockerfile لزميل (30 ثانية)

« ملف Dockerfile هذا يفعل خمسة أشياء : ينطلق من قاعدة رسمية، ويثبّت مجلد العمل، وينسخ الكود، ويثبّت أثناء البناء عبر RUN، ويشغّل عبر CMD. نطهو بـ docker build، ونشغّل بـ docker run : فيعمل التطبيق بالمثل على كل الأجهزة. RUN تبني، وCMD تشغّل — وهذا هو التمييز الوحيد الواجب حفظه. »

يُقال مع عرض Dockerfile الخاص بإدير ثم البناء خطوة بخطوة.

قالب جاهز للنسخ — أول Dockerfile لتطبيق Node

FROM node:20-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]

تطبيق Python

يغلّف إدير سكربت Python : FROM python:3.12-slim، وCOPY للمتطلبات ثم RUN pip install، وCMD بالصيغة JSON.

صفحة ثابتة

موقع عرض : ينطلق إدير من قاعدة خادم خفيفة، وينسخ الملفات، ويعلن المنفذ، وCMD يشغّل الخادم.

سياق ضخم

بناء بطيء : يضيف إدير ملف .dockerignore (node_modules و.git) فيصبح السياق خفيفا مجددا.

RUN ملغوم

زميل يشغّل الخادم داخل RUN : فيتجمّد البناء ولا يبدأ أبدا — فينقل إدير التشغيل إلى CMD.

✓ ممارسات جيدة

  • أمر تشغيل واحد في CMD (بالصيغة JSON).
  • سمِّ الصورة اسم:إصدار منذ البناء.
  • اقرأ البناء خطوة بخطوة عند الفشل.

✗ أخطاء شائعة

  • تشغيل الخادم داخل RUN بدلا من CMD.
  • نسيان .dockerignore (سياق ضخم).
  • نسخ node_modules المحلي داخل الصورة.

النقاط الأساسية

  • FROM وWORKDIR وCOPY وRUN وCMD : أساس كل Dockerfile.
  • البناء يطهو الصورة، والتشغيل ينفّذها (« . » هو السياق المرسل إلى المحرك).
  • RUN = البناء (يجمّد طبقة)، وCMD = البدء (بالصيغة JSON).
  • سمِّ اسم:إصدار منذ البناء ؛ واقرأ آخر خطوة عند الفشل.

تحدي 48 ساعة — طبِّق غدا

غلّف تطبيقا مصغرا حقيقيا (تطبيقك أو تطبيق إدير) : Dockerfile في 7 أسطر (FROM وWORKDIR وCOPY وRUN وEXPOSE وCMD)، وبناء موسوم 1.0 مقروء خطوة بخطوة، ثم تشغيل مع منفذ منشور مُتحقق منه في المتصفح.

قائمة الخروج من القسم
  • أستطيع كتابة Dockerfile مصغر (FROM وWORKDIR وCOPY وRUN وEXPOSE وCMD).
  • أعرف البناء (مع فهم السياق) وقراءة الفشل عند آخر خطوة.
  • أميز RUN (البناء) وCMD (البدء) دون تردد.
تقييم ذاتي 1-5 : هل أضع كل تعليمة في زمنها الصحيح (البناء مقابل التشغيل)؟هل تنطلق صورتي دون تعديل على جهاز آخر؟

أسئلة شائعة

أين أكتب Dockerfile؟

في جذر المشروع، باسم « Dockerfile » بالضبط. والسياق هو المجلد المرسل إلى المحرك : ابقَ في الجذر لأجل COPY . . وخفّفه عبر .dockerignore (node_modules و.git) كي لا ترسل مئات Mo عند كل بناء.

لماذا البناء بطيء جدا؟

غالبا سياق ضخم (node_modules و.git) يُرسَل في كل مرة. ويحل .dockerignore وترتيب الطبقات (الاعتماديات أولا، ثم الكود — انظر 2.2) نسبة 80 % من الحالات قبل أي تحسين آخر.

تحقّق من فهمك

في Dockerfile، ماذا يفعل RUN مقارنة بـ CMD؟

موارد إضافية (اختياري، للتعمّق أكثر)

اختبار المستوى 2أسئلة جديدة وأصعب للتحقق من مكتسباتك