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 ही सुरुवातीच्या वापरकर्त्यांना चुकणारी बाब आहे
कोणत्याही वापरकर्त्याने परिभाषित केलेल्या नेटवर्कवर, Docker एक एम्बेडेड DNS सर्व्हर चालवतो. प्रत्येक कंटेनरला तो 127.0.0.11 येथे दिसतो. हा सर्व्हर सेवेची नावे सध्याच्या कंटेनर पत्त्यांमध्ये रूपांतरित करतो. त्यामुळे web कोणतीही संरचना न करता db या होस्टनावावर, 5432 या पोर्टवर डेटाबेसशी जोडले जाते.
docker compose exec web getent hosts dbयामुळे 172.18.0.2 db सारखी ओळ प्रदर्शित होते. काहीही प्रदर्शित न झाल्यास, दोन्ही सेवा एकाच नेटवर्कवर नाहीत.
जवळपास प्रत्येकजण एकदा करत असलेली चूक म्हणजे अनुप्रयोगाच्या संरचनेत localhost वापरणे. कंटेनरच्या आत localhost म्हणजे तोच कंटेनर. तो host किंवा दुसरी सेवा नसते. Postgres क्लायंट हे स्पष्टपणे कळवतात:
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?कनेक्शन स्ट्रिंग postgresql://postgres:example@db:5432/postgres असावी. त्यातील host हा सेवेचे नाव आहे.
नंतर वेळ वाचवणारे दोन तपशील लक्षात ठेवा. नावे सध्या चालू असलेल्या कंटेनरकडे सोडवली जातात. त्यामुळे docker compose up -d --scale web=3 एक नाव आणि तीन पत्ते देते. DNS परिणाम कायमस्वरूपी cache करणारा क्लायंट बंद झालेल्या कंटेनरशी जोडलेला राहू शकतो. तसेच, --network शिवाय साध्या docker run द्वारे वापरले जाणारे जुने bridge नेटवर्क नाव-निराकरण देत नाही. म्हणून 2016 मधील कंटेनर 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 काढून टाकते आणि प्रक्रियेला host चे interfaces थेट वापरू देते.
services:
probe:
image: alpine:3.20
network_mode: host
command: sleep infinityहे वापरण्याची ठोस कारणे आहेत. स्थानिक network वरील broadcast किंवा multicast traffic पाहण्याची गरज असलेली प्रक्रिया bridge च्या मागून तो traffic पाहू शकत नाही, कारण bridge हा traffic container कडे forward करत नाही. याची उदाहरणे म्हणजे media server साठी device discovery किंवा home automation hub. Host चे interface counters वाचणाऱ्या monitoring agent ला host चे interfaces आवश्यक असतात. तसेच address translation चा एक टप्पा वगळला जातो. उच्च packet rates असताना हे महत्त्वाचे ठरते.
याची किंमत विशिष्ट आहे.
ports: कार्य करत नाही. Host network mode वापरल्यास published ports वगळले जातात आणि container मधील प्रक्रिया ज्या ports वर bind करते, त्याच ports वर container bind करतो, अशी Docker ची सूचना आहे. 8080 port हवी असलेली दोन host mode containers एकमेकांशी संघर्ष करतात आणि दुसरा container bind: address already in use मुळे बंद होतो.
Service name द्वारे name resolution दोन्ही दिशांनी बंद होते. Container project network वर नसल्यामुळे ते db resolve करू शकत नाही आणि इतर services देखील ते resolve करू शकत नाहीत. ते त्या services पर्यंत फक्त host वर प्रकाशित केलेल्या ports द्वारे पोहोचू शकते. हा port सामान्यतः 127.0.0.1 असतो.
Isolation संपते. Host mode container मधील एखादी प्रक्रिया 0.0.0.0 वर bind केल्यास ती तुमच्या server च्या प्रत्येक interface वर, public interface सहित, listening करते. हे 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 का प्रकाशित करते आणि ते कसे दुरुस्त करावे येथे दिले आहे.
चार आदेशांमध्ये याचे डीबगिंग कसे करावे
प्रथम प्रत्येक container प्रत्यक्षात कोणत्या network वर आहे ते तपासा:
docker network inspect shop_defaultContainers ब्लॉकमध्ये जोडलेल्या प्रत्येक container ची address सूची दिलेली असते. या सूचीमध्ये एखादी service नसल्यास, ती वेगळ्या network वर आहे, host mode मध्ये आहे किंवा चालू नाही.
तुमच्या स्वतःच्या image मध्ये कोणतीही 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 अयशस्वी झाल्यास service चालू आहे, पण त्या port वर listening करत नाही किंवा तिच्या स्वतःच्या container मध्ये 127.0.0.1 वर listening करत आहे, 0.0.0.0 वर नाही. Development servers मध्ये ही शेवटची समस्या सामान्य आहे. यावरील उपाय Docker मध्ये नसून application च्या bind address मध्ये आहे.
Docker मधील बगसारखी दिसणारी आणखी एक समस्या असते. 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 पुन्हा तयार करा, कारण आधीपासून अस्तित्वात असलेले 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 मागे ठेवा.