आपकी Compose सेवा ऐसे API पर समय-सीमा पार कर जाती है जिसे उसी मशीन का ब्राउज़र बिना किसी शिकायत के खोलता है। यही अंतर सुराग है: जो अनुरोध काम करता है वह VPN टनल वाले होस्ट से निकलता है, और जो अटक जाता है वह अपना नेटवर्क स्टैक रखने वाले कंटेनर से निकलता है। कंटेनर के अंदर कुछ भी टनल के रूट नहीं जानता, इसलिए नाम कैसे भी लिखा जाए निजी गंतव्य अगम्य रहता है। समाधान होस्ट के माध्यम से जानबूझकर की गई छलांग है, अधिक चतुर रूट तालिका नहीं।

दो रास्ते क्यों अलग हैं, इससे शुरू करें, फिर तय करें कि टनल कहाँ रहनी चाहिए।

होस्ट क्यों काम करता है और कंटेनर क्यों नहीं

टनल उठाने से होस्ट को एक इंटरफ़ेस, रूट का समूह और आम तौर पर VPN द्वारा दी गई रिज़ॉल्वर प्रविष्टि मिलती है। कंटेनर को इसमें से कुछ भी विरासत में नहीं मिलता: वह इंजन के ब्रिज पर एक इंटरफ़ेस और उसी ब्रिज की ओर इशारा करने वाले डिफ़ॉल्ट रूट के साथ शुरू होता है। होस्ट पर स्थापित रूट उस नेमस्पेस के भीतर चल रही किसी भी चीज़ के लिए अदृश्य हैं।

इसीलिए लक्षण सिर्फ़ टूटे हुए नहीं बल्कि असंगत दिखते हैं। होस्ट निजी नाम हल करता है और जुड़ता है, क्योंकि वहाँ नाम और रूट दोनों मौजूद हैं। कंटेनर अपना पैकेट ऐसे निजी पते पर भेजता है जहाँ ब्रिज मार्ग पर कुछ भी नहीं पहुँच सकता, और अनुरोध समय-सीमा पार कर जाता है। कंटेनर की hosts फ़ाइल में नाम जोड़ने से कुछ नहीं बदलता, क्योंकि पता ही कंटेनर जहाँ बैठा है वहाँ से अगम्य है।

कंटेनर के भीतर से होस्ट तक पहुँचें

कंटेनर में कोई प्रक्रिया जो localhost डायल करती है, कंटेनर को डायल करती है। Docker Desktop host.docker.internal को ऐसे नाम के रूप में प्रकाशित करता है जो इंजन चलाने वाली मशीन की ओर वापस इशारा करता है; Linux इंजन इसे अनिर्धारित छोड़ देते हैं जब तक सेवा मांगे नहीं, और नीचे दिया मैपिंग यही करता है। इसके साथ एप्लिकेशन निजी पते के बजाय नाम और पोर्ट को लक्ष्य बनाता है।

services:
  app:
    extra_hosts:
      - "host.docker.internal:host-gateway"
    environment:
      INTERNAL_API_HOST: "host.docker.internal:8666"

टनल छलांग के होस्ट पक्ष पर ही रहती है, और उस चर में पोर्ट वही है जिस पर प्रॉक्सी सुनेगा। टनल खोने वाला कंटेनर अब एक ज्ञात छलांग पर विफल होता है, ऐसे रूट को आज़माने के बजाय जो उसके पास कभी था ही नहीं।

चुनें कि टनल कहाँ रहती है

निजी API चाहने वाली Compose सेवा के लिए तीन रूप संभव हैं, और वे इस बात में भिन्न हैं कि टनल किस प्रक्रिया के पास है। VPN क्लाइंट कंटेनर इमेज के भीतर चल सकता है, जिसके लिए टनल उपकरण उजागर करना और उसके साथ आने वाली नेटवर्क प्रशासन क्षमता देना आवश्यक है। एप्लिकेशन अलग टनल कंटेनर का नेटवर्क नेमस्पेस साझा कर सकता है, जिससे दोनों प्रक्रियाएँ एक स्टैक और एक रूट तालिका देखती हैं। या टनल होस्ट पर ही रह सकती है, होस्ट से कंटेनर में एक संकरे फ़ॉरवर्डर के साथ।

