انتقال للمقال
وقت القراءة: ≈ 15 دقيقة

مقدمة عن الـ Docker

السلام عليكم ورحمة الله وبركاته


المقدمة

لنبدأ رحلة جديدة في المحيط ونرسي سفينتنا المليئة بالحاويات في ميناء مدونة الطبراني الجميلة

حسنًا لنبدأ سلسلة جديدة من المقالات عن الـ Docker، الأداة التي غيرت العالم وسهلت عمليات التطوير بشتى أنواعها
في هذه السلسلة سنبدأ من الأساسيات، نشرح ما هو الـ Docker، وكيف كان العالم قبل وجوده، وما المشاكل التي يحلها، ثم ننتقل إلى شرح عملي لكيفية استخدامه في مشاريعنا اليومية، مع أمثلة عملية بسيطة ومفهومة للجميع

بالطبع هذه المقالة ستكون مقدمة تعريفية عن الـ Docker
لذا لنبدأ بأول سؤال لدينا وهو كيف كان العالم قبل وجود الـ Docker؟

العالم قبل الـ Docker

قبل أي شيء عليك أن تعلم أن الـ Docker لم تخترع الذرة وما تفعله ليس جديدًا كليًا، بل هي فقط سهلت وبسطت عملية كانت معقدة وصعبة في السابق

المشكلة الأساسية التي كان يواجهها المطورون هي تجهيز البيئة التي سينفذ فيها التطبيق
بمعنى أنه لو لديك تطبيق لموقع معين
والموقع يقوم باستخدام PHP إصدار 8.2، و MySQL إصدار 8.0، و Redis إصدار 7.0 وبعض المكتبات الأخرى

هنا تحتاج من كل شخص يريد تشغيل هذا التطبيق أن يقوم بتجهيز بيئة مشابهة على جهازه الشخصي
وأيضًا في حالة الـ Deployment وتشغيل التطبيق على Server تحتاج إلى تجهيز نفس البيئة هناك أيضًا

أي شخص يريد تشغيل التطبيق عليه أن يقوم بتثبيت نفس الإصدارات من البرامج والمكتبات التي يعتمد عليها التطبيق
بدون أي خطأ في التثبيت أو اختلاف في الإصدارات لكي يعمل التطبيق بشكل صحيح
نفس الأمر الـ Server

الأمر قديمًا كان يتم بشكل يدوي
وكل شخص قد يواجه مشاكل مختلفة في التثبيت أو الإعدادات بسبب اختلافات في أنظمة التشغيل سواء كانت Windows، MacOS، أو Linux
أو حتى اختلافات في توزيعات Linux نفسها
مثل Ubuntu، Debian، CentOS، وغيرها

كل هذه الاختلافات كانت تسبب مشاكل كبيرة جدًا في تجهيز بيئة لكي نستطيع تشغيل تطبيقنا بشكل صحيح

المشكلة الأخرى هي في حالة أننا قررنا تحديث إصدار أحد البرامج التي يعتمد عليها التطبيق
مثلًا تحديث MySQL من إصدار 8.0 إلى 8.1
أو تحديث PHP من إصدار 8.2 إلى 8.3

هنا علينا التأكد أن جميع الذين يعملون على التطبيق قاموا بتحديث بيئاتهم أيضًا بنفس الطريقة
وعلينا أن نحدث الـ Server أيضًا بنفس الطريقة
وكل هذا كان يتم يدويًا وبصعوبة بالغة بحسب كل نظام تشغيل وكل شخص

وتخيل لو لدينا أكثر من Server بحيث لدينا Server للـ Development وآخر للـ Testing وآخر للـ Production
علينا تجهيز نفس البيئة على كل هذه الـ Servers
وأي تعديل على الإصدارات وأننا اعتمدنا على مكتبة جديدة أو أداة جديدة
علينا تحديث كل هذه الـ Servers بنفس الطريقة يدويًا


لاحظ أن مشكلتنا الأساسية هنا هي في تجهيز البيئة التي سيعمل فيها التطبيق
والتجهيز يكون بشكل يدوي دون خطأ
وقد يختلف تجهيز وتثبيت البرامج والمكتبات بين جهاز وآخر وبين نظام تشغيل وآخر

