الوحدة 1 · الـ Containers من المبادئ الأولى
ما هو الـ container حقًا
14 دقراءة 3 داختر بحكمة
الدرس في لمحة
اشرح ما هو الـ container فعلًا (عملية Linux عادية مع namespaces وcgroups ونظام ملفات قادم من image)، وكيف ترتبط الـ images بالـ containers.
لا فيديو هنا، بل الشيء الحقيقي: درس مكتوب وأمثلة قابلة للتشغيل واختبار وتدريب.
في الساعة 2:40 فجرًا ذات ليلة، بدأت إحدى خدمات Skylane تفشل في فحوص الصحة على كل الـ nodes دفعة واحدة، مع أن الكود لم يتغيّر. تبيّن أن مكتبة أساسية على خادم البناء رُقّيت بصمت، فلم يعد البرنامج الذي شحنّاه مطابقًا للبرنامج الذي اختبرناه. وُجدت الـ containers (الحاويات) لتضع حدًّا لمثل هذه الليالي: تشحن البرنامج ومعه كل ما يحتاج إليه في حزمة واحدة، فيكون ما اختبرته هو نفسه ما يعمل.
أنا Amara Diallo. أتولّى المناوبة (on-call) على الـ clusters في Skylane، وكل ما في هذه الدورة إمّا شيء كسرته بنفسي أو شيء رأيته ينكسر أمامي. سنعمل على خدمة واحدة من البداية إلى النهاية.
المشروع: notes-api
notes-api واجهة HTTP API صغيرة لإدارة الملاحظات، مكتوب بـ TypeScript ويعمل على Node.js 24. يخزّن بياناته في Postgres ويعرض أربعة مسارات: GET /notes وPOST /notes وGET /healthz (هل العملية حيّة؟) وGET /readyz (هل تصل إلى قاعدة البيانات؟). يستمع على المنفذ (port) 3000، ويقرأ إعداداته من متغيّرات البيئة مثل DATABASE_URL.
بنهاية الدورة ستكون قد بنيت الـ image الخاصة به، وشغّلته مع Postgres على جهازك، ونشرته على Kubernetes مع فحوص الصحة والتوسّع التلقائي وخطة للتراجع.
الـ container عملية
لا يوجد داخل نواة Linux كائن اسمه «container». حين تشغّل container، يبدأ الـ runtime عملية عادية ويغلّفها بثلاثة أشياء:
- الـ Namespaces تغيّر ما تستطيع العملية رؤيته: شجرة عمليات خاصة بها (تطبيقك هو PID 1)، وواجهات شبكة خاصة، واسم مضيف خاص، ورؤية خاصة لأنظمة الملفات المركّبة.
- مجموعات التحكّم (cgroups) تحدّ ما تستطيع استهلاكه: وقت المعالج، والذاكرة، والإدخال والإخراج.
- الـ image (صورة الحاوية) تقدّم نظام الملفات الجذري: ملف Node.js التنفيذي، وكودك المترجَم، و
node_modules، وبعض مكتبات النظام.
ولأنه لا يوجد نظام تشغيل ضيف يحتاج إلى الإقلاع، يبدأ الـ container بسرعة البرنامج الذي بداخله. والثمن أن كل الـ containers على المضيف تتشارك نواة واحدة. الآلة الافتراضية جدار أقوى؛ أما الـ container فباب محكم القفل. لهذا تُصرّ الدروس اللاحقة على المستخدمين غير الـ root وعلى الـ images الصغيرة: فأنت تقلّص ما يستطيع المهاجم فعله إن تجاوز ذلك الباب.
على macOS وWindows، يشغّل Docker Desktop آلة Linux افتراضية خفيفة واحدة ويضع الـ containers داخلها. النموذج هو نفسه، كل ما في الأمر أن هناك طبقة إضافية واحدة في الأسفل.
الـ image مقابل الـ container
الـ image لقطة لنظام ملفات مقسّمة إلى layers (طبقات)، للقراءة فقط، مع بيانات وصفية: أي أمر يُشغَّل، وأي منفذ يتوقّعه التطبيق، وبأي مستخدم يعمل. أما الـ container فنسخة قيد التشغيل من الـ image، فوقها layer رقيقة قابلة للكتابة.
ينطبق تشبيه الـ class والـ object هنا جيدًا: image واحدة، وcontainers كثيرة. حين نوسّع notes-api إلى ست نسخ في Kubernetes، فهذه image واحدة وستة containers. والـ layer القابلة للكتابة في كل container خاصة به وقابلة للتخلّص منها، لذا فالقاعدة من اليوم الأول: الـ containers قطيع يُستبدل، والبيانات تعيش في مكان آخر. سيحفظ Postgres ملفاته في volume (وحدة تخزين دائمة)، وليس أبدًا في الـ layer القابلة للكتابة داخل container.
في الدرس التالي ستكتب أول Dockerfile لـ notes-api، وتحوّل الكود المصدري إلى image تستطيع تشغيلها.
أهم النقاط
- الـ container عملية Linux عادية، تعزلها النواة بالـ namespaces وتحدّ مواردها بالـ cgroups.
- تتشارك الـ containers نواة المضيف، ولهذا تبدأ خلال أجزاء من الثانية، ولهذا أيضًا يكون عزلها أضعف من عزل الآلة الافتراضية.
- الـ image قالب للقراءة فقط مكوّن من layers لنظام الملفات مع بيانات وصفية؛ والـ container نسخة واحدة قيد التشغيل منها، فوقها layer رقيقة قابلة للكتابة.
- كل ما يكتبه الـ container في نظام ملفاته الخاص يختفي عند حذف الـ container، إلا إذا وضعته في volume.