पहले दो प्रोफ़ाइल फ़ाइलें, पुनः कनेक्शन व्यवहार और रिज़ॉल्वर नीति परियोजना में खींच लाते हैं, और फ़ाइल की हर सेवा को टनल के स्वास्थ्य पर निर्भर बना देते हैं। एक API कॉल के लिए यह बहुत अधिक युग्मन है। एक ही आंतरिक एंडपॉइंट पढ़ने वाले विकास स्टैक के लिए होस्ट-पक्षीय फ़ॉरवर्डर सबसे छोटा परिवर्तन है जो क्रेडेंशियल वहीं रखता है जहाँ प्लेटफ़ॉर्म टीम उन्हें प्रबंधित करती है।

होस्ट पर एक संकरा मार्ग प्रकाशित करें

फ़ॉरवर्डर जो विरासत में पाता है उससे शुरू करें: इसे उस खाते के अंतर्गत चलाएँ जिसके पास टनल है, और उसके आउटबाउंड सॉकेट होस्ट के रूट और होस्ट का रिज़ॉल्वर ले लेंगे। nginx का एक location ब्लॉक एक मार्ग कवर करता है।

server {
    listen 8666;
    location /search/ {
        proxy_pass http://10.20.30.40:8090/;
        proxy_set_header Host internal-api.example;
        proxy_read_timeout 60s;
    }
}

पते और पोर्ट को अस्थायी मानें और वह जोड़ी डालें जिस पर API वास्तव में सुनता है। हर अतिरिक्त upstream अपना location ब्लॉक पाता है, और हर ब्लॉक को केवल वही मार्ग स्वीकार करने चाहिए जिन्हें यह सेवा कॉल करती है, ताकि प्रॉक्सी निजी नेटवर्क में सामान्य दरवाज़ा न बन जाए। जो क्लाइंट host-gateway से आते हैं उनके लिए श्रोता को ब्रिज पते पर बाँधें, केवल तभी loopback पर जब क्लाइंट होस्ट का नेटवर्क नेमस्पेस साझा करता हो, और कभी भी 0.0.0.0 पर नहीं। ऐसा पोर्ट भी चुनें जो अभी मुक्त हो: पहले से लिया गया नंबर प्रॉक्सी को सुनते नहीं रहने देता जबकि कंटेनर समय-सीमा पार करता रहता है, जिसे उस नेटवर्क खराबी से अलग नहीं पहचाना जा सकता जिससे आपने शुरू किया था।

पोर्ट, नाम और TLS निर्णय

नाम विभेदन रूटिंग की तरह ही बँटता है। कंटेनर की सार्वजनिक खोजें इंजन के रिज़ॉल्वर से गुज़रती हैं, इसलिए होस्ट पर हल होने वाला निजी नाम कंटेनर के भीतर नहीं हल होगा। प्रॉक्सी वह घटक है जो निजी नाम हल करता है, क्योंकि उसे होस्ट का रिज़ॉल्वर विरासत में मिलता है।

TLS वह निर्णय है जिसे टाला जाता है और फिर अगली विफलता की व्याख्या करता है। अगर प्रॉक्सी बाइट्स को अछूता भेजता है, तो कंटेनर API का अपना प्रमाणपत्र देखता है और अपने ट्रस्ट स्टोर में आंतरिक CA चाहता है। अगर प्रॉक्सी TLS समाप्त करता है, तो वह भरोसा होस्ट पर चला जाता है और एप्लिकेशन प्राप्त host हेडर से लिंक बनाने लगता है। एक व्यवस्था चुनें और उसे हर संसाधन पर लागू करें, क्योंकि दूसरी व्यवस्था द्वारा जारी रीडायरेक्ट ऐसे होस्टनाम की ओर जाता है जिसे कंटेनर हल नहीं कर सकता।

सेवा के भीतर से सत्यापित करें

अनुरोध कंटेनर से भेजें, होस्ट से नहीं: प्रॉक्सी मार्ग पर सादा curl, फिर एप्लिकेशन का अपना स्वास्थ्य जाँच। जब प्रॉक्सी उत्तर देता है पर एप्लिकेशन अब भी विफल होता है, तो तीन चीज़ों की तुलना करें: जो आधार URL वह बनाता है, उसके वातावरण में कोई भी प्रॉक्सी चर, और जिस CA पर वह भरोसा करता है। सभी कंटेनर के वातावरण और लॉग में होते हैं, और इनमें से कोई एक ठीक करने से VPN अछूता रहता है।

चुनी गई व्यवस्था को ताज़ा रहते ही परियोजना के README में लिखें। वरना इस समय-सीमा से टकराने वाला अगला व्यक्ति वही दोपहर यह दोबारा खोजने में बिताएगा कि टनल होस्ट पर रहती है।

संबंधित लेख