كل هذه العوامل تجعل من عملية تشغيل التطبيقات أمرًا صعبًا ومعقدًا جدًا
وقد يأخذ وقتًا طويلًا جدًا في التجهيز والتثبيت
بمجرد أننا نريد فقط تشغيل التطبيق لا أكثر حتى ولو على جهازنا الشخصي

المشكلة الأخرى في حالة أنني لدي تطبيق طورته بـ PHP إصدار 7.4
وصديقي أرسل لي تطبيق طوره بـ PHP إصدار 8.2

هنا لا يمكنني تشغيل تطبيقه على جهازي الذي يحتوي على PHP إصدار 7.4
وحتى لو قمت بتثبيت PHP إصدار 8.2 على جهازي
قد يؤثر ذلك على تطبيقاتي الأخرى التي تعتمد على PHP إصدار 7.4
وهنا تبدأ المشاكل في تعارض الإصدارات بين التطبيقات المختلفة على نفس الجهاز

الحل باستخدام الـ Virtual Machine

الآن بعد أن فهمنا المشاكل التي كانت تواجهنا قبل وجود الـ Docker

دعنا نوضح نقطة أن هذه المشاكل التي عرضناها كانت تُحل في السابق باستخدام الـ Virtual Machines
وهي عن طريق أننا نقوم بإنشاء جهاز وهمي كامل على جهازنا الشخصي
ونثبت عليه نظام تشغيل كامل مثل Linux أو Windows
ثم نقوم بتثبيت جميع البرامج والمكتبات التي يحتاجها التطبيق على هذا الجهاز الوهمي
وبهذا نضمن أن التطبيق سيعمل في بيئة معزولة تمامًا عن جهازنا الشخصي

هذا الحل جيد جدًا ويقدم عزلًا كاملًا للتطبيق عن جهازنا الشخصي
لكنه كان يعاني من عدة مشاكل

أولها أننا ما زلنا نعاني من مشكلة تجهيز البيئة بشكل يدوي
لأننا عندما ننشئ Virtual Machine جديدة نحتاج إلى القيام بنفس الخطوات يدويًا لكي نجهز البيئة ونثبت البرامج والمكتبات التي يحتاجها التطبيق

المشكلة الثانية كانت في الأداء والموارد التي يحتاجها الـ Virtual Machine
بحيث أن الـ Virtual Machines تأخذ مساحة وموارد كبيرة من جهازنا الشخصي
لأننا عندما ننشئ Virtual Machine داخل جهازنا الشخصي
فنحن نقوم بتثبيت نظام تشغيل كامل سواء كان Linux أو Windows بكل ما فيه من برامج وخدمات سواء

  • خدمات الـ GUI أو Desktop Environment
  • خدمات الـ USB والـ Audio/Video والـ Bluetooth و Power Management وغيرها من الخدمات التي تكون موجودة في الـ Operating System
  • تطبيقات افتراضية تأتي مع الـ Operating System مثل File Manager، Web Browser، Calculator، وغيرها
  • ... والعديد من البرامج والخدمات الأخرى

كل هذا يتم تثبيته على الـ Virtual Machine
بمجرد أننا نريد فقط تشغيل تطبيق معين
وتطبيقنا لا يحتاج إلى كل هذه البرامج والخدمات التي تكون موجودة في الـ Operating System

بمعنى تخيل لو كانت مساحة جهازك الشخصي هي 500GB
ولدينا ثلاث تطبيقات نريد تشغيلها وكل تطبيق يحتاج إلى Virtual Machine خاصة به
لنفترض أن كل تطبيق يحتاج إلى 5GB

هنا سننشئ ثلاث Virtual Machines على جهازنا الشخصي
تخيل أن مساحة كل Virtual Machine قد تصل من 50GB إلى 100GB بحسب نوع الـ Operating System الذي سنثبت عليه
ولأن كل Virtual Machine تحتاج إلى نظام تشغيل كامل عليه بكل ما فيه من برامج وخدمات
كأنك تنسخ الـ Operating System الخاص بجهازك الشخصي ثلاث مرات فكل Virtual Machine ستكون نسخة كاملة من الـ Operating System وتأخذ مساحة وموارد كبيرة من جهازك الشخصي

