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

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 द्वारा service name का उपयोग करना वह हिस्सा है जिसे शुरुआती लोग अक्सर भूल जाते हैं

किसी भी 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 इसे स्पष्ट रूप से report करते हैं:

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 है।

दो विवरण जो बाद में समय बचाते हैं। Names वर्तमान में चल रहे container के अनुसार resolve होते हैं, इसलिए docker compose up -d --scale web=3 तीन addresses के साथ एक नाम देता है, और जो client DNS को हमेशा के लिए cache कर लेता है, वह खुद को एक मृत container से जोड़ लेगा। और एक साधारण docker run द्वारा उपयोग किया जाने वाला legacy bridge network, जिसमें कोई --network नहीं है, container names को बिल्कुल भी resolve नहीं कर सकता: वहाँ containers एक-दूसरे को केवल IP address से ढूँढते हैं, और वे host के /etc/resolv.conf की एक copy के माध्यम से बाहरी hostnames को देखते हैं। यही कारण है कि 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 container के अपने network namespace को हटा देता है और process को सीधे host के interfaces का उपयोग करने देता है।

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 के पीछे से इसे नहीं देख सकता, क्योंकि bridge उस traffic को container तक forward नहीं करता है। एक monitoring agent जो host के interface counters को पढ़ता है, उसे host के interfaces की आवश्यकता होती है। और आप address translation hop को छोड़ देते हैं, जो उच्च packet rates पर मायने रखता है।

इसकी लागत विशिष्ट है।

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

Service name द्वारा name resolution दोनों दिशाओं में समाप्त हो जाता है। Container project network पर नहीं है, इसलिए यह db को resolve नहीं कर सकता, और अन्य services इसे resolve नहीं कर सकतीं। यह अभी भी host पर published ports के माध्यम से उन तक पहुँच सकता है, आमतौर पर 127.0.0.1 पर। Linux पर यह किसी भी listening port पर उस container के IP address के माध्यम से सीधे bridge container तक भी पहुँच सकता है, क्योंकि host के पास अपने bridge networks पर containers तक खुली पहुँच होती है और host mode container, host के network stack को साझा करता है। जब containers को फिर से बनाया जाता है तो वे addresses बदल जाते हैं, इसलिए loopback पर published port एक स्थिर मार्ग है।

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

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

जब आपको host के interfaces की आवश्यकता हो, तभी host mode का उपयोग करें। किसी 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 container को उसके address के साथ list करता है। उस list से गायब कोई भी service किसी अलग network पर है, या host mode में है, या चल नहीं रही है।

उसी network से जुड़े एक अस्थायी container से name resolution का परीक्षण करें, ताकि आपको अपने स्वयं के images के अंदर किसी 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 का विफल होना यह दर्शाता है कि नाम और network ठीक हैं और समस्या स्वयं connection की है। यदि nc, Connection refused report करता है, तो सामान्य कारण यह है कि service उस port पर listen नहीं कर रही है, या अपने container के अंदर 0.0.0.0 के बजाय 127.0.0.1 पर listen कर रही है। यह development servers के साथ आम है, और इसका समाधान application के bind address में है, न कि Docker में। यदि nc अटक जाता है और time out हो जाता है, तो रास्ते में traffic को रोकने वाली किसी चीज़ को देखें, जैसे कि firewall rule, या कोई container जो paused है या जवाब नहीं दे रहा है।

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

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

फिर sudo systemctl restart docker चलाएं और प्रभावित networks को फिर से बनाएं, क्योंकि एक मौजूदा 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 के पीछे रखें।

क्या यह लेख उपयोगी था?