Docker Compose networking: default network आणि DNS
Default project bridge, service name ने DNS, host mode कधी उपयुक्त, projects मध्ये एकच network कसे वापरावे आणि UFW वगळणारा published port जाणून घ्या.
तुमचे app सुरू होण्यापूर्वी Compose काय तयार करते
Docker Compose networking ची सुरुवात एका नियमाने होते: docker compose up project साठी private network तयार करते, प्रत्येक service त्याला जोडते आणि त्या services ना service name द्वारे एकमेकांपर्यंत पोहोचू देते. यासाठी तुम्हाला एकही networks: line लिहावी लागत नाही. Compose networking बद्दलचा बहुतांश गोंधळ default network आधीपासूनच उपलब्ध असतो हे माहीत नसल्यामुळे निर्माण होतो.
ही एक लहान file आहे. ती shop नावाच्या directory मध्ये compose.yaml म्हणून save करा.
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आता list मध्ये 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 मध्ये translation केले जाते.
docker compose down हे network पुन्हा delete करते. त्यामुळे जुन्या project मधील stale container network open ठेवू शकतो: Docker error while removing network: network shop_default has active endpoints सह नकार देते आणि त्यावर अजून जोडलेला container stop किंवा remove करणे हा उपाय आहे.
Compose तुमच्यासाठी नवीन असल्यास, Compose file layout आणि lifecycle commands आधी वाचणे उपयुक्त ठरेल, कारण पुढील सर्व मजकूर तुम्ही project start आणि stop करू शकता असे गृहीत धरतो.
सेवेच्या नावाने DNS resolution ही beginners कडून सुटणारी बाब आहे
कोणत्याही user-defined network वर Docker embedded DNS server चालवतो. प्रत्येक container ला तो 127.0.0.11 येथे दिसतो. हा server service names चे सध्याच्या container addresses मध्ये resolution करतो. त्यामुळे कोणत्याही configuration शिवाय web हा db hostname वर, 5432 port द्वारे database शी जोडतो.
docker compose exec web getent hosts dbयातून 172.18.0.2 db सारखी ओळ दिसते. काहीही output न आल्यास दोन्ही 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 name.
नंतर वेळ वाचवणारे दोन महत्त्वाचे मुद्दे आहेत. Names सध्या चालू असलेल्या containers कडे resolve होतात. त्यामुळे docker compose up -d --scale web=3 एक name आणि तीन addresses देऊ शकते. DNS कायम cache करणारा client स्वतःला बंद झालेल्या container शी जोडून ठेवू शकतो. तसेच --network नसलेल्या साध्या docker run ने वापरलेले legacy bridge network container names चे resolution करू शकत नाही. त्या network वरील containers एकमेकांना फक्त IP address द्वारे शोधतात. बाहेरील hostnames साठी ते host च्या /etc/resolv.conf ची copy वापरतात. म्हणून 2016 मधील container links संबंधीचा सल्ला तुम्हाला दिसणाऱ्या सध्याच्या वर्तनाशी जुळत नाही.
दोन सेवा जोडण्यासाठी ports: ची आवश्यकता नाही
ports: कंटेनरमधील पोर्ट host वर प्रकाशित करते. Docker च्या बाहेरून येणाऱ्या नेटवर्क ट्रॅफिकसाठी ती वापरली जाते. सेवा-ते-सेवा ट्रॅफिकशी तिचा काहीही संबंध नाही. प्रकल्पाच्या नेटवर्कवर संपूर्ण पोर्ट श्रेणीमध्ये हे ट्रॅफिक आधीपासूनच कार्यरत असते.
त्यामुळे अनेक जण त्यांच्या database सेवेमध्ये जोडतात ते ports: - "5432:5432" निरुपयोगी असून प्रत्यक्षात हानिकारक आहे: यामुळे server च्या सार्वजनिक interface वर Postgres उघडे होते. ते हटवा. Migration साठी ते तुमच्या laptop वरून उपलब्ध हवे असल्यास, "127.0.0.1:5432:5432" वापरून ते loopback ला bind करा आणि SSH tunnel द्वारे त्याच्याशी संपर्क साधा. Listening socket, published port आणि firewall rule यांमधील फरक Linux वर ports आणि listening services कसे कार्य करतात येथे स्पष्ट केला आहे.
Compose अंतर्गत expose: हे केवळ documentation आहे. ते काहीही उघडत नाही, कारण त्याच network वरील containers दरम्यान काहीही बंद केलेले नव्हते.
network_mode host योग्य कधी आहे आणि त्याची किंमत काय आहे
Host mode कंटेनरचा स्वतंत्र network namespace काढून टाकतो आणि process ला host चे interfaces थेट वापरू देतो.
services:
probe:
image: alpine:3.20
network_mode: host
command: sleep infinityहे वापरण्याची ठोस कारणे आहेत. स्थानिक नेटवर्कवरील broadcast किंवा multicast traffic पाहण्याची गरज असलेला process bridge च्या मागून ते पाहू शकत नाही, कारण bridge हा traffic कंटेनरकडे forward करत नाही. याची उदाहरणे म्हणजे media server साठी device discovery किंवा home automation hub. Host चे interface counters वाचणाऱ्या monitoring agent ला host चे interfaces आवश्यक असतात. तसेच address translation चा एक टप्पा टाळला जातो. Packet rate जास्त असताना याला महत्त्व असते.
याची किंमत काही विशिष्ट स्वरूपाची आहे.
ports: काम करणे थांबवते. Host network mode वापरताना published ports वगळले जातात, असा Docker इशारा देतो. Container चा process ज्या port वर bind होतो, त्याच port वर तो bind होतो. Port 8080 हवा असलेले दोन host mode containers एकमेकांशी collision करतात आणि दुसरा container bind: address already in use मुळे बंद पडतो.
Service name द्वारे name resolution दोन्ही दिशांनी उपलब्ध राहत नाही. Container project network वर नसल्यामुळे ते db resolve करू शकत नाही. इतर services देखील ते resolve करू शकत नाहीत. Host वर published केलेल्या ports द्वारे ते services पर्यंत पोहोचू शकते. सामान्यतः हा पत्ता 127.0.0.1 असतो. Linux वर ते bridge container च्या container IP address वरील कोणत्याही listening port पर्यंत थेट पोहोचू शकते. याचे कारण म्हणजे host ला त्याच्या bridge networks वरील containers कडे खुला access असतो आणि host mode container host चा network stack share करतो. Containers पुन्हा तयार केल्यावर हे addresses बदलतात. त्यामुळे loopback वर published केलेला port हा स्थिर मार्ग असतो.
Isolation राहत नाही. Host mode container मध्ये 0.0.0.0 bind करणारा process तुमच्या server च्या प्रत्येक interface वर listening करतो. Public interface देखील त्यात समाविष्ट असतो. हे apt ने install केलेल्या package प्रमाणेच असते. याचा एक फायदा आहे. हा traffic नेहमीच्या input path मधून जातो. त्यामुळे UFW rules त्यावर लागू होतात. Published ports बाबत हे लागू होत नाही.
Host mode हे Linux Docker Engine चे feature आहे. Docker Desktop मध्ये ते फक्त version 4.34 पासून आणि ते enable केल्यानंतरच उपलब्ध आहे. यावर आणखी काही मर्यादा आहेत. Containers host IP addresses वर bind करू शकत नाहीत. फक्त TCP आणि UDP हाताळले जातात. तुमच्या team पैकी काही जण Linux servers वापरत असतील आणि काही जण Docker Desktop वापरत असतील, तर तीच file वेगवेगळ्या प्रकारे कार्य करेल.
Host चे interfaces आवश्यक असतील तेव्हा host mode वापरा. Connection problem सोडवण्यासाठी ते वापरू नका. कारण बहुतेक वेळा त्यामुळे एक problem दूर होऊन त्याऐवजी अधिक कठीण problem निर्माण होते.
बाह्य नेटवर्कसह दोन Compose प्रकल्प कनेक्ट करा
एका प्रकल्पाने तयार केलेले नेटवर्क दुसऱ्या प्रकल्पाला दिसत नाही. म्हणून proxy/compose.yaml मधील reverse proxy ला app/compose.yaml मधील app दिसत नाही, जरी दोन्ही एकाच server वर असले तरी. यासाठी असे नेटवर्क वापरा ज्याची मालकी कोणत्याही प्रकल्पाकडे नसते.
ते एकदाच, manually तयार करा:
docker network create edgeत्यानंतर प्रत्येक प्रकल्पात ते 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: trueApplication बाजू:
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 नावाचे नेटवर्क शोधते. ती असल्यास तुम्ही तुमच्या file मध्ये नेटवर्कला एक नाव आणि host वर दुसरे नाव देऊ शकता.
नेटवर्क अस्तित्वात नसल्यास Compose सुरू होण्यास नकार देते आणि नेटवर्क external म्हणून घोषित केले होते, पण ते सापडले नाही, असा संदेश देते. ते आधी तयार करा.
Application file internal सोबत काय करते ते लक्षात घ्या. Database फक्त त्या प्रकल्पाच्या स्थानिक नेटवर्कवर असतो. त्यामुळे proxy त्याच्यापर्यंत पोहोचू शकत नाही आणि फक्त app पोहोचू शकतो. नेटवर्कखाली internal: true जोडल्यास बाहेरील जगाकडे जाणारा त्याचा route पूर्णपणे काढून टाकला जातो. Database साठी हा चांगला default आहे. मात्र तो सेट करण्यापूर्वी एक परिणाम लक्षात घ्या: internal नेटवर्कवरील container काहीही download करू शकत नाही. त्यामुळे startup वेळी apt-get update किंवा pip install चालवणारा entrypoint hang होईल आणि नंतर timeout मुळे fail होईल.
Routing rules आणि certificates सह पूर्ण कार्यरत setup साठी एकाच Traefik instance मागे अनेक apps चालवणे पहा.
प्रकाशित ports UFW ला वळसा घालतात
Compose networking मधील हा भाग सुरक्षा-घटनेत रूपांतरित होऊ शकतो. तुम्ही एखादा port प्रकाशित करता, UFW सक्रिय आहे आणि SSH वगळता सर्वकाही नाकारते याची तपासणी करता, तरीही service internet वरून पोहोचण्यायोग्य राहते.
sudo ufw status
curl http://203.0.113.10:8080UFW सांगते की port अवरोधित आहे. तरीही curl page परत करते. काहीही बिघडलेले नाही. Docker स्वतःचे address translation आणि forwarding नियम थेट iptables मध्ये लिहिते. प्रकाशित container port कडे येणारा traffic host कडे पोहोचवण्याऐवजी container कडे forward केला जातो. त्यामुळे locally destined traffic साठी UFW व्यवस्थापित करत असलेल्या chain मधून तो जात नाही. Docker चे नियम UFW च्या नियमांपूर्वीही match होतात.
तात्पुरता उपाय म्हणजे आवश्यक त्या ठिकाणीच publish करणे:
ports:
- "127.0.0.1:8080:80"यामुळे host side loopback शी bind होते. त्यामुळे port server मधून आणि SSH tunnel द्वारे पोहोचण्यायोग्य राहतो, पण इतर कोणत्याही ठिकाणाहून पोहोचता येत नाही. Public entry point reverse proxy च्या मागे ठेवा आणि 80 व 443 जाणीवपूर्वक publish करा. DOCKER-USER chain सह प्रकाशित port filter करणे आवश्यक असलेल्या प्रकरणांचे स्पष्टीकरण Docker UFW ला थेट वळसा घालून ports का प्रकाशित करते आणि ते कसे दुरुस्त करावे येथे दिले आहे.
चार commands मध्ये debugging कशी करावी
प्रथम प्रत्येक container प्रत्यक्षात कोणत्या network वर आहे ते तपासा:
docker network inspect shop_defaultContainers block शी जोडलेल्या प्रत्येक container ची माहिती आणि त्याचा address दाखवतो. या list मध्ये एखादी service नसल्यास ती वेगळ्या network वर आहे, host mode मध्ये आहे किंवा चालू नाही.
तुमच्या images मध्ये कोणतेही tooling ठेवण्याची गरज पडू नये म्हणून, त्याच network शी जोडलेल्या तात्पुरत्या container मधून name resolution तपासा:
docker run --rm --network shop_default busybox nslookup db
docker run --rm --network shop_default busybox nc -zv db 5432nslookup अयशस्वी झाल्यास name resolution किंवा network membership मध्ये समस्या आहे. nslookup यशस्वी होत असताना nc अयशस्वी झाल्यास name आणि network योग्य आहेत; समस्या connection मध्येच आहे. nc ने Connection refused दाखवल्यास नेहमीचे कारण म्हणजे service त्या port वर listen करत नाही किंवा स्वतःच्या container मध्ये 0.0.0.0 ऐवजी 127.0.0.1 वर listen करते. Development servers मध्ये ही बाब सामान्य आहे. याचे निराकरण Docker मध्ये नसून application च्या bind address मध्ये करावे. nc hang होऊन timeout होत असल्यास traffic मध्ये काहीतरी अडथळा आणत आहे का ते तपासा, जसे firewall rule किंवा paused अथवा प्रतिसाद न देणारा container.
Docker bug सारखी दिसणारी आणखी एक समस्या आहे. Containers एकमेकांशी संवाद साधू शकतात, पण office किंवा VPN network वरील machine पर्यंत पोहोचू शकत नसतील, तर Docker subnet त्या network शी overlap होत असण्याची शक्यता आहे. Docker default ने 172.17.0.0/16 पासून addresses allocate करतो. Pool /etc/docker/daemon.json मध्ये बदला:
{
"default-address-pools": [
{ "base": "10.200.0.0/16", "size": 24 }
]
}त्यानंतर sudo systemctl restart docker चालवा आणि प्रभावित networks पुन्हा तयार करा. Existing network तयार करताना निश्चित केलेला subnetच वापरत राहतो.
FAQ
सेवांच्या नावाने माझे containers एकमेकांपर्यंत का पोहोचू शकत नाहीत?
ते एकाच network वर नाहीत. Compose प्रत्येक service ला <project>_default वर आपोआप ठेवते. परंतु एखाद्या service मध्ये networks: list जोडल्यावर, ती list त्या service साठी networks चा संपूर्ण संच बनते आणि default network गृहीत धरली जात नाही. docker network inspect <network> चालवा आणि दोन्ही containers Containers block मध्ये दिसतात का ते तपासा. तसेच कोणतीही service network_mode: host वापरत नाही ना ते तपासा. host mode container कोणत्याही Docker network वर नसतो आणि service names resolve करू शकत नाही.
एका service ला दुसऱ्या service पर्यंत पोहोचण्यासाठी ports publish करणे आवश्यक आहे का?
नाही. Compose network वर त्या network मधील इतर containers ना प्रत्येक container चा प्रत्येक port उपलब्ध असतो. ports: चा उपयोग केवळ Docker च्या बाहेरील traffic साठी container उघडण्यासाठी केला जातो आणि expose: हे documentation आहे. Database port publish करणे ही सामान्य आणि खर्चिक सवय आहे, कारण त्यामुळे database तुमच्या server च्या public interface वर उपलब्ध होतो.
bridge आणि host networking मध्ये काय फरक आहे?
Bridge मुळे container ला स्वतःचा network namespace आणि virtual switch वरील address मिळतो. Containers मधील name resolution आपोआप होते आणि बाहेर जाणारा traffic translate केला जातो. Host मुळे container थेट host चा network stack वापरतो: स्वतंत्र address नसतो, service name द्वारे resolution होत नाही, port publishing लागत नाही आणि host वरील इतर listeners पासून isolation राहत नाही. Process ला host चे interfaces आवश्यक नसतील, तर bridge हा default आणि योग्य पर्याय आहे.
दोन वेगवेगळ्या Compose files मधील containers कसे जोडू?
docker network create edge वापरून shared network तयार करा. त्यानंतर दोन्ही files मध्ये ते external: true द्वारे declare करा आणि परस्पर communication आवश्यक असलेल्या services ना त्याला attach करा. Compose ते create किंवा delete करणार नाही. Create step वगळल्यास Compose सुरू होण्यास नकार देते आणि network external म्हणून declared आहे, परंतु सापडले नाही असा error देते.
UFW ने port block केला असताना माझा container internet वरून का पोहोचण्याजोगा आहे?
कारण published port Docker ने iptables मध्ये जोडलेल्या forwarding rules द्वारे हाताळला जातो. या rules UFW च्या rules आधी match होतात. तसेच forwarded traffic UFW ज्या chain मधून filtering करते त्या chain मधून जात नाही. "127.0.0.1:8080:80" वापरून host side ला loopback वर bind करा आणि public services ports 80 आणि 443 वरील reverse proxy मागे ठेवा.