الآن فرضنا أن مساحة كل تطبيق هي 5GB ومساحة كل Virtual Machine هي 50GB
هكذا كل تطبيق سيحتاج إلى 55GB من المساحة على جهازنا الشخصي
بالتالي فإن تشغيل الثلاث تطبيقات سيكلفنا 165GB من المساحة على جهازنا الشخصي
ونحن في الأصل نحتاج فقط إلى 15GB لتشغيل التطبيقات الثلاثة
ولوافترضنا أننا نحتاج لمساحة احتياطية تقدر بـ 10GB لكل تطبيق
فهذا يعني أن الناتج النهائي سيكون 195GB من المساحة على جهازنا الشخصي
وهو رقم كبير جدًا مقارنة بالمساحة التي نحتاجها في الأصل لتشغيل التطبيقات وهي 15GB فقط
بالتالي لقد ضاع منا حوالي 180GB من المساحة على جهازنا الشخصي فقط بسبب أننا نستخدم الـ Virtual Machines كحل لتشغيل التطبيقات بشكل معزول

بالطبع هذه الأرقام تقريبية فقط لنحاول توضيح وتقريب الفكرة لا أكثر


المشكلة الأساسية ليست في الـ Virtual Machine كمفهوم بحد ذاته
بل المشكلة تكمن في أننا نقوم بتشغيل نظام تشغيل كامل على جهازنا الشخصي
بكل ما فيه من برامج وخدمات سواء GUI أو خدمات الـ USB والـ Audio/Video وغيرها من الخدمات والتطبيقات التي ذكرناها سابقًا
والتي لا نحتاجها لكي نشغل ونجهز بيئة التطبيق الذي نريد تشغيله
وكل هذا بمجرد أننا نريد فقط تشغيل تطبيق معين حجم قد لا يتجاوز الـ 5GB أو 10GB في بعض الأحيان

بالتالي لو وجدنا طريقة للتخلص من هذه البرامج والخدمات غير الضرورية التي تكون موجودة في الـ Operating System
بمعنى أننا نريد تثبيت فقط الـ Operating System بدون أي برامج أو خدمات إضافية
وكل هذا فقط حتى نستطيع أن نوفر بيئة تشغيل للتطبيق وبشكل معزول عن جهازنا الأساسي

مفهوم الـ Containerization

هنا ظهر مفهوم الـ Containerization كحل لهذه المشكلة
مفهوم الـ Containerization يعتمد على فكرة الـ Containers
والـ Container هو بيئة تشغيل معزولة للتطبيق يشبه الـ Virtual Machine
لكن الفرق الأساسي هو أن الـ Container لا يحتاج إلى تثبيت نظام تشغيل كامل عليه
هو فقط يحتاج لتثبيت الـ Operating System الأساسي كبرنامج خام بدون أي برامج أو خدمات إضافية

بمعنى أن الـ Container يستخدم نواة نظام التشغيل Kernel الموجودة على جهازك الأساسي
ولا يحتاج إلى تثبيت نواة جديدة أو نظام تشغيل كامل مثل الـ Virtual Machine
والـ Kernel هو الجزء الأساسي في نظام التشغيل الذي يتعامل مع الـ Hardware ويقوم بإدارة الموارد مثل الـ RAM، الـ CPU، والـ Storage بغض النظر عن نوع نظام التشغيل
بمعنى لو كنت تستخدم Windows أو MacOS أو Linux على جهازك الشخصي
فالـ Container سيستخدم نفس الـ Kernel الخاص بجهازك الشخصي
ويقوم بتشغيل التطبيق داخل بيئة معزولة باستخدام هذا الـ Kernel كأنه برنامج مثل أي برنامج آخر يعمل على جهازك الشخصي

هذا يعني أن الـ Container يأخذ مساحة أقل بكثير من الـ Virtual Machine
ويستهلك موارد أقل من حيث الـ RAM والـ CPU
لأنه لا يحتاج إلى تشغيل نظام تشغيل كامل بكل خدماته وبرامجه بل هو يعتمد على الـ Kernel الخاص بجهازك الشخصي

بالعودة إلى المثال السابق حيث لدينا ثلاث تطبيقات نريد تشغيلها
كل تطبيق يحتاج إلى 5GB من المساحة

