SSD Nodes Learn Hosting plans →
নির্দেশিকা Matt Connorদ্বারা Matt Connor · আপডেট করা হয়েছে 2026-08-07

Docker Compose networking: DNS, host mode ও port

Default project network কীভাবে তৈরি হয়, service name দিয়ে DNS, host mode কখন উপযোগী, project ভাগ করে network ব্যবহার এবং UFW এড়ানো published port জানুন।

অ্যাপ শুরু হওয়ার আগে Compose যা তৈরি করে

Docker Compose networking-এর শুরু একটি নিয়ম দিয়ে: docker compose up project-এর জন্য একটি private network তৈরি করে, প্রতিটি service-কে তাতে যুক্ত করে, এবং service name ব্যবহার করে service-গুলোকে একে অপরের কাছে পৌঁছানোর সুযোগ দেয়। এটি করতে আপনাকে একটি networks: line-ও লিখতে হয় না। Compose networking নিয়ে বেশিরভাগ বিভ্রান্তির কারণ হলো, default network আগে থেকেই তৈরি থাকে—এটি না জানা।

এখানে একটি ছোট file আছে। এটিকে shop নামের একটি directory-তে compose.yaml হিসেবে সংরক্ষণ করুন।

services:
  web:
    image: nginx:1.27
    ports:
      - "8080:80"
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: example

এটি চালু করুন এবং Docker কী তৈরি করেছে তা দেখুন:

docker compose up -d
docker network ls

তালিকায় এখন shop_default নামের একটি network আছে। Compose এটির নাম <project>_default হিসেবে নির্ধারণ করে, এবং project name default হিসেবে lowercase directory name হয়। এটি docker compose -p myproject up -d দিয়ে অথবা file-এর top-level name: myproject দিয়ে পরিবর্তন করুন। এর driver হলো bridge, যা host-এর ভেতরের একটি virtual switch। প্রতিটি container একটি private subnet-এ একটি address পায়, এবং বাইরে যাওয়ার সময় outbound traffic host-এর address-এ translate হয়।

docker compose down আবার সেই network মুছে দেয়। এ কারণেই পুরোনো project-এর একটি stale container কোনো network ধরে রাখতে পারে: Docker error while removing network: network shop_default has active endpoints দিয়ে প্রত্যাখ্যান করে, এবং সমাধান হলো network-টির সঙ্গে এখনও যুক্ত container-টি stop করা অথবা remove করা।

Compose আপনার কাছে নতুন হলে, Compose file-এর বিন্যাস ও lifecycle command আগে পড়ে নেওয়া উপকারী। কারণ পরের সবকিছু ধরে নিচ্ছে যে আপনি একটি project start এবং stop করতে পারেন।

Service name দিয়ে DNS: যে বিষয়টি নতুন ব্যবহারকারীরা প্রায়ই বাদ দেন

যে কোনো user-defined network-এ Docker একটি embedded DNS server চালায়। প্রতিটি container এই server-এ 127.0.0.11 ঠিকানার মাধ্যমে পৌঁছাতে পারে। এটি service name-কে বর্তমানে চলমান container-এর address-এ resolve করে। তাই কোনো configuration ছাড়াই web hostname db ব্যবহার করে port 5432-এ database-এ পৌঁছাতে পারে।

docker compose exec web getent hosts db

এটি 172.18.0.2 db-এর মতো একটি line প্রদর্শন করে। কিছুই প্রদর্শিত না হলে দুইটি service একই network-এ নেই।

প্রায় সবাই একবার যে ভুলটি করে, তা হলো application config-এ localhost ব্যবহার করা। কোনো container-এর ভেতরে localhost বলতে সেই container-কেই বোঝায়, host বা অন্য service-কে নয়। Postgres client এটি স্পষ্টভাবে জানায়:

could not connect to server: Connection refused
	Is the server running on host "localhost" (127.0.0.1) and accepting
	TCP connections on port 5432?

