Docker Compose నెట్వర్కింగ్: DNS, host mode, UFW
Compose default bridge, service పేరుతో DNS, host mode ఎప్పుడు ఉపయోగించాలి, projects మధ్య ఒకే network పంచుకోవడం, UFW దాటే published port గురించి తెలుసుకోండి.
మీ app ప్రారంభమయ్యే ముందు Compose ఏమి నిర్మిస్తుంది
Docker Compose నెట్వర్కింగ్ ఒక నియమంతో ప్రారంభమవుతుంది: docker compose up ప్రాజెక్ట్ కోసం ఒక ప్రైవేట్ నెట్వర్క్ను సృష్టించి, ప్రతి serviceను దానికి అనుసంధానిస్తుంది. ఆ serviceలు service పేరు ద్వారా పరస్పరం చేరుకోగలవు. దీని కోసం మీరు ఒక్క networks: పంక్తి కూడా రాయాల్సిన అవసరం లేదు. డిఫాల్ట్ నెట్వర్క్ ఇప్పటికే ఉందని తెలియకపోవడం వల్లే Compose నెట్వర్కింగ్పై ఎక్కువ గందరగోళం ఏర్పడుతుంది.
ఇది ఒక చిన్న 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 పేరు డిఫాల్ట్గా చిన్న అక్షరాలతో ఉన్న directory పేరుగా ఉంటుంది. దీన్ని docker compose -p myproject up -d తో లేదా fileలోని top-level name: myproject తో మార్చవచ్చు. దీని driver bridge. ఇది hostలోని virtual switch. ప్రతి containerకు private subnetలో ఒక address లభిస్తుంది. బయటకు వెళ్లే network trafficలో host address ఉపయోగించేలా అనువాదం జరుగుతుంది.
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 commands ముందుగా చదవండి. కిందివన్నీ మీరు projectను start మరియు stop చేయగలరని భావిస్తాయి.
సేవా పేరుతో DNS అనేది ప్రారంభ వినియోగదారులు తరచుగా గమనించని విషయం
ఏ user-defined networkలోనైనా, Docker ప్రతి containerకు 127.0.0.11 వద్ద కనిపించే embedded DNS serverను అమలు చేస్తుంది. ఇది సేవా పేర్లను ప్రస్తుతం ఉన్న container addressలకు resolve చేస్తుంది. అందువల్ల web ఎలాంటి configuration లేకుండానే db hostnameలోని databaseను 5432 portపై చేరుకుంటుంది.
docker compose exec web getent hosts dbఅది 172.18.0.2 db వంటి ఒక పంక్తిని ముద్రిస్తుంది. ఏమీ ముద్రించకపోతే, రెండు సేవలు ఒకే networkలో లేవు.
దాదాపు ప్రతి ఒక్కరూ ఒకసారి చేసే పొరపాటు application configలో localhostను ఉపయోగించడం. ఒక containerలో localhost అనేది ఆ containerనే సూచిస్తుంది; hostను లేదా ఇతర సేవను కాదు. 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 భాగం సేవా పేరు.
తర్వాత సమయం ఆదా చేసే రెండు వివరాలు ఉన్నాయి. పేర్లు ప్రస్తుతం నడుస్తున్నదానికి resolve అవుతాయి. అందువల్ల docker compose up -d --scale web=3 ఒకే పేరుతో మూడు addressలను అందిస్తుంది. DNSను ఎప్పటికీ cache చేసే client, పనిచేయని containerకే తనను తాను పరిమితం చేసుకుంటుంది. అలాగే --network లేకుండా సాధారణ docker run ఉపయోగించే legacy bridge networkలో name resolution పూర్తిగా ఉండదు. అందుకే 2016లోని container links గురించిన సూచనలు మీరు ఇప్పుడు చూస్తున్న దానికి సరిపోలవు.
రెండు సేవలను కనెక్ట్ చేయడానికి ports: అవసరం లేదు
ports: కంటైనర్ పోర్ట్ను హోస్ట్లో ప్రచురిస్తుంది. Docker వెలుపల నుంచి వచ్చే నెట్వర్క్ ట్రాఫిక్ కోసం ఇది ఉపయోగపడుతుంది. సేవల మధ్య ట్రాఫిక్కు దీనితో సంబంధం లేదు. ప్రాజెక్ట్ నెట్వర్క్లోని మొత్తం పోర్ట్ పరిధిలో ఆ ట్రాఫిక్ ఇప్పటికే పనిచేస్తుంది.
అందువల్ల చాలామంది తమ database serviceకు జోడించే ports: - "5432:5432" ఉపయోగం లేకుండా నిజమైన హానిని కలిగిస్తుంది: ఇది సర్వర్ public 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దీన్ని ఉపయోగించడానికి సరైన కారణాలు ఉన్నాయి. Local networkలోని broadcast లేదా multicast trafficను చూడాల్సిన processకు bridge వెనుక నుంచి ఆ traffic కనిపించదు. ఎందుకంటే bridge ఆ trafficను containerకు forward చేయదు. ఉదాహరణకు, media server కోసం device discovery లేదా home automation hub కోసం discovery అవసరం కావచ్చు. Host interface countersను చదివే monitoring agentకు కూడా host interfaces అవసరం. అదనంగా, address translation hop తొలగిపోతుంది. అధిక packet rates ఉన్నప్పుడు ఇది ముఖ్యమైనది.
దీని ఖర్చులు స్పష్టంగా ఉంటాయి.
ports: ఇక పనిచేయదు. Host network mode ఉపయోగించినప్పుడు published ports విస్మరించబడతాయని Docker హెచ్చరిస్తుంది. Container తన process bind చేసిన portsను ఉపయోగిస్తుంది. 8080 port కావాలనుకునే రెండు host mode containers పరస్పరం ఢీకొంటాయి. రెండవది bind: address already in use కారణంగా ఆగిపోతుంది.
రెండు దిశల్లోనూ service name ద్వారా name resolution ఉండదు. Container project networkలో ఉండదు. అందువల్ల అది dbను resolve చేయలదు. ఇతర services కూడా దాన్ని resolve చేయలేవు. Hostలో publish చేసిన ports ద్వారా మాత్రమే అవి containerను చేరుకోగలవు. సాధారణంగా ఆ ports 127.0.0.1 వద్ద అందుబాటులో ఉంటాయి.
Isolation ఉండదు. Host mode containerలో process 0.0.0.0ను bind చేస్తే, అది మీ 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 నుంచి మాత్రమే support చేస్తుంది. అదీ మీరు దీన్ని enable చేసిన తర్వాత మాత్రమే. ఇంకా కొన్ని పరిమితులు ఉన్నాయి: containers host IP addressesను bind చేయలేవు. TCP మరియు UDP మాత్రమే handle చేయబడతాయి. మీ teamలో కొంతమంది Linux serversపై, మరికొంతమంది Docker Desktopపై ఉంటే, ఒకే file భిన్నంగా పనిచేస్తుందని భావించండి.
Host interfaces అవసరమైనప్పుడు host modeను ఉపయోగించండి. Connection problemను సరిచేయడానికి దీన్ని ఉపయోగించవద్దు. సాధారణంగా ఇది ఒక సమస్యను మరింత క్లిష్టమైన సమస్యతో భర్తీ చేస్తుంది.
రెండు Compose ప్రాజెక్ట్లను బాహ్య networkతో అనుసంధానించడం
ఒక project సృష్టించిన network మరొక projectకు కనిపించదు. అందువల్ల proxy/compose.yamlలోని reverse proxyకి, అదే serverలో ఉన్నప్పటికీ, app/compose.yamlలోని app కనిపించదు. ఏ project స్వంతం కాని networkను ఉపయోగించాలి.
దాన్ని ఒకసారి చేతితో సృష్టించండి:
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: 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 కొత్త networkను సృష్టించకుండా ఇప్పటికే ఉన్న networkకు అనుసంధానమవుతుంది. అలాగే docker compose downలో దాన్ని అలాగే ఉంచుతుంది. ప్రత్యేకమైన name: key ప్రాముఖ్యత ఎక్కువగా ఉంటుంది. అది లేకపోతే Compose ఖచ్చితంగా edge పేరున్న network కోసం చూస్తుంది. దీన్ని ఉపయోగిస్తే మీ fileలో networkకు ఒక పేరు, hostలో మరో పేరు ఇవ్వవచ్చు.
Network లేకపోతే Compose ప్రారంభించడానికి నిరాకరిస్తుంది. ఆ network externalగా ప్రకటించబడిందని, కానీ కనుగొనలేకపోయామని తెలియజేస్తుంది. ముందుగా దాన్ని సృష్టించండి.
Application file internalతో ఏమి చేస్తుందో గమనించండి. Database ఆ projectకు స్థానికమైన networkలో మాత్రమే ఉంటుంది. అందువల్ల proxy దాన్ని చేరుకోలదు; app మాత్రమే చేరుకోగలదు. Network కింద internal: trueను జోడిస్తే, బయట ప్రపంచానికి వెళ్లే దాని routeను పూర్తిగా తొలగిస్తుంది. Databaseకు ఇది మంచి default. అయితే దీన్ని సెట్ చేయడానికి ముందు ఒక పరిమితిని తెలుసుకోండి: internal networkలోని container ఏదీ download చేయలదు. అందువల్ల startup సమయంలో apt-get update లేదా pip installను అమలు చేసే entrypoint hang అయి, చివరకు timeoutతో విఫలమవుతుంది.
Routing rules మరియు certificatesతో కూడిన పూర్తి ఉదాహరణ setup కోసం ఒకే Traefik instance వెనుక అనేక appలను నడపడం చూడండి.
UFWను దాటే Published ports
ఇది Compose networkingలో భద్రతా సంఘటనకు దారితీసే భాగం. మీరు ఒక portను publish చేసి, UFW activeగా ఉందని, SSH తప్ప మిగతావన్నీ deny చేస్తున్నదని తనిఖీ చేసినా, service internet నుంచి ఇప్పటికీ అందుబాటులో ఉంటుంది.
sudo ufw status
curl http://203.0.113.10:8080Port blockedగా ఉందని UFW చెబుతుంది. అయినప్పటికీ curl pageను తిరిగి అందిస్తుంది. ఏదీ విఫలమవడం లేదు. Docker తన సొంత address translation మరియు forwarding rulesను నేరుగా iptablesలో రాస్తుంది. Published container portకు వచ్చే traffic hostకు అందకుండా containerకు forward అవుతుంది. అందువల్ల locally destined traffic కోసం UFW నిర్వహించే chain గుండా అది వెళ్లదు. Docker rules కూడా UFW rules కంటే ముందే match అవుతాయి.
సంక్షిప్త పరిష్కారం: అవసరమైన చోట మాత్రమే publish చేయండి.
ports:
- "127.0.0.1:8080:80"ఇలా చేస్తే host side loopbackకు bind అవుతుంది. అందువల్ల port server నుంచే, అలాగే SSH tunnel ద్వారా మాత్రమే అందుబాటులో ఉంటుంది. ఇతర ఎక్కడి నుంచీ అందుబాటులో ఉండదు. Public entry pointను reverse proxy వెనుక ఉంచండి. ఆ reverse proxy 80 మరియు 443లను ఉద్దేశపూర్వకంగా publish చేయాలి. Published portను filter చేయాల్సిన సందర్భాల్లో ఉపయోగించే DOCKER-USER chainతో సహా పూర్తి వివరణ Docker UFWను నేరుగా ఎలా దాటుకుని publish చేస్తుంది, దాన్ని ఎలా పరిష్కరించాలిలో ఉంది.
నాలుగు ఆదేశాలతో సమస్యను ఎలా డీబగ్ చేయాలి
మొదట ప్రతి container వాస్తవంగా ఏ networkలో ఉందో తెలుసుకోండి:
docker network inspect shop_defaultContainers blockలో కనెక్ట్ అయిన ప్రతి container, దాని addressతో కనిపిస్తుంది. ఆ జాబితాలో లేని 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 విఫలమైతే service నడుస్తోంది, కానీ ఆ portలో listening చేయడం లేదు. లేదా తన containerలోని 127.0.0.1పై listening చేస్తోంది, 0.0.0.0పై కాదు. Development serversలో ఇది సాధారణం. పరిష్కారం Dockerలో కాదు, application యొక్క bind addressలో ఉంటుంది.
Docker bugలా కనిపించే మరో సమస్య ఉంది. Containers పరస్పరం communicate చేయగలిగినా, మీ office లేదా VPN networkలోని machineను చేరుకోలేకపోతే, Docker subnet ఆ networkతో overlap అయ్యే అవకాశం ఉంది. Docker డిఫాల్ట్గా 172.17.0.0/16 నుంచి subnetలను కేటాయిస్తుంది. /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: జాబితాను జోడించిన వెంటనే, ఆ జాబితానే దానికి సంబంధించిన పూర్తి networkల సమితిగా మారుతుంది. అప్పుడు 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 మధ్య automatic name resolutionను, బయటికి వెళ్లే trafficకు address translationను అందిస్తుంది. host containerను నేరుగా host యొక్క network stackపై ఉంచుతుంది. అందువల్ల ప్రత్యేక address ఉండదు, service name ద్వారా resolution ఉండదు, port publishing అవసరం ఉండదు, అలాగే hostలోని ఇతర listeners నుంచి isolation ఉండదు. bridge default ఎంపిక. Processకు host interfaces అవసరం లేనంత వరకు ఇదే సరైన ఎంపిక.
రెండు వేర్వేరు Compose filesలోని containersను ఎలా connect చేయాలి?
docker network create edgeతో shared networkను సృష్టించండి. తరువాత రెండు filesలో external: trueతో దాన్ని declare చేసి, పరస్పరం communicate చేయాల్సిన servicesను దానికి attach చేయండి. Compose ఆ networkను సృష్టించదు లేదా తొలగించదు. Create దశను వదిలేస్తే, Compose ప్రారంభం కావడానికి నిరాకరిస్తుంది. Network externalగా declare చేయబడింది కానీ కనుగొనబడలేదు అని అది నివేదిస్తుంది.
UFW portను block చేసినప్పటికీ నా container internet నుంచి ఎందుకు చేరుకోగలుగుతోంది?
Published portను Docker iptablesకు జోడించే forwarding rules నిర్వహిస్తాయి. ఆ rules, UFW rules కంటే ముందుగా match అవుతాయి. అలాగే forwarded traffic, UFW filter చేసే chain ద్వారా వెళ్లదు. "127.0.0.1:8080:80"తో host sideను loopbackకు bind చేయండి. Public servicesను ports 80 మరియు 443పై reverse proxy వెనుక ఉంచండి.