باستخدام الـ Containers لن نحتاج إلى تخصيص 50GB لكل تطبيق كما في حالة الـ Virtual Machine
لأننا لن نقوم بتثبيت نظام تشغيل كامل على كل Container
نحن فقط سنثبت الـ Operating System الأساسي كبرنامج خام بدون أي برامج أو خدمات إضافية
والذي يصل حجمه من 1MB إلى أقل من 1GB بحسب نوع الـ Operating System الذي سنستخدمه
فعلى سبيل المثال لو استخدمنا Alpine Linux كنظام تشغيل أساسي للـ Container
فإن حجمه سيكون حوالي 10MB فقط

بالتالي لو لدينا ثلاث تطبيقات كل تطبيق يحتاج إلى 5GB من المساحة
باستخدام الـ Containers سنحتاج فقط إلى حوالي 15GB لتشغيل التطبيقات الثلاثة
ولن نحتاج إلى تخصيص 150GB كما في حالة الـ Virtual Machines

هذه أحد الفوائد الكبيرة للـ Containers مقارنة بالـ Virtual Machines
أنه يأخذ مساحة وموارد أقل بكثير

ومثل الـ Virtual Machines، الـ Containers توفر عزل كامل للتطبيق عن جهازنا الشخصي
بالتالي ما يحدث في الـ Container لن يؤثر على جهازنا الشخصي
والـ Container لا يهتم بنوع الـ Operating System الذي يعمل عليه جهازنا الشخصي
سواء كان Windows، MacOS، أو Linux

تخيله كبرنامج مستقل بذاته يعمل على جهازك الشخصي
وهذا البرنامج المنعزل قام بتشغيل Linux كنظام تشغيل أساسي بدون أي برامج أو خدمات إضافية
ثم قام بتشغيل تطبيقك داخل هذا النظام المعزول
وكل هذا في مساحة وموارد أقل بكثير من الـ Virtual Machine

تلخيص للمشاكل قبل وجود الـ Docker

نستطيع تلخيص كل المشاكل التي كنا نواجهها قبل وجود الـ Docker في النقاط التالية:

  • تجهيز البيئة التي سيعمل فيها التطبيق بشكل يدوي
  • اختلاف الـ Operating System بين المطورين وأجهزة الـ Server وأنواع توزيعاتها وإصداراتها المختلفة
  • تحديث وتغير الإصدارات والمكتبات التي يعتمد عليها التطبيق بشكل يدوي
  • تعارض الإصدارات بين التطبيقات المختلفة على نفس الجهاز، في حالة وجود أكثر من تطبيق يستخدم إصدارات مختلفة من نفس البرنامج
  • استهلاك موارد كبيرة من الجهاز عند استخدام الـ Virtual Machines كحل لهذه المشاكل
  • صعوبة في عملية الـ Deployment والتشغيل على أكثر من Server لأنها تحتاج إلى تجهيز يدوي لكل Server حيث أنه قد يختلف من Server لآخر
  • ... ومشاكل أخرى

وقلنا أن الـ Container استطاع أن يحل مشكلة استهلاك الموارد والمساحة بشكل كبير مقارنة بالـ Virtual Machines
لكن يظل هناك العديد من المشاكل التي لم تُحل بعد مثل تجهيز البيئة بشكل يدوي، واختلاف أنظمة التشغيل، وتحديث الإصدارات بشكل يدوي، وتعارض الإصدارات، وصعوبة عملية الـ Deployment

الآن السؤال هو كيف يمكننا إنشاء وإدارة الـ Container بسهولة؟
هنا يأتي دور الـ Docker التي سهلت وبسطت عملية إنشاء وإدارة الـ Containers بشكل كبير جدًا
والعمليات والتجهيزات التي كنا نقوم بها يدويًا أصبحت الآن تتم بشكل آلي وسهل جدًا باستخدام الـ Docker

ما هو الـ Docker ؟

الآن بعد أن فهمنا مفهوم الـ Container
دعنا نتعرف على الـ Docker

الـ Docker هو برنامج مفتوح المصدر لإنشاء وإدارة وتشغيل الـ Containers
بمعنى أن الـ Docker يوفر لنا مجموعة من الأدوات والتقنيات التي تسهل علينا إنشاء Containers وإدارتها وتشغيلها