Connection string হওয়া উচিত postgresql://postgres:example@db:5432/postgres। এখানে host অংশটি হলো service name।

পরে সময় বাঁচাতে দুটি বিষয় মনে রাখুন। Name বর্তমানে চলমান container-এর address-এ resolve হয়। তাই docker compose up -d --scale web=3 একটি name-এর সঙ্গে তিনটি address দিতে পারে। কোনো client যদি DNS result অনির্দিষ্টকাল cache করে, তাহলে সেটি একটি বন্ধ হয়ে যাওয়া container-এর address-এ আটকে থাকবে। আর কোনো --network ছাড়া সাধারণ docker run দিয়ে ব্যবহৃত পুরোনো bridge network-এ কোনো name resolution নেই। তাই 2016 সালের container link-সংক্রান্ত নির্দেশনা আপনার বর্তমান ফলাফলের সঙ্গে মিলবে না।

দুটি service সংযুক্ত করতে ports: প্রয়োজন নেই

ports: host-এ একটি container port প্রকাশ করে। এটি Docker-এর বাইরে থেকে আসা network traffic-এর জন্য ব্যবহৃত হয়। Service-to-service traffic-এর সঙ্গে এর কোনো সম্পর্ক নেই। একই project network-এ সম্পূর্ণ port range জুড়েই এই traffic আগে থেকেই কাজ করে।

তাই database service-এ অনেকে যে ports: - "5432:5432" যোগ করেন, তা কোনো উপকার করে না; বরং প্রকৃত ক্ষতি করে: এটি server-এর public interface-এ Postgres প্রকাশ করে। এটি মুছে দিন। Migration-এর জন্য laptop থেকে service-এ সংযোগ প্রয়োজন হলে "127.0.0.1:5432:5432" ব্যবহার করে এটিকে loopback interface-এ bind করুন এবং SSH tunnel-এর মাধ্যমে সংযোগ করুন। listening socket, published port এবং firewall rule-এর পার্থক্য Linux-এ port ও listening service কীভাবে কাজ করে-এ ব্যাখ্যা করা হয়েছে।

Compose-এর ক্ষেত্রে expose: শুধু documentation হিসেবে কাজ করে। এটি কোনো কিছু open করে না, কারণ একই network-এ থাকা containerগুলোর মধ্যে আগে থেকেই কোনো port বন্ধ ছিল না।

যখন network_mode host উপযুক্ত, এবং এর খরচ

Host mode container-এর নিজস্ব network namespace বাদ দিয়ে process-কে সরাসরি host-এর interface ব্যবহার করতে দেয়।

services:
  probe:
    image: alpine:3.20
    network_mode: host
    command: sleep infinity

এটি ব্যবহারের বাস্তব কারণ আছে। কোনো process-এর local network-এর broadcast বা multicast traffic দেখার প্রয়োজন হলে, যেমন media server বা home automation hub-এর device discovery-এর জন্য, bridge-এর পেছন থেকে সেটি এই traffic দেখতে পারে না। কারণ bridge এই traffic container-এ forward করে না। কোনো monitoring agent-এর host-এর interface counter পড়ার প্রয়োজন হলে host-এর interface ব্যবহার করতেই হবে। এছাড়া address translation-এর একটি ধাপ বাদ যায়, যা উচ্চ packet rate-এর ক্ষেত্রে গুরুত্বপূর্ণ।

তবে এর নির্দিষ্ট কিছু খরচ আছে।

ports: আর কাজ করে না। Docker জানায় যে host network mode ব্যবহার করলে published port বাতিল করা হয়, এবং container তার process যে port-এ bind করে, সেই port-এই bind করে। একই host mode-এর দুটি container যদি port 8080 ব্যবহার করতে চায়, তাহলে সংঘর্ষ হয় এবং দ্বিতীয়টি bind: address already in use-সহ বন্ধ হয়ে যায়।

