الحصول على عنوان IP لحاوية Docker: دليل عملي وشامل مع أمثلة توضيحية
توفر Docker القدرة على حزم وتشغيل التطبيقات في بيئات معزولة جزئياً تُعرف بالحاويات (Containers). بصفتك مطوراً أو مهندساً للبنية التحتية، لا شك أنك على دراية بمفاهيم Docker والحاويات. لذا، لن نغوص في أساسياتها، بل سنتجاوز المقدمات التقليدية لنتعمق مباشرة في جوهر الموضوع: هل تساءلت يوماً عن كيفية تحديد عنوان IP الخاص بحاوية Docker؟

فهم شبكة Docker: كيف تعمل؟
للبدء، دعنا نستكشف آلية عمل شبكات Docker. سنركز بشكل خاص على الشبكة الافتراضية من نوع bridge (الجسر)، والتي تُستخدم تلقائياً عند عدم تحديد نوع شبكة آخر عند إنشاء الحاويات.

تعمل شبكة bridge كشبكة خاصة داخلية للمضيف (host)، مما يسمح للحاويات المتصلة بها بالتواصل فيما بينها. يتم توفير الوصول الخارجي لهذه الحاويات عن طريق تعيين (exposing) المنافذ. تُعد شبكات bridge مثالية للتطبيقات التي تعمل في حاويات مستقلة وتحتاج إلى التفاعل مع بعضها البعض.
في الرسم التوضيحي أعلاه، يمكن لحاويتي db و web التواصل عبر شبكة bridge أنشأها المستخدم تُسمى mybridge. إذا لم تقم بإنشاء شبكات Docker مخصصة من قبل، فسترى قائمة شبكات مشابهة لما يلي:
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
c3cd46f397ce bridge bridge local
ad4e4c24568e host host local
1c69593fc6ac none null local
تُظهر القائمة الشبكة الافتراضية bridge، بالإضافة إلى شبكتي host و none. سنتجاهل الأخيرتين ونركز على شبكة bridge في أمثلتنا القادمة.
عناوين IP لحاويات Docker
بشكل افتراضي، تُمنح كل حاوية عنوان IP خاصاً بها لكل شبكة Docker تتصل بها. تُنشأ كل شبكة بقناع شبكة فرعية (subnet mask) افتراضي، يُستخدم لاحقاً كمجموعة عناوين (pool) لتوزيع عناوين IP. عادةً ما تستخدم Docker الشبكة الفرعية الافتراضية 172.17.0.0/16 لشبكات الحاويات. لتعميق فهمنا، سنطبق ذلك على حالة استخدام حقيقية.

مثال عملي: بيئة Hive و Hadoop على Docker
لتوضيح ذلك، سنستخدم بيئة Hive و Hadoop تحتوي على 5 حاويات Docker. إليك ملف docker-compose.yml الذي سنقوم بتشغيله:
version: "3"
services:
namenode:
image: bde2020/hadoop-namenode:2.0.0-hadoop2.7.4-java8
volumes:
- namenode:/hadoop/dfs/name
environment:
- CLUSTER_NAME=test
env_file:
- ./hadoop-hive.env
ports:
- "50070:50070"
datanode:
image: bde2020/hadoop-datanode:2.0.0-hadoop2.7.4-java8
volumes:
- datanode:/hadoop/dfs/data
env_file:
- ./hadoop-hive.env
environment:
SERVICE_PRECONDITION: "namenode:50070"
ports:
- "50075:50075"
hive-server:
image: bde2020/hive:2.3.2-postgresql-metastore
env_file:
- ./hadoop-hive.env
environment:
HIVE_CORE_CONF_javax_jdo_option_ConnectionURL: "jdbc:postgresql://hive-metastore/metastore"
SERVICE_PRECONDITION: "hive-metastore:9083"
ports:
- "10000:10000"
hive-metastore:
image: bde2020/hive:2.3.2-postgresql-metastore
env_file:
- ./hadoop-hive.env
command: /opt/hive/bin/hive --service metastore
environment:
SERVICE_PRECONDITION: "namenode:50070 datanode:50075 hive-metastore-postgresql:5432"
ports:
- "9083:9083"
hive-metastore-postgresql:
image: bde2020/hive-metastore-postgresql:2.3.0
volumes:
namenode:
datanode:
هذا الملف مأخوذ من مستودع docker-hive على GitHub. ولتسهيل القراءة، إليك تمثيل مرئي للملف:

أفضل بكثير! الآن لنقم بتشغيل هذه الحاويات:
docker-compose up -d
يمكننا الآن رؤية الحاويات الخمسة تعمل:
$ docker ps --format \
"table {{.ID}}\t{{.Status}}\t{{.Names}}"
CONTAINER ID STATUS NAMES
158741ba0339 Up 1 minutes dockerhive_hive-metastore-postgresql
607b00c25f29 Up 1 minutes dockerhive_namenode
2a2247e49046 Up 1 minutes dockerhive_hive-metastore
7f653d83f5d0 Up 1 minutes (healthy) dockerhive_hive-server
75000c343eb7 Up 1 minutes (healthy) dockerhive_datanode
بعد ذلك، دعنا نتحقق من شبكات Docker لدينا:
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
c3cd46f397ce bridge bridge local
9f6bc3c15568 docker-hive_default bridge local
ad4e4c24568e host host local
1c69593fc6ac none null local
لحظة… هناك شبكة جديدة تُسمى docker-hive_default! افتراضياً، يقوم Docker Compose بإنشاء شبكة واحدة لتطبيقك. ويُعطى اسم شبكة التطبيق بناءً على ‘اسم المشروع’ (project name)، والذي يُشتق من اسم المجلد الذي يوجد فيه ملف docker-compose.yml. بما أن مجلدنا يُسمى docker-hive، فهذا يفسر ظهور الشبكة الجديدة.
كيفية الحصول على عنوان IP لحاوية Docker – أمثلة عملية
الآن وقد لفتنا انتباهك، حان الوقت لكشف الغموض حول كيفية استرداد عناوين IP للحاويات.