بمعنى أنها لم تخترع مفهوم الـ Containerization بل هي استطاعت أتمتة وتبسيط عملية إنشاء وإدارة الـ Containers
وجعلها في متناول الجميع
قبل الـ Docker كان استخدام الـ Containers معقدًا جدًا ويحتاج إلى معرفة عميقة بنظام التشغيل وكانت مخصصة لأشخاص معينين فقط لديهم خبرة كبيرة في هذا المجال
لكن الـ Docker قدم واجهة بسيطة وسهلة الاستخدام لإنشاء وإدارة الـ Containers وجعلها متاحة لجميع المطورين بغض النظر عن خبرتهم في هذا المجال


ملحوظة: كلمة Docker تعني عامل الميناء الذي يقوم بتحميل وتفريغ البضائع من السفن
وكلمة Dock تعني رصيف الميناء الذي ترسو عليه السفن
والـ Container تعني الحاوية التي تستخدم لنقل البضائع

يمكننا استخدام هذا التشبيه لفهم دور الـ Docker في عالم البرمجة
بحيث أن الحاويات تكون معزولة تمامًا عن بعضها البعض
ونحن نستطيع أن نرسل الحاويات من مكان إلى آخر بسهولة
ونستطيع أن ندير هذه الحاويات بسهولة باستخدام الـ Docker، الشخص الذي يقوم بتحميل وتفريغ هذه الحاويات من وإلى السفن

كل Container يحتوي على كل ما يحتاجه التطبيق لكي يعمل بشكل صحيح
ولا يهتم أين يعمل هذا الـ Container هل سيذهب إلى القطب الشمالي أو إلى جبال الهيمالايا أو إلى صحراء الربع الخالي
أو إلى مخبأ كنز اللحية السوداء في أحد الجزر النائية في البحار والمحيطات السبع العميقة

أي مكان أو جهاز أو Server يعمل عليه الـ Docker يستطيع تشغيل الـ Container بكل سهولة
بغض النظر عن نظام التشغيل أو البيئة التي يعمل عليها هذا الجهاز أو الـ Server

الفرق بين الـ Docker والـ Virtual Machine

الآن بعد أن فهمنا مفهوم الـ Container والـ Docker
دعنا نوضح الفرق الجوهري بين الـ Docker Containers والـ Virtual Machines

في الـ Virtual Machine فنحن نقوم بإنشاء جهاز وهمي كامل على جهازنا الشخصي به نظام تشغيل كامل بداية من طبقات متعددة تبدأ من الـ Hardware وصولًا إلى التطبيقات
ويحتاج إلى Hypervisor وهو برنامج وسيط بين الـ Virtual Machine ونظام التشغيل المضيف
لكي يساعدك في تشغيل الـ Virtual Machine على جهازك الشخصي

وهذا يعني أن كل Virtual Machine تحتاج إلى نظام تشغيل كامل خاص بها
مما يستهلك مساحة وموارد كبيرة من الجهاز كما شرحنا سابقًا

+----------------+  +----------------+  +----------------+
|     App 1      |  |     App 2      |  |     App 3      |
|      5GB       |  |      5GB       |  |      5GB       |
+----------------+  +----------------+  +----------------+
|   Libraries    |  |   Libraries    |  |   Libraries    |
+----------------+  +----------------+  +----------------+
|   Guest OS     |  |   Guest OS     |  |   Guest OS     |
|   (Ubuntu)     |  |   (CentOS)     |  |   (Debian)     |
|     20GB       |  |     15GB       |  |     10GB       |
+----------------+  +----------------+  +----------------+
|                    Hypervisor                         |
+-------------------------------------------------------+
|                  Host OS (Windows)                    |
+-------------------------------------------------------+
|                      Hardware                         |
+-------------------------------------------------------+

لاحظ أن كل تطبيق حجمه 5GB لكن كل تطبيق احتاج إلى نظام تشغيل كامل بكل برامجه وخدماته وكل ما فيه من إضافات بحجم يتراوح بين 10GB إلى 20GB
عندما نقول أن Ubuntu يأخذ 20GB فهذا يشمل كل البرامج والخدمات التي تأتي مع نظام التشغيل Ubuntu بشكل افتراضي
نفس الأمر مع CentOS و Debian وكل أنظمة التشغيل الأخرى
بالتالي تشغيل الثلاث تطبيقات باستخدام الـ Virtual Machines كلفنا حوالي 60GB من المساحة على جهازنا الشخصي


