تعرّف على Docker

نشره Fahad في

كتبه 01walid على موقع webtuts :

قليلة هي تلك المشاريع والابتكارات التي تُحدِث نقلة نوعية في عالم البرمجيات والتقنية بشكل عام، وإن كنا سنشهد في هذه العشرية إحدى هذه المشاريع، فهو Docker بامتياز. فما هو Docker هذا؟

هذا المقال يهدف بشكل خاص إلى التعريف بمشروع Docker والفكرة التي جاء بها، وليس لكيفية البدء به (والتي ستكون في مقال منفصل إن شاء الله)، حيث لا يمكن البدء به إذا لم نفهم فكرته وأهميته في عالم البرمجيات.

لمن هذا المقال؟

  • لمدراء الخواديم (SysAdmins) بالدرجة الأولى
  • للمبرمجين ومطوري الويب بالدرجة الثانية

 

docker

قبل أن نتحدث عن ماهية Docker أحب أولا ذكر أهم 03 مشاكل نواجهها حاليا كمطورين ومدراء خواديم والتي يحاول Docker معالجتها…

1. جحيم الاعتماديات (the dependecy hell)

الأغلبية الساحقة  من مشاريع الويب “الجدية” والكبيرة لا تكون قائمة بذاتها، بل هي عبارة عن مكتبات تتواصل فيما بينها أو تعتمد على مكتبات أخرى من أجل أن تعمل، مطوروا Ruby، Python وحتى node.js و php يفهمون ذلك جيدا، وكل من هذه اللغات حاول حل المشكلة على نطاقه الخاص عبر إنشاء أدوات مساعدة تعرف بـ”مدراء الاعتماديات” أو “مدراء حزم” (dependency/package managers) أمثلة ذلك:

  • pip بالنسبة لبايثون
  • gem بالنسبة لروبي
  • npm بالنسبة لـ node.js
  • وأخيرا محاولة متواضعة من php عبر composer..

وقد تذهب اللغة إلى أبعد من ذلك مثل ما فعلت بايثون بإنشاء بيئات وهمية تعزل فيها المكتبات والاعتماديات مثل مشروع virtualenv.

كل من هذه اللغات تستعمل مدراء الاعتماديات/الحزم لجلب وإدارة المكتبات الخارجية التي يعتمد عليها المشروع (third party librairies)، لكن السؤال هنا، إذا كانت هذه اللغات وفرت هذه الأدوات، فأين المشكل؟

في الحيقيقة بالرغم من توفر هذه الأدوات، تبقى هناك مشاكل عالقة دائما خاصة على مستوى تنصيب المشروع على الخواديم (deployment) من ذلك:

  • كثرة الاعتماديات، مما يأخذ وقتا في التنزيل، وأحيانا لا توجد تلك الاعتمادية على منصة الخادوم البعيد وقد تحتاج إلى عمل تجميع يدوي لها، وهذا يجعل الأمر مُتعبا.
  • اعتمادية تعتمد في حد ذاتها على اعتمادية أخرى، قد تكون مثلا تشترط منصة Java بأكملها، وقد تكون أيضا هذه الأخيرة تعتمد على اعتماديات أخرى وهكذا…
  • تعارض الاعتماديات، وجود إحداها يتطلب غياب الأخرى واستحالة عملهما معا في نفس الوقت
  • نسخة الاعتمادية التي تم تنزيلها مغايرة للتي تم تطوير المشروع بها. والنسخة الجديدة تأتي بتغيرات غير متوافقة رجعيا (API backward compatibility)

كل هذه المشاكل وغيرها، تجعل من ناقلية المشروع من مكان إلى آخر أو من خادوم إلى آخر، عملية شاقّة.

2. صعوبة نشر، تنصيب، نقل مشاريع الويب

مشاريع الويب الكبيرة تحتاج إلى عدد من الاحتياطات:

  • متغيرات بيئة (environment variables) يجب تعيينها مسبقا
  • إعداد لنظام الـ cache
  • إعداد للخادوم nginx أو غيره
  • إعدادات أمنية
  • تحديث النظام وبرمجياته قد يسبب عطلا ما للمشروع،…

