SSD Nodes Learn Hosting plans →
गाइड Matt Connorलेखक: Matt Connor · अपडेट किया गया: 2026-08-07

Docker Compose networking कैसे काम करता है?

Docker Compose नेटवर्किंग के मुख्य पहलुओं को समझें। इसमें सर्विस नेम DNS, डिफॉल्ट ब्रिज नेटवर्क, होस्ट मोड का उपयोग और UFW को बायपास करने वाले पब्लिश्ड पोर्ट्स की जानकारी दी गई है।

Compose आपके app के शुरू होने से पहले क्या बनाता है

Docker Compose नेटवर्किंग एक नियम से शुरू होती है: docker compose up प्रोजेक्ट के लिए एक प्राइवेट नेटवर्क बनाता है, हर सर्विस को उससे जोड़ता है, और उन सर्विसेज को सर्विस के नाम से एक-दूसरे तक पहुँचने की अनुमति देता है। इसके लिए आपको एक भी networks: लाइन लिखने की आवश्यकता नहीं है। Compose नेटवर्किंग को लेकर अधिकांश भ्रम इस बात से पैदा होता है कि लोग यह नहीं जानते कि डिफ़ॉल्ट रूप से यह पहले से मौजूद है।

यहाँ एक छोटी फाइल है। इसे shop नामक डायरेक्टरी में 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 नामक एक नेटवर्क है। Compose इसे <project>_default नाम देता है, और प्रोजेक्ट का नाम डिफ़ॉल्ट रूप से लोअरकेस डायरेक्टरी का नाम होता है। इसे docker compose -p myproject up -d के साथ या फाइल में टॉप-लेवल name: myproject के साथ ओवरराइड करें। इसका ड्राइवर bridge है, जो होस्ट के अंदर एक वर्चुअल स्विच है। प्रत्येक कंटेनर को एक प्राइवेट सबनेट पर एक एड्रेस मिलता है, और बाहर जाने वाला ट्रैफिक बाहर निकलते समय होस्ट के एड्रेस में ट्रांसलेट हो जाता है।

docker compose down उस नेटवर्क को फिर से डिलीट कर देता है। यही कारण है कि किसी पुराने प्रोजेक्ट का कोई पुराना कंटेनर नेटवर्क को खुला रख सकता है: Docker error while removing network: network shop_default has active endpoints के साथ मना कर देता है, और इसका समाधान उस कंटेनर को रोकना या हटाना है जो अभी भी उससे जुड़ा हुआ है।

यदि आप Compose में नए हैं, तो Compose फाइल लेआउट और लाइफसाइकिल कमांड्स को पहले पढ़ना उचित है, क्योंकि नीचे दी गई हर बात यह मानकर चलती है कि आप किसी प्रोजेक्ट को शुरू और बंद कर सकते हैं।

DNS द्वारा सर्विस का नाम खोजना वह हिस्सा है जिसे शुरुआती लोग अक्सर भूल जाते हैं

किसी भी user-defined network पर, Docker एक embedded DNS server चलाता है जिसे प्रत्येक container 127.0.0.11 पर देखता है। यह service names को वर्तमान container addresses में resolve करता है। इसलिए web बिना किसी configuration के, hostname db और port 5432 पर database तक पहुँच जाता है।

docker compose exec web getent hosts db

यह 172.18.0.2 db जैसी एक line print करता है। यदि यह कुछ भी print नहीं करता है, तो इसका मतलब है कि दोनों services एक ही network पर नहीं हैं।

लगभग हर कोई एक बार यह गलती जरूर करता है कि application config में localhost का उपयोग करता है। एक container के अंदर, localhost वही container होता है, न कि host और न ही दूसरी service। Postgres clients इसे स्पष्ट रूप से रिपोर्ट करते हैं:

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 का नाम है।

दो विवरण जो बाद में समय बचाते हैं। Names हमेशा उसी चीज़ पर resolve होते हैं जो अभी चल रही है, इसलिए docker compose up -d --scale web=3 तीन addresses के साथ एक नाम देता है, और जो client DNS को हमेशा के लिए cache कर लेता है, वह खुद को एक मृत container से जोड़ लेगा। और बिना किसी --network के साधारण docker run द्वारा उपयोग किया जाने वाला legacy bridge network में कोई name resolution नहीं होता है, यही कारण है कि 2016 के container links के बारे में दी गई सलाह आज के समय से मेल नहीं खाती है।

