Docker Compose networking: service name DNS, host mode
Compose-ன் default project bridge, service name மூலம் DNS, host mode எப்போது பயனுள்ளது, projects இடையே network பகிர்வு, UFW-ஐத் தாண்டும் published port ஆகியவற்றை அறிக.
உங்கள் app தொடங்குவதற்கு முன் Compose உருவாக்குவது
Docker Compose networking ஒரு விதியுடன் தொடங்குகிறது: docker compose up திட்டத்திற்காக ஒரு private network-ஐ உருவாக்கி, ஒவ்வொரு service-ஐயும் அதனுடன் இணைக்கிறது. அந்த services-கள் service name மூலம் ஒன்றையொன்று அணுகவும் இது அனுமதிக்கிறது. இதற்காக நீங்கள் ஒரு networks: வரியைக்கூட எழுத வேண்டியதில்லை. Compose networking குறித்த பெரும்பாலான குழப்பங்கள், இந்த default ஏற்கனவே உள்ளது என்பதை அறியாததால் ஏற்படுகின்றன.
இது ஒரு சிறிய 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 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 கிடைக்கும். வெளியே செல்லும் network traffic, செல்லும் வழியில் host-ன் address-க்கு மாற்றப்படுகிறது.
docker compose down அந்த network-ஐ மீண்டும் நீக்குகிறது. இதனால் பழைய project-ஐச் சேர்ந்த stale container ஒன்று network-ஐ தொடர்ந்து பயன்படுத்திக் கொண்டிருக்கலாம். அப்போது Docker error while removing network: network shop_default has active endpoints என்ற பிழையைத் தரும். அதனுடன் இன்னும் இணைக்கப்பட்டுள்ள container-ஐ stop செய்வது அல்லது remove செய்வதே தீர்வு.
Compose உங்களுக்கு புதிதாக இருந்தால், Compose file layout மற்றும் lifecycle commands பகுதியை முதலில் படிக்கவும். கீழே உள்ள அனைத்தும், நீங்கள் ஒரு project-ஐ start செய்து stop செய்யத் தெரியும் என்ற அடிப்படையில் எழுதப்பட்டுள்ளது.
தொடக்கநிலையினர் தவறவிடும் பகுதி: service name மூலம் DNS
User-defined network எதிலும், Docker ஒவ்வொரு container-க்கும் 127.0.0.11 இல் அணுகக்கூடிய embedded DNS server-ஐ இயக்குகிறது. இது service names-ஐ தற்போதைய container addresses-ஆகத் தீர்க்கிறது. எனவே web எந்த configuration-மும் தேவையின்றி, db என்ற hostname-இல் உள்ள database-ஐ 5432 port வழியாக அணுகுகிறது.
docker compose exec web getent hosts dbஇது 172.18.0.2 db போன்ற ஒரு வரியை அச்சிடும். எதுவும் அச்சிடப்படாவிட்டால், இரண்டு 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 தற்போது இயங்கிக்கொண்டிருப்பதற்கேற்ப resolve ஆகும். ஆகவே docker compose up -d --scale web=3 ஒரு name-க்கு மூன்று addresses-ஐ வழங்கும். DNS-ஐ நிரந்தரமாக cache செய்யும் client, செயலிழந்த container-ஐயே தொடர்ந்து பயன்படுத்தும். மேலும், --network இல்லாமல் plain docker run பயன்படுத்தும்போது உருவாகும் legacy bridge network-இல் name resolution எதுவும் இல்லை. அதனால் 2016-ஆம் ஆண்டின் container links பற்றிய ஆலோசனைகள், நீங்கள் இப்போது காண்பதுடன் பொருந்தாது.
இரண்டு services-ஐ இணைக்க ports: தேவையில்லை
ports:, ஒரு container port-ஐ host-ல் publish செய்கிறது. Docker-க்கு வெளியிலிருந்து வரும் network traffic-க்காக இது பயன்படுகிறது. service-to-service traffic-க்கு இதனுடன் எந்தத் தொடர்பும் இல்லை. Project network-ல் உள்ள முழு port range வழியாக அந்த traffic ஏற்கனவே இயங்குகிறது.
அதனால், பலர் தங்கள் database service-க்கு சேர்க்கும் ports: - "5432:5432" பயனற்றது மட்டுமல்ல; உண்மையான பாதிப்பையும் ஏற்படுத்துகிறது. இது server-ன் 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, container-ன் சொந்த network namespace-ஐ நீக்கி, process-ஐ host-ன் interfaces-ஐ நேரடியாகப் பயன்படுத்த அனுமதிக்கிறது.
services:
probe:
image: alpine:3.20
network_mode: host
command: sleep infinityஇதைக் பயன்படுத்துவதற்கான நடைமுறை காரணங்கள் உள்ளன. Local network-ல் உள்ள broadcast அல்லது multicast traffic-ஐ காண வேண்டிய process, bridge-ன் பின்னால் இருந்து அதை காண முடியாது. Media server-க்கான device discovery அல்லது home automation hub போன்றவை இதற்கு எடுத்துக்காட்டுகள். Bridge அந்த traffic-ஐ container-க்கு forward செய்யாது. Host-ன் interface counters-ஐப் படிக்கும் monitoring agent-க்கு host-ன் interfaces தேவை. மேலும் address translation hop தவிர்க்கப்படுகிறது. High packet rates இருக்கும் போது இது முக்கியமானது.
இதற்கான செலவுகள் குறிப்பிட்டவை.
ports: செயல்படாது. Host network mode பயன்படுத்தும் போது published ports நிராகரிக்கப்படும் என்று Docker எச்சரிக்கிறது. Process bind செய்யும் port-களில் container நேரடியாக bind செய்யும். port 8080 தேவைப்படும் இரண்டு host mode containers ஒன்றுடன் ஒன்று மோதும். இரண்டாவது container bind: address already in use பிழையுடன் நிறுத்தப்படும்.
இரு திசைகளிலும் service name மூலம் name resolution இருக்காது. Container project network-ல் இல்லாததால், அது db-ஐ resolve செய்ய முடியாது. மற்ற services-களும் அதை resolve செய்ய முடியாது. Host-ல் publish செய்யப்பட்ட 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 முதல் மட்டுமே ஆதரிக்கிறது. அதுவும் இதை enable செய்த பிறகே பயன்படுத்த முடியும். மேலும் containers-ஆல் host IP addresses-க்கு bind செய்ய முடியாது. TCP மற்றும் UDP மட்டுமே கையாளப்படும். உங்கள் team-இன் ஒரு பகுதி Linux servers-ல், மற்றொரு பகுதி Docker Desktop-ல் இருந்தால், ஒரே file வெவ்வேறு விதமாகச் செயல்படும் என்று எதிர்பார்க்கவும்.
Host-ன் interfaces தேவைப்படும் போது host mode-ஐப் பயன்படுத்தவும். Connection problem-ஐ சரிசெய்ய இதைப் பயன்படுத்த வேண்டாம். இது பொதுவாக ஒரு பிரச்சினைக்கு பதிலாக இன்னும் கடினமான மற்றொரு பிரச்சினையை உருவாக்கும்.
External network மூலம் இரண்டு Compose projects-ஐ இணைத்தல்
ஒரு project உருவாக்கிய network, மற்றொரு project-க்கு தெரியாது. அதனால் ஒரே server-ல் இருந்தாலும், proxy/compose.yaml-இல் உள்ள reverse proxy-யால் app/compose.yaml-இல் உள்ள app-ஐ அணுக முடியாது. இதற்கான தீர்வு, எந்த project-க்கும் சொந்தமில்லாத network-ஐ பயன்படுத்துவதாகும்.
அதை ஒருமுறை கைமுறையாக உருவாக்கவும்:
docker network create edgeபின்னர் ஒவ்வொரு project-லும் அதை external network ஆக அறிவிக்கவும். 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 என்பது புதிய network-ஐ உருவாக்காமல் ஏற்கனவே உள்ள network-இல் Compose இணைக்க வேண்டும் என்பதைக் குறிப்பிடுகிறது. மேலும், அந்த network-ஐ docker compose down-இல் அப்படியே விட வேண்டும் என்றும் குறிப்பிடுகிறது. தனியான name: key முக்கியமானது. அது இல்லாமல், Compose edge என்ற பெயருடன் சரியாகப் பொருந்தும் network-ஐத் தேடும். இதைப் பயன்படுத்தினால், உங்கள் file-ல் network-க்கு ஒரு பெயரையும் host-ல் வேறு பெயரையும் பயன்படுத்தலாம்.
Network இல்லை என்றால், Compose தொடங்க மறுக்கும். Network external ஆக அறிவிக்கப்பட்டுள்ளது, ஆனால் அதைக் கண்டறிய முடியவில்லை என்று அது தெரிவிக்கும். முதலில் அந்த network-ஐ உருவாக்கவும்.
Application file internal-ஐ எவ்வாறு பயன்படுத்துகிறது என்பதைக் கவனிக்கவும். Database அந்த project-க்கு மட்டும் உரிய network-இல் உள்ளது. எனவே proxy-யால் அதை அணுக முடியாது; app மட்டுமே அதை அணுக முடியும். ஒரு network-ன் கீழ் internal: true-ஐச் சேர்ப்பது இன்னும் கடுமையான கட்டுப்பாட்டை வழங்குகிறது. இதனால் வெளியுலகிற்கான அதன் route முழுமையாக நீக்கப்படும். Database-க்கு இது நல்ல இயல்புநிலை அமைப்பாகும். ஆனால் அமைப்பதற்கு முன் ஒரு முக்கிய விளைவை அறிந்துகொள்ளவும்: internal network-இல் உள்ள container எதையும் download செய்ய முடியாது. எனவே startup நேரத்தில் apt-get update அல்லது pip install-ஐ இயக்கும் entrypoint தொங்கியிருந்து, பின்னர் timeout பிழையுடன் தோல்வியடையும்.
Routing rules மற்றும் certificates உடன் முழுமையான செயல்பாட்டு அமைப்புக்கு, ஒரே Traefik instance-ன் பின்னால் பல app-களை இயக்குதல் என்பதைப் பார்க்கவும்.
Published ports UFW-ஐத் தவிர்த்து அணுகப்படுகின்றன
Compose networking-இன் இந்தப் பகுதி security incident-ஆக மாறக்கூடும். நீங்கள் ஒரு port-ஐ publish செய்கிறீர்கள். UFW active நிலையில் இருந்து SSH-ஐத் தவிர அனைத்தையும் deny செய்கிறது என்பதைச் சரிபார்க்கிறீர்கள். இருந்தாலும் service internet-இலிருந்து அணுகக்கூடியதாகவே உள்ளது.
sudo ufw status
curl http://203.0.113.10:8080UFW அந்த port blocked என்று கூறுகிறது. ஆனால் curl அந்தப் பக்கத்தைத் திருப்பி வழங்குகிறது. எதுவும் செயலிழக்கவில்லை. Docker தனது சொந்த address translation மற்றும் forwarding rules-ஐ நேரடியாக iptables-ல் எழுதுகிறது. Published container port-க்கு வரும் traffic, host-க்கு deliver செய்யப்படாமல் container-க்கு forward செய்யப்படுகிறது. ஆகவே locally destined traffic-ஐ நிர்வகிக்கும் UFW chain வழியாக அது செல்லாது. Docker-ன் rules, UFW-ன் rules-க்கு முன்பே match செய்யப்படுகின்றன.
சுருக்கமான தீர்வு, தேவையான இடத்தில் மட்டும் publish செய்வதாகும்:
ports:
- "127.0.0.1:8080:80"இதனால் host பக்கமானது loopback-க்கு bind செய்யப்படுகிறது. எனவே அந்த port-ஐ server-இலிருந்தும் SSH tunnel வழியாகவும் அணுகலாம். வேறு எந்த இடத்திலிருந்தும் அதை அணுக முடியாது. Public entry point-ஐ reverse proxy-க்குப் பின்னால் அமைத்து, 80 மற்றும் 443-ஐ திட்டமிட்டு publish செய்யுங்கள். Published port-ஐ filter செய்ய வேண்டிய நிலைகளுக்கான DOCKER-USER chain உட்பட முழு விளக்கம், Docker ஏன் UFW-ஐத் தாண்டி நேரடியாக publish செய்கிறது, அதை எவ்வாறு சரிசெய்வது என்பதில் உள்ளது.
நான்கு commands மூலம் இதை debug செய்வது எப்படி
ஒவ்வொரு 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's bind address-ஐச் சரிசெய்ய வேண்டும்.
Docker bug போலத் தோன்றும் இன்னொரு failure உள்ளது. Containers ஒன்றுடன் ஒன்று தொடர்புகொள்ள முடிகிறது, ஆனால் உங்கள் office அல்லது VPN network-இல் உள்ள machine-ஐ அடைய முடியவில்லை என்றால், Docker subnet அந்த network-உடன் overlap ஆகிறது. Docker இயல்பாக 172.17.0.0/16 முதல் address-களை 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: பட்டியலைச் சேர்த்தவுடன், அந்தப் பட்டியல் அதற்கான முழுமையான network தொகுப்பாகிறது; default network இனி தானாக சேர்க்கப்படாது. docker network inspect <network> இயக்கி, Containers block-ல் இரண்டு containers-உம் இருப்பதைச் சரிபார்க்கவும். எந்த service-உம் network_mode: host பயன்படுத்தவில்லை என்பதையும் சரிபார்க்கவும். ஏனெனில் host mode container எந்த Docker network-லும் இருப்பதில்லை; அதனால் service பெயர்களை resolve செய்ய முடியாது.
ஒரு 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 இடையே பெயர் resolution தானாக நடைபெறும்; வெளியே செல்லும் traffic translate செய்யப்படும். host, container-க்கு host-ன் network stack-ஐ நேரடியாக வழங்குகிறது. இதனால் தனிப்பட்ட address இல்லை, service பெயர் மூலம் resolution இல்லை, port publishing இல்லை, மேலும் host-ன் பிற listeners-இலிருந்து isolation இல்லை. bridge தான் default. Process-க்கு host-ன் interfaces தேவைப்படாவிட்டால் இதுவே சரியான தேர்வு.
இரண்டு வேறு Compose files-ல் உள்ள containers-ஐ எவ்வாறு இணைப்பது?
docker network create edge மூலம் shared network-ஐ உருவாக்கவும். பின்னர் இரண்டு files-லும் external: true மூலம் அதை declare செய்து, தொடர்புகொள்ள வேண்டிய services-ஐ அதில் attach செய்யவும். Compose அந்த network-ஐ உருவாக்கவோ நீக்கவோ செய்யாது. Create படியைத் தவிர்த்தால், Compose start செய்ய மறுத்து, 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 traffic அனைத்தையும் ports 80 மற்றும் 443-ல் reverse proxy-க்கு பின்னால் வைக்கவும்.