Docker والحاويات

شبكات الحاويات

18 دقيقة الدرس 7 من 30

شبكات الحاويات

الشبكات هي المكان الذي تحدث فيه معظم المفاجآت في بيئات Docker الإنتاجية. حاوية تعمل بشكل مثالي بمعزل عن غيرها قد تفشل بصمت حين تحاول الوصول إلى قاعدة بيانات على نفس الخادم — أو إلى خدمة في حاوية أخرى — لأن المطور لم يفهم كيف يعزل Docker مكدس الشبكة. هذا الدرس يسد تلك الفجوة: ستفهم كل مشغّل شبكة تأتي به Docker، وكيف يعمل نشر المنافذ على مستوى النواة، وكيف يتيح نظام DNS للحاويات إيجاد بعضها بالاسم بدلاً من عنوان IP.

كيف تعزل Docker الشبكات

تحصل كل حاوية على مساحة اسم شبكة (network namespace) خاصة بها — وهي بنية أولية في نواة Linux تمنح الحاوية رؤية خاصة لواجهات الشبكة وجداول التوجيه وقواعد iptables. من داخل الحاوية، تكون eth0 هي واجهتها الوحيدة ولا علم لها بالمحوّل الفعلي للخادم أو الحاويات الأخرى، إلا إذا ربطتها صراحةً. تقوم Docker بتوصيل مساحات الأسماء ببعضها باستخدام أحد عدة مشغّلات الشبكة.

مشغّلات الشبكة الثلاثة الأساسية

bridge (الافتراضي)

هو المشغّل الافتراضي. تنشئ Docker جسراً إيثرنت افتراضياً (docker0) على الخادم. تحصل كل حاوية متصلة بشبكة bridge على زوج veth: طرف داخل مساحة اسم الحاوية والطرف الآخر مرتبط بالجسر. يمكن للحاويات على نفس الجسر الوصول إلى بعضها عبر IP. تمر الحركة الخارجة من الجسر عبر ترجمة عناوين الشبكة (NAT) في iptables من خلال الواجهة الفعلية للخادم.

عند إنشاء جسر محدد من المستخدم (أي جسر غير docker0)، يُفعّل Docker أيضاً خادم DNS مدمج — يمكن للحاويات حل أسماء بعضها باستخدام اسم الحاوية. جسر docker0 الافتراضي لا يمتلك هذه الميزة، لذا تحثّ التوثيقات على عدم الاعتماد على --link في بيئات الإنتاج.

تمييز رئيسي: جسر docker0 المدمج يمنح الحاويات عناوين IP لكن بدون DNS. شبكة الجسر المحددة من المستخدم تضيف دقة أسماء الحاويات بواسطة DNS تلقائياً. اصنع دائماً شبكة مسماة للتطبيقات متعددة الحاويات — هذه أهم عادة واحدة في شبكات Docker.

host

مع --network host، تشارك الحاوية مساحة اسم شبكة الخادم بالكامل. لا يوجد عزل: eth0 داخل الحاوية هي حرفياً eth0 الخادم. لا NAT، ولا حاجة لنشر المنافذ. يمنح هذا أقل زمن استجابة ممكن (بدون قفزة veth، بدون ترجمة iptables) ويُستخدم في التطبيقات الحرجة من ناحية الأداء — تداول التردد العالي، وعملاء الشبكة المبنية على eBPF، والبروكسيات الجانبية مثل Envoy في بعض الإعدادات.

مخاطر الإنتاج: على Linux، يعمل --network host كما هو موصوف. لكن على Docker Desktop لنظامي macOS وWindows، تعمل الحاوية داخل VM يعمل بنظام Linux، لذا يمنحك --network host شبكة VM لا شبكة جهازك. كود يعمل بشكل مثالي على مُشغّل CI يعمل بنظام Linux قد يتصرف بشكل مختلف على جهاز Mac لدى المطور.

none

تحصل الحاوية على مساحة اسمها الخاصة لكن لا تُهيَّأ أي واجهات — فقط loopback (lo). يُستخدم لمهام الدُفعات التي تعالج البيانات من وحدات التخزين المُركَّبة (volumes) دون أي إدخال/إخراج شبكي، أو كموقف أمني مُحكم للحاويات التي يجب أن لا تُرسل البيانات للخارج. يمكنك دائماً إرفاق واجهات إضافية لاحقاً باستخدام docker network connect.

نشر المنافذ

عنوان IP لحاوية bridge خاص بالخادم — لا يمكن لشيء خارجي الوصول إليها مباشرة. نشر المنافذ يربط منفذ الخادم بمنفذ الحاوية عبر قواعد iptables DNAT التي تديرها Docker عنك.

# ربط منفذ الخادم 8080 بمنفذ الحاوية 80 docker run -d -p 8080:80 nginx # الربط بواجهة خادم محددة فقط (تجنب 0.0.0.0 في الإنتاج) docker run -d -p 127.0.0.1:8080:80 nginx # النشر دون تحديد منفذ الخادم — تختار Docker منفذاً مؤقتاً docker run -d -p 80 nginx docker port <container_id> # لمعرفة المنفذ المُعيَّن # منفذ UDP (الافتراضي هو TCP) docker run -d -p 5353:5353/udp my-dns-server

عند نشر 0.0.0.0:8080->80، تُدرج Docker قاعدة DNAT في PREROUTING لـ iptables حتى يُعاد توجيه أي حزمة تصل على منفذ 8080 بالخادم إلى IP الخاصة للحاوية على المنفذ 80. هذا يعني أن الحاوية قابلة للوصول من الإنترنت إذا كان جدار حماية الخادم يسمح بالمنفذ 8080 — وهو سبب شائع للتعرض غير المقصود. يُفضَّل الربط بـ 127.0.0.1 واستخدام بروكسي عكسي (Nginx أو Caddy) أمامه، يُنهي TLS ويتحكم في الوصول.