दो services को connect करने के लिए आपको ports: की आवश्यकता नहीं है

ports: एक container port को host पर publish करता है। यह Docker के बाहर से आने वाले traffic के लिए है। इसका service-to-service traffic से कोई लेना-देना नहीं है, जो project network पर पहले से ही पूरी port range में काम करता है।

इसलिए, जो ports: - "5432:5432" बहुत से लोग अपनी database service में जोड़ते हैं, वह कोई लाभ नहीं पहुँचाता बल्कि वास्तविक नुकसान करता है: यह Postgres को सर्वर के public interface पर expose कर देता है। इसे हटा दें। यदि आप migration के लिए इसे अपने laptop से access करना चाहते हैं, तो इसे "127.0.0.1:5432:5432" के साथ loopback पर bind करें और SSH tunnel के माध्यम से access करें। listening socket, published port और firewall rule के बीच का अंतर Linux पर ports और listening services कैसे काम करती हैं में समझाया गया है।

expose: Compose के अंतर्गत केवल documentation है। यह कुछ भी open नहीं करता, क्योंकि एक ही network पर स्थित containers के बीच कुछ भी बंद नहीं था।

जब network_mode host का उपयोग करना सही है, और इसकी क्या कीमत चुकानी पड़ती है

Host mode कंटेनर के अपने network namespace को हटा देता है और प्रोसेस को सीधे host के interfaces का उपयोग करने देता है।

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

इसे चुनने के ठोस कारण हो सकते हैं। यदि किसी प्रोसेस को local network पर broadcast या multicast traffic देखने की आवश्यकता है, जैसे कि media server या home automation hub के लिए device discovery, तो वह bridge के पीछे से इसे नहीं देख सकता, क्योंकि bridge उस traffic को कंटेनर तक forward नहीं करता है। एक monitoring agent जिसे host के interface counters पढ़ने होते हैं, उसे host के interfaces की आवश्यकता होती है। इसके अलावा, आप address translation के चरण को छोड़ देते हैं, जो अधिक packet rates पर महत्वपूर्ण होता है।

इसकी कुछ विशिष्ट कीमतें चुकानी पड़ती हैं।

ports: काम करना बंद कर देता है। Docker चेतावनी देता है कि host network mode का उपयोग करते समय published ports को अनदेखा कर दिया जाता है, और कंटेनर वही bind करता है जो उसका प्रोसेस bind करता है। यदि दो host mode कंटेनर port 8080 का उपयोग करना चाहते हैं, तो वे आपस में टकराएंगे, और दूसरा कंटेनर bind: address already in use के साथ बंद हो जाएगा।

Service name द्वारा name resolution दोनों दिशाओं में समाप्त हो जाता है। कंटेनर project network पर नहीं होता है, इसलिए वह db को resolve नहीं कर सकता, और अन्य services भी उसे resolve नहीं कर सकतीं। यह उन तक केवल host पर published ports के माध्यम से पहुँचता है, आमतौर पर 127.0.0.1 पर।

Isolation समाप्त हो जाता है। host mode कंटेनर के अंदर जो प्रोसेस 0.0.0.0 bind करता है, वह आपके सर्वर के हर interface पर listen कर रहा होता है, जिसमें public interface भी शामिल है, बिल्कुल वैसे ही जैसे apt के साथ इंस्टॉल किया गया कोई पैकेज। इसका एक फायदा यह है: यह traffic सामान्य input path का पालन करता है, इसलिए UFW rules इस पर लागू होते हैं, जो published ports के मामले में सच नहीं है।

Host mode एक Linux Docker Engine फीचर है। Docker Desktop इसे केवल version 4.34 के बाद और आपके द्वारा enable करने पर ही सपोर्ट करता है, जिसमें यह अतिरिक्त सीमा है कि कंटेनर host IP addresses को bind नहीं कर सकते और केवल TCP और UDP ही हैंडल किए जाते हैं। यदि आपकी टीम के आधे सदस्य Linux servers पर हैं और आधे Docker Desktop पर, तो उम्मीद रखें कि एक ही फाइल अलग-अलग व्यवहार करेगी।

Host mode का उपयोग तब करें जब आपको host के interfaces की आवश्यकता हो। किसी connection समस्या को ठीक करने के लिए इसका सहारा न लें, क्योंकि यह आमतौर पर एक समस्या को दूसरी अधिक कठिन समस्या से बदल देता है।

दो Compose प्रोजेक्ट्स को एक external नेटवर्क से जोड़ना