দুই দিকেই service name ব্যবহার করে name resolution বন্ধ থাকে। container project network-এ থাকে না, তাই এটি db resolve করতে পারে না, এবং অন্য service-গুলোও এটিকে resolve করতে পারে না। এটি কেবল host-এ published port-এর মাধ্যমে তাদের কাছে পৌঁছাতে পারে, সাধারণত 127.0.0.1-এ।

Isolation থাকে না। host mode container-এর ভেতরে কোনো process 0.0.0.0-এ bind করলে, সেটি আপনার server-এর প্রতিটি interface-এ, public interface-সহ, listening করে—যেমন apt দিয়ে install করা কোনো package করে। এর একটি সুবিধা আছে: এই traffic স্বাভাবিক input path অনুসরণ করে। তাই UFW rule এতে প্রযোজ্য হয়, যা published port-এর ক্ষেত্রে সত্য নয়।

Host mode একটি Linux Docker Engine feature। Docker Desktop-এ এটি কেবল version 4.34 থেকে সমর্থিত এবং enable করার পর ব্যবহার করা যায়। এর অতিরিক্ত সীমাবদ্ধতা হলো, container host IP address-এ bind করতে পারে না এবং কেবল TCP ও UDP পরিচালিত হয়। আপনার দলের অর্ধেক Linux server এবং অর্ধেক Docker Desktop ব্যবহার করলে একই file ভিন্নভাবে কাজ করবে।

যখন host-এর interface প্রয়োজন, তখন host mode ব্যবহার করুন। Connection সমস্যা সমাধানের জন্য এটি ব্যবহার করবেন না, কারণ সাধারণত এটি একটি সমস্যার বদলে আরও জটিল সমস্যা তৈরি করে।

একটি external network দিয়ে দুইটি Compose project সংযুক্ত করুন

একটি project যে network তৈরি করে, অন্য project সেটি দেখতে পায় না। তাই একই server-এ থাকলেও proxy/compose.yaml-এর reverse proxy app/compose.yaml-এর app-এ পৌঁছাতে পারে না। এর সমাধান হলো এমন একটি network ব্যবহার করা, যার মালিক কোনো project নয়।

এটি একবার হাতে তৈরি করুন:

docker network create edge

এরপর প্রতিটি project-এ এটিকে external হিসেবে ঘোষণা করুন। proxy-এর দিকটি:

services:
  proxy:
    image: traefik:v3.1
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks:
      - edge

networks:
  edge:
    name: edge
    external: true

application-এর দিকটি:

services:
  app:
    image: nginx:1.27
    networks:
      - edge
      - internal
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: example
    networks:
      - internal

networks:
  edge:
    name: edge
    external: true
  internal:

external: true Compose-কে নতুন network তৈরি না করে একটি বিদ্যমান network-এ সংযুক্ত হতে বলে এবং docker compose down-এ সেটি রেখে যেতে বলে। আলাদা name: key-টির গুরুত্ব বেশি: এটি না থাকলে Compose ঠিক edge নামের একটি network খুঁজবে। এটি থাকলে আপনার file-এ network-টির একটি নাম এবং host-এ অন্য নাম ব্যবহার করতে পারবেন।

network-টি না থাকলে Compose start করতে অস্বীকার করবে এবং জানাবে যে network-টি external হিসেবে ঘোষণা করা হলেও সেটি পাওয়া যায়নি। আগে network-টি তৈরি করুন।

application file-এ internal কীভাবে ব্যবহৃত হয়েছে, তা লক্ষ করুন। database শুধু ওই project-এর local network-এ থাকে। তাই proxy সেখানে পৌঁছাতে পারে না; কেবল app সেখানে পৌঁছাতে পারে। কোনো network-এর অধীনে internal: true যোগ করলে বাইরের network-এ যাওয়ার route-ও পুরোপুরি সরিয়ে দেওয়া হয়। database-এর জন্য এটি একটি ভালো default। তবে সেট করার আগে একটি গুরুত্বপূর্ণ সীমাবদ্ধতা জেনে নিন: internal network-এ থাকা container কিছু download করতে পারে না। তাই startup-এর সময় apt-get update বা pip install চালানো কোনো entrypoint hang করবে এবং পরে timeout error দিয়ে ব্যর্থ হবে।

