Kako se lahko znotraj vsebnika Docker povežem z lokalnim gostiteljem računalnika?

Torej imam Nginx teče znotraj docker posodo, Imam mysql teče na localhost, Želim se povezati z MySql iz mojega Nginx. MySql teče na lokalnem gostitelju in ne izpostavlja vrat zunanjemu svetu, zato je vezan na lokalni gostitelj in ne na naslov IP računalnika.

Ali obstaja kakršen koli način za povezavo s tem MySql ali katerim koli drugim programom na lokalnem gostitelju iz tega vsebnika docker?

To vprašanje se razlikuje od vprašanja "Kako dobiti naslov IP gostitelja dockerja znotraj vsebnika dockerja" zaradi dejstva, da je naslov IP gostitelja dockerja lahko javni IP ali zasebni IP v omrežju, ki je lahko dosegljiv iz vsebnika dockerja ali ne (mislim na javni IP, če gostuje v AWS ali kaj podobnega). Tudi če imate naslov IP gostitelja dockerja, to še ne pomeni, da se lahko na ta naslov IP povežete z gostiteljem dockerja znotraj vsebnika, saj je vaše omrežje dockerja lahko prekrivno, gostiteljsko, mostovno, macvlan, ni ga itd., kar omejuje dosegljivost tega naslova IP.

Rešitev

Urejanje: Če uporabljate Docker-for-mac ali Docker-for-Windows 18.03+, se povežite s storitvijo mysql z gostiteljem host.docker.internal.

Od različice Docker 18.09.3 to ne deluje v storitvi Docker-for-Linux. Popravek je bil predložen 8. marca 2019 in upamo, da bo vključen v zbirko kode. Do takrat lahko to obidemo z uporabo vsebnika, kot je opisano v qoomonovem odgovoru.


TLDR

V ukazu docker run uporabite --network="host", potem bo 127.0.0.1 v vašem vsebniku docker kazalo na vaš gostitelj docker.

Opomba: Ta način deluje samo v programu Docker za Linux v skladu z dokumentacijo.


Opomba o omrežnih načinih vsebnika Docker

Docker ponuja različne načine omrežnega delovanja pri izvajanju vsebnikov. Glede na izbrani način se boste različno povezali s podatkovno zbirko MySQL, ki teče na gostitelju dockerja.

docker run --network="bridge" (privzeto)

Docker privzeto ustvari most z imenom docker0. Tako gostitelj docker kot vsebniki docker imajo naslov IP na tem mostu.

če na gostitelju Docker vnesete sudo ip addr show docker0, boste dobili izpis, ki bo videti takole:

[vagrant@docker:~] $ sudo ip addr show docker0
4: docker0:  mtu 1500 qdisc noqueue state UP group default
    link/ether 56:84:7a:fe:97:99 brd ff:ff:ff:ff:ff:ff
    inet 172.17.42.1/16 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::5484:7aff:fefe:9799/64 scope link
       valid_lft forever preferred_lft forever

Moj gostitelj docker ima torej naslov IP 172.17.42.1 na omrežnem vmesniku docker0.

Zdaj zaženite nov zabojnik in v njem odprite lupino: V zabojniku vtipkajte ip addr show eth0 in ugotovite, kako je nastavljen njegov glavni omrežni vmesnik:

root@e77f6a1b3740:/# ip addr show eth0
863: eth0:  mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 66:32:13:f0:f1:e3 brd ff:ff:ff:ff:ff:ff
    inet 172.17.1.192/16 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::6432:13ff:fef0:f1e3/64 scope link
       valid_lft forever preferred_lft forever

Tu ima moj vsebnik naslov IP 172.17.1.192. Zdaj si oglejte usmerjevalno tabelo:

root@e77f6a1b3740:/# route
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         172.17.42.1     0.0.0.0         UG    0      0        0 eth0
172.17.0.0      *               255.255.0.0     U     0      0        0 eth0

Torej je naslov IP gostitelja dockerja 172.17.42.1 nastavljen kot privzeta pot in je dostopen iz vašega vsebnika.

root@e77f6a1b3740:/# ping 172.17.42.1
PING 172.17.42.1 (172.17.42.1) 56(84) bytes of data.
64 bytes from 172.17.42.1: icmp_seq=1 ttl=64 time=0.070 ms
64 bytes from 172.17.42.1: icmp_seq=2 ttl=64 time=0.201 ms
64 bytes from 172.17.42.1: icmp_seq=3 ttl=64 time=0.116 ms

docker run --network="host"