أما مع الـ Docker فالأمر مختلف تمامًا
لأن الـ Containers تشترك في نفس الـ Kernel الخاص بنظام التشغيل الخاص بجهازك الشخصي
ولا يحتاج إلى Hypervisor كما في حالة الـ Virtual Machines
بل يعتمد على Docker Engine وهو مجرد برنامج مثله مثل أي برنامج آخر يعمل على جهازك الشخصي
ويقوم الـ Docker Engine بإدارة وتشغيل الـ Containers على جهازك الشخصي
والـ Docker Engine يستخدم الـ Kernel الخاص بجهازك بالتالي لا يحتاج إلى تثبيت نظام تشغيل كامل له

+----------------+  +----------------+  +----------------+
|     App 1      |  |     App 2      |  |     App 3      |
+----------------+  +----------------+  +----------------+
|   Libraries    |  |   Libraries    |  |   Libraries    |
+----------------+  +----------------+  +----------------+
|    Base OS     |  |    Base OS     |  |    Base OS     |
| (Alpine Linux) |  | (Alpine Linux) |  | (Alpine Linux) |
|     10MB       |  |      10MB      |  |      10MB      |
+----------------+  +----------------+  +----------------+
|                   Docker Engine                       |
+-------------------------------------------------------+
|                  Host OS (Windows)                    |
+-------------------------------------------------------+
|                      Hardware                         |
+-------------------------------------------------------+

لاحظ أن كل تطبيق حجمه 5GB لكن كل تطبيق احتاج إلى نظام تشغيل أساسي فقط كبرنامج خام بحجم 10MB فقط
عندما نقول أن Alpine Linux يأخذ 10MB فهذا يشمل الـ Operating System الأساسي فقط بدون أي برامج أو خدمات إضافية
بالتالي تشغيل الثلاث تطبيقات باستخدام الـ Docker Containers كلفنا حوالي 15GB من المساحة على جهازنا الشخصي

بالمناسبة لو بدلنا Alpine Linux بنظام تشغيل آخر مثل Ubuntu أو Debian أو CentOS
تجد أن حجم الـ Base OS الخاص بـ Ubuntu قد يصل إلى 100MB و Debian إلى 150MB و CentOS إلى 200MB
وهذا أقل بكثير من حجم نظام التشغيل الكامل الذي نحتاجه في حالة الـ Virtual Machines

المفاهيم الأساسية في الـ Docker

لكي نفهم الـ Docker بشكل جيد علينا أن نفهم بعض المفاهيم الأساسية:

Docker Image

الـ Docker Image هو قالب أو نموذج يحتوي على كل ما يحتاجه التطبيق لكي يعمل
مثل:

  • نظام التشغيل الأساسي (مثل Ubuntu أو Alpine Linux)
  • البرامج والمكتبات المطلوبة (مثل PHP، MySQL، Redis)
  • كود التطبيق نفسه
  • ملفات الإعدادات

Docker Container

الـ Docker Container هو نسخة من الـ Docker Image
فلو افترضنا أن لدينا Docker Image هو Class أو Interface
فالـ Docker Container هو الـ Object أو الـ Instance الذي يتم إنشاؤه من هذا الـ Image

بمعنى أن الـ Image هو القالب أو النموذج
والـ Container هو التطبيق الذي يعمل فعليًا بناءً على هذا القالب

يمكنك إنشاء عدة Containers من نفس الـ Image
كل Container سيكون معزولًا عن الآخر
ويمكنك تشغيلهم جميعًا في نفس الوقت

مثل فكرة إنشاء أكثر من Object من نفس الـ Class في الـ OOP
وكل Object يعمل بشكل مستقل عن الآخر

Dockerfile

الـ Dockerfile هو ملف نصي يحتوي على مجموعة من التعليمات لإنشاء Docker Image

في هذا الملف نكتب خطوات بناء الـ Image خطوة بخطوة
مثل:

  • ما هو نظام التشغيل الأساسي الذي سنستخدمه
  • ما هي البرامج التي سنثبتها
  • ما هي المكتبات التي سنحتاجها
  • كيف سننسخ كود التطبيق إلى الـ Image
  • ما هي الأوامر التي سنشغلها عند بدء تشغيل الـ Container

