Docker নেটওয়ার্ক এবং পোর্ট ফরওয়ার্ডিং
কন্টেইনারগুলো কীভাবে একে অপরকে দেখে, পোর্ট পাবলিশ করা সাধারণ EXPOSE থেকে কীভাবে আলাদা, এবং কেন Docker ufw নিয়ম এড়িয়ে যায়।
আপডেট: ২৩ আগস্ট, ২০২৬
কন্টেইনার সমস্যার অর্ধেকই নেটওয়ার্ক-সংক্রান্ত: কোনো সার্ভিস ডেটাবেসে পৌঁছাতে পারছে না, একটি পোর্ট দখল হয়ে আছে, প্যানেল হঠাৎ করেই পুরো ইন্টারনেটের সামনে খুলে গেছে। চলুন দেখে নিই এটি কীভাবে কাজ করে।
তিন ধরনের নেটওয়ার্ক
- bridge — ডিফল্ট। কন্টেইনারগুলো অভ্যন্তরীণ অ্যাড্রেস পায় এবং একে অপরের সাথে যোগাযোগ করে; তারা হোস্টের NAT-এর মাধ্যমে বাইরে যায়।
- host — কন্টেইনার সরাসরি হোস্টের নেটওয়ার্ক ব্যবহার করে; পোর্ট পাবলিশ করা লাগেও না, কাজও করে না। দ্রুত, কিন্তু কোনো আইসোলেশন নেই: কন্টেইনারের পোর্ট 80-ই হোস্টের পোর্ট 80।
- none — কোনো নেটওয়ার্কই নেই। যেসব কাজে নেটওয়ার্ক লাগে না, তাদের জন্য।
আপনি বা Compose যে কাস্টম নেটওয়ার্ক তৈরি করেন, তা ডিফল্ট bridge থেকে একটি গুরুত্বপূর্ণ দিক দিয়ে আলাদা: এতে নেম রেজোলিউশন কাজ করে। app কন্টেইনার db নাম দিয়ে db কন্টেইনারে পৌঁছাতে পারে।
docker network create backend
docker network ls
docker network inspect backend
Compose-এ প্রতিটি প্রজেক্টের জন্য এমন নেটওয়ার্ক স্বয়ংক্রিয়ভাবে তৈরি হয়।
পোর্ট পাবলিশ করা
ports:
- "127.0.0.1:8080:8080" # accessible only from the machine itself
- "80:80" # accessible to the whole internet
বাঁদিকে হোস্টের পোর্ট, ডানদিকে কন্টেইনারের ভেতরের পোর্ট। একটি ইমেজে থাকা EXPOSE ডিরেক্টিভ কিছুই পাবলিশ করে না: এটি শুধু একটি নোট, অ্যাপ্লিকেশন কোন পোর্টে লিসেন করে।
নিয়মটি সহজ: শুধু সেটাই পাবলিশ করুন যা বাইরে থেকে অ্যাক্সেসযোগ্য হওয়া দরকার। ডেটাবেস, প্যানেল এবং অভ্যন্তরীণ API 127.0.0.1-এ রাখুন, আর সার্টিফিকেটসহ একটি ওয়েব সার্ভার সেগুলো বাইরে উন্মুক্ত করবে।
Docker নিজেই
iptablesরুল লেখে এবং তাufw-এর ম্যানেজ করা চেইনের আগেই লেখে।-p 8080:8080হিসেবে পাবলিশ করা একটি পোর্টufw“deny” দেখালেও ইন্টারনেট থেকে অ্যাক্সেসযোগ্য থাকবে। ফায়ারওয়ালের উপর ভরসা করবেন না — পোর্টটি127.0.0.1-এ বাইন্ড করুন।
কন্টেইনারগুলোর মধ্যে যোগাযোগ
services:
app:
networks: [frontend, backend]
db:
networks: [backend]
proxy:
networks: [frontend]
ports:
- "80:80"
- "443:443"
networks:
frontend:
backend:
এখানে ডেটাবেস শুধু অ্যাপ্লিকেশনের কাছেই অ্যাক্সেসযোগ্য, আর বাইরের দিকে মুখ করে আছে শুধু ওয়েব সার্ভার। যেকোনো স্ট্যাকের জন্য এটাই সঠিক সেটআপ।
কন্টেইনারের ভেতরে প্রতিবেশীকে তার সার্ভিস নাম দিয়ে অ্যাড্রেস করুন: postgres://db:5432/app। কন্টেইনারের ভেতরে localhost অ্যাড্রেস মানে কন্টেইনার নিজেই, হোস্ট নয় — latest-এর পরে এটি দ্বিতীয় সবচেয়ে সাধারণ ভুল।
হোস্টেই চলা কোনো সার্ভিসে কন্টেইনার থেকে পৌঁছাতে host.docker.internal নামটি ব্যবহার করুন, এটি যোগ করে:
extra_hosts:
- "host.docker.internal:host-gateway"
ডায়াগনস্টিকস
docker compose exec app ping -c2 db
docker compose exec app getent hosts db
sudo ss -tulpn | grep LISTEN
docker port <container>
ss দেখাবে একটি পোর্ট আসলে কোন ইন্টারফেসে লিসেন করছে: 0.0.0.0:8080 — বাইরের জন্য খোলা, 127.0.0.1:8080 — নয়।
সাধারণ ভুল
- “Port already in use”। এটি অন্য কোনো কন্টেইনার বা হোস্টের সার্ভিস দখল করে রেখেছে।
sudo ss -tulpn | grep :80অপরাধীকে খুঁজে বের করবে। - আলাদা Compose প্রজেক্টের কন্টেইনারগুলো একে অপরকে দেখতে পায় না। প্রতিটি প্রজেক্টের নিজস্ব নেটওয়ার্ক থাকে।
networks: { shared: { external: true } }দিয়ে সেগুলো স্পষ্টভাবে সংযুক্ত করুন। - অ্যাপ্লিকেশন কন্টেইনারের ভেতরে
127.0.0.1-এ লিসেন করছে। তাহলে পাবলিশ করেও লাভ নেই: কন্টেইনারের বাইরে থেকে আপনি এতে পৌঁছাতে পারবেন না। অ্যাপ্লিকেশনটি0.0.0.0-এ লিসেন করার জন্য কনফিগার করুন। - ব্যান্ডউইথ। প্রতি হোস্টে সর্বোচ্চ 500 Mbps শেয়ার করা। ফাইল ডিস্ট্রিবিউশন বাকি সবকিছুর সাথে এটি ভাগ করে নেয়।