routing rule ও certificate-সহ সম্পূর্ণ কার্যকর setup-এর জন্য দেখুন একটি Traefik instance-এর পেছনে একাধিক app চালানো

Published port UFW-এর নিয়ন্ত্রণ এড়িয়ে যায়

Compose networking-এর এই অংশটিই security incident-এ রূপ নিতে পারে। আপনি একটি port publish করেন, UFW সক্রিয় আছে এবং SSH ছাড়া সবকিছু deny করছে কি না পরীক্ষা করেন, কিন্তু service-টি তবুও Internet থেকে reachable থাকে।

sudo ufw status
curl http://203.0.113.10:8080

UFW জানায় যে port-টি blocked। কিন্তু curl তবুও page ফেরত দেয়। কোনো কিছু নষ্ট হয়নি। Docker সরাসরি iptables-এ নিজস্ব address translation এবং forwarding rule লিখে, আর published container port-এ আসা traffic host-এ deliver না হয়ে container-এ forward হয়। তাই locally destined traffic-এর জন্য UFW যে chain পরিচালনা করে, traffic সেটির মধ্য দিয়ে যায় না। Docker-এর rule-ও UFW-এর আগে match হয়।

সংক্ষিপ্ত সমাধান হলো, যেখানে প্রয়োজন শুধু সেখানেই publish করা:

    ports:
      - "127.0.0.1:8080:80"

এতে host side loopback-এ bind হয়। ফলে port-টি server নিজে এবং SSH tunnel-এর মাধ্যমে reachable থাকে, কিন্তু অন্য কোনো স্থান থেকে নয়। Public entry point-কে এমন একটি reverse proxy-এর পেছনে রাখুন, যা উদ্দেশ্যপ্রণোদিতভাবে 80 এবং 443 publish করে। যেসব ক্ষেত্রে published port filter করতেই হবে, সেসবের জন্য DOCKER-USER chain-সহ পূর্ণ ব্যাখ্যা কেন Docker সরাসরি UFW-এর নিয়ম এড়িয়ে port publish করে এবং কীভাবে এটি ঠিক করবেন-এ রয়েছে।

চারটি কমান্ডে সমস্যাটি কীভাবে ডিবাগ করবেন

প্রতিটি container আসলে কোন network-এ যুক্ত আছে, তা দিয়ে শুরু করুন:

docker network inspect shop_default

Containers block-এ সংযুক্ত প্রতিটি container-এর address তালিকাভুক্ত থাকে। কোনো service এই তালিকায় না থাকলে সেটি অন্য network-এ আছে, host mode-এ চলছে, অথবা চালু নেই।

একই network-এ যুক্ত একটি অস্থায়ী container থেকে name resolution পরীক্ষা করুন। এতে নিজের image-এর ভেতরে কোনো tooling রাখার প্রয়োজন হয় না:

docker run --rm --network shop_default busybox nslookup db
docker run --rm --network shop_default busybox nc -zv db 5432

nslookup ব্যর্থ হলে name resolution বা network membership-এ সমস্যা নির্দেশ করে। nslookup সফল হলেও nc ব্যর্থ হলে service চলছে, কিন্তু ওই port-এ listening করছে না। অথবা service-টি নিজের container-এর ভেতরে 127.0.0.1-এ listening করছে, 0.0.0.0-এ নয়। Development server-এ এটি প্রায়ই ঘটে। এর সমাধান Docker-এ নয়, application-এর bind address-এ করতে হবে।

আরেকটি সমস্যা Docker-এর bug বলে মনে হতে পারে। Container-গুলো পরস্পরের সঙ্গে যোগাযোগ করতে পারলেও office বা VPN network-এর কোনো machine-এ পৌঁছাতে না পারলে Docker subnet সম্ভবত ওই network-এর সঙ্গে overlap করছে। Docker ডিফল্টভাবে 172.17.0.0/16 থেকে address বরাদ্দ করে। /etc/docker/daemon.json-এ pool পরিবর্তন করুন:

