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 husahau
Kwenye mtandao wowote uliosanidiwa na mtumiaji, Docker huendesha seva ya DNS iliyopachikwa ambayo kila container huiona kwenye 127.0.0.11. Hii hutatua majina ya huduma na kuyageuza kuwa anwani za container husika. Kwa hivyo, web hufikia database kwenye hostname ya db, kwenye port 5432, bila kuhitaji 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 kwenye usanidi wa programu. Ndani ya container, localhost ni container hiyo yenyewe, si seva pangaji (host) wala 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?Connection string inapaswa kuwa postgresql://postgres:example@db:5432/postgres. Sehemu ya host ni jina la huduma.
Maelezo mawili ambayo huokoa muda baadaye. Majina hutatuliwa kulingana na kile kinachoendelea sasa, kwa hivyo docker compose up -d --scale web=3 hutoa jina moja lenye anwani tatu, na mteja anayehifadhi (cache) DNS milele atajifunga kwenye container iliyokufa. Na mtandao wa zamani wa bridge unaotumiwa na docker run ya kawaida bila --network hauna utatuzi wa majina hata kidogo, ndiyo maana ushauri kuhusu viungo vya container (container links) wa mwaka 2016 haulingani na kile unachokiona sasa.
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
Host mode huondoa network namespace ya container na kuruhusu mchakato (process) kutumia interfaces za seva moja kwa moja.
services:
probe:
image: alpine:3.20
network_mode: host
command: sleep infinityKuna sababu za msingi za kuhitaji hili. Mchakato unaohitaji kuona broadcast au multicast traffic kwenye mtandao wa ndani, kama vile ugunduzi wa vifaa kwa ajili ya media server au hub ya home automation, hauwezi kuiona ukiwa nyuma ya bridge, kwa sababu bridge haisambazi traffic hiyo kwenda kwenye container. Monitoring agent inayosoma counters za interface ya seva inahitaji interfaces za seva hiyo. Pia, unaepuka hatua ya address translation, jambo ambalo ni muhimu katika viwango vya juu vya packet.
Gharama zake ni mahususi.
ports: huacha kufanya kazi. Docker huonya kuwa published ports hupuuzwa unapotumia host network mode, na container hufungamana na chochote ambacho mchakato wake hufungamana nacho. Container mbili za host mode zinazotaka port 8080 zitagongana, na ya pili itakufa ikiwa na bind: address already in use.
Name resolution kwa kutumia jina la huduma (service name) haipo tena katika pande zote mbili. Container haipo kwenye project network, kwa hivyo haiwezi kutatua db, na huduma nyingine haziwezi kuitatua. Inazifikia tu kupitia ports zilizochapishwa (published) kwenye seva, kwa kawaida kupitia 127.0.0.1.
Isolation haipo tena. Mchakato unaofungamana na 0.0.0.0 ndani ya container ya host mode unasikiliza kwenye kila interface ya seva yako, ikiwemo ile ya umma, sawa kabisa na kifurushi kilichosakinishwa kwa kutumia apt. Kuna faida moja hapa: traffic hii hufuata njia ya kawaida ya input, kwa hivyo sheria za UFW hutumika, jambo ambalo si kweli kwa published ports.
Host mode ni kipengele cha Linux Docker Engine. Docker Desktop inaiunga mkono kuanzia toleo la 4.34 na kuendelea na baada tu ya kuiwasha, huku kukiwa na vikwazo zaidi kwamba containers haziwezi kufungamana na host IP addresses na ni TCP na UDP pekee zinazoshughulikiwa. Ikiwa nusu ya timu yako inatumia Linux servers na nusu nyingine inatumia Docker Desktop, tarajia faili moja kufanya kazi kwa njia tofauti.
Tumia host mode unapohitaji interfaces za seva. Usiitumie kutatua tatizo la muunganisho, kwa sababu kwa kawaida hubadilisha tatizo moja na kuleta jingine 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 kutatua hitilafu kwa amri nne
Anza kwa kuuliza kila container iko kwenye mtandao upi kihalisi:
docker network inspect shop_defaultBlock ya Containers inaorodhesha kila container iliyounganishwa pamoja na anwani yake. Huduma inayokosekana kwenye orodha hiyo iko kwenye mtandao tofauti, au iko katika host mode, au haijawashwa.
Jaribu utatuzi wa majina (name resolution) kutoka kwenye container ya muda iliyounganishwa kwenye mtandao uleule, ili usihitaji zana zozote ndani ya images zako:
docker run --rm --network shop_default busybox nslookup db
docker run --rm --network shop_default busybox nc -zv db 5432nslookup inayofeli inaashiria tatizo la utatuzi wa majina au uanachama wa mtandao. nslookup inayofaulu wakati nc ikifeli inamaanisha huduma inafanya kazi lakini haisikilizi kwenye port hiyo, au inasikiliza kwenye 127.0.0.1 ndani ya container yake badala ya 0.0.0.0. Hali hiyo ya mwisho ni ya kawaida kwa seva za maendeleo (development servers), na suluhisho liko kwenye bind address ya programu, siyo kwenye Docker.
Hitilafu nyingine inayoweza kuonekana kama hitilafu ya Docker ni hii. Ikiwa containers zinaweza kuwasiliana lakini haziwezi kufikia mashine kwenye mtandao wa ofisi yako au VPN, inawezekana subnet ya Docker inagongana na mtandao huo. Docker hutenga anwani kuanzia 172.17.0.0/16 kwenda juu kwa chaguo-msingi. Hamisha pool hiyo kwenye /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 iliyoathirika, kwa sababu mtandao uliopo huhifadhi subnet uliyoundiwa 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.