بمجرد أن نكتب الـ Dockerfile يمكننا بناء Image منه بأمر واحد بسيط
وهذا يضمن أن أي شخص يستخدم نفس الـ Dockerfile سيحصل على نفس الـ Image بالضبط
بغض النظر عن نظام التشغيل الذي يستخدمه

بالتالي مهما كان الجهاز الذي يستخدمه المطور أو الـ Server الذي سيشغل التطبيق عليه
ومهما كان الـ Operating System الخاص به
طالما أنه يستخدم نفس الـ Dockerfile سيحصل على نفس الـ Image والبيئة التي يحتاجها التطبيق
ويستطيع إنشاء Container منها وتشغيل التطبيق بدون أي مشاكل

وشكل ملف الـ Dockerfile يكون بسيط جدًا وسهل الفهم

FROM php:8.2.30-cli

WORKDIR /app

COPY . .

CMD ["php", "index.php"]

في هذا المثال البسيط، نقوم بإنشاء Docker Image يحتوي على PHP إصدار 8.2.30
ثم نقوم بتحديد مجلد العمل داخل الـ Container ليكون /app
ثم نقوم بنسخ كل ملفات التطبيق إلى داخل الـ Container
وأخيرًا نحدد الأمر الذي سيتم تشغيله عند بدء تشغيل الـ Container وهو تشغيل ملف index.php باستخدام PHP
الآن أي شخص يستخدم هذا الـ Dockerfile سيحصل على نفس الـ Image والبيئة التي يحتاجها التطبيق

لاحظ أن في هذا المثال استخدمنا PHP فقط ولم نحدد أي Operating System
بمعنى أننا لم نحتج إلى تثبيت أي Operating System من الأساس
كل ما ثبتناه هو PHP فقط داخل الـ Container وشغلنا التطبيق به دون الحاجة إلى أي Operating System على الإطلاق

بالطبع هذا مثال بسيط جدًا لم نحتج فيه إلى الكثير من البرامج أو المكتبات ولم نحتاج إلى Operating System
لكن في التطبيقات الحقيقية قد نحتاج إلى تثبيت برامج ومكتبات أخرى
مثل MySQL، Redis، Nginx، وغيرها من البرامج التي يحتاجها التطبيق لكي يعمل بشكل صحيح
وقد نحتاج إلى استخدام Operating System أساسي مثل Ubuntu أو Alpine Linux
كل هذا يتم تحديده في ملف الـ Dockerfile بكل سهولة
وأي شخص يستخدم نفس الـ Dockerfile سيحصل على نفس الـ Image والبيئة التي يحتاجها التطبيق

يمكننا القيام بأمور كثيرة جدًا باستخدام الـ Dockerfile
وفي أمور تحتاج إلى شرح عملي مفصل سنراها في المقالات القادمة

Docker Hub

الـ Docker Hub هو مستودع عام لحفظ ومشاركة الـ Docker Images
يمكنك أن تتخيله كأنها GitHub ولكن للـ Docker Images
أو أنه Package Manager للـ Docker Images
ولديه موقع إلكتروني يمكنك زيارته على الرابط التالي: https://hub.docker.com/

يمكنك رفع الـ Images التي أنشأتها على الـ Docker Hub ومشاركتها مع الآخرين
أو يمكنك تنزيل Images جاهزة أنشأها آخرون واستخدامها في مشاريعك

هناك آلاف الـ Images الجاهزة على الـ Docker Hub
مثل Images لـ MySQL، Redis، PostgreSQL، Nginx، PHP، Python وغيرها الكثير

هذا يوفر عليك الوقت والجهد في إنشاء Images من الصفر
يمكنك ببساطة استخدام Image جاهزة وتخصيصها حسب احتياجاتك

وغالبًا ما تكون هذه الـ Images محدثة بأحدث الإصدارات من البرامج والمكتبات ومدعومة من الشركات المطورة لها

كيف يحل الـ Docker المشاكل التي ذكرناها؟

الآن بعد أن فهمنا المفاهيم الأساسية
دعنا نرى كيف يحل الـ Docker المشاكل التي كنا نواجهها

