Mitandao ya Docker Compose: DNS, host mode na UFW
Elewa mtandao wa bridge wa mradi, DNS kwa jina la huduma, wakati wa kutumia host mode, kushirikisha mitandao na kwa nini port iliyochapishwa hupita UFW.
Programu ya Compose hujenga nini kabla ya programu yako kuanza
Mitandao ya Docker Compose huanza na kanuni moja: docker compose up huunda mtandao wa faragha wa mradi, huunganisha kila huduma kwenye mtandao huo, na huruhusu huduma hizo kufikiana kwa kutumia jina la huduma. Huhitaji kuandika mstari wowote wa networks: ili kupata hilo. Mkanganyiko mwingi kuhusu mitandao ya Compose hutokana na kutofahamu kuwa mtandao wa chaguo-msingi tayari upo.
Hapa kuna faili dogo. Lihifadhi kama compose.yaml katika 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 imeunda:
docker compose up -d
docker network lsOrodha sasa ina mtandao unaoitwa shop_default. Compose huuita <project>_default, na jina la mradi kwa chaguo-msingi huwa jina la saraka lililoandikwa kwa herufi ndogo. Libadilishe kwa kutumia docker compose -p myproject up -d au kwa kutumia name: myproject ya kiwango cha juu katika faili hiyo. Kiendeshaji chake ni bridge, ambacho ni swichi pepe ndani ya mwenyeji. Kila kontena hupata anwani kwenye subnet ya faragha, na trafiki ya kutoka nje hutafsiriwa kutumia anwani ya mwenyeji inapotoka.
docker compose down hufuta mtandao huo tena. Hii ndiyo sababu kontena lililosalia kutoka mradi wa zamani linaweza kuuzuia mtandao huo: Docker hukataa kwa kutumia error while removing network: network shop_default has active endpoints, na suluhisho ni kusimamisha au kuondoa kontena ambalo bado limeunganishwa kwenye mtandao huo.
Ikiwa Compose ni mpya kwako, mpangilio wa faili ya Compose na amri za mzunguko wa maisha zinafaa kusomwa kwanza, kwa sababu kila kitu hapa chini kinachukulia kuwa unaweza kuanzisha na kusimamisha mradi.
DNS kwa jina la huduma ni sehemu ambayo wanaoanza hukosa
Kwenye mtandao wowote uliobainishwa na mtumiaji, Docker huendesha seva ya DNS iliyojengewa ndani ambayo kila kontena huiona kwenye 127.0.0.11. Hutatua majina ya huduma kuwa anwani za sasa za kontena. Kwa hiyo web hufikia hifadhidata kwa jina la mpangishaji db, kwenye porti 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 haziko kwenye mtandao mmoja.
Kosa ambalo karibu kila mtu hufanya mara moja ni kutumia localhost katika usanidi wa programu. Ndani ya kontena, localhost ni kontena hiyo, si mpangishaji wala huduma nyingine. Wateja wa Postgres huonyesha hilo wazi:
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?Mfuatano wa muunganisho unapaswa kuwa postgresql://postgres:example@db:5432/postgres. Sehemu ya mpangishaji ni jina la huduma.
Maelezo mawili yatakayookoa muda baadaye. Majina hutatuliwa kulingana na kinachoendeshwa sasa, kwa hiyo docker compose up -d --scale web=3 hutoa jina moja lenye anwani tatu, na mteja anayohifadhi DNS milele itajifunga kwenye kontena iliyokufa. Pia, mtandao wa zamani wa bridge unaotumiwa na docker run ya kawaida bila --network hauna utatuzi wa majina kabisa. Ndiyo sababu ushauri kuhusu viungo vya kontena kutoka 2016 haulingani na unachokiona.
Huhitaji ports: kuunganisha huduma mbili
ports: huchapisha port ya container kwenye host. Hii ni kwa traffic inayoingia kutoka nje ya Docker. Haihusiani na traffic kati ya huduma, ambayo tayari hufanya kazi katika anuwai nzima ya port kwenye mtandao wa project.
Kwa hiyo, ports: - "5432:5432" ambayo watu wengi huongeza kwenye huduma yao ya database haina manufaa na husababisha madhara makubwa: huifanya Postgres ipatikane kwenye interface ya umma ya server. Ifute. Ikiwa unataka kuifikia kutoka kwenye laptop yako kwa ajili ya migration, ifunge kwenye loopback kwa "127.0.0.1:5432:5432" kisha uifikie kupitia SSH tunnel. Tofauti kati ya listening socket, port iliyochapishwa, na firewall rule imeelezwa katika jinsi port 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 zilizo kwenye mtandao huo huo.
Wakati network_mode host inafaa, na gharama zake
Hali ya host huondoa namespace ya mtandao ya container yenyewe na kuruhusu mchakato kutumia interfaces za host moja kwa moja.
services:
probe:
image: alpine:3.20
network_mode: host
command: sleep infinityKuna sababu halisi za kuhitaji hali hii. Mchakato unaohitaji kuona traffic ya broadcast au multicast kwenye mtandao wa ndani, kama vile ugunduzi wa vifaa kwa seva ya midia au kitovu cha otomatiki wa nyumbani, hauwezi kuiona ukiwa nyuma ya bridge, kwa sababu bridge haisambazi traffic hiyo kwa container. Wakala wa ufuatiliaji anayesoma vihesabu vya interfaces za host anahitaji interfaces za host. Pia unapita hatua ya tafsiri ya anwani, jambo muhimu wakati wa viwango vya juu vya pakiti.
Gharama zake ni mahususi.
ports: huacha kufanya kazi. Docker huonya kwamba ports zilizochapishwa hutupiliwa mbali unapotumia hali ya mtandao ya host, na container hufunga port yoyote ambayo mchakato wake umefungia. Containers mbili za hali ya host zinazotaka port 8080 hugongana, na ya pili hukoma kwa bind: address already in use.
Utatuzi wa majina kwa kutumia jina la service huondoka katika pande zote mbili. Container haipo kwenye mtandao wa project, kwa hiyo haiwezi kutatua db, na services nyingine haziwezi kuitatua. Inaweza kuzifikia kupitia ports zilizochapishwa kwenye host pekee, kwa kawaida kwenye 127.0.0.1.
Utenganishaji huondoka. Mchakato unaofunga 0.0.0.0 ndani ya container ya hali ya host unasikiliza kwenye kila interface ya server yako, ikiwemo ya umma, sawa kabisa na package iliyosakinishwa kwa apt. Kuna faida moja: traffic hii hupitia njia ya kawaida ya kuingiza traffic, kwa hiyo sheria za UFW huitumia, tofauti na ports zilizochapishwa.
Hali ya host ni kipengele cha Linux Docker Engine. Docker Desktop huiunga mkono kuanzia toleo la 4.34 pekee na baada ya kuiwezesha, huku ikiwa na vikwazo zaidi kwamba containers haziwezi kufunga anwani za IP za host na kwamba hushughulikiwa TCP na UDP pekee. Ikiwa nusu ya timu yako iko kwenye server za Linux na nusu nyingine iko kwenye Docker Desktop, tarajia faili hiyo hiyo ifanye kazi kwa njia tofauti.
Tumia hali ya host unapohitaji interfaces za host. Usiitumie kurekebisha tatizo la muunganisho, kwa sababu kwa kawaida hubadilisha tatizo moja na kuwa gumu zaidi.
Unganisha miradi miwili ya Compose kwa kutumia mtandao wa nje
Mtandao ulioundwa na mradi mmoja hauonekani kwa mradi mwingine. Ndiyo sababu reverse proxy iliyo katika proxy/compose.yaml haiwezi kuona programu iliyo katika app/compose.yaml, hata ikiwa iko kwenye server hiyo hiyo. Suluhisho ni kutumia mtandao ambao haumilikiwi na mradi wowote.
Uunde mara moja, wewe mwenyewe:
docker network create edgeKisha uutangaze kuwa wa nje 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 huiambia Compose iambatane na mtandao uliopo badala ya kuunda mwingine, na iuache mahali pake kwenye docker compose down. Kifunguo tofauti cha name: ni muhimu zaidi kuliko inavyoonekana: bila hicho, Compose hutafuta mtandao wenye jina kamili edge; ukiwa nacho, unaweza kuuita mtandao kwa jina moja katika faili yako na kwa jina jingine kwenye host.
Ikiwa mtandao haupo, Compose hukataa kuanza na kuripoti kuwa mtandao ulitangazwa kuwa wa nje lakini haukupatikana. Uunde kwanza.
Zingatia kile ambacho faili ya programu hufanya kwa internal. Hifadhidata iko kwenye mtandao wa ndani wa mradi huo pekee, kwa hiyo proxy haiwezi kuifikia na ni app pekee inayoweza kuifikia. Kuongeza internal: true chini ya mtandao kunaenda hatua zaidi na kuondoa kabisa njia yake ya kufikia ulimwengu wa nje. Huo ni mpangilio mzuri wa msingi kwa hifadhidata, lakini kuna gharama unayopaswa kuijua kabla ya kuuweka: container iliyo kwenye mtandao wa ndani haiwezi kupakua chochote, kwa hiyo entrypoint inayoendesha apt-get update au pip install wakati wa kuanza itakwama na hatimaye ishindwe kwa sababu ya timeout.
Kwa usanidi kamili wa mfano wenye kanuni za uelekezaji na vyeti, angalia kuendesha programu kadhaa nyuma ya mfano mmoja wa Traefik.
Bandari zilizochapishwa hupita UFW
Hii ndiyo sehemu ya mitandao ya Compose inayoweza kusababisha tukio la usalama. Unachapisha bandari, unakagua kwamba UFW inatumika na inakataa kila kitu isipokuwa SSH, lakini huduma bado inafikika kutoka kwenye intaneti.
sudo ufw status
curl http://203.0.113.10:8080UFW inasema bandari imezuiwa. curl bado inarudisha ukurasa. Hakuna kilichoharibika. Docker huandika moja kwa moja kanuni zake za utafsiri wa anwani na usambazaji katika iptables. Trafiki kwenda kwenye bandari iliyochapishwa ya container hupelekwa kwenye container badala ya kuwasilishwa kwa host. Kwa hiyo, trafiki hiyo haipiti kwenye chain inayosimamiwa na UFW kwa trafiki inayolengwa ndani ya host. Pia, kanuni za Docker hulinganishwa kabla ya kanuni za UFW.
Suluhisho fupi ni kuchapisha bandari pale tu inapohitajika:
ports:
- "127.0.0.1:8080:80"Hii hufunga upande wa host kwenye loopback. Kwa hiyo, bandari inafikika kutoka kwenye server yenyewe na kupitia SSH tunnel, lakini haifikiki kutoka sehemu nyingine. Weka sehemu ya kuingilia ya umma nyuma ya reverse proxy inayochapisha 80 na 443 kwa makusudi. Maelezo kamili, pamoja na chain ya DOCKER-USER kwa hali ambazo lazima uchuje bandari iliyochapishwa, yako katika kwa nini Docker huchapisha moja kwa moja kupita UFW na jinsi ya kurekebisha hali hiyo.
Jinsi ya kutatua tatizo kwa amri nne
Anza kwa kuchunguza kila kontena liko kwenye mtandao gani hasa:
docker network inspect shop_defaultKizuizi cha Containers huorodhesha kila kontena lililounganishwa pamoja na anwani yake. Huduma ambayo haipo kwenye orodha hiyo iko kwenye mtandao tofauti, inatumia hali ya host, au haifanyi kazi.
Jaribu utatuzi wa majina kutoka kwenye kontena la muda lililounganishwa kwenye mtandao huo huo. Hivyo, huhitaji zana zozote ndani ya image zako:
docker run --rm --network shop_default busybox nslookup db
docker run --rm --network shop_default busybox nc -zv db 5432nslookup inaposhindikana, tatizo liko kwenye utatuzi wa majina au uanachama wa mtandao. nslookup ikifaulu huku nc ikishindikana, huduma inafanya kazi lakini haisikilizi kwenye port hiyo, au inasikiliza kwenye 127.0.0.1 ndani ya kontena lake badala ya 0.0.0.0. Hili hutokea mara nyingi kwenye seva za kutengeneza programu. Suluhisho liko kwenye anwani ya bind ya programu, si kwenye Docker.
Kuna hitilafu nyingine inayoweza kuonekana kama hitilafu ya Docker. Ikiwa kontena zinaweza kuwasiliana lakini haziwezi kufikia mashine iliyo kwenye mtandao wa ofisi au VPN, subnet ya Docker huenda inaingiliana na mtandao huo. Docker hutenga anwani kuanzia 172.17.0.0/16 kwenda juu kwa chaguo-msingi. Hamisha pool 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 iliyotumika wakati wa kuundwa kwake.
FAQ
Kwa nini kontena zangu haziwezi kufikiana kwa kutumia jina la huduma?
Haziko kwenye mtandao mmoja. Compose huweka kila huduma kwenye <project>_default kiotomatiki, lakini mara tu unapoongeza orodha ya networks: kwenye huduma, orodha hiyo huwa seti kamili ya mitandao yake na mtandao chaguo-msingi hauongezwi tena moja kwa moja. Tekeleza 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 inayotumia hali ya host haiko kwenye mtandao wowote wa Docker na haiwezi kutatua majina ya huduma.
Je, ninahitaji kuchapisha port ili huduma moja ifikie nyingine?
Hapana. Kwenye mtandao wa Compose, kila port ya kila kontena inaweza kufikiwa na kontena nyingine zilizo kwenye mtandao huo. ports: ipo tu ili kufichua kontena kwa trafiki kutoka nje ya Docker, na expose: ni kwa ajili ya nyaraka. Kuchapisha port ya hifadhidata ni desturi ya kawaida na yenye gharama, kwa sababu huiweka hifadhidata kwenye kiolesura cha umma cha seva yako.
Kuna tofauti gani kati ya mtandao wa bridge na wa host?
Bridge huipa kontena namespace yake ya mtandao na anwani kwenye switch pepe, pamoja na utatuzi wa majina kiotomatiki kati ya kontena na tafsiri ya trafiki inayotoka. Host huipa kontena stack ya mtandao ya host moja kwa moja: hakuna anwani tofauti, hakuna utatuzi kwa jina la huduma, hakuna uchapishaji wa port, na hakuna utengaji kutoka kwa wasikilizaji wengine wa host. Bridge ndiyo chaguo-msingi na jibu sahihi isipokuwa mchakato unahitaji violesura vya host.
Ninaunganishaje kontena kutoka faili mbili tofauti za Compose?
Unda mtandao unaoshirikiwa kwa kutumia docker network create edge, kisha uutangaze kwenye faili zote mbili kwa kutumia external: true na uunganishe huduma zinazohitaji kuwasiliana. Compose haitaunda wala kuufuta. Ukiruka hatua ya kuunda, Compose hukataa kuanza na huripoti kuwa mtandao umetangazwa kuwa wa nje lakini haujapatikana.
Kwa nini kontena yangu inafikika kutoka kwenye intaneti wakati UFW inazuia port?
Kwa sababu port iliyochapishwa hushughulikiwa na sheria za uelekezaji ambazo Docker huongeza kwenye iptables. Sheria hizo hulinganishwa kabla ya sheria za UFW, na trafiki inayopitishwa haiingii kwenye chain ambayo UFW huchuja. Funga upande wa host kwenye loopback kwa kutumia "127.0.0.1:8080:80" na weka huduma yoyote ya umma nyuma ya reverse proxy kwenye port 80 na 443.