ماذا عن نقل المشروع من خادوم إلى آخر؟ أو في حالة وجود أكثر من خادوم… وكل منه له نظامه الخاص (من CentOs إلى Ubuntu مثلا أو حتى BSD)….

3. التطوير، التسليم والزرع المتواصل للمشاريع ( continuous delivery/integration)

مشاريع الويب الجدية تتبع دورة تطوير معينة، تحسين دائم، إدخال لميزات جديدة بشكل دوري، قفل للثغرات … إلخ،  بعد هذا يجب إجراء سلسلة من الفحوصات (unit tests مثلا) للتأكد من سلامة المشروع وأنه أهل للمرحلة الإنتاجية منه (production ready)، كل هذا سهل محليا،… لكن عملية إبقاء جميع الخواديم مسايرة لوتيرة التطوير هذه أمر شاق ومتعب، خاصة حينما نحتاج إلى تحديث الاعتماديات أو وجود إعتماديات جديدة وبالتالي احتياطات جديدة…

هذه المشاكل ليس حصرا، فهناك غيرها من المشاكلة الأمنية (مثال ثغرة في مشروع الويب تمكن المخترق من الوصول إلى النظام)، مشاكل عزل (قاعدة البيانات في نفس بيئة التطبيق نفسه مما قد يسمح للوصول السهل لها من قبل المخترق)، مشاكل نسخ اختياطي (backups)،.. الخ

إذا ما هو Docker؟

Docker عبارة عن أداة جديدة تستغل ميزات الإصدارات الأخيرة من نواة Linux الخاصة بعزل المهام والعمليات (processes)، عمليات الإدخال والإخراج (i/o)، حجز الذاكرة وتحديدها، صلاحيات القراءة والكتابة للقرص الصلب… وغير ذلك، في إنشاء حاويات (containers) ركز على هذه الكلمة جيدا، حيث أن هذه الحاويات تلعب دور غلاف حاوي لتطبيق ما (مشروع ويب مثلا)، بحيث يصبح قائما بذاته، مكتفٍ ذاتيا.

أي أن مشروع الويب وكامل الاعتماديات التي يحتاجها ليعمل + التوزيعة المناسبة له (Fedora, Ubuntu.. الخ) بجميع التهيئات ومتغيرات البيئة التي يحتاجها، كل هذا في حاوية (قد تكون حاوية واحدة أو عدة حاويات تتخاطب في ما بينها عملا بمبدأ “عزل الاهتمامات” SoC).

لتقريب الصورة، تخيل أنه باستعمال Docker يمكنك عمل التالي:

  • طورت تطبيقك على Ubuntu أو تعلم أنه يعمل بشكل جيد على توزيعة Ubuntu وبالتحديد الإصدارة 14.04 منها، وبالتالي تقول لـ Docker استعمل نسخة Ubuntu 14.04 (يتكفل هو بتزيل الصورة الخام من Ubuntu 14.04 – حوالي 60 إلى 300 Mb تقريبا- واستعمالها كتوزيعة للحاوية)
  • مشروع الويب خاصتي يستعمل Python وبالتحديد النسخة 2.7 منها، ويعمل بشكل جيد على هذه النسخة، لم أجرب على Python 3، تقول لـ Docker نصب Python2.7 في الحاوية التي بها نظام Ubuntu 14.04 الذي سبق تنزيل صورته الخام
  • مشروع الويب خاصتي يستعمل مكتبة Flask أو Django و مكتبة Numpy الخاصة ببايثون، يتم تثبيتهم عبر pip وبالتالي تقول لـ Docker نصب لي على الحاوية التي بها Ubuntu 14.04 و Python 2.7 السابقة تطبيق Pip عبر مدير حزم Ubuntu (أي apt-get install python-pip) ثم باستعمال pip نصب لي مكتاب بايثون السابق ذكرها
  • مشروع الويب الخاص بي يحتاج قاعدة بيانات MySQL، نصبها يا Docker عبر مدير حزم Ubuntu
  • أيضا نحتاج nginx أو apache، كذلك تطلب من Docker أن ينصبه عبر مدير حزم Ubuntu