ممارسة إنتاجية: لا تنشر المنافذ مباشرة إلى 0.0.0.0 لقواعد البيانات (Postgres أو Redis أو MongoDB). اربطها بـ 127.0.0.1 أو بشكل أفضل لا تنشرها أبداً — يمكن للحاويات على نفس شبكة user-defined الوصول إلى بعضها دون أي منفذ منشور.

DNS للحاويات في شبكات Bridge المحددة من المستخدم

عندما تكون الحاويات على نفس شبكة user-defined، يجيب محلل DNS المدمج في Docker (127.0.0.11) على الاستعلامات باستخدام أسماء الحاويات والأسماء المستعارة للخدمات كأسماء مضيف. يُحقَن المحلل في /etc/resolv.conf لكل حاوية تلقائياً.

# إنشاء شبكة معزولة docker network create app-net # تشغيل حاوية Postgres — لا منفذ منشور مطلوب docker run -d --name db --network app-net \ -e POSTGRES_PASSWORD=secret postgres:16-alpine # تشغيل حاوية التطبيق على نفس الشبكة docker run -d --name api --network app-net \ -e DATABASE_URL=postgres://postgres:secret@db:5432/mydb \ my-api-image # من داخل 'api'، تُحلَّل 'db' إلى IP حاوية Postgres docker exec api nslookup db # Server: 127.0.0.11 # Address: 127.0.0.11:53 # Name: db

هكذا بالضبط تربط Docker Compose الخدمات ببعضها — تنشئ شبكة مشتركة وكل خدمة تكون متاحة باسمها. فهم هذا يجعل إعدادات Compose أقل غموضاً.

مخطط: شبكة Bridge

Docker bridge network — two containers communicating via docker0 bridge with NAT to the internet Linux Host eth0 (host NIC) Internet / External Traffic iptables NAT docker0 bridge (172.17.0.1) veth veth Container A (api) eth0: 172.17.0.2 DNS: 127.0.0.11 Published: 0.0.0.0:8080 → 80 Container B (db) eth0: 172.17.0.3 DNS: 127.0.0.11 No published port db:5432 outbound
شبكة Docker bridge: تشترك الحاويات في جسر افتراضي، وتصل إلى بعضها عبر IP (أو بالاسم في شبكة user-defined)، وتصل إلى الإنترنت عبر NAT في iptables على واجهة الشبكة للخادم.

فحص الشبكات وتصحيح الأخطاء

# سرد كل الشبكات docker network ls # فحص شبكة — رؤية الحاويات المتصلة وعناوين IP الخاصة بها docker network inspect app-net # ربط حاوية تعمل حالياً بشبكة إضافية docker network connect app-net existing-container # فصل الاتصال docker network disconnect app-net existing-container # تشغيل حاوية تصحيح مؤقتة على نفس الشبكة docker run --rm --network app-net nicolaka/netshoot \ nmap -p 5432 db # فحص قواعد iptables التي أنشأتها Docker (يتطلب صلاحيات root) iptables -t nat -L -n --line-numbers | grep DOCKER

الشبكات متعددة الخوادم: Overlay Networks

شبكتا bridge وhost هما بنيتان تعملان على خادم واحد. عندما تحتاج الحاويات إلى التواصل عبر خوادم متعددة (مجموعة Swarm أو كلبنة بناء قبل الانتقال إلى Kubernetes)، يوفر Docker المشغّل overlay الذي ينشئ شبكة افتراضية موزعة باستخدام أنفاق VXLAN. يخرج Overlay عن نطاق هذا الدرس لكن من المهم معرفة أنه موجود — يسري نفس النموذج الذهني (شبكة user-defined ودقة الاسم عبر DNS) لكن ممتداً عبر خوادم متعددة.

قائمة تحقق الإنتاج

  • استخدم دائماً شبكات bridge المحددة من المستخدم — لا تعتمد أبداً على جسر docker0 الافتراضي أو --link.
  • لا تنشر منافذ قواعد البيانات على 0.0.0.0 — أبقها داخلية للشبكة؛ فقط حاوية التطبيق/البروكسي تحتاج منفذاً منشوراً.
  • اربط منافذ البروكسي العكسي بشكل صريح — استخدم 127.0.0.1:80:80 إذا كان بروكسي على مستوى الخادم (Nginx) يتولى إنهاء TLS.
  • استخدم أسماء الحاويات كأسماء مضيف في سلاسل الاتصال؛ عناوين IP الثابتة تنكسر في كل مرة تُعاد فيها إنشاء حاوية.
  • افصل الشبكات حسب مستوى الثقة — حاوية الواجهة الأمامية يجب ألا تشارك شبكة مع قاعدة البيانات؛ ضع API كطبقة وسطى بينهما.
ممارسة Google SRE: عامل شبكات الحاويات كمناطق جدار حماية. على نطاق Google، كل اتصال بين الخدمات مسموح به صراحةً؛ كل ما عدا ذلك مرفوض. طبق نفس المبدأ محلياً: أنشئ شبكة واحدة لكل طبقة (frontend وbackend وdata) واربط الحاويات فقط بالشبكات التي تحتاجها فعلاً. هذه العادة تتحول مباشرة إلى قواعد Kubernetes NetworkPolicy حين تنتقل إلى k8s.