Docker: একটি কন্টেইনারকে VPN দিয়ে চালান, অন্যটিকে সরাসরি রাখুন
টানেলকে তার নিজের কন্টেইনার দিন, শুধু যে সেবাগুলোর এটি দরকার সেগুলোকে সেই নেমস্পেস ভাগ করতে দিন, তারপর মালিকের পরে কী আসে তা হিসাব করুন: পোর্ট, localhost, DNS.
একটি হোস্ট, দুটি ওয়ার্কলোড, এবং একটি প্রয়োজন যা তাদের আলাদা করে: একটি ডাউনলোড ক্লায়েন্ট যা একটি বাণিজ্যিক VPN থেকে বেরোতে হবে, এবং একটি ম্যানেজমেন্ট ইন্টারফেস যা হোস্টের সংযোগ ব্যবহার চালিয়ে যাবে। হোস্টে VPN ক্লায়েন্ট ইনস্টল করলে প্রয়োজনটি সঙ্গে সঙ্গেই ব্যর্থ হয়, কারণ তখন দুটি ওয়ার্কলোড একটি বহির্গমন পথ ভাগ করে। যে প্যাটার্নটি আসলে কাজ করে তা হলো টানেলকে তার নিজের কন্টেইনারে সরিয়ে নেওয়া এবং শুধু যে ওয়ার্কলোডগুলোর এটি দরকার সেগুলোকে সেই কন্টেইনারের নেটওয়ার্ক নেমস্পেসে যোগ দিতে দেওয়া. বাকি সব সাধারণ Docker পথ ধরে রাখে, এবং পরে যে বিবরণ আসে তা নেমস্পেসের মালিক কে তার পরিণতি।
কেন একটি ভাগ করা নেমস্পেস নিয়ম বদলে দেয়
যে কন্টেইনার অন্যের নেমস্পেসে যোগ দেয় সে নিজের নেটওয়ার্ক স্ট্যাক পায় না। এটি যে কন্টেইনারে যোগ দিয়েছে তার মতোই একই ইন্টারফেস, একই রাউটিং টেবিল এবং একই loopback দেখে, আর ঠিক এজন্যই প্যাটার্নটি কাজে লাগে: ওয়ার্কলোড স্বাভাবিকভাবে রিজলভ করে ও সংযোগ করে, আর নিচের টানেল অ্যাপ্লিকেশনকে না জানিয়েই ট্রাফিক ধরে নেয়। খরচটা হলো, প্রতিটি নেটওয়ার্ক-সদৃশ সেটিংয়ের এখন একজন মালিক, আর যোগ দেওয়া কন্টেইনার সেই মালিক নয়।
এই মালিকানা নিয়মটি বেশিরভাগ কনফিগারেশন প্রশ্নের উত্তর দেয় সেগুলো জিজ্ঞাসা করার আগেই। কোনো সেটিং নেটওয়ার্ক স্ট্যাকে থাকলে তা সাইডকারের। আর যদি তা প্রক্রিয়াটিকে বর্ণনা করে, তবে তা ওয়ার্কলোডের সঙ্গে থাকে।
loopback হলো সেই অংশ যা মানুষকে অবাক করে। যোগ দেওয়া কন্টেইনারের ভিতরে localhost সাইডকারের loopback-এ রিজলভ হয়, নিজের কোনো আলাদা ঠিকানায় নয়, তাই যে সেবা 127.0.0.1-এ যুক্ত হয়ে বিচ্ছিন্নতার আশা করে সে এখন টানেল কন্টেইনারের সঙ্গে সেই ঠিকানা ভাগ করে।
যে কন্টেইনার নেমস্পেসের মালিক তার উপরেই পোর্ট প্রকাশ করুন
পোর্ট ম্যাপিং নেমস্পেসের মালিকেরই, এমনকি যখন শোনা প্রক্রিয়াটি অন্য কন্টেইনারে চলে। ম্যাপিংটি সাইডকারে ঘোষণা করুন, আর ওয়ার্কলোড তার নিজের প্রক্রিয়া কনফিগারেশন অপরিবর্তিত রাখুক। যোগ দেওয়া সেবার উপর ম্যাপিং কাজ করতে পারে না, ইঞ্জিন এটি প্রত্যাখ্যান করুক বা কন্টেইনার কীভাবে চালু হয়েছে তার উপর নির্ভর করে চুপচাপ উপেক্ষা করুক, আর এজন্যই এক মুহূর্ত আগে পৌঁছানো যেত এমন একটি ইন্টারফেস প্যাটার্ন প্রয়োগ করার সঙ্গে সঙ্গে হারিয়ে যায়।
services:
gluetun:
image: qmcgaw/gluetun
cap_add: [NET_ADMIN]
ports: ["8080:8080"]
client-vpn:
image: example/client
network_mode: "service:gluetun"
client-direct:
image: example/client
ports: ["8081:8080"]এই ব্লকটিকে তিনটি সেবা নয়, তিনটি সিদ্ধান্ত হিসেবে পড়ুন। সাইডকার টানেল ও প্রকাশিত পোর্টের মালিক; যোগ দেওয়া ক্লায়েন্ট কোনো নেটওয়ার্কই ঘোষণা করে না; সরাসরি ক্লায়েন্ট ডিফল্ট নেটওয়ার্কে নিজের একটি ম্যাপিং রাখে। NET_ADMIN সক্ষমতাই সাইডকারকে ইন্টারফেস তৈরি ও রুট বদলাতে দেয়, আর এজন্যই এই কন্টেইনারটি যে ওয়ার্কলোডদের সেবা দেয় তাদের চেয়ে বেশি বিশেষাধিকার দরকার।
যে সেবা সরাসরি থাকে সে নিজের নেটওয়ার্ক রাখে
যে ওয়ার্কলোড টানেলের ভিতর দিয়ে যাবে না সেটি ডিফল্ট ব্রিজ বা নিজের একটি ব্যবহারকারী-নির্ধারিত নেটওয়ার্ক রাখে, নিজের প্রকাশিত পোর্ট ও নিজের বহির্গামী পথ নিয়ে। দুটি কন্টেইনার নাম দিয়ে কথা বলতে পারবে বলে এটিকে সাইডকার নেটওয়ার্কে জুড়ে দেওয়ার লোভ হয়, আর সেই এক ধাপই চুপচাপ এর ট্রাফিক টানেলে সরিয়ে দেয়। তাদের একে অপরকে পৌঁছাতে হলে আলাদা একটি ব্যবহারকারী-নির্ধারিত নেটওয়ার্ক বানান, দুটোকেই তাতে জুড়ুন, আর সাইডকারকে একমাত্র বাইরের পথ হিসেবে রাখুন।
দুটি প্রশ্ন আলাদা রাখুন: কোন কন্টেইনারগুলো একে অপরকে পৌঁছাতে পারে, আর কোনটি কোথা দিয়ে বেরোয়। এগুলো মিলিয়ে ফেলাই এই ডিজাইন আবার হোস্ট-ব্যাপী VPN-এ ফিরে যাওয়ার সবচেয়ে সাধারণ উপায়।
প্রথম ঘণ্টার জন্য একটি ব্যর্থতার ম্যাট্রিক্স
বেশিরভাগ প্রথম প্রচেষ্টা চারটি উপায়ের একটিতে ব্যর্থ হয়, আর প্রতিটির কারণ আলাদা। এই ক্রমে সেগুলো দেখুন, কারণ প্রথম দুটি প্রায় প্রতিটি রিপোর্টের ব্যাখ্যা দেয়।
| Symptom | Likely cause |
|---|---|
| Web UI unreachable after the change | Port mapping declared on the joining container instead of the sidecar |
| Both containers show the provider's exit address | The direct service was attached to the sidecar network |
| Internal names stop resolving | Resolver settings live on the host, not in the shared namespace |
| Health check fails but the app works | The check probes localhost, which now means the sidecar |
চতুর্থ সারিটাই মানুষ ভুল করে অ্যাপ্লিকেশনের বাগ বলে تشخیص করে। ওয়ার্কলোডের নিজের loopback-এর বিরুদ্ধে লেখা একটি প্রোব এখন টানেল কন্টেইনারকে পরীক্ষা করছে, তাই এটি হয় ব্যর্থ হয়, নয়তো পুরোপুরি ভুল সেবার কথা জানায়।
যখন একটি হোস্টনামেরই টানেল দরকার
কখনও পূর্ণ টানেল বেশি হয়ে যায়: একটি অভ্যন্তরীণ নামকে কর্পোরেট VPN দিয়ে যেতে হবে, অথচ একটি স্থানীয় সকেট বা ডিসপ্লে সংযোগ কাজ চালিয়ে যাবে। কন্টেইনারের ভিতরে পূর্ণ টানেল সেই পথ এবং হোস্টকে সম্বোধন করা সবকিছু ভেঙে দেয়, তাই শুধু যে প্রিফিক্সটি দরকার সেটাই রুট করুন। ক্লায়েন্টের চারপাশে একটি বিভক্ত রাউটিং মোড়ক তা করে, নামকৃত হোস্টকে টানেল দিয়ে পাঠায় আর বাকি সবের জন্য আগের রুট অপরিবর্তিত রাখে।
এটি বেছে নিন যখন আপনার একটি মাত্র সেবায় পৌঁছানো দরকার এবং কন্টেইনারের সব ট্রাফিক সরানোর চেষ্টা করছেন না। এটি সাইডকার থেকে আলাদা একটি হাতিয়ার এবং আলাদা প্রশ্নের উত্তর দেয়।
যাচাই করুন, তারপর এটিকে রিস্টার্টেও টিকিয়ে রাখুন
প্রতিটি কন্টেইনারকে জিজ্ঞাসা করুন সে কোন ঠিকানা থেকে আসছে বলে দেখাচ্ছে। টানেলের ভিতরেরটি প্রদানকারীর ঠিকানা ছাপাবে আর সরাসরিটি হোস্টের বহির্গমন ছাপাবে। একই উত্তর মানে সরাসরি সেবাটি ভুল নেমস্পেস উত্তরাধিকারে পেয়েছে বা হোস্ট-স্তরের VPN এখনও সবকিছু ধরছে, আর এই দুটি সমাধান আলাদা। প্রতিটি compose সম্পাদনার পরে আবার যাচাই চালান, কারণ একটি কপি করা সার্ভিস ব্লকই সমস্যাটি ফিরিয়ে আনতে যথেষ্ট।
তিনটি জিনিস পরে সাধারণত ভাঙে। DNS নেমস্পেসের মালিককে অনুসরণ করে, তাই রিজলভার ও অনুসন্ধান ডোমেইন সেটিংস হোস্টে নয়, সাইডকারে থাকা উচিত। পোর্ট-ফরওয়ার্ডেড VPN পুনঃসংযোগে তার শোনার পোর্ট বদলায়, তাই প্রদানকারীর ফরওয়ার্ড করা পোর্ট আর কন্টেইনার-পাশের শোনার পোর্ট ক্লায়েন্ট কনফিগারেশন বা পোর্ট ম্যাপিংয়ে আবার লিখতে হয়, সাধারণত প্রদানকারীর API পড়ে এমন একটি ছোট আপডেটারের মাধ্যমে। আর localhost-এর বিরুদ্ধে লেখা যেকোনো প্রোব এখন ওয়ার্কলোডের বদলে টানেল কন্টেইনারকেই জিজ্ঞাসা করছে।
প্যাটার্নটি লিখে রাখুন, কোন কন্টেইনার নেমস্পেসের মালিক এবং কোন পোর্টগুলো তার, তা সহ। পরের মানুষ একটি সেবা যোগ করবে, ভুল ব্লকটি কপি করবে, আর এই নিবন্ধের প্রথম ব্যর্থতাটি পুনরুৎপাদন করবে।