एक प्रोजेक्ट द्वारा बनाया गया नेटवर्क दूसरे को दिखाई नहीं देता है। यही कारण है कि proxy/compose.yaml में मौजूद reverse proxy, app/compose.yaml वाले ऐप को नहीं देख पाता, भले ही वे एक ही सर्वर पर हों। इसका समाधान एक ऐसा नेटवर्क है जिसका स्वामित्व किसी भी प्रोजेक्ट के पास न हो।

इसे एक बार मैन्युअल रूप से बनाएँ:

docker network create edge

फिर प्रत्येक प्रोजेक्ट में इसे external के रूप में घोषित करें। प्रॉक्सी साइड:

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

एप्लीकेशन साइड:

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 को एक नया नेटवर्क बनाने के बजाय मौजूदा नेटवर्क से जुड़ने और docker compose down पर उसे यथावत छोड़ने का निर्देश देता है। अलग name: की (key) दिखने से कहीं अधिक महत्वपूर्ण है: इसके बिना Compose ठीक उसी नाम के नेटवर्क को खोजता है जो edge में दिया गया है, और इसके साथ आप अपनी फाइल में नेटवर्क को कुछ और और होस्ट पर कुछ और नाम दे सकते हैं।

यदि नेटवर्क मौजूद नहीं है, तो Compose स्टार्ट होने से मना कर देता है और रिपोर्ट करता है कि नेटवर्क को external घोषित किया गया था लेकिन वह मिल नहीं सका। इसे पहले बनाएँ।

ध्यान दें कि एप्लीकेशन फाइल internal के साथ क्या करती है। डेटाबेस केवल उस प्रोजेक्ट-लोकल नेटवर्क पर स्थित होता है, इसलिए प्रॉक्सी उस तक नहीं पहुँच सकता और केवल app ही ऐसा कर सकता है। किसी नेटवर्क के अंतर्गत internal: true जोड़ने से बाहरी दुनिया के लिए उसका रूट पूरी तरह से हट जाता है। डेटाबेस के लिए यह एक अच्छा डिफ़ॉल्ट है, लेकिन इसे सेट करने से पहले एक लागत के बारे में जानना जरूरी है: एक internal नेटवर्क पर मौजूद कंटेनर कुछ भी डाउनलोड नहीं कर सकता, इसलिए स्टार्टअप पर apt-get update या pip install चलाने वाला entrypoint हैंग हो जाएगा और फिर टाइमआउट के साथ विफल हो जाएगा।

राउटिंग नियमों और सर्टिफिकेट के साथ पूर्ण सेटअप के लिए, running several apps behind one Traefik instance देखें।

Published ports UFW को bypass करते हैं

यह Docker Compose नेटवर्किंग का वह हिस्सा है जो सुरक्षा संबंधी घटना (security incident) का कारण बनता है। आप एक port publish करते हैं, आप जाँचते हैं कि UFW सक्रिय है और SSH को छोड़कर सब कुछ deny कर रहा है, फिर भी वह service इंटरनेट से सुलभ (reachable) रहती है।

sudo ufw status
curl http://203.0.113.10:8080

UFW कहता है कि port blocked है। इसके बावजूद curl पेज को return कर देता है। कुछ भी खराब नहीं है। Docker अपने स्वयं के address translation और forwarding नियमों को सीधे iptables में लिखता है। published container port पर आने वाला traffic host तक पहुँचने के बजाय सीधे container को forward कर दिया जाता है। इसलिए, यह उस chain से कभी नहीं गुजरता जिसे UFW स्थानीय traffic के लिए manage करता है। Docker के नियम UFW के नियमों से पहले match होते हैं।

इसका संक्षिप्त समाधान यह है कि port को केवल वहीं publish करें जहाँ इसकी आवश्यकता हो:

    ports:
      - "127.0.0.1:8080:80"

यह host side को loopback पर bind कर देता है। इस प्रकार, port केवल सर्वर से, SSH tunnel के माध्यम से, या कहीं और से नहीं, बल्कि केवल स्थानीय रूप से सुलभ होता है। public entry point को एक reverse proxy के पीछे रखें जो जानबूझकर 80 और 443 को publish करता है। पूर्ण विवरण, जिसमें उन मामलों के लिए DOCKER-USER chain शामिल है जहाँ आपको published port को filter करना ही है, यहाँ देखें: Docker UFW को bypass करके port क्यों publish करता है और इसे कैसे ठीक करें