{
  "default-address-pools": [
    { "base": "10.200.0.0/16", "size": 24 }
  ]
}

এরপর sudo systemctl restart docker চালিয়ে সমস্যাগ্রস্ত network-গুলো নতুন করে তৈরি করুন। কারণ বিদ্যমান network তৈরির সময় নির্ধারিত subnet-ই ধরে রাখে।

FAQ

কেন service name ব্যবহার করে আমার container-গুলো একে অপরের কাছে পৌঁছাতে পারে না?

তারা একই network-এ নেই। Compose প্রতিটি service-কে স্বয়ংক্রিয়ভাবে <project>_default-এ যুক্ত করে। কিন্তু কোনো service-এ networks: list যোগ করলে সেটিই ওই service-এর network-এর সম্পূর্ণ তালিকা হয়ে যায় এবং default network আর অন্তর্ভুক্ত থাকে না। docker network inspect <network> চালিয়ে দেখুন, উভয় container Containers block-এ আছে কি না। কোনো service-এ network_mode: host ব্যবহার করা হয়েছে কি না তাও পরীক্ষা করুন। host mode container কোনো Docker network-এ থাকে না এবং service name resolve করতে পারে না।

একটি service যেন অন্য service-এ পৌঁছাতে পারে, তার জন্য কি port publish করতে হবে?

না। Compose network-এ থাকা প্রতিটি container-এর প্রতিটি port ওই network-এর অন্য container-গুলোতে পৌঁছানো যায়। ports: শুধু Docker-এর বাইরের traffic-এর জন্য container প্রকাশ করে, আর expose: documentation হিসেবে ব্যবহৃত হয়। Database port publish করা একটি প্রচলিত কিন্তু ঝুঁকিপূর্ণ অভ্যাস, কারণ এতে database আপনার server-এর public interface-এ উন্মুক্ত হয়ে যায়।

bridge এবং host networking-এর মধ্যে পার্থক্য কী?

bridge container-কে নিজস্ব network namespace এবং virtual switch-এ একটি address দেয়। এতে container-গুলোর মধ্যে স্বয়ংক্রিয় name resolution এবং outbound traffic translation থাকে। host container-কে সরাসরি host-এর network stack ব্যবহার করায়। এতে আলাদা address, service name দিয়ে resolution, port publishing বা host-এর অন্য listener থেকে isolation থাকে না। bridge হলো default এবং সাধারণত সঠিক পছন্দ। শুধু process-এর host-এর interface প্রয়োজন হলে host ব্যবহার করুন।

দুটি আলাদা Compose file-এর container কীভাবে সংযুক্ত করব?

docker network create edge দিয়ে একটি shared network তৈরি করুন। এরপর উভয় file-এ external: true দিয়ে network-টি declare করুন এবং যেসব service-এর মধ্যে যোগাযোগ দরকার, সেগুলোতে network-টি যুক্ত করুন। Compose network-টি তৈরি বা মুছে কোনোটিই করবে না। তৈরি করার ধাপ বাদ দিলে Compose start করতে অস্বীকার করবে এবং network-টিকে declared external but not found হিসেবে জানাবে।

UFW port block করলেও আমার container Internet থেকে কেন পৌঁছানো যায়?

কারণ published port Docker-এর iptables-এ যোগ করা forwarding rule দিয়ে পরিচালিত হয়। এই rule-গুলো UFW-এর rule-এর আগে match হয়। এ ছাড়া forwarded traffic UFW যে chain filter করে, তার মধ্য দিয়েও যায় না। "127.0.0.1:8080:80" দিয়ে host side-কে loopback-এ bind করুন এবং public service-গুলো 80 ও 443 port-এ একটি reverse proxy-এর পেছনে রাখুন।