Alternativno lahko zaženete vsebnik docker z [nastavitvami omrežja, nastavljenimi na host] (http://docs.docker.com/engine/reference/run/#network-host). Tak zabojnik si bo delil omrežni niz z gostiteljem dockerja in z vidika zabojnika se bo localhost (ali 127.0.0.1) nanašal na gostitelja dockerja.

Zavedajte se, da bodo vsa vrata, odprta v vsebniku docker, odprta tudi v gostitelju docker. In to brez uporabe možnosti p ali -P docker run.

Konfiguracija IP na mojem gostitelju docker:

[vagrant@docker:~] $ ip addr show eth0
2: eth0:  mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 08:00:27:98:dc:aa brd ff:ff:ff:ff:ff:ff
    inet 10.0.2.15/24 brd 10.0.2.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:fe98:dcaa/64 scope link
       valid_lft forever preferred_lft forever

in iz vsebnika docker v načinu host:

[vagrant@docker:~] $ docker run --rm -it --network=host ubuntu:trusty ip addr show eth0
2: eth0:  mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 08:00:27:98:dc:aa brd ff:ff:ff:ff:ff:ff
    inet 10.0.2.15/24 brd 10.0.2.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:fe98:dcaa/64 scope link
       valid_lft forever preferred_lft forever

Kot lahko vidite, imata tako gostitelj docker kot vsebnik docker isti omrežni vmesnik in zato tudi isti naslov IP.


Povezovanje s strežnikom MySQL iz vsebnikov

način mostu

Za dostop do MySQL, ki teče na gostitelju docker, iz zabojnikov v načinu most morate zagotoviti, da storitev MySQL posluša povezave na IP naslovu 172.17.42.1.

To storite tako, da v konfiguracijski datoteki MySQL (my.cnf) določite bind-address = 172.17.42.1 ali bind-address = 0.0.0.0.

Če morate nastaviti okoljsko spremenljivko z naslovom IP prehoda, lahko v vsebniku zaženete naslednjo kodo :

export DOCKER_HOST_IP=$(route -n | awk '/UG[ \t]/{print $2}')

nato v svoji aplikaciji uporabite okoljsko spremenljivko DOCKER_HOST_IP za odprtje povezave s sistemom MySQL.

Note: če uporabite bind-address = 0.0.0.0, bo strežnik MySQL poslušal za povezave na vseh omrežnih vmesnikih. To pomeni, da je vaš strežnik MySQL lahko dosegljiv iz interneta; poskrbite, da ustrezno nastavite pravila požarnega zidu.

Opomba 2: če uporabite bind-address = 172.17.42.1, vaš strežnik MySQL ne bo poslušal povezav, vzpostavljenih na 127.0.0.1. Procesi, ki tečejo na gostitelju dockerja in bi se želeli povezati z MySQL, bi morali uporabiti naslov IP 172.17.42.1.

način gostitelja

Če želite do MySQL, ki teče na gostitelju docker, dostopati iz zabojnikov v načinu gostitelja, lahko v konfiguraciji MySQL ohranite bind-address = 127.0.0.1 in vse, kar morate storiti, je, da se iz svojih zabojnikov povežete na 127.0.0.1:

[vagrant@docker:~] $ docker run --rm -it --network=host mysql mysql -h 127.0.0.1 -uroot -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 36
Server version: 5.5.41-0ubuntu0.14.04.1 (Ubuntu)

Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

opomba: Uporabite mysql -h 127.0.0.1 in ne mysql -h localhost; sicer bi se odjemalec MySQL poskušal povezati prek vtičnice Unix.

Komentarji (28)

To mi je delovalo na kupu NGINX/PHP-FPM, ne da bi se dotaknil kakršne koli kode ali omrežja, kjer aplikacija pričakuje, da se bo lahko povezala z localhost.

Namestite mysqld.sock z gostitelja v vsebnik.

Poiščite lokacijo datoteke mysql.sock na gostitelju, kjer teče mysql: netstat -ln | awk '/mysql(.*)?\.sock/ { print $9 }'

Namestite to datoteko na mesto, ki ga pričakuje docker: docker run -v /hostpath/to/mysqld.sock:/containerpath/to/mysqld.sock

Možne lokacije datoteke mysqld.sock:

/tmp/mysqld.sock
/var/run/mysqld/mysqld.sock 
/var/lib/mysql/mysql.sock
/Applications/MAMP/tmp/mysql/mysql.sock # if running via MAMP
Komentarji (7)

Ne strinjam se z odgovorom Thomasleveila.

Če bo mysql vezan na 172.17.42.1, bo drugim programom, ki uporabljajo podatkovno zbirko v gostitelju, preprečil dostop do nje. To bo delovalo le, če so vsi uporabniki vaše zbirke podatkov povezani z dockerjem.

Če bo mysql vezan na 0.0.0.0.0, bo odprl db zunanjemu svetu, kar ni samo zelo slabo, ampak tudi v nasprotju s tem, kar želi narediti avtor prvotnega vprašanja. Izrecno pravi "MySql teče na localhostu in ne izpostavlja vrat zunanjemu svetu, zato je vezan na localhost"

Odgovor na komentar ivanta

"Zakaj ne bi mysql vezali tudi na docker0?"

To ni mogoče. V dokumentaciji za mysql/mariadb je izrecno navedeno, da vezava na več vmesnikov ni mogoča. Povezati se lahko samo na 0, 1 ali vse vmesnike.

Za zaključek naj povem, da NISEM našel nobenega načina, da bi iz vsebnika docker dosegel podatkovno zbirko (samo lokalni gostitelj) v gostitelju. To se vsekakor zdi zelo zelo pogost vzorec, vendar ne vem, kako to storiti.

Komentarji (4)