قلنا أنه يوفر لنا Dockerfile وهو ملف نصي يحتوي على تعليمات لإنشاء Docker Image
وبالتالي يمكننا استخدام هذا الـ Dockerfile لحل المشاكل التي ذكرناها سابقًا
فبدلًا من أن يقوم كل شخص بتجهيز البيئة يدويًا على جهازه
يمكننا إنشاء Dockerfile واحد يحتوي على جميع التعليمات لتجهيز البيئة ثم نعطيه لجميع أعضاء الفريق أو نرفعه على الـ Server
ثم نبني Docker Image من هذا الـ Dockerfile
ونقوم بإنشاء Container من هذا الـ Image لتشغيل التطبيق في بيئة جاهزة تمامًا في بضع ثوانٍ
وسيحصل الجميع على بيئة جاهزة تمامًا بكل ما تحتاجه من برامج ومكتبات
بدون الحاجة إلى تثبيت أي شيء يدويًا

هذا يضمن أن الجميع يعملون في نفس البيئة بالضبط
ولن يكون هناك اختلافات بسبب أنظمة التشغيل المختلفة


وأيضًا عندما نريد تحديث إصدار أحد البرامج
مثل تحديث PHP من 8.2 إلى 8.3

نقوم فقط بتعديل الـ Dockerfile وتغيير رقم الإصدار
ثم سيقوم كل شخص بإعادة بناء الـ Image من الـ Dockerfile الجديد
وإعادة تشغيل الـ Container من الـ Image الجديد
وهكذا نكون قد حدثنا البيئة بكل سهولة وسرعة
بدون الحاجة إلى تحديث أي شيء يدويًا على جهازه

نفس الأمر في حالة الـ Server


وفي حالة أن هناك شخص لديه تطبيقات تعمل بإصدارات مختلفة من نفس البرنامج
فمثلًا لديك تطبيق يعمل بـ PHP 7.4 على جهازك الشخصي
والتطبيق الآخر يعمل بـ PHP 8.2

هنا ببساطة باستخدام الـ Docker سنقوم بإنشاء Dockerfile لكل تطبيق
وكل Dockerfile سيحدد الإصدار المطلوب من PHP
ثم نبني Docker Image من كل Dockerfile
كل Image ستحتوي على الإصدار المطلوب من PHP لكل تطبيق بشكل معزول
وعندما تشغل Container من كل Image سيعمل كل تطبيق في بيئته الخاصة
دون أن يؤثر أحدهما على الآخر

لأن كل Container معزول تمامًا عن الآخر
لأن الـ Container كما قلنا كأنه برنامج مستقل بذاته يعمل على جهازك الشخصي
وكل ما فيه من برامج ومكتبات يتم تثبيتها داخل الـ Container نفسه
ولا يؤثر على جهازك الشخصي أو على الـ Containers الأخرى

الخلاصة

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

وكما قلنا في البداية، الـ Docker غيرت العالم وجعلت من السهل جدًا إنشاء وإدارة وتشغيل الـ Containers
والتي كانت معقدة جدًا في السابق
وتحتاج لأشخاص متخصصين في هذا المجال

والآن باستخدام الـ Docker أصبح بإمكان أي مطور مهما كانت خبرته في هذا المجال
أن يقوم بإنشاء وإدارة وتشغيل الـ Containers بكل سهولة

الـ Docker يقدم لنا العديد من الفوائد مثل:

  • تبسيط عملية تجهيز البيئة: لا حاجة للتثبيت اليدوي للبرامج
  • تحقيق مبدأ الـ Consistency: الجميع يعمل في نفس البيئة بالضبط
  • تحقيق مبدأ الـ Isolation: كل تطبيق يعمل في بيئته الخاصة دون تداخل
  • توفير الموارد: استهلاك أقل للمساحة والذاكرة مقارنة بالـ Virtual Machines
  • سرعة التشغيل: تشغيل Container يأخذ ثوان معدودة فقط
  • سهولة النشر: يمكن نشر نفس الـ Image على أي Server بكل سهولة ولأكثر من شخص

في المقالات القادمة سنتعمق أكثر في استخدام الـ Docker
وسنتعلم كيف نكتب Dockerfile وننشئ Docker Image ونديرها وننشيء منها Container
مع أمثلة عملية خطوة بخطوة