1. استخدام الأمر Docker Inspect
يُعد الأمر docker inspect أداة ممتازة لاسترداد معلومات مفصلة ومنخفضة المستوى حول كائنات Docker. يمكنك استخلاص أي حقل من مخرجات JSON بطريقة مباشرة تماماً. هل نستخدمه للحصول على عنوان IP من حاوية dockerhive_datanode؟
$ docker inspect -f \
'{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' \
75000c343eb7
172.18.0.5
ألم نذكر سابقاً أن Docker يستخدم الشبكة الفرعية الافتراضية 172.17.0.0/16 لشبكات الحاويات؟ لماذا إذن عنوان IP الذي تم إرجاعه هو 172.18.0.5، وهو خارج هذا النطاق؟

للإجابة على هذا التساؤل، يجب أن نلقي نظرة على إعدادات الشبكة لدينا:
$ docker network inspect -f \
'{{range .IPAM.Config}}{{.Subnet}}{{end}}' 9f6bc3c15568
172.18.0.0/16
لقد قمنا بتنفيذ هذا المثال في جهاز افتراضي (VM) من نوع Compute Engine، وفي هذا الاختبار، تم تعيين شبكة فرعية مختلفة لشبكة Docker وهي 172.18.0.0/16. هذا يفسر الأمر!
علاوة على ذلك، يمكننا أيضاً البحث عن جميع عناوين IP داخل شبكة docker-hive_default. وبهذه الطريقة، لا نحتاج إلى البحث عن عنوان IP لكل حاوية على حدة:
$ docker network inspect -f \
'{{json .Containers}}' 9f6bc3c15568 | \
jq '.[] | .Name + ":" + .IPv4Address'
"dockerhive_hive-metastore-postgresql:172.18.0.6/16"
"dockerhive_hive-metastore:172.18.0.2/16"
"dockerhive_namenode:172.18.0.3/16"
"dockerhive_datanode:172.18.0.5/16"
"dockerhive_hive-server:172.18.0.4/16"

إذا لم تلاحظ، فقد استخدمنا أداة jq للمساعدة في تحليل كائن الخريطة (map object) الخاص بالحاويات (Containers).
2. استخدام الأمر Docker Exec
في المثال التالي، سنعمل مع حاوية dockerhive_namenode.
$ docker exec dockerhive_namenode cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.18.0.3 607b00c25f29
3. من داخل حاوية Docker
$ docker exec -it dockerhive_namenode /bin/bash
# running inside the dockerhive_namenode container
ip -4 -o address
7: eth0 inet 172.18.0.3/16 brd 172.18.255.255 scope global eth0
يمكننا أيضاً العثور على عناوين IP لحاويات أخرى موجودة ضمن نفس الشبكة، وذلك من داخل إحدى الحاويات:
التواصل مع Data node
# running inside the dockerhive_namenode container
ping dockerhive_datanode
PING dockerhive_datanode (172.18.0.5): 56 data bytes
64 bytes from 172.18.0.5: icmp_seq=0 ttl=64 time=0.092 ms
التواصل مع Hive metastore
# running inside the dockerhive_namenode container
ping dockerhive_hive-metastore
PING dockerhive_hive-metastore_1 (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: icmp_seq=0 ttl=64 time=0.087 ms
التواصل مع Hive server
# running inside the container
ping dockerhive_hive-server
PING dockerhive_hive-server (172.18.0.4): 56 data bytes
64 bytes from 172.18.0.4: icmp_seq=0 ttl=64 time=0.172 ms
الخلاصة التقنية
لقد تم تنفيذ جميع الأمثلة المذكورة في هذا الدليل على جهاز افتراضي (VM) يعمل بتوزيعة Linux على Compute Engine. من المهم ملاحظة أن الأوامر قد تختلف قليلاً عند تطبيقها في بيئات macOS أو Windows. يجب أيضاً الانتباه إلى أن عناوين IP المستخدمة في الأمثلة هي عناوين داخلية خاصة بشبكة docker-hive_default النموذجية. إذا كان لديك حالة استخدام تتطلب الاتصال بهذه الحاويات من خارج الشبكة الداخلية، فستحتاج إلى استخدام عنوان IP الخارجي للجهاز المضيف (host machine)، مع التأكد من أنك قد قمت بتعيين المنافذ (exposing ports) بشكل صحيح للحاويات. أما في البيئات التي تعتمد على أنظمة تنسيق الحاويات مثل Kubernetes، فمن الأفضل ترك مهمة إدارة عناوين IP والوصول الخارجي للنظام نفسه، حيث يوفر آليات متقدمة للتعامل مع هذه الجوانب بكفاءة ومرونة.
ملاحظة: الرسوم التوضيحية مقدمة من icons8.com بواسطة Murat Kalkavan.