مثال تطبيقي على إنشاء صورة لمشروعك

عمار الخوالدةمنذ 5 سنوات

مقدمة

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

تتعدد الاحتياجات للحاويات بحسب المشروع الذي تعمل عليه، فقد تختلف الحزم أو المتطلبات والإعدادات من مشروع لآخر تعمل عليه، فقد تعمل على مشروع بحاجة إلى نسخة من بايثون إضافة إلى إعدادات خاصة بـ Nginx لاستخدامه كوكيل ( Proxy )، وفي مشروع آخر قد تحتاج إلى نسخة محددة من PHP مع نسخة وإعدادات لسيرفر Apache، غالبا ستقوم بالبحث في Docker Hub عن صورة مناسبة لك، لكن في كثير من الأحيان قد لا تجد ما تحتاج إليه بالضبط، فستكون عندها مضطرا لإنشاء صورة لتستخدمها لإنشاء الحاوية التي تحتاجها.

 

كيف يتم إنشاء صورة

يتم إنشاء الصور عن طريق أوامر معينة تُكتب داخل ملف نصي يُسمى Dockerfile، وهو يحتوي على أوامر أو إرشادات متسلسلة توضح لـ Docker كيف يقوم ببناء الصورة، يتم غالبا إنشاء صور Docker بناء على صور أخرى، فحتى تُنشئ مثلا صورة لـ Nginx فأنت بحاجة لبناءها فوق صورة Ubuntu مثلا، فـ Nginx لن يعمل دون نظام تشغيل، ( في حالات قليلة قد يتم إنشاء صور Docker من الصفر بالفعل لمعلومات أكثر اضغط على هذا الرابط ).

إنشاء الصورة

في البداية قم بإنشاء ملف باسم "Dockerfile" وهو الملف النصي الذي سيحتوي على التعليمات الخاصة بإنشاء الصورة، تكتب أوامر Docker بالصيغة الآتية:

INSTRUCTION [arguments]

 

حيث أن INSTRUCTION هو أي أمر من أوامر Docker والتي سنتعرف على بعضها الآن، و arguments هي الجمل التي ستكتب بعد الأمر كمعلومات تُمرر إلى هذا الأمر ليقوم بمعالجتها بحسب الأمر، ويمكن كتابة التعليقات في الملف مسبوقة بإشارة #

 

أول أمر يكتب في بداية جميع ملفات Dockerfile هو الأمر FROM ويُمرر له اسم الصورة التي تريد بناء صورتك عليها، مثال:

FROM ubuntu:16.04

 

بهذا السطر حددنا لـ Docker أننا سنبني صورة فوق صورة Ubuntu بنسخة 16.04، فعند إنشاء حاوية من صورتك، سيقوم Docker بسحب صورة Ubuntu ثم ينفذ باقي الأوامر فوق صورة Ubuntu.

 

من الأوامر المهمة المستخدمة بكثرة، الأمر RUN وهو أمر يقوم بتنفيذ أوامر في الطرفية الخاصة بالحاوية، مثال:

RUN apt-get update && apt-get install -y nodejs npm
RUN mkdir /application

 

لاحظ أن الجمل التي بعد الأمر RUN كلها أوامر عادية، الأول يقوم بتحديث المستودعات وتنصيب حزمة NodeJs، والثاني سيقوم بإنشاء ملف، بإمكانك كتابة الأمر RUN عدة مرات.

 

في حال أردت نسخ ملف من جهازك إلى الحاوية، بامكانك استخدام الأمر COPY أو الأمر ADD وهما يقومان بالعمل نفسه تقريبا، إلا أن COPY مقروء أكثر والأمر ADD يدعم إضافة الملفات إلى الحاوية من رابط معين وليس من جهازك فقط، تكمن فائدة هذين الأمرين بشكل أساسي في نسخ ملفات مشروعك إلى الحاوية، أو نسخ ملف إعدادات لحزمة معينة أو أي حزمة أخرى. مثال:

COPY package.json /application
ADD https://example.com/folder/file.js /application

 

أحيانا قد تحتاج إلى تنفيذ أمر في الطرفية أثناء تشغيل الحاوية وليس أثناء بناءها ( مع كل تشغيل للحاوية )، وهنا بإمكانك استخدام الأمر CMD وتنفيذ الأمر الذي تريده ( لا يمكنك إلا استخدام نسخة واحدة من الأمر CMD وان كتبت أكثر من واحدة فسيتم تنفيذ الأخيرة فقط)، استخدم معها الأمر WORKDIR لتحديد مجلد العمل الذي سيتم فيه تنفيذ الأوامر، مثال:

WORKDIR /application
CMD npm start

 

أو يمكنك استخدام ENTRYPOINT للوظيفة نفسها.

لكن ما الفرق بين CMD و ENTRYPOINT ؟
باختصار فإن معظم الصور تستخدمُ الأمر:

/bin/sh -c

كـ ENTRYPOINT لها، بالتالي يتم تمرير الأمر الموجود في CMD إلى الـ ENTRYPOINT، لذلك فبإمكانك تغيير الـ ENTRYPOINT وسيُمرر الأمر الموجود في CMD إلى تلك الـ ENTRYPOINT مثال:

ENTRYPOINT ["/bin/cat"]
CMD ["/path/to/file"]

 

هذا الأمر سيطبع الملف الذي تم تحديده في CMD باستخدام الأمر cat، فقد تم تمرير هذا المسار إلى الـ ENTRYPOINT.

 

 

قد تحتاج أحيانا لتعيين متغيرات البيئة Environment Variables في الصورة، ويمكنك فعل ذلك باستخدام الأمر ENV كما في المثال التالي:

ENV VAR=value

