إجابة قصيرة: لا يمكنك ذلك. لا توجد طريقة مدعومة في Docker لإضافة منفذ منشور إلى حاوية قيد التشغيل. تكون تعيينات المنافذ ثابتة عند إنشاء الحاوية، ولا يمكن لـ docker run أو docker container update تغييرها لاحقًا. علم --publish-add موجود فقط لخدمات Swarm، وليس للحاويات المستقلة.
إذا لم تتمكن من إعادة تشغيل الحاوية، فهذه هي الخيارات التي تعمل فعليًا:
| الأسلوب | هل يضيف تعيين منفذ Docker حقيقي؟ | هل يعمل على Docker Desktop (macOS/Windows)؟ | هل يبقى بعد إعادة التشغيل؟ |
|---|---|---|---|
حاوية جانبية socat |
لا (إعادة توجيه TCP) | نعم | نعم، إذا أعيد تشغيل الحاوية الجانبية |
| وكيل عكسي (Nginx/Traefik/HAProxy) | لا (بروكسي) | نعم | نعم |
قاعدة DNAT في iptables على المضيف |
لا (قاعدة NAT على المضيف) | لا، لينكس أصلي فقط | لا، إلا إذا تم حفظها |
إعادة إنشاء الحاوية مع -p |
نعم | نعم | نعم |
الطريقة الوحيدة التي تنتج منفذًا منشورًا حقيقيًا مُدارًا بواسطة Docker — وهو الذي يظهر في docker ps و docker port — هي إعادة إنشاء الحاوية. كل شيء آخر يمرر حركة المرور في طبقة أعلى أو أسفل من سجلات منافذ Docker. اختر بناءً على ما إذا كان يمكنك تحمل إعادة التشغيل، واقرأ التحذيرات أدناه قبل تشغيل أي شيء في الإنتاج.
تشرح هذه المقالة كل طريقة، والأوامر الدقيقة، وأين تفشل كل واحدة.
الخلفية: كيف يعمل تعيين منافذ Docker
المبادئ الأساسية لتعيين منافذ الحاويات
في Docker، يتم تسهيل الاتصال بين المنفذ الداخلي للحاوية ومنفذ الجهاز المضيف من خلال تعيين المنافذ. عادةً، نحدد تعيينات المنافذ باستخدام معلمات -p أو --publish عند بدء تشغيل حاوية، كما هو موضح أدناه:
docker run -d -p 8080:80 nginx
يقوم الأمر أعلاه بتعيين المنفذ 8080 على الجهاز المضيف إلى المنفذ 80 داخل الحاوية. ونتيجة لذلك، يمكن للمستخدمين الخارجيين الوصول إلى خدمة الويب التي تعمل داخل الحاوية من خلال المنفذ 8080 على المضيف.
لماذا لا يسمح Docker بذلك
بمجرد بدء تشغيل الحاوية، لا يدعم Docker عمومًا إضافة تعيينات منافذ جديدة ديناميكيًا. بمعنى آخر، تظل تعيينات المنافذ الأولية ثابتة طوال دورة حياة الحاوية. إذا كنت بحاجة إلى إضافة المزيد من تعيينات المنافذ، فإن النهج التقليدي يتضمن إيقاف الحاوية وإعادة تشغيلها، مما قد يعطل الخدمات ويكون غير مقبول في بيئات الإنتاج.
الحلول الأربعة
لإضافة تعيينات منافذ ديناميكيًا إلى حاوية قيد التشغيل، يمكن استخدام عدة طرق:
2.1 حاوية جانبية تعيد توجيه المنفذ (موصى به)
حاوية منفصلة تنشر منفذ المضيف الجديد وتعيد توجيه حركة المرور إلى الحاوية الأصلية عبر شبكة Docker مشتركة. هذا هو الخيار الأكثر أمانًا لأن الحاوية الأصلية لا تُلمس أبدًا.
تصحيح مهم أولاً: لا يمكنك الجمع بين --network container:<name> و -p. توثق وثائق شبكات Docker أن --publish و --publish-all و --expose غير مدعومة للحاويات التي تستخدم وضع الشبكة container:، لأن مثل هذه الحاوية لا تملك مساحة اسم شبكة خاصة بها لتعيين المنافذ إليها. أي دليل يخبرك بتشغيل docker run -p 8081:81 --net container:your-container ... خاطئ، وسيرفضه Docker.
النمط العملي يستخدم شبكة معرّفة من قبل المستخدم حتى تتمكن الحاوية الجانبية من الوصول إلى الهدف باسم الحاوية:
# 1. أنشئ شبكة واربط الحاوية قيد التشغيل بها (لا حاجة لإعادة التشغيل)
docker network create app-net
docker network connect app-net your-container
# 2. شغّل حاوية جانبية socat تنشر المنفذ 8081 وتعيد التوجيه إلى منفذ الهدف 81
docker run -d --name port-sidecar \
--network app-net \
--restart unless-stopped \
-p 8081:81 \
alpine/socat \
TCP-LISTEN:81,fork,reuseaddr TCP:your-container:81
لاحظ أن docker network connect يعمل على حاوية قيد التشغيل، لذا لا تسبب الخطوة 1 أي توقف. تستمع الحاوية الجانبية على المنفذ 81 داخل مساحة الاسم الخاصة بها، وينشر -p 8081:81 ذلك إلى المضيف.
تحذيرات:
- هذا إعادة توجيه TCP، وليس تعيين منفذ Docker. لن يظهر في
docker port your-container. alpine/socatيعيد توجيه TCP فقط. بالنسبة لـ UDP استخدمUDP-LISTEN/UDP، وبالنسبة لـ HTTP مع توجيه قائم على المضيف، يفضل استخدام Nginx أو Traefik أو Caddy أو HAProxy.- أضف
--restart unless-stopped(كما هو أعلاه) أو سيختفي إعادة التوجيه عند إعادة التشغيل. - القفزة الإضافية تكلف قدرًا صغيرًا من زمن الوصول وتضيف عملية إضافية للمراقبة.
2.2 قاعدة DNAT في iptables على المضيف (لينكس أصلي فقط)
على مضيف لينكس أصلي، يمكنك إضافة قاعدة DNAT تعيد توجيه منفذ المضيف إلى عنوان IP الداخلي للحاوية:
# احصل على عنوان IP للحاوية
CONTAINER_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' your-container)
# أعد توجيه منفذ المضيف 8081 إلى منفذ الحاوية 81
sudo iptables -t nat -A DOCKER -p tcp --dport 8081 \
-j DNAT --to-destination "${CONTAINER_IP}:81"
يمنحك هذا تحكمًا دقيقًا ولكنه يحمل أكبر مخاطر تشغيلية من أي طريقة هنا:
- لن يعمل Docker Desktop على macOS وWindows بهذه الطريقة. تعمل الحاويات داخل جهاز افتراضي لينكس، لذا فإن قواعد
iptablesعلى جهازك لا تلمس مسار شبكات Docker. هذه الطريقة مخصصة للينكس الأصلي فقط. - القواعد لا تبقى. تُفقد عند إعادة التشغيل أو إعادة تحميل جدار الحماية أو الانتقال بين nftables/iptables. استخدم آلية استمرار جدار الحماية الخاصة بتوزيعتك إذا كنت بحاجة إلى بقائها.
- يمتلك Docker سلسلة
DOCKER. ينشئ Docker هذه القواعد ويديرها من تكوين منافذ الحاويات قيد التشغيل، وتقول وثائقه إنه لا يجب تعديل القواعد التي ينشئها Docker. للتصفية المخصصة، يخصص DockerDOCKER-USERكمكان للقواعد المعرفة من قبل المستخدم، لأن القواعد المضافة إلىFORWARDتُعالج بعد قواعد Docker الخاصة. - عناوين IP للحاويات غير مستقرة. يتغير العنوان كلما أعيد إنشاء الحاوية، مما يترك قاعدة قديمة تعيد التوجيه بصمت إلى لا مكان.
- يتجاوز سجلات Docker. لن يظهر المنفذ في
docker psأوdocker port.
2.3 تشغيل socat مباشرة على المضيف
يمكنك أيضًا تشغيل socat كعملية مضيف عادية بدلاً من داخل حاوية:
socat TCP-LISTEN:8081,fork,reuseaddr TCP:<container_ip>:81
يعمل هذا على لينكس الأصلي، حيث يمكن توجيه عنوان IP للحاوية من المضيف. على Docker Desktop لنظامي macOS وWindows، لا يمكن الوصول إلى عنوان IP للحاوية ليس من جهازك، لذا استخدم الحاوية الجانبية في القسم 2.1 بدلاً من ذلك. في كلتا الحالتين، تحتاج إلى مشرف عمليات (systemd، أو --restart على الحاوية الجانبية) ليبقى بعد إعادة التشغيل، لأن عملية socat المجردة تموت مع غلافها.
2.4 إعادة إنشاء الخدمة باستخدام Docker Compose
هذه هي الطريقة الوحيدة التي تنتج منفذًا منشورًا حقيقيًا مُدارًا بواسطة Docker. أضف التعيين إلى compose.yaml:
services:
app:
image: your-image:tag
ports:
- "8081:81"
ثم أعد إنشاء تلك الخدمة فقط:
docker compose up -d app
يعيد Compose إنشاء الحاوية، لذا هناك انقطاع قصير — هذا ليس تغييرًا مباشرًا. لاحظ أن Docker الحديث يستخدم docker compose (أمر فرعي)، وليس الثنائي المستقل القديم docker-compose. احتفظ بالحالة في وحدات تخزين مسماة أو روابط تحميل حتى تبقى بعد إعادة الإنشاء.
2.5 تحرير ملفات تكوين Docker الداخلية (غير موصى به)
ستجد نصائح لتحرير /var/lib/docker/containers/<id>/config.v2.json و hostconfig.json يدويًا لإضافة إدخال PortBindings، ثم إعادة تشغيل الخفي. يعمل هذا أحيانًا، لكن تعامل معه كخيار أخير:
- هذه ملفات تنفيذ داخلية بدون ضمانات استقرار، وليست واجهة برمجة تطبيقات مدعومة. يمكن أن يتغير التنسيق بين إصدارات Docker.
- يحتفظ الخفي بحالة الحاوية في الذاكرة. تحرير الملفات تحت خفي قيد التشغيل يخاطر بأن يتم استبدال تغييراتك، ويمكن أن تترك التعديلات الجزئية حالة شبكة الحاوية غير متسقة مع بياناتها الوصفية.
- يجب إيقاف الخفي قبل التحرير، مما يؤثر على كل حاوية على المضيف.
- إذا تم تمكين
live-restore، تستمر الحاويات في العمل عبر إعادة تشغيل الخفي — لكن هذا لا يطبق تعيين منفذ محرر. لا يغير Live-restore القاعدة التي تنص على أن المنفذ المنشور الجديد يتطلب إعادة إنشاء الحاوية.
إذا وصلت إلى نقطة تحرير حالة الخفي يدويًا، فإن إعادة إنشاء الحاوية مع العلم -p الصحيح أسرع وأكثر أمانًا.
الخلاصة
لا يدعم Docker إضافة منفذ منشور إلى حاوية قيد التشغيل، ولا يغير أي حل بديل ذلك. ما تقدمه لك الطرق أعلاه هو طريقة لتوجيه حركة مرور جديدة إلى حاوية لا يمكنك إعادة تشغيلها.
اختر بهذا الترتيب:
- هل يمكنك تحمل إعادة تشغيل قصيرة؟ أعد إنشاء الحاوية مع العلم
-pالصحيح، أو أضفports:إلىcompose.yamlوشغّلdocker compose up -d. هذه هي الطريقة الوحيدة التي تنتج تعيين منفذ Docker حقيقي. - لا يمكنك إعادة التشغيل؟ استخدم الحاوية الجانبية
socatفي القسم 2.1، أو وكيلًا عكسيًا إذا كنت بحاجة إلى توجيه HTTP أو TLS أو فحوصات الصحة. - لينكس أصلي وتحتاج إلى إعادة توجيه مؤقتة سريعة؟ تعمل قاعدة DNAT في
iptables، لكن احفظها عمدًا وتوقع أن يتدخل Docker في سلاسله الخاصة. - تجنب تحرير ملفات تكوين الخفي يدويًا.
إذا كانت تعيينات المنافذ تتغير كثيرًا، فهذه عادة إشارة تصميم: ضع وكيلًا عكسيًا أمام الخدمة من البداية، ودعه يمتلك المنافذ المواجهة للمضيف بحيث تبقى دورة حياة الحاوية والتوجيه مستقلين.
المصادر: Docker: Publishing ports, Docker: Container networking modes, Docker: Packet filtering and firewalls, Docker and iptables, docker container port.
يمكنك زيارة Novita AI للحصول على مثيلات GPU وواجهات برمجة تطبيقات النماذج.