اليقين: كل إعداد، وأي بدائية يحرّك
الغاية التي طلبتَها: «أن أكون واثقاً تماماً من أي إعدادٍ أعدّله». ليس مفاهيم جديدة؛ هو جمع الخيوط. بنيت كل بدائيةٍ بيدك؛ الآن نربط كل علامةٍ في Docker و Compose و daemon.json بالبدائية التي تحرّكها.
النموذج الذهني الكامل
الجدول الكبير — علامة Docker ← البدائية
عزل الرؤية — namespaces (I)
| العلامة | تفعل | البدائية |
|---|---|---|
--hostname | اسم مضيفٍ خاص | UTS namespace |
--pid=host | يرى كل عمليات المضيف | يلغي PID namespace |
--network=host | يشارك مكدّس الشبكة | يلغي net namespace |
--network=container:X | يشارك شبكة كونتينر آخر = Pod | setns على net ns |
--ipc=host | يشارك ذاكرة IPC | يلغي IPC namespace |
--userns-remap | root وهمي معزول | user namespace (IV) |
--init | tini كـ PID 1 يحصد الأبناء | سلوك PID 1 |
عزل الموارد — cgroups (II)
| العلامة | تفعل | الملف |
|---|---|---|
--memory=512m | حدّ ذاكرةٍ صلب | memory.max |
--cpus=1.5 | حصةٌ زمنية صلبة | cpu.max |
--cpu-shares=512 | وزنٌ نسبي تنافسي | cpu.weight |
--cpuset-cpus=0,1 | تقييدٌ على أنويةٍ بعينها | cpuset.cpus |
--pids-limit=100 | حدّ العمليات (يمنع fork bomb) | pids.max |
--device-read-bps | حدّ معدّل قراءة جهاز | io.max |
نظام الملفات — overlay + mounts (III)
| العلامة | تفعل | البدائية |
|---|---|---|
-v /h:/c (bind) | يربط مسار مضيفٍ داخل الكونتينر | mount داخل mnt namespace |
-v name:/c (volume) | تخزينٌ يديره Docker | mount من volumes/ |
--tmpfs /tmp | نظام ملفاتٍ في الذاكرة | mount tmpfs |
--read-only | rootfs للقراءة فقط | mount ro + سطح هجومٍ أقل (IV) |
-v ...:z / :Z | إعادة وسم SELinux | LSM relabel (IV) |
الصلاحية والأمان (IV)
| العلامة | تفعل | البدائية |
|---|---|---|
--cap-drop=ALL | يسقط كل القدرات | capabilities bounding set |
--cap-add=NET_BIND_SERVICE | يعيد قدرةً بعينها | capability واحدة |
--security-opt seccomp=p.json | مرشّح syscalls مخصّص | seccomp BPF |
--security-opt no-new-privileges | يمنع تصعيد الامتياز | no_new_privs bit |
--user 1000:1000 | يشغّل بـ UID غير root | تغيير UID/GID المنفّذ |
--privileged | يفتح كل الدفاعات الأربع | كل القدرات + لا seccomp + أجهزة |
--device=/dev/... | يكشف جهازاً بعينه (بديل آمن) | device cgroup + mknod |
الشبكة (VI) و daemon.json
| العلامة / المفتاح | تفعل / يضبط | البدائية / الإقليم |
|---|---|---|
-p 8080:80 | ينشر منفذاً | DNAT في iptables/nft |
--network mynet | يربط بشبكةٍ معرّفة (DNS بالاسم) | bridge + veth + embedded DNS |
--network none | عزلٌ شبكي تام | net namespace فارغ |
storage-driver | overlay2 / btrfs | III |
default-runtime | runc / crun / runsc / kata | V |
live-restore | إبقاء الكونتينرات عند ترقية dockerd | V (الـ shim) |
userns-remap | تفعيل user namespace عام | IV |
منهجية التشخيص — أين تنظر عند أي مشكلة
| العَرَض | الطبقة | أداة الكشف |
|---|---|---|
| «يرى عمليات لا يجب أن يراها» | namespace | lsns, /proc/PID/ns/ |
OOMKilled / خروج 137 | cgroup memory | memory.events, memory.max |
| «بطء/خنق CPU غير مفسّر» | cgroup cpu | cpu.stat (throttling) |
| «الصورة ضخمة بلا سبب» | layers | docker history, whiteouts (III) |
Operation not permitted كـ root | cap/seccomp/LSM | status Cap*, dmesg |
| «لا يصل للإنترنت» | NAT/forward | iptables -t nat, conntrack |
| «كونتينران لا يتحلّان بالاسم» | embedded DNS | افتراضية vs user-defined (VI) |
| «مات ولم ألتقط الخطأ» | shim/logs | docker logs (V) |
لكل عَرَضٍ بُعدٌ واحدٌ مسؤول. اسأل «أي سؤالٍ من الأربعة انتُهك؟» فتعرف أين تنظر — بدل تخمينٍ عشوائي.
اللغز الختامي — المهندس العكسي
- اقرأ إعداداً، تنبّأ بالبدائية: خذ
docker-compose.ymlحقيقياً من مشروعٍ سابق لك. لكل خيارٍ فيه اكتب: أي بدائية kernel، أي ملف/أداة تفحصه للتحقق، ماذا يحدث لو أزلته. لا تترك خياراً مجهولاً. - من البدائية للعلامة (عكسياً): «عمليةٌ لا ترى عمليات المضيف، محدودةٌ بنصف نواة و256م، بلا
CAP_NET_RAW، بـ rootfs للقراءة فقط، على شبكةٍ معزولةٍ تخرج للإنترنت لكن لا تُنشر منافذها». اكتب أمرdocker runالكامل، واذكر لكل علامةٍ بدائيتها. اختبار اليقين النهائي. - الافتراضات:
docker run alpine sleep 1000بلا علامات، ثم شرّحه:lsns,statusللقدرات، cgroup الافتراضي, seccomp, الشبكة. وثّق كل دفاعٍ يطبّقه Docker افتراضياً نيابةً عنك — الإعدادات «الآمنة» التي كنت تثق بها عمياءً، الآن تراها بعينيك.
الخلاصة الكبرى — من مستخدمٍ إلى مهندس
بدأت تعرف Docker كأوامر. الآن تعرفه كـ تركيبٍ لبدائيات kernel تستطيع بناءها بيدك. الفرق هو الفرق بين من يحفظ الوصفة ومن يفهم الكيمياء.
راجع الأوراق المرجعية في صفحة المراجع: النماذج الذهنية، أوامر الكشف، وخريطة الإعداد ← البدائية كاملةً للطباعة.
كل ما بنيته يدير كونتينرات على مضيفٍ واحد. حين تصير المضيفات عشرات، يظهر سؤالٌ جديد: من يقرّر أي كونتينر على أي مضيف؟ من يعيد جدولته إن مات مضيف؟ من يصل شبكاته عبر الأجهزة (حصاد بذرة overlay في VI)؟ هذا عالم Kubernetes — وستدخله ولديك ميزةٌ نادرة: تعرف ما يجري داخل كل عقدةٍ حتى الـ syscall. k8s لا يخترع كونتينراً جديداً؛ يكلّم containerd (V) عبر CRI، ويجمع كونتيناتك في Pods (التي رأيتها مراراً: مشاركة namespaces).
أنت الآن واثق. هذه كانت الغاية.