كما أن بإمكانك تحديد أكثر من متغير بأمر ENV واحد:

ENV VAR1=value \
    VAR2=value

 

باستخدام الأمر EXPOSE يمكنك تحديد المنافذ (Ports) المستخدمة ضمن الحاوية، فلو قمنا بإنشاء سيرفر باستخدام Node يستخدم البورت 80، سنضع الأمر EXPOSE كالتالي:

EXPOSE 80

قد تتساءل، ما الفائدة من تحديد البورتات المستخدمة باستخدام EXPOSE ونحن في كل الأحوال سنستخدم الخيار p- ضمن الأمر run لتحديد البورت؟

عند تحديد البورت باستخدام EXPOSE فإنك لن تتمكن من الوصول إلى هذا البورت من جهازك إلا ان استخدمت الخيار p-، لكن سيكون بإمكان الحاويات الأخرى الوصول إلى هذا البورت ضمن تلك الحاوية، أما عند استخدامك لـ p- سواء بوجود EXPOSE أو عدمه فالنتيجة واحدة. لكن يفضل استخدام EXPOSE ليكون بمثابة توثيق للبورتات التي سيتم استخدامها، كذلك يمكنك كتابة EXPOSE واستخدام الخيار P- بدلا من p- لنشر جميع البورتات المحددة في EXPOSE إلى الخارج دون إعادة كتابتها ضمن الأمر run.

للقراءة عن فائدة EXPOSE بالتفصيل راجع هذه الإجابة.

 

لتفاصيل أكثر عن المزيد من أوامر ملفات Docker راجع المرجع الرسمي، بعد الانتهاء من كتابة الاوامر السابقة للملف، هذا هو الملف كاملا:

 

FROM ubuntu:16.04
# جلب صورة ابونتو

RUN apt-get update && apt-get install -y nodejs npm
# تحديث المستودعات وتحميل نود

RUN mkdir /application
# انشاء المجلد الذي سيحوي التطبيق

COPY package.json /application
# نسخ ملف حزم npm
# الى المجلد الذي أنشأناه
# يجب ان يتوفر ملف package.json
# الى جانب ملف Dockerfile

WORKDIR /application
# تحديد مجلد العمل

CMD npm start
# تنفيذ الامر npm start

 

سنقوم الآن ببناء الصورة باستخدام الأمر:

docker build -t 3alamproimg:latest .

 

الخيار -t يمكنك من تحديد اسم و tag للصورة، ففي المثال السابق اخترنا الاسم 3alamproimg للصورة، واستخدمنا latest كاسم للـ tag، ثم نحدد المجلد الذي يحتوي على ملف Dockerfile ووضعت اشارة النقطة للدلالة على ان الملف موجود في نفس مجلد العمل الذي أنا اتصفحه.

 

سينفذ Docker الاوامر السابقة سطرا سطرا وسيطبع السطر الذي يعمل عليه، وفي حال حدث أي خطأ ستعلم أين حصل، بعد الانتهاء من بناء الصورة سيطبع لك:

Successfully built a499ec6eafd0
Successfully tagged 3alamproimg:latest

بالطبع سيختلف الـ id الخاص بالصورة عندك. بامكانك الآن تنفيذ الامر docker images لعرض جميع الصور الموجودة لديك، ويجب أن تظهر الصورة التي قمت بانشائها:

 

 

جرب الآن تشغيل حاوية من الصورة التي قمنا بانشائها:

docker run 3alamproimg

وسيختلف الناتج بالطبع بحسب ملف package.json لديك.

في الدرس القادم باذن الله سنشرح طريقة ربط الحاويات بعضها ببعض باستخدام أداة docker-compose، بحيث تتمكن الحاويات من الاتصال ببعضها.

المحاضر

عمار الخوالدة

الكلمات الدليلية

عن الدرس

4 إعجاب
4 متابع
0 مشاركة
3739 مشاهدات
منذ 5 سنوات

التعليقات (4)

AMMAR HUSSEIN:

.if possible please share a sample file package.json.

I received error when I test the sample from visual studio code.

Thanks,

عمار الخوالدة:

أي ملف package.json فيه سكربت start يفترض يشتغل، ضع تفاصيل ال error الذي يظهر لك.

AMMAR HUSSEIN:

Ammars-MacBook-Pro:docker ammarhussein$ more package.json 

{

    "name" : "test",az

    "description" : "JavaScript's functional programming helper library.",

    "keywords" : ["util", "functional", "server", "client", "browser"],

    "contributors" : [],

    "dependencies" : [],

  }

Ammars-MacBook-Pro:docker ammarhussein$ docker run 3alamproimg

npm ERR! Linux 4.19.76-linuxkit

npm ERR! argv "/usr/bin/nodejs" "/usr/bin/npm" "start"

npm ERR! node v4.2.6

npm ERR! npm  v3.5.2

 

npm ERR! missing script: start

npm ERR! 

npm ERR! If you need help, you may report this error at:

npm ERR!     <https://github.com/npm/npm/issues>

 

npm ERR! Please include the following file with any support request:

npm ERR!     /application/npm-debug.log

عمار الخوالدة:

المشكلة بسبب عدم وجود سكربت باسم start، يمكن تغيير الامر لأي أمر آخر تريده، او استخدم امر start 

مثلا:

 

"scripts": {    "start": "echo 'Hello World!'" }

تفاصيل اكثر:

 

https://www.freecodecamp.org/news/introduction-to-npm-scripts-1dbb2ae01633/

 

لايوجد لديك حساب في عالم البرمجة؟

تحب تنضم لعالم البرمجة؟ وتنشئ عالمك الخاص، تنشر المقالات، الدورات، تشارك المبرمجين وتساعد الآخرين، اشترك الآن بخطوات يسيرة !