इसे चार commands में debug कैसे करें

सबसे पहले यह पता लगाएँ कि प्रत्येक container वास्तव में किस network पर है:

docker network inspect shop_default

Containers block उन सभी attached containers की सूची दिखाता है जो उनके address के साथ हैं। यदि कोई service उस सूची में नहीं है, तो वह किसी अन्य network पर है, host mode में है, या चल नहीं रही है।

उसी network से जुड़े एक अस्थायी (throwaway) container से name resolution का परीक्षण करें, ताकि आपको अपनी images के अंदर किसी tool की आवश्यकता न पड़े:

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 पर listen नहीं कर रही है, या वह अपने container के अंदर 127.0.0.1 के बजाय 0.0.0.0 पर listen कर रही है। यह समस्या development servers के साथ आम है, और इसका समाधान application के bind address में है, न कि Docker में।

एक और विफलता जो Docker bug जैसी दिखती है। यदि containers आपस में बात कर सकते हैं लेकिन आपके office या VPN network पर किसी machine तक नहीं पहुँच पा रहे हैं, तो संभव है कि Docker का subnet उस network के साथ overlap कर रहा हो। Docker डिफ़ॉल्ट रूप से 172.17.0.0/16 से ऊपर address allocate करता है। /etc/docker/daemon.json में pool को बदलें:

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

इसके बाद sudo systemctl restart docker चलाएँ और प्रभावित networks को recreate करें, क्योंकि एक मौजूदा network उसी subnet को बनाए रखता है जिसके साथ उसे बनाया गया था।

FAQ

मेरे containers एक-दूसरे को service name से क्यों नहीं ढूँढ पा रहे हैं?

वे एक ही network पर नहीं हैं। Compose हर service को स्वचालित रूप से <project>_default पर डाल देता है, लेकिन जिस क्षण आप किसी service में networks: सूची जोड़ते हैं, वह सूची उसके लिए networks का पूर्ण सेट बन जाती है और default network अब लागू नहीं रहता। docker network inspect <network> चलाएँ और जाँचें कि क्या दोनों containers Containers ब्लॉक में दिखाई दे रहे हैं। यह भी देखें कि कोई भी service network_mode: host का उपयोग न कर रही हो, क्योंकि host mode container किसी भी Docker network पर नहीं होता और service names को resolve नहीं कर सकता।

क्या एक service को दूसरी तक पहुँचने के लिए ports publish करने की आवश्यकता है?

नहीं। Compose network पर, हर container का हर port उस network पर मौजूद अन्य containers के लिए सुलभ होता है। ports: केवल container को Docker के बाहर से आने वाले traffic के लिए expose करने हेतु होता है, और expose: केवल documentation के लिए है। Database port को publish करना एक सामान्य और महंगी गलती है, क्योंकि यह database को आपके सर्वर के public interface पर डाल देता है।

bridge और host networking में क्या अंतर है?

Bridge container को उसका अपना network namespace और virtual switch पर एक पता देता है, जिसमें containers के बीच स्वचालित name resolution और translated outbound traffic की सुविधा होती है। Host container को सीधे host का network stack देता है: इसमें कोई अलग पता, service name द्वारा resolution, port publishing या host के अन्य listeners से कोई isolation नहीं होता। Bridge default है और यही सही विकल्प है, जब तक कि process को host के interfaces की आवश्यकता न हो।

मैं दो अलग-अलग Compose files से containers को कैसे जोड़ूँ?

docker network create edge के साथ एक shared network बनाएँ, फिर इसे दोनों files में external: true के साथ घोषित करें और उन services को attach करें जिन्हें आपस में बात करने की आवश्यकता है। Compose इसे न तो बनाएगा और न ही हटाएगा। यदि आप create करने का चरण छोड़ देते हैं, तो Compose start होने से मना कर देगा और सूचित करेगा कि network external के रूप में घोषित है लेकिन मिला नहीं।

जब UFW port को block करता है, तो मेरा container internet से सुलभ क्यों है?

क्योंकि published port को उन forwarding rules द्वारा संभाला जाता है जिन्हें Docker iptables में जोड़ता है। वे rules UFW के rules से पहले match होते हैं, और forwarded traffic वैसे भी उस chain से नहीं गुजरता जिसे UFW filter करता है। Host side को "127.0.0.1:8080:80" के साथ loopback पर bind करें और किसी भी public service को ports 80 और 443 पर reverse proxy के पीछे रखें।