Jinsi Docker Compose inavyosimamia mtandao
Elewa jinsi Docker Compose inavyounda mtandao wa bridge, DNS kwa jina la huduma, na matumizi ya host mode. Jifunze pia jinsi bandari zilizochapishwa zinavyokwepa sheria za UFW.
Mambo ambayo Compose huandaa kabla ya programu yako kuanza
Mtandao wa Docker Compose huanza na kanuni moja: docker compose up hutengeneza mtandao wa ndani kwa ajili ya mradi, huunganisha kila huduma kwenye mtandao huo, na kuruhusu huduma hizo kuwasiliana kwa kutumia jina la huduma. Huhitaji kuandika hata mstari mmoja wa networks: ili kupata hilo. Mkanganyiko mwingi kuhusu mtandao wa Compose hutokana na kutojua kuwa usanidi huo wa msingi upo tayari.
Hii hapa ni faili ndogo. Ihifadhi kama compose.yaml kwenye saraka inayoitwa shop.
services:
web:
image: nginx:1.27
ports:
- "8080:80"
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: exampleIanzishe na uangalie kile ambacho Docker imetengeneza:
docker compose up -d
docker network lsOrodha hiyo sasa ina mtandao unaoitwa shop_default. Compose huupa jina <project>_default, na jina la mradi huwa ni jina la saraka lililobadilishwa kuwa herufi ndogo (lowercase). Unaweza kubatilisha hili kwa kutumia docker compose -p myproject up -d au kwa kuweka name: myproject katika ngazi ya juu ya faili. Dereva wake ni bridge, ambao ni swichi ya mtandao ya kidijitali ndani ya seva pangishi (host). Kila kontena hupata anwani kwenye subnet ya ndani, na trafiki inayotoka nje hutafsiriwa kwenda kwenye anwani ya seva pangishi wakati wa kutoka.
docker compose down hufuta mtandao huo tena. Hii ndiyo sababu kontena la zamani kutoka mradi wa kale linaweza kuzuia mtandao usifutike: Docker hukataa kwa kutoa ujumbe wa error while removing network: network shop_default has active endpoints, na suluhisho ni kusimamisha au kufuta kontena lililounganishwa kwenye mtandao huo.
Ikiwa Compose ni ngeni kwako, mpangilio wa faili ya Compose na amri za mzunguko wa maisha inafaa kusomwa kwanza, kwa sababu kila kitu hapa chini kinachukulia kuwa unaweza kuanzisha na kusimamisha mradi.
DNS kwa jina la huduma ni sehemu ambayo wanaoanza hujisahau
Kwenye mtandao wowote uliotengenezwa na mtumiaji, Docker huendesha seva ya DNS iliyopachikwa ambayo kila kontena huiona katika 127.0.0.11. Hii hubadilisha majina ya huduma kuwa anwani za kontena husika. Kwa hivyo web hufikia hifadhidata kwenye hostname db, kwenye port 5432, bila usanidi wowote.
docker compose exec web getent hosts dbHiyo huchapisha mstari kama 172.18.0.2 db. Ikiwa haichapishi chochote, huduma hizo mbili hazipo kwenye mtandao mmoja.
Kosa ambalo karibu kila mtu hufanya mara moja ni kutumia localhost katika usanidi wa programu. Ndani ya kontena, localhost ni kontena hilo lenyewe, si seva pangaji (host) na si huduma nyingine. Wateja wa Postgres huripoti hili kwa uwazi:
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?Mstari wa muunganisho unapaswa kuwa postgresql://postgres:example@db:5432/postgres. Sehemu ya host ni jina la huduma.
Maelezo mawili yanayookoa muda baadaye. Majina hubadilika kulingana na kile kinachoendeshwa sasa, kwa hivyo docker compose up -d --scale web=3 hutoa jina moja lenye anwani tatu, na mteja anayehifadhi DNS milele atajifunga kwenye kontena lililokufa. Na mtandao wa zamani wa bridge unaotumiwa na docker run ya kawaida bila --network hauwezi kutatua majina ya kontena hata kidogo: kontena huko hupata kila mmoja kwa anwani ya IP pekee, na hutafuta hostname za nje kupitia nakala ya /etc/resolv.conf ya seva pangaji. Hiyo ndiyo sababu ushauri kuhusu viungo vya kontena (container links) kutoka 2016 haulingani na kile unachokiona.
Hauhitaji ports: ili kuunganisha huduma mbili
ports: huchapisha port ya container kwenye host. Hii ni kwa ajili ya trafiki inayotoka nje ya Docker. Haina uhusiano wowote na trafiki ya huduma-kwa-huduma, ambayo tayari hufanya kazi katika masafa yote ya port kwenye mtandao wa mradi.
Kwa hivyo, ports: - "5432:5432" ambayo watu wengi huongeza kwenye huduma yao ya database haisaidii chochote na inadhuru: inafichua Postgres kwenye interface ya umma ya seva. Ifute. Ikiwa unataka iweze kufikiwa kutoka kwenye laptop yako kwa ajili ya migration, iunganishe na loopback kwa kutumia "127.0.0.1:5432:5432" na uifikie kupitia SSH tunnel. Tofauti kati ya listening socket, published port, na firewall rule imeelezwa katika jinsi ports na huduma zinazosikiliza zinavyofanya kazi kwenye Linux.
expose: ni kwa ajili ya nyaraka pekee chini ya Compose. Haifungui chochote, kwa sababu hakuna kilichofungwa kati ya containers kwenye mtandao mmoja.
Wakati network_mode host inapofaa, na gharama zake
Hali ya host huondoa namespace ya mtandao ya kontena na kuruhusu mchakato kutumia interfaces za seva pangaji moja kwa moja.
services:
probe:
image: alpine:3.20
network_mode: host
command: sleep infinityKuna sababu za kweli za kutaka hili. Mchakato unaohitaji kuona trafiki ya broadcast au multicast kwenye mtandao wa ndani, kama vile ugunduzi wa vifaa kwa seva ya media au kitovu cha otomatiki cha nyumbani, hauwezi kuiona ukiwa nyuma ya bridge, kwa sababu bridge haisambazi trafiki hiyo kwa kontena. Wakala wa ufuatiliaji (monitoring agent) anayesoma kaunta za interface za seva pangaji anahitaji interfaces za seva pangaji. Na unaruka hatua ya kutafsiri anwani, jambo ambalo ni muhimu kwa viwango vya juu vya pakiti.
Gharama zake ni mahususi.
ports: huacha kufanya kazi. Docker huonya kuwa port zilizochapishwa hutupwa wakati wa kutumia hali ya mtandao ya host, na kontena hufunga chochote ambacho mchakato wake hufunga. Kontena mbili za hali ya host zinazotaka port 8080 hugongana, na ya pili hufa na bind: address already in use.
Utatuzi wa majina kwa jina la huduma hupotea katika pande zote mbili. Kontena halipo kwenye mtandao wa mradi, kwa hivyo haliwezi kutatua db, na huduma nyingine haziwezi kulitatua. Bado linaweza kuzifikia kupitia port zilizochapishwa kwenye seva pangaji, kwa kawaida katika 127.0.0.1. Kwenye Linux linaweza pia kufikia kontena la bridge moja kwa moja kwenye anwani ya IP ya kontena hilo kwenye port yoyote inayosikiliza, kwa sababu seva pangaji ina ufikiaji wazi kwa kontena kwenye mitandao yake ya bridge na kontena la hali ya host hushiriki stack ya mtandao ya seva pangaji. Anwani hizo hubadilika wakati kontena zinapoundwa upya, kwa hivyo port iliyochapishwa kwenye loopback ndiyo njia thabiti.
Kutengwa (isolation) hupotea. Mchakato unaofunga 0.0.0.0 ndani ya kontena la hali ya host unasikiliza kwenye kila interface ya seva yako, ikiwemo ile ya umma, kama vile kifurushi kilichosakinishwa na apt. Kuna faida moja kwa hilo: trafiki hii hufuata njia ya kawaida ya kuingiza (input path), kwa hivyo sheria za UFW hutumika kwake, jambo ambalo si kweli kwa port zilizochapishwa.
Hali ya host ni kipengele cha Linux Docker Engine. Docker Desktop inaiunga mkono kuanzia toleo la 4.34 na kuendelea na baada tu ya kuiwasha, ikiwa na vikwazo zaidi kwamba kontena haziwezi kufunga anwani za IP za seva pangaji na TCP na UDP pekee ndizo zinazoshughulikiwa. Ikiwa nusu ya timu yako iko kwenye seva za Linux na nusu iko kwenye Docker Desktop, tarajia faili moja kufanya kazi kwa njia tofauti.
Tumia hali ya host unapohitaji interfaces za seva pangaji. Usiitumie kutatua tatizo la muunganisho, kwa sababu kwa kawaida hubadilisha tatizo moja na lingine gumu zaidi.
Kuunganisha miradi miwili ya Compose kwa kutumia mtandao wa nje
Mtandao ulioundwa na mradi mmoja hauonekani kwa mwingine. Hii ndiyo sababu reverse proxy iliyo kwenye proxy/compose.yaml haiwezi kuona programu iliyo kwenye app/compose.yaml, hata kama ziko kwenye seva moja. Suluhisho ni mtandao ambao haumilikiwi na mradi wowote kati ya hiyo miwili.
Uunde mara moja, kwa mkono:
docker network create edgeKisha uutangaze kama external katika kila mradi. Upande wa 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: trueUpande wa programu:
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 humwambia Compose aunganishe kwenye mtandao uliopo badala ya kuunda mpya, na auache uendelee kuwepo wakati wa docker compose down. Ufunguo tofauti wa name: ni muhimu zaidi kuliko unavyoonekana: bila huo, Compose hutafuta mtandao unaoitwa hasa edge, na ukiwa nao unaweza kuupa mtandao jina moja kwenye faili yako na jina lingine kwenye host.
Ikiwa mtandao haupo, Compose hukataa kuanza na kutoa taarifa kwamba mtandao ulitangazwa kama external lakini haukuweza kupatikana. Uunde kwanza.
Zingatia kile faili ya programu inachofanya na internal. Database hukaa kwenye mtandao huo wa ndani wa mradi pekee, kwa hivyo proxy haiwezi kuifikia na ni app pekee inayoweza. Kuongeza internal: true chini ya mtandao huenda mbali zaidi na kuondoa njia yake ya kuelekea nje ya mtandao kabisa. Hiyo ni hali nzuri ya kawaida (default) kwa database, ikiwa na gharama moja unayopaswa kuijua kabla ya kuiweka: container iliyo kwenye mtandao wa ndani haiwezi kupakua chochote, kwa hivyo entrypoint inayotekeleza apt-get update au pip install wakati wa kuanza itakwama na kisha kufeli kwa sababu ya timeout.
Kwa usanidi kamili uliokamilika wenye sheria za routing na vyeti, angalia kuendesha programu kadhaa nyuma ya instance moja ya Traefik.
Bandari zilizochapishwa hupita UFW
Hii ndiyo sehemu ya mtandao wa Compose inayoweza kusababisha tukio la kiusalama. Unachapisha bandari (port), unahakikisha kuwa UFW imewashwa na inakataa kila kitu isipokuwa SSH, lakini huduma bado inapatikana kutoka kwenye Internet.
sudo ufw status
curl http://203.0.113.10:8080UFW inasema bandari imefungwa. curl inarudisha ukurasa huo hata hivyo. Hakuna kilichoharibika. Docker huandika sheria zake za utafsiri wa anwani na usambazaji (forwarding) moja kwa moja kwenye iptables, na trafiki inayoelekea kwenye bandari ya container iliyochapishwa husambazwa kwenye container badala ya kupelekwa kwa mwenyeji (host), kwa hivyo haipiti kamwe kwenye mnyororo (chain) ambao UFW inasimamia kwa trafiki inayoelekea ndani. Sheria za Docker pia hulinganishwa kabla ya zile za UFW.
Suluhisho la haraka ni kuchapisha pale tu unapohitaji:
ports:
- "127.0.0.1:8080:80"Hiyo hufunga upande wa mwenyeji kwenye loopback, kwa hivyo bandari inapatikana kutoka kwa seva yenyewe na kupitia SSH tunnel, na si mahali pengine popote. Weka sehemu ya kuingilia ya umma nyuma ya reverse proxy inayochapisha 80 na 443 kwa makusudi. Ufafanuzi kamili, ikijumuisha mnyororo wa DOCKER-USER kwa hali ambazo lazima uchuje bandari iliyochapishwa, uko katika kwa nini Docker huchapisha moja kwa moja kupita UFW na jinsi ya kurekebisha.
Jinsi ya kuitatua kwa amri nne
Anza kwa kuuliza ni mtandao gani kila kontena liko kweli:
docker network inspect shop_defaultKizuizi cha Containers huorodhesha kila kontena lililounganishwa na anwani yake. Huduma inayokosekana kwenye orodha hiyo iko kwenye mtandao tofauti, au katika hali ya host, au haiendeshwi.
Jaribu utatuzi wa majina kutoka kwa kontena la muda lililounganishwa kwenye mtandao huo huo, ili usihitaji zana yoyote ndani ya picha zako mwenyewe:
docker run --rm --network shop_default busybox nslookup db
docker run --rm --network shop_default busybox nc -zv db 5432nslookup inaposhindwa inaashiria utatuzi wa jina au uanachama wa mtandao. nslookup ikifanikiwa wakati nc ikishindwa inamaanisha jina na mtandao ni sawa na tatizo ni muunganisho wenyewe. Ikiwa nc inaripoti Connection refused, sababu ya kawaida ni kwamba huduma haisikilizi kwenye port hiyo, au inasikiliza kwenye 127.0.0.1 ndani ya kontena lake badala ya 0.0.0.0. Hiyo ya mwisho ni ya kawaida na seva za maendeleo, na suluhisho liko kwenye anwani ya kufunga (bind address) ya programu, si katika Docker. Ikiwa nc inakwama na muda kuisha, tafuta kitu kinachotupa trafiki njiani, kama vile sheria ya firewall, au kontena lililositishwa au lisilojibu.
Kushindwa kwingine kunakoonekana kama hitilafu ya Docker. Ikiwa kontena zinaweza kuongea na kila mmoja lakini haziwezi kufikia mashine kwenye mtandao wako wa ofisi au VPN, subnet ya Docker pengine inagongana na mtandao huo. Docker hutenga kutoka 172.17.0.0/16 kwenda juu kwa chaguo-msingi. Hamisha bwawa (pool) katika /etc/docker/daemon.json:
{
"default-address-pools": [
{ "base": "10.200.0.0/16", "size": 24 }
]
}Kisha endesha sudo systemctl restart docker na uunde upya mitandao iliyoathiriwa, kwa sababu mtandao uliopo huhifadhi subnet uliyoundwa nayo.
FAQ
Kwa nini kontena zangu haziwezi kuwasiliana kwa kutumia jina la huduma?
Hazipo kwenye mtandao mmoja. Compose huweka kila huduma kwenye <project>_default kiotomatiki, lakini pindi tu unapoongeza orodha ya networks: kwenye huduma, orodha hiyo inakuwa ndiyo seti kamili ya mitandao kwa huduma hiyo na ile ya awali haitumiki tena. Endesha docker network inspect <network> na uhakikishe kuwa kontena zote mbili zinaonekana kwenye sehemu ya Containers. Pia hakikisha kuwa hakuna huduma inayotumia network_mode: host, kwa sababu kontena iliyo kwenye host mode haipo kwenye mtandao wowote wa Docker na haiwezi kutatua majina ya huduma.
Je, ninahitaji kufungua port ili huduma moja ifikie nyingine?
Hapana. Kwenye mtandao wa Compose, kila port ya kila kontena inaweza kufikiwa na kontena nyingine zilizopo kwenye mtandao huo. ports: ipo kwa ajili ya kufungua kontena ili ipokee trafiki kutoka nje ya Docker pekee, na expose: ni kwa ajili ya kumbukumbu tu. Kufungua port ya database ni mazoea ya kawaida na hatari, kwa sababu huweka database kwenye interface ya umma ya seva yako.
Kuna tofauti gani kati ya bridge na host networking?
Bridge huipa kontena namespace yake ya mtandao na anwani kwenye switch ya mtandaoni, ikiwa na utatuzi wa majina kiotomatiki kati ya kontena na trafiki inayotoka nje inayotafsiriwa. Host huipa kontena stack ya mtandao ya seva moja kwa moja: hakuna anwani tofauti, hakuna utatuzi kwa jina la huduma, hakuna kufungua port, na hakuna utengano kutoka kwa wasikilizaji wengine wa seva. Bridge ndiyo chaguo chaguo-msingi na sahihi isipokuwa kama mchakato unahitaji kutumia interfaces za seva yenyewe.
Ninawezaje kuunganisha kontena kutoka faili mbili tofauti za Compose?
Tengeneza mtandao wa pamoja kwa kutumia docker network create edge, kisha utangaze mtandao huo kwenye faili zote mbili kwa kutumia external: true na uunganishe huduma zinazohitaji kuwasiliana. Compose haitatengeneza wala kufuta mtandao huo. Ukiruka hatua ya kuutengeneza, Compose itakataa kuanza na itaripoti kuwa mtandao umetangazwa kama external lakini haujapatikana.
Kwa nini kontena yangu inaweza kufikiwa kutoka Internet wakati UFW imefunga port hiyo?
Kwa sababu port iliyofunguliwa hushughulikiwa na sheria za forwarding ambazo Docker huongeza kwenye iptables. Sheria hizo hulinganishwa kabla ya zile za UFW, na trafiki iliyosafirishwa haipiti kwenye chain inayochujwa na UFW hata hivyo. Funga upande wa seva kwenye loopback kwa kutumia "127.0.0.1:8080:80" na uweke huduma yoyote ya umma nyuma ya reverse proxy kwenye port 80 na 443.