اجمع لي كل هذا في صورة واحدة (image) يمكن تشغيلها على أي خادوم أو حاسوب به Docker عبر الأمر:

 
docker run my_image

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

FROM ubuntu 14.04

# Install Python
RUN apt-get install -y python-dev

# Install pip
RUN apt-get install -y python-pip

# Install requirements.txt
ADD requirements.txt /src/requirements.txt
RUN cd /src; pip install -r requirements.txt

# Add the Flask App
ADD . /src

# EXPOSE PORT
EXPOSE 80

# Run the Flask APP
CMD python src/app.py

يمكن حفظ هذه الأوامر في ملف باسم Dockerfile، يمكنك أيضا تشغيل هذا الملف لبناء صورة (image) لحاوية container من خلال Docker عبر الأمر التالي:

docker build -t <your username>/my-flask-app .

لاحظ النقطة في آخر الأمر، والتي تعني “استعمل ملف DockerFile الموجود في المجلد الحالي”، أما تعليمة t- بعد أمر build هي لاعطاء وسم (tag) للحاوية التي نريد بناءها. عادة من المتعارف عليه هو اعطاء اسم مستخدمك يليه “/” يليه اسم تطبيقك.

 مفهوم الحاويات (Containers)

الحاوية في Linux عبارة عن غلاف يطبّق مجموعات من القيود لعزل عملية أو مجموعة عمليات (processes) عن باقي مهام وعمليات النظام  من ناحية السياق (context)، الذاكرة RAM، القراءة والكتابة، الشابكة (Network)… الخ، بحيث تكون في معزل تام عن باقي الـ processes في النظام. أي نفس فكرة الـ sandboxing.

مفهوم الحاويات ليس جديدا، فقد بدأ بالظهور منذ أواخر عام 2007، حين عرض مهندسون لدى Google مشروع cgroups (اختصارا لـ Control Groups) ليتم دمجه في نواة Linux، منذ ذلك الوقت cgroups كان اللبنة الأساسية لعزل الموارد وكبحها في نظام Linux على مستوى النواة.

بعدها جاء مشروع LXC (اختصارا لـ LinuX Containers) والذي جمع بين cgroups وميزة عزل نطاقات الأسماء (namespace isolation) في نواة Linux، لتوفير إمكانية إنشاء مجموعات منفصلة عن بعضها من العمليات (process groups)، كل مجموعة مكتفية ذاتيا و/أو محدودة المواد، بحيث لا تدري كل مجموعة عن الأخرى بالرغم من أنهم يشاركون نفس النواة (نواة Linux). هذه المجموعات عُرفت باسم الحاويات Containers.

على الرغم من أن LXC الأقرب لفكرة Docker، إلا أنه بقي على مستوى منخفض ولم يوفر واجهة برمجية سهلة للمطورين مثل ما قدمه Docker.

إضافات Docker

