VPN চালু, ব্রাউজার অভ্যন্তরীণ সাইটে পৌঁছায়, অথচ কন্টেইনার একই নামগুলো এখনও রিজলভ করতে পারে না। EAI_AGAIN-এর মতো নাম-রিজলভ ত্রুটিতে প্যাকেজ ইনস্টল মরে যায়, অথবা কোনো অ্যাপ্লিকেশন এমন একটি ডেটাবেস হোস্ট খুঁজে পায় না যা হোস্ট মেশিন কোনো অভিযোগ ছাড়াই রিজলভ করে। কন্টেইনার VPN যে রিজলভার ইনস্টল করেছে তা ব্যবহার করছে না। কন্টেইনার তৈরি হওয়ার সময় Docker হোস্টের রিজলভার কনফিগারেশন কপি করেছিল, এবং এরপর আর কিছুই তা আবার কপি করেনি।

একই মেশিনে রিজলভারের দুই রূপ

Linux-এ Docker প্রতিটি কন্টেইনারকে তৈরি হওয়ার মুহূর্তে হোস্টের রিজলভার কনফিগারেশনের একটি কপি দেয়, লুপব্যাক ঠিকানা বাদ দেয় এবং 127.0.0.11-এ একটি এমবেডেড DNS সার্ভার চালায় যা কোয়েরি বাইরে পাঠায়। কন্টেইনার চালু হওয়ার পর /etc/resolv.conf পুনর্লিখন করা VPN ক্লায়েন্ট তার ভেতরে কিছুই বদলায় না। কন্টেইনার রিস্টার্ট করা কেবল তখনই সাহায্য করে যখন সেই মুহূর্তে হোস্ট রিজলভারটি কাকতালীয়ভাবে সঠিক থাকে।

macOS বা Windows-এ Docker Desktop একটি স্তর যোগ করে, কারণ ডেমনটি ভার্চুয়াল মেশিনে বাস করে। হোস্টের VPN রিজলভারটি ওই VM-এর কাছে কখনও দৃশ্যমান নাও হতে পারে, তাই রিস্টার্ট করলে কিছুই বদলায় না। সমাধান বেছে নেওয়ার আগে দুই রূপ তুলনা করুন: হোস্টের রিজলভার তালিকার পাশে docker exec mycontainer cat /etc/resolv.conf।

হোস্ট অভ্যন্তরীণ রিজলভার তালিকাভুক্ত করার সময় কন্টেইনার যদি পাবলিক রিজলভার তালিকাভুক্ত করে, তবে তা পাবলিক নাম রিজলভ করবে আর অভ্যন্তরীণ নামে ব্যর্থ হবে। এই বিভাজনই এই সমস্যার স্বাক্ষর।

বিকল্প A: প্রতি কন্টেইনারে টানেল রিজলভার পাস করা

Docker প্রতি কন্টেইনারের জন্য DNS সেটিংস গ্রহণ করে, এবং এটি কার্যকর সবচেয়ে ছোট পরিবর্তন। প্রথমে VPN-এর রিজলভার ঠিকানা পড়ুন: macOS-এ scutil --dns, Linux-এ resolvectl status বা ক্লায়েন্টের নিজস্ব স্ট্যাটাস আউটপুট। তারপর সেগুলোসহ কন্টেইনার চালু করুন, উদাহরণস্বরূপ docker run --dns 192.168.2.1 --dns 192.168.123.1 myimage। Compose-এ একই সেটিং সার্ভিসের অধীনে একটি তালিকা, যেখানে এটি কারও শেল ইতিহাসের বদলে ভার্সন কন্ট্রোলে থাকে।

/etc/docker/daemon.json-এ dns অ্যারে প্রতিটি নতুন কন্টেইনারে প্রযোজ্য, যা বেশি গোছানো শোনায়, কিন্তু তা নয়। টানেল বন্ধ থাকলেও এটি প্রযোজ্য, এবং তখন কেবল VPN দিয়ে পৌঁছানো যায় এমন রিজলভার সাধারণ ইমেজ পুল ভেঙে দেয়। প্রতি কন্টেইনারের সেটিংস যুক্তি করা সহজ এবং ফিরিয়ে নেওয়াও সহজ।

বিকল্প B: কন্টেইনারকে হোস্ট নেটওয়ার্ক ভাগ করতে দেওয়া

হোস্ট নেটওয়ার্কিং কপিটিকে সম্পূর্ণ এড়িয়ে যায়, কারণ কন্টেইনার হোস্টের রিজলভার ও হোস্টের টানেল ব্যবহার করে। এটি আপনার সম্ভাব্য কাঙ্ক্ষিত নেটওয়ার্ক বিচ্ছিন্নতাও সরিয়ে দেয়, এবং Docker Desktop-এর অধীনে একইভাবে আচরণ করে না। Linux-এ অভ্যন্তরীণ নাম রিজলভ করতে হওয়া এককালীন টুলের জন্য এটি প্রায়োগিক পছন্দ।

বিল্ডের ক্ষেত্রে দুই বিকল্পের কোনোটিই প্রযোজ্য নয়, কারণ বিল্ড ধাপ রানটাইম ফ্ল্যাগ উত্তরাধিকার পায় না। প্ল্যাটফর্ম যেখানে অনুমতি দেয় সেখানে হোস্ট নেটওয়ার্কিং দিয়ে বিল্ড করুন, অথবা নির্ভরতা ইনস্টলেশন এমন একটি ধাপে রাখুন যার টানেল দরকার নেই।

কোনো বিকল্পই যা ঠিক করে না

কন্টেইনারের কাছে পথ না থাকলে DNS ঠিকানা অর্থহীন। VPN রিজলভার সাধারণত টানেলের ঠিকানা ক্ষেত্রের ভেতরে থাকে, তাই কন্টেইনারের ওই প্রিফিক্সে পথ দরকার। Docker-এর ডিফল্ট ব্রিজ সাধারণত হোস্ট দিয়ে বাইরে রুট করে, এবং হোস্টে টানেল রুট থাকলে ও ফরওয়ার্ডিং চালু থাকলে তা যথেষ্ট। নিজস্ব ঠিকানা পুলসহ কাস্টম ব্রিজ নেটওয়ার্ক VPN সাবনেটের সাথে সংঘর্ষে যেতে পারে, আর তখন কোয়েরিগুলো সম্পূর্ণ ভিন্ন জায়গায় চলে যায়।

রিজলভারটি নিজে ডিবাগ করার আগে Docker নেটওয়ার্কের সাবনেট VPN সাবনেটের বিপরীতে মিলিয়ে দেখুন। ওভারল্যাপ এমন ব্যর্থতা তৈরি করে যা দেখতে ঠিক একটি নষ্ট DNS সার্ভারের মতো।

কন্টেইনারের ভেতরে যাচাই করুন

ব্রাউজার বা ল্যাঙ্গুয়েজ রানটাইমের বদলে কন্টেইনারের ভেতরে getent hosts db.internal দিয়ে পরীক্ষা করুন, কারণ সেগুলো নিজেদের DNS নীতি ও নিজেদের ক্যাশিং প্রয়োগ করে। যদি getent নামটি রিজলভ করে আর অ্যাপ্লিকেশন এখনও ব্যর্থ হয়, তবে রিজলভার এখন সঠিক এবং বাকি সমস্যাটি অ্যাপ্লিকেশন স্তরের। যদি না করে, তবে DNS ধাপটি শেষ হয়নি।

DNS সেটিংস বদলানোর পর কন্টেইনারটি পুনরায় তৈরি করুন। চলমান কন্টেইনারের ভেতরে /etc/resolv.conf সম্পাদনা করা তার সাথে মিলিয়ে যায় এবং কনফিগারেশন সমস্যাটি ঠিক ততক্ষণ লুকিয়ে রাখে যতক্ষণ কেউ এটি রিস্টার্ট করতে না নেয়।

সম্পর্কিত নিবন্ধ