Docker কনটেইনার কেন VPN-এর পেছনের হোস্টে পৌঁছায় না
ব্রিজ কনটেইনারের নিজের নেমস্পেস থাকে, তাই হোস্ট টানেল তাদের কাছে অদৃশ্য। DNS সম্পাদনার আগে হোস্ট নেটওয়ার্কিং, tun ডিভাইস ও macvlan তুলনা করুন।
কর্পোরেট VPN-এর পেছনে কিছুতে পৌঁছাতে না পারা কনটেইনার সাধারণত টানেলের চেয়ে ভিন্ন নেটওয়ার্ক নেমস্পেসে বাস করে। হোস্ট ক্লায়েন্টের রুট, DNS সার্ভার ও ফায়ারওয়াল মার্ক হোস্টের স্ট্যাকের অন্তর্গত; ব্রিজ-নেটওয়ার্ক কনটেইনারের নিজের স্ট্যাক থাকে। এই একক তথ্যই প্ল্যাটফর্ম দলে আসা বেশিরভাগ প্রতিবেদন ব্যাখ্যা করে, আর এ কারণেই «VPN নষ্ট» এবং «Docker VPN এড়িয়ে যায়» দুটোই একসাথে ভুল হতে পারে। একটি উপসর্গের পেছনে দুটি সম্পূর্ণ ভিন্ন ব্যবস্থা লুকিয়ে থাকে, তাই কোনো সেটিং বদলানোর আগে নির্ধারণ করুন আপনারটি কোনটি।
টানেল কার নেমস্পেসের অধীনে তা খুঁজে বের করুন
macOS বা Windows-এর Docker Desktop-এ কনটেইনারগুলো একটি Linux ভার্চুয়াল মেশিনের ভেতরে চলে। ডেস্কটপে ইনস্টল করা VPN ক্লায়েন্ট ডেস্কটপ অপারেটিং সিস্টেমে একটি টানেল তৈরি করে, আর ভার্চুয়াল মেশিন তা কখনো দেখে না। কোনো কনটেইনার কনফিগারেশন এটি সারায় না, কারণ কনটেইনারের যে ইন্টারফেস দরকার তা তার নেটওয়ার্ক নেমস্পেসে একেবারেই নেই।
Linux হোস্টে টানেল হোস্ট নেমস্পেসে বাস করে, আর ব্রিজ কনটেইনার সাধারণত হোস্টের রাউটিং টেবিলের মাধ্যমে বাইরে যাওয়ার পথে সোর্স NAT প্রয়োগ করে সেখানে পৌঁছায়। সেই পথ ব্যর্থ হলে কারণ সাধারণত অনুপস্থিত রুট নয়, বরং ফরওয়ার্ডিং নীতি, রিভার্স-পাথ ফিল্টারিং বা ওভারল্যাপিং সাবনেট। আরও পড়ার আগে নিশ্চিত করুন আপনি দুই জগতের কোনটিতে আছেন:
docker info --format '{{.OperatingSystem}}'
docker run --rm --net=host alpine ip route | head -5
docker run --rm alpine ip route | head -5
দুটি রাউটিং টেবিলের এই পার্থক্যই এক পর্দায় গোটা সমস্যা। হোস্টের দৃশ্যে টানেল ইন্টারফেস থাকলে আর ব্রিজের দৃশ্যে না থাকলে আপনি নেমস্পেস বিচ্ছিন্নতা দেখছেন, আর বাকি সব কিছু হলো তা কীভাবে অতিক্রম করবেন তার সিদ্ধান্ত।
হোস্ট নেটওয়ার্কিং একটি পরীক্ষা, নকশা নয়
কনটেইনারকে হোস্ট নেটওয়ার্কিং দিয়ে চালানো, যাকে Docker হোস্ট নেটওয়ার্ক নেমস্পেস ভাগাভাগি হিসেবে নথিভুক্ত করে, তাকে সরাসরি টানেল ইন্টারফেস ও তার রুট উত্তরাধিকার দেয়। এরপর একই অনুরোধ সফল হলে রুট তত্ত্ব নিশ্চিত হয় এবং ব্যর্থতাটি নেমস্পেস বিচ্ছিন্নতা, কোনো প্রমাণপত্র, DNS বা অ্যাক্সেস নিয়ম নয়।
docker run --rm --net=host curl -sS -o /dev/null -w '%{http_code}\n' https://api.internal/health
এটিকে নির্ণায়ক হিসেবে রাখুন। হোস্ট নেটওয়ার্কিং পোর্ট প্রকাশ এবং কনটেইনার থেকে আপনি যে বিচ্ছিন্নতা চেয়েছিলেন তার বেশিরভাগ ছেড়ে দেয়, আর Docker Desktop-এ «host» মানে ভার্চুয়াল মেশিন, ডেস্কটপ নয়, তাই কোন হোস্টকে সম্বোধন করছিলেন তা ভুলে গেলে সেখানকার সফলতা বা ব্যর্থতা আপনাকে বিভ্রান্ত করতে পারে।
একটি tun ডিভাইস এবং তার সাথে আসা বিশেষাধিকার
কনটেইনারের ভেতরের VPN ক্লায়েন্টের একটি টানেল ডিভাইস ও তা কনফিগার করার অনুমতি দরকার। প্রচলিত শর্টকাট হলো --privileged, যা সব ডিভাইস দেয় এবং গোটা কনটেইনার জুড়ে নিরাপত্তা নীতি শিথিল করে। এটি এই কাজের প্রয়োজনের চেয়ে অনেক বেশি, আর পর্যালোচনায় তা সমর্থন করা কঠিন।
sudo modprobe tun
docker run --rm -it --device /dev/net/tun --cap-add NET_ADMIN myvpn-client
সরু রূপটি একক ডিভাইস নোড ম্যাপ করে এবং শুধু নেটওয়ার্ক প্রশাসনের সক্ষমতা যোগ করে। নোডটি যাতে থাকে সেজন্য আগে হোস্টে মডিউলটি লোড করুন। কনটেইনার চালু হয়ে ক্লায়েন্ট যদি জানায় যে সে টানেল ডিভাইস খুলতে পারছে না, তবে প্রোফাইলকে সন্দেহ করার আগে ম্যাপিংটি দেখুন, কারণ ওই ত্রুটি সাধারণত আক্ষরিক।
এই নকশার মানে হলো ক্লায়েন্ট প্রতিটি কনটেইনারের জন্য আলাদা চলে। প্রতিটি ওয়ার্কলোডের নিজস্ব টানেল দরকার হলে এটি সঠিক উত্তর, আর আপনি যদি শুধু হোস্টের টানেল দৃশ্যমান চেয়ে থাকেন তাহলে এটি ভুল উত্তর, যা প্ল্যাটফর্ম দল সম্ভবত ধরে নিয়েছিল আপনি করছেন।
ব্রিজ NAT VPN-এর দেখা উৎস বদলে দেয়
ডিফল্ট ব্রিজে কনটেইনারের বাইরের ট্রাফিক হোস্ট ঠিকানায় অনূদিত হয়। তাই VPN-এর পেছনে কর্পোরেট পক্ষ কনটেইনারের নয়, হোস্টের টানেল ঠিকানা দেখে, সোর্সভিত্তিক অ্যাক্সেস নিয়ম এমনভাবে আচরণ করে যেন অনুরোধটি হোস্ট পাঠিয়েছে, আর দুটি কনটেইনার VPN সার্ভারের কাছে অপরিচ্ছেদ্য হয়ে পড়ে।
macvlan বা ipvlan এর বদলে কনটেইনারকে একটি LAN ঠিকানা দেয়, যা LAN আবিষ্কারে সাহায্য করে এবং কনটেইনারকে সেগমেন্টে সমকক্ষের মতো দেখায়। এটি হোস্ট টানেলও সম্পূর্ণ এড়িয়ে যায়, তাই এমন কনটেইনার শুধু-VPN প্রিফিক্সে পৌঁছাবে না, যদি VPN ওই LAN থেকেও পৌঁছানোর মতো না হয়।
দুটি রূপই বৈধ; তারা ভিন্ন চাহিদার উত্তর দেয়। চাহিদা যদি হয় «এই কনটেইনারকে শুধু-VPN সেবায় পৌঁছাতে হবে», তবে আপনি হোস্টের মধ্য দিয়ে রাউটিং আর কনটেইনারের ভেতরে টানেল সমাপ্ত করার মধ্যে বাছাই করছেন। এই সিদ্ধান্তটি মোতায়েনের আগে লিখুন, প্রথম ব্যর্থ অনুরোধের পরে নয়। যা-ই বাছুন, দূর প্রান্ত যে সোর্স ঠিকানা দেখবে তা লিখে রাখুন, কারণ তার অ্যাক্সেস নিয়ম ও লগ ঠিক সেটাই দেখাবে। যে নকশা ওই ঠিকানা বলতে পারে না, তা শেষ হয়নি।
DNS ডিমনকে অনুসরণ করে, টানেলকে নয়
কনটেইনার চালু হওয়ার সময় তার রেজলভার কনফিগারেশন পায়, যা ডিমন বা ইমেজ থেকে নকল করা। VPN সংযুক্ত হওয়ার পরে যে ঠিকানাগুলো পাঠায় সেগুলো ওই নকলের জন্য অনেক দেরিতে আসে, আর সেগুলো কনটেইনারে নয়, হোস্ট রেজলভারে পাঠানো হয়।
সেবার জন্য রেজলভারটি স্পষ্টভাবে নির্ধারণ করুন, বা টানেলের মাধ্যমে পৌঁছানো যায় এমন একটি অভ্যন্তরীণ রেজলভারে নির্দেশ করুন। যে কনটেইনার একটি ব্যক্তিগত নামকে সার্বজনীন ঠিকানায় সমাধান করে সে সাধারণত ভাঙা রুটে নয়, একটি সার্বজনীন রেজলভার ব্যবহার করছে, আর সমাধানটি কম্পোজ ফাইলে বা ডিমন কনফিগারেশনে।
একই যুক্তি প্রস্থান ঠিকানার প্রশ্নেও খাটে। প্রতিটি কনটেইনারকে আলাদা VPN ঠিকানা থেকে দেখা দিতে হলে একটি হোস্ট টানেল তা দিতে পারে না, কারণ NAT তাদের এক উৎসে সংকুচিত করে। কার্যকর রূপ হলো প্রতিটি কনটেইনারের নেমস্পেসে একটি ক্লায়েন্ট বা যে সাইডকার টানেলের মালিক ও তার স্ট্যাক ভাগ করে, আর দুটোই অ্যাপ্লিকেশনকে কীভাবে সম্বোধন করা হয় তা বদলে দেয়।
টিকেট বন্ধ করার আগে চেকলিস্ট: টানেলের মালিক নেমস্পেস চিহ্নিত করুন, হোস্ট নেটওয়ার্কিং দিয়ে পথ প্রমাণ করুন, শুধু দরকারি tun ডিভাইস ম্যাপ করুন, NAT-এর পরে সোর্স ঠিকানা মনে রাখুন, রেজলভার স্পষ্টভাবে নির্ধারণ করুন এবং প্রতি-কনটেইনার প্রস্থান ঠিকানাকে ফ্ল্যাগ নয়, স্থাপত্য সিদ্ধান্ত হিসেবে ধরুন।