في أيامه الأولى، اعتمد مشروع Docker على LXC وبنى عليه، أي استعمله كـ backend أو driver، (لكن الآن يمكن استعمال بدائل لـ LXC) لكنه أضاف عدة أمور عصرية، بعضها مستوحى من أنظمة إدارة النسخ (Version Control Systems) من ذلك:

  • مفهوم Docker image لبناء لقطات من الحاويات (نفس فكرة ملفات .iso) يمكن تصديرها واسترادها، وبالتالي يمكن بناء صورة للمشروع بأكمله ثم يكفي استراد تلك الصورة على الخاودم، يتوجب فقط أن يكون Docker مُنصّبا.
  • إمكانية عمل “إيداع” (Commit) للتغيرات التي قمت بها على صورة المشروع الخاص بك، وبالتالي إمكانية الرجوع للوراء في حال الخطأ، هذه الميزة تسمح أيضا لـ Docker أن يكون وسيلة حفظ احتياطي “backup”.
  • كل صورة بنيتها يمكنك مشاركتها مع المجتمع في فهرس docker، والذي كان اسمه Docker index ثم تحول مؤخرا إلى docker hub. ستجد فيه مثلا صور لـتطبيق WordPress منصبة على Ubuntu جاهزة للاستهلاك المباشر، أليس هذا رائعا؟
  • مفهوم الـ Dockerfile الذي سبق عرض ماهيته، وهو وسيلة لأتمتة وسرد خطوات بناء مشروعك أو حاويتك. الأتمتة التي تتيحها ملفات Dockerfiles تسمح بانتهاج نسق Continuous integration الذي تكلمنا عنه، تخيل أنك تريد تجربة مشروعك على Python 3 مثلا، كل ما عليك هو تغيير نسخة Python في ملف Dockerfile وبناء حاوية جديدة لتجرب عليها الناتج، فإن كان جيدا تدفعه للخادوم، وإن لم يكن كذلك تحذفه. نفس الشيء مع إصدارات المكتبات التي يعتمد عليها مشروعك.

هذه بعض مما أضافه Docker لما هو موجود، وهي وحدها كفيلة بإحداث قفزة وتحول نوعي في طريقتنا لبناء ونشر البرامج.

لكن السؤال الذي قد يطرحه البعض: أليس ما يعمله Docker هو نفسه ما تعمله الآلات الافتراضية Virtual Machines ومحاكاة الأنظمة؟

باختصار، نعم ولا :D وسنلخص الأمر في النقاط التالية:

  • Docker أخف بكثير من الآلات الافتراضية، يمكنك تشغيل العشرات من الحاويات في حاسوب عادي واحد، في حين لا يمكنك تشغيل 3-4 آلات افتراضية في حاسوب عادي واحد ولو كان قويا نسبيا (يثقل النظام). أي أن Docker يستهلك موارد أقل بكثير.
  • الآلات الافتراضية تقوم بمحاكاة كـــامــل النظام وكل ما فيه ووضعه فوق النظام المضيف، في حين Docker يتشارك النواة (Linux kernel) مع النظام المضيف.
  • ما يقوم به Docker هو تنزيل التوزيعات فقط، أي الـ bins/libs لكل توزيعة وفقط، في حين يتشارك النواة مع النظام المضيف ولا يُنزّل نواة جديدة مع تلك التوزيعة. تلك الـ bins/libs كفيلة لمحاكاة بيئة التوزيعة المرجوة، أما النواة فهي متشابهة بين جميع التوزيعات وبالتالي يتقاسمها مع النظام المضيف (لهذا Docker لا يعمل إلا على Linux).
  • Docker يعزل التطبيق واعتمادياته فقط، في حين الآلات الافتراضية تعزل كامل النظام وما فيه من تطبيقات.

الصورتان التاليتان توضحان الفرق بين Docker والآلات الافتراضية:

docker-vm

docker-docker

من خلال الصورتين يمكن ملاحظة أن وزن Docker على الخادوم بشكل عام أخف بكثير من الثقل الذي تحدثه الآلات الافتراضية.

الجدير بالذكر أيضا أن القائمين على مشروع Docker قاموا بتوفير ما يسمى بـ Docker Hub، يمكن فيه مشاركة صور (images) لمشروعك (إن كان مفتوح المصدر)، تجد فيه صورا للحلول مفتوحة المصدر المعروفة، كصور WordPress, joomla, mysql, nginx .. الخ، بحيث يمكنك استهلاكها مباشرة أو استيرادها والبناء عليها :) أدعوك ﻷن تلقي عليه نظرة.

يمكن أيضا أن تكون مستودعا خاصا لك، لمشاريعك التجارية غير مفتوحة المصدر / مجانية، تجلب منه وتسترد صورك الخاصة التي قمت ببنائها.

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

إذا كانت لغتك الانجليزية جيدة، فأنصحك بمشاهدة الفيديو التالية لفهم أعمق للمقال: