منظر نظام الملفات في العمليات المحصورة
كيف يبدو نظام الملفات للعمليات التي تعمل داخل حاوية؟ قد يعتقد المرء فورًا أن هذا يتعلق بمساحة اسم التثبيت (Mount Namespace)—يجب أن ترى العمليات داخل الحاوية نظام ملفات مستقلًا تمامًا. بهذه الطريقة، يمكن تنفيذ العمليات داخل أدلة الحاوية، مثل /tmp، دون أي تأثير من الجهاز المضيف أو الحاويات الأخرى. هل هذا هو الحال بالفعل؟
دور مساحة اسم التثبيت (Mount Namespace)
تعمل مساحة اسم التثبيت (Mount Namespace) بشكل مختلف قليلاً عن مساحات الأسماء الأخرى، حيث أن تأثيرها على رؤية عملية الحاوية لنظام الملفات لا يظهر إلا مع عملية تثبيت. ومع ذلك، كمستخدمين عاديين، نرغب في سيناريو أكثر سهولة: في كل مرة يتم إنشاء حاوية جديدة، نريد أن ترى عملية الحاوية نظام ملفات يمثل بيئة معزولة بدلاً من أن يكون موروثًا من المضيف. كيف يمكن تحقيق ذلك؟
ليس من الصعب تخيل أنه يمكننا إعادة تثبيت دليل الجذر بالكامل “/” قبل بدء عملية الحاوية. بفضل مساحة اسم التثبيت، سيكون هذا التثبيت غير مرئي للمضيف، مما يسمح لعملية الحاوية بالعمل بحرية داخله. في نظام التشغيل Linux، يوجد أمر يسمى chroot يمكنه إنجاز هذه المهمة بسهولة في شل. كما يوحي الاسم، فهو يساعدك على “تغيير نظام ملفات الجذر”، معيدًا توجيه دليل الجذر للعملية إلى موقع محدد.
صور الحاويات وrootfs
في الواقع، تم اختراع مساحة اسم التثبيت بناءً على تحسينات مستمرة لـ chroot، وهي أول مساحة اسم في Linux. لجعل دليل الجذر هذا يبدو أكثر “واقعية” للحاويات، نقوم عادةً بتثبيت نظام ملفات كامل لنظام تشغيل تحت هذا الجذر، مثل ISO Ubuntu 16.04. ونتيجة لذلك، بعد بدء الحاوية، سيكشف تنفيذ “ls /” داخل الحاوية عن جميع أدلة وملفات Ubuntu 16.04. يُعرف نظام الملفات هذا المثبت على دليل الجذر للحاوية، والذي يوفر بيئة تنفيذ معزولة لعمليات الحاوية، باسم “صورة الحاوية”. كما أن له مصطلحًا تقنيًا آخر: rootfs (نظام ملفات الجذر).
إن /bin/bash الذي يتم تنفيذه بعد الدخول إلى الحاوية هو الملف القابل للتنفيذ تحت دليل /bin، وهو مختلف تمامًا عن /bin/bash الخاص بالمضيف. الآن يجب أن تفهم أن المبدأ الأساسي وراء مشاريع Docker يتضمن أساسًا تكوين مساحة اسم Linux (Linux Namespace) لعملية المستخدم المراد إنشاؤها، وتعيين معلمات Cgroups محددة، وتغيير دليل الجذر للعملية (Change Root). وهكذا، تولد حاوية كاملة.
النواة المشتركة وتبعيات التطبيق في الحاويات
ومع ذلك، يفضل Docker استخدام استدعاء النظام pivot_root للخطوة الأخيرة من التبديل، ويعود إلى chroot إذا لم يدعم النظام pivot_root. على الرغم من أن هذين الاستدعاءين لهما وظائف متشابهة، إلا أن هناك اختلافات طفيفة. علاوة على ذلك، من الضروري توضيح أن rootfs يتضمن فقط ملفات وتكوينات وأدلة نظام التشغيل، وليس النواة. في Linux، يتم تخزين هذين الجزأين بشكل منفصل، حيث يتم تحميل صورة النواة لإصدار معين فقط أثناء الإقلاع. لذلك، يتضمن rootfs فقط “قشرة” نظام التشغيل، وليس “روحه”.
إذن، أين “روح” نظام التشغيل للحاويات؟ في الواقع، تشترك جميع الحاويات على نفس الجهاز في نواة نظام التشغيل المضيف. هذا يعني أنه إذا كان تطبيقك يحتاج إلى تكوين معلمات النواة، أو تحميل وحدات نواة إضافية، أو التفاعل مباشرة مع النواة، فيجب أن تلاحظ أن هذه العمليات والتبعيات تستهدف نواة نظام التشغيل المضيف، وهو “متغير عام” لجميع الحاويات على ذلك الجهاز. هذا هو أحد العيوب الرئيسية للحاويات مقارنة بالأجهزة الافتراضية: فالأخيرة لا تحتوي فقط على أجهزة محاكاة كصندوق رمل، بل تقوم أيضًا بتشغيل نظام تشغيل ضيف كامل داخل كل صندوق رمل لاستخدام التطبيقات. ومع ذلك، نظرًا لوجود rootfs، تتمتع الحاويات بميزة مهمة تم الإعلان عنها على نطاق واسع: التناسق.
مفهوم الطبقات في صور الحاويات
ما هو “التناسق” في الحاويات؟ بسبب الاختلافات بين بيئات الخادم السحابي والمحلي، كانت عملية تعبئة التطبيقات دائمًا واحدة من أكثر الخطوات “إيلامًا” عند استخدام PaaS. ومع ذلك، مع الحاويات، أو بشكل أكثر دقة، مع صور الحاويات (أي rootfs)، تم حل هذه المشكلة بأناقة.
نظرًا لأن rootfs لا يعبئ التطبيق فحسب، بل يعبئ نظام التشغيل بأكمله بملفاته وأدلته، فإنه يغلف جميع التبعيات اللازمة لتشغيل التطبيق. في الواقع، بالنسبة لمعظم المطورين، كان فهمهم لتبعيات التطبيق يقتصر على مستوى لغة البرمجة، مثل Godeps.json لجولانج. ومع ذلك، هناك حقيقة تم تجاهلها لفترة طويلة وهي أن نظام التشغيل نفسه هو “مكتبة التبعيات” الأكثر اكتمالًا التي يحتاجها التطبيق لتشغيله.
مع قدرة صور الحاويات على “تعبئة نظام التشغيل”، تصبح بيئة التبعية الأساسية هذه أخيرًا جزءًا من صندوق رمل التطبيق. وهذا يمنح الحاويات تناسقها الذي يتم الترويج له: بغض النظر عما إذا كان على جهاز محلي أو في السحابة أو في أي مكان آخر، يحتاج المستخدمون فقط إلى فك ضغط صورة الحاوية لإعادة إنشاء بيئة التنفيذ الكاملة المطلوبة لتشغيل التطبيق.
التصميم الطبقي المتزايد في صور الحاويات
هذا التناسق على مستوى نظام التشغيل يسد الفجوة بين بيئات التطوير المحلية والتنفيذ عن بُعد للتطبيقات. ومع ذلك، ربما لاحظت مشكلة أخرى صعبة: هل نحتاج إلى إعادة إنشاء rootfs في كل مرة نطور فيها تطبيقًا جديدًا أو نحدث تطبيقًا موجودًا؟ قد يكون الحل البديهي هو حفظ rootfs بعد كل عملية “ذات معنى” أثناء إنشائه، مما يسمح للزملاء باستخدام rootfs الذي يحتاجونه.
لكن هذا الحل ليس قابلاً للتوسع. السبب هو أنه بمجرد أن يعدل الزملاء هذا rootfs، لن تكون هناك علاقة بين rootfs القديم والجديد، مما يؤدي إلى تشتت شديد. نظرًا لأن هذه التعديلات تستند إلى rootfs قديم، فهل يمكننا جعل هذه التغييرات تزايدية؟ فائدة هذا النهج هي أن الجميع يحتاج فقط إلى الحفاظ على المحتوى التزايدي بالنسبة إلى rootfs الأساسي، بدلاً من إنشاء “fork” مع كل تعديل.
الإجابة هي بالطبع نعم. هذا هو السبب وراء عدم اتباع Docker للعملية القياسية لإنشاء rootfs عند تنفيذ صور Docker، بل قام بابتكار صغير: قدم Docker مفهوم الطبقات في تصميم صوره. كل عملية يقوم بها المستخدمون لإنشاء صورة تولد طبقة، وهي rootfs تزايدي. هذه الفكرة لم تأت من العدم، بل استفادت من قدرة تسمى نظام الملفات الموحد (Union File System أو UnionFS)، وتتمثل وظيفتها الرئيسية في تثبيت موحد (union mount) لأدلة متعددة من مواقع مختلفة في دليل واحد.
الطبقات في الحاويات

الطبقات في الحاويات
الجزء 1: الطبقات القابلة للقراءة فقط. هذه هي الطبقات الخمس السفلية من rootfs لهذه الحاوية، والتي تتوافق مع الطبقات الخمس لصورة ubuntu:latest. يتم تثبيتها كقراءة فقط (ro+wh، أي readonly+whiteout). تحتوي كل طبقة بشكل تزايدي على جزء من نظام تشغيل Ubuntu.
الجزء 2: الطبقة القابلة للقراءة والكتابة. هذه هي الطبقة العليا من rootfs لهذه الحاوية (6e3be5d2ecccae7cc)، مثبتة كـ rw، أي قراءة وكتابة. قبل كتابة أي ملفات، يكون هذا الدليل فارغًا. بمجرد إجراء عملية كتابة داخل الحاوية، تظهر التعديلات بشكل تزايدي في هذه الطبقة. ولكن هل فكرت ماذا يحدث إذا أردت حذف ملف من الطبقة القابلة للقراءة فقط؟ لتحقيق هذا الحذف، يقوم AuFS بإنشاء ملف whiteout في الطبقة القابلة للقراءة والكتابة “لإخفاء” الملف في الطبقة القابلة للقراءة فقط. على سبيل المثال، حذف ملف باسم foo من الطبقة القابلة للقراءة فقط يؤدي في الواقع إلى إنشاء ملف باسم .wh.foo في الطبقة القابلة للكتابة. وبالتالي، عند تثبيت هذه الطبقات بشكل موحد، يتم إخفاء ملف foo بواسطة ملف .wh.foo و"يختفي". هذه الوظيفة هي ما يعنيه أسلوب التثبيت “ro+wh”، أي قراءة فقط مع whiteout.
الجزء 3: طبقة التهيئة. هذه طبقة داخلية تم إنشاؤها بواسطة مشروع Docker، وتنتهي بـ “-init”، وتقع بين الطبقات القابلة للقراءة فقط والطبقة القابلة للقراءة والكتابة. طبقة التهيئة مخصصة لتخزين معلومات مثل /etc/hosts و /etc/resolv.conf. تنشأ الحاجة لمثل هذه الطبقة لأن هذه الملفات تنتمي أصلاً إلى صورة Ubuntu القابلة للقراءة فقط، ولكنها غالبًا ما تتطلب قيمًا محددة، مثل اسم المضيف، ليتم كتابتها عند بدء تشغيل الحاوية. وبالتالي، يلزم إجراء تعديلات في الطبقة القابلة للقراءة والكتابة. ومع ذلك، فإن هذه التعديلات تنطبق عادةً فقط على الحاوية الحالية وليس المقصود إدراجها مع الطبقة القابلة للقراءة والكتابة عند تنفيذ docker commit. لذلك، فإن نهج Docker هو تثبيت هذه الملفات المعدلة في طبقة منفصلة. عندما ينفذ المستخدم docker commit، يتم إدراج الطبقة القابلة للقراءة والكتابة فقط، مع استبعاد هذا المحتوى.
مزايا التصميم الطبقي في صور الحاويات
من خلال تصميم “الصورة الطبقية”، مع صور Docker كنواة، أصبح الفنيون من شركات وفرق مختلفة مرتبطين بشكل وثيق. علاوة على ذلك، نظرًا لأن العمليات على صور الحاويات تزايدية، فإن المحتوى الذي يتم سحبه أو دفعه في كل مرة يكون أصغر بكثير من أنظمة التشغيل الكاملة المتعددة؛ الطبقات المشتركة تعني أن المساحة الإجمالية المطلوبة لجميع صور الحاويات هذه أقل من مجموع كل صورة على حدة. إن سرعة التعاون هذه القائمة على صور الحاويات تتجاوز بكثير قدرة صور أقراص الأجهزة الافتراضية التي يمكن أن يصل حجمها إلى عدة غيغابايت.
الأهم من ذلك، بمجرد نشر صورة، فإن تنزيلها في أي مكان في العالم يعطي نفس المحتوى تمامًا، مما يعيد إنتاج البيئة الأصلية التي أنشأها منشئ الصورة بالكامل.
تأثير صور الحاويات على سير عمل تطوير البرمجيات
لم يؤد اختراع صور الحاويات إلى سد كل خطوة في عملية “التطوير - الاختبار - النشر” فحسب، بل يشير أيضًا إلى أن صور الحاويات ستصبح الطريقة الرئيسية لتوزيع البرمجيات في المستقبل. تقدم طريقة التوزيع هذه مزايا مثل كونها خفيفة الوزن، شديدة التناسق، وتسهيل التعاون، مما يجعل تطوير البرمجيات ونشرها أكثر كفاءة وموثوقية. بفضل خفة وزنها وتناسقها وكفاءتها، أصبحت تقنية الحاويات أداة أساسية بشكل متزايد في تطوير البرمجيات وعملياتها. مع استمرار تطور التكنولوجيا والابتكار، هناك سبب للاعتقاد بأن تقنية الحاويات ستلعب دورًا أكثر أهمية في المستقبل.
Novita AI، المنصة الشاملة للإبداع اللامحدود التي تمنحك إمكانية الوصول إلى أكثر من 100 واجهة برمجة تطبيقات. من توليد الصور ومعالجة اللغة إلى تحسين الصوت ومعالجة الفيديو، بنظام الدفع حسب الاستخدام الرخيص، يحررك من متاعب صيانة وحدة معالجة الرسومات أثناء بناء منتجاتك الخاصة. جربها مجانًا.
