حاوية التطوير لا تصل إلى مضيف متاح عبر VPN فقط: أين تبحث
المتصفح والحاوية لديهما سياقات مختلفة للمحلّل والوكيل والمسار. اكتشف أيّها تستخدمه العملية الفاشلة قبل أن تغيّر أي إعداد في VPN.
تفتح واجهة API الخاصة في متصفح سطح المكتب وتفشل داخل حاوية التطوير. هذا ليس تناقضًا، ونادرًا ما يكون السبب هو الـ VPN نفسه. طلب المتصفح والطلب الفاشل صدرا من عمليتين مختلفتين، بمحلّلات ووكلاء ومسارات مختلفة، وغالبًا من فضاءات أسماء شبكية مختلفة تمامًا. عبارة «على حاسوبي المحمول» قد تعني مضيف Windows، أو توزيعة WSL، أو الجهاز الافتراضي Docker Desktop، أو حاوية داخل ذلك الجهاز — أربعة سياقات يمكن لكل منها أن يجيب عن اسم المضيف نفسه بشكل مختلف. اكتشف أيّها تستخدمه العملية الفاشلة قبل أن تلمس أي إعداد.
حدّد العملية قبل تغيير أي إعداد
ابدأ بمحرّك الحاويات لا بعميل VPN. اسأل عن السياق الذي تتحدث إليه سطر الأوامر، وعن نظام التشغيل الذي يعمل عليه ذلك المحرّك، لأن حاوية Linux يديرها جهاز افتراضي لسطح المكتب تسلك مسارًا مختلفًا عن حاوية يديرها خدمة محلية:
docker context ls
docker info --format '{{.OperatingSystem}} / {{.Name}}'
docker run --rm alpine ip route
على Windows يخبرك wsl -l -v ما إذا كانت التوزيعة تعمل تحت WSL 2، وهو ما يضعها خلف مبدّل افتراضي خاص بها. هذه التفصيلة تحدد ما إذا كانت الحاوية تشارك جدول التوجيه الخاص بالمضيف أم تجلس خلف NAT يحتاج إلى منفذ مُمرَّر أو اسم مضيف للوصول إلى المضيف.
ثبّت طلبًا واحدًا وقارن
اختر نقطة نهاية غير ضارة على المضيف الخاص واستخدمها في كل مقارنة: من المتصفح، ومن طرفية المضيف، ومن توزيعة WSL، ومن داخل الحاوية. سجّل أربعة أشياء لكل محاولة: العنوان المُحلَّل، وما إذا استُخدم وكيل، وصنف الفشل، والزمن المنقضي. البحث عن الاسم وإنشاء الاتصال والتحقق من TLS وحالة HTTP أربع مشكلات مختلفة، وخلطها في عبارة «لا يعمل» يهدر صباحًا كاملًا.
نفّذ المقارنة داخل الحاوية الفاشلة، مع مهلة حتى لا يحتجز جدار حماية صامت الطرفية دقائق. الحاوية الجديدة تعيد إنتاج سياق شبكة المحرّك، لكنها لا تعيد فضاء الأسماء أو متغيرات الوكيل أو المحلّل الخاصة بحاوية التطبيق، لذلك فإن docker exec إلى الحاوية الحقيقية هو الاختبار الموثوق، أما الحاوية الجانبية فهي مجرد وسيلة لعزل ما إذا كان الفرق في المحرّك أم في الحاوية:
docker exec -it app /bin/sh -c "getent hosts api.internal; curl -v --max-time 8 https://api.internal/ 2>&1 | tail -20"
docker run --rm --network container:app curlimages/curl:latest -sv --max-time 8 https://api.internal/ 2>&1 | tail -20
صورة alpine الأساسية تحمل busybox ولا تحمل curl، وهذا بالضبط نوع التفصيلة التي تجعل كتلة تشخيص منسوخة تفشل: اختر صورة تحمل العميل، أو أضفه داخل التشغيل نفسه. المقارنة بمواقع عامة لا علاقة لها بالموضوع لا تعزل شيئًا. إذا عمل https://example.com من الحاوية، فقد علمت أن الحاوية تملك وصولًا إلى الإنترنت، ولم تعلم شيئًا عن قدرتها على الوصول إلى عنوان خاص عبر النفق. وبالمثل، فتح طرفية جديدة يثبت فقط أن الطرفية الجديدة تعمل، لا أنها تشترك في بيئة تشغيل مع التطبيق الذي فشل.
يمكن لـ Docker Desktop أن يعمل مع VPN
إن توثيق Docker نفسه حول VPN واتصال المضيف يصف ذلك بأنه إعداد مدعوم، والخلاصة الصادقة هي أنه يعمل بدلًا من أن يكون معطوبًا تلقائيًا. لا تفترض أن الجهاز الافتراضي لسطح المكتب يتجاوز نفق المضيف بحكم التصميم؛ ففي كثير من الإعدادات يتبع المرور نفق المضيف بشكل صحيح، ولهذا تنتج أسطورة «Docker يتجاهل الـ VPN» نصائح واثقة وخاطئة.
ما يبقى مهمًا هو الواجهة الخلفية المستخدمة، وسياسة النفق المنقسم لدى العميل، وإعدادات المحلّل التي تلقّاها الجهاز الافتراضي. عميل VPN يثبّت المسارات دون DNS، أو يدفع خادم DNS لا يستطيع الجهاز الوصول إليه، ينتج فشل البحث عن الاسم داخل الحاوية بينما يعمل المضيف لأنه يملك محلّلًا إضافيًا أو إجابة مخزّنة. هذه مشكلة محلّل ترتدي زي حاوية. وهي تصمد أمام كل إعادة اتصال VPN تحاولها، لأن النفق يحمل بالفعل المرور الذي طلبت منه حمله.
تداخل العناوين و MTU فشلان مختلفان
فشلان يستحقان تشخيصًا خاصًا لأنهما يُفهمان عادة على أنهما سياسة وصول. الأول هو تداخل العناوين: إذا دفع الـ VPN نطاقًا يتصادم مع الشبكة الفرعية الافتراضية لجسر شبكة الحاوية، فإن مسار الحاوية لذلك النطاق يشير إلى الجسر المحلي ولا يصل إلى النفق أبدًا. افحص الشبكات الفرعية الفعلية بدلًا من التخمين:
docker network inspect bridge --format '{{range .IPAM.Config}}{{.Subnet}}{{end}}'
ip route get 10.20.30.40
الثاني مشكلة MTU. إذا أُقيم الاتصال واكتمل TLS لكن الاستجابات الأكبر تتوقف، فلديك مشكلة حجم حزمة، لا مشكلة تفويض، واستبدال سجلات DNS لن يصلحها أبدًا. اختبر بطلب صغير وآخر كبير قبل أن تغيّر أي شيء، وسجّل النتيجتين.
إصلاح التداخل هو شبكة فرعية مختلفة للحاوية أو مسار محدود النطاق، يختاره مالك خطة العناوين. وإصلاح توقف MTU هو تثبيت أو تقليل MTU للنفق أو الواجهة إلى قيمة تصمد أمام المسار، ويُطبَّق في الطبقة التي تتحكم بها.
إعداد الوكيل لكل عملية، لا لكل جهاز
داخل الحاوية، يشير localhost إلى سياق الشبكة الخاص بتلك الحاوية، لذا لا يمكن الوصول إلى وكيل يعمل على المضيف هناك بذلك الاسم. يوفّر Docker Desktop الاسم host.docker.internal للوصول إلى المضيف، وعلى Linux تضيفه صراحةً بواسطة --add-host=host.docker.internal:host-gateway. في الحالتين يمنحك ذلك الاسم مسارًا إلى المضيف؛ وهو لا ينشئ خدمة وكيل ولا يخوّلك استخدام واحدة.
استخدم عنوان الوكيل ومنفذه المقدّمين للبيئة الفعلية، وتحقق من يقرأهما. المتغيرات المصدَّرة في صدفة تفاعلية لا تُعدّ تلقائيًا كل إضافة محرر وخادم لغة وأداة بناء وخفيّة خلفية. العملية المهمة هي التي أصدرت الطلب الفاشل، لذا افحص بيئتها لا بيئة طرفيتك.
أخيرًا، اجعل الإصلاح يشرح نفسه. الحل المفيد يسمّي الحدود التي كانت خاطئة، والإعداد الذي غيّرها، ومجموعة العمليات التي يتأثر بها الآن. إعادة تشغيل الـ VPN والمحرر والمحرّك بالترتيب قد تغيّر العَرَض، لكنها لا تترك شيئًا يستفيد منه الشخص التالي.