W jaki sposób mogę połączyć się z hostem lokalnym komputera z wnętrza kontenera Docker?

1447

Więc mam Nginx działający w kontenerze dokującym, mam mysql działający na localhost, chcę połączyć się z MySql z poziomu mojego Nginx. MySql działa na localhost i nie ujawnia portu światowi zewnętrznemu, więc jest powiązany z localhost, nie jest powiązany z adresem IP komputera.

Czy jest jakiś sposób na połączenie się z tym MySql lub innym programem na localhost z tego kontenera dokowanego?

To pytanie różni się od „Jak uzyskać adres IP hosta dokera z wnętrza kontenera dokera” ze względu na fakt, że adres IP hosta dokera może być publicznym adresem IP lub prywatnym adresem IP w sieci, który może lub może niedostępne z poziomu kontenera dokera (mam na myśli publiczny adres IP, jeśli jest hostowany w AWS lub coś takiego). Nawet jeśli masz adres IP hosta dokera, nie oznacza to, że możesz połączyć się z hostem dokera z poziomu kontenera, biorąc pod uwagę ten adres IP, ponieważ Twoja sieć Docker może być nakładką, hostem, mostem, macvlanem, brak itp., Co ogranicza dostępność ten adres IP.

Phil
źródło
Dlaczego nie powiązać mysql również z docker0?
ivant
2
W przypadku komputera z systemem Windows: - $ docker run -d - nazwa MyWebServer -P httpd
Lokesh S
Możliwy duplikat Jak uzyskać adres IP hosta
dokera
Bez network: hostciebie nie możesz wrócić z kontenera do hosta. Tylko host do kontenera. To jest główna ideologia stojąca za pojemnikami. Są izolowane zarówno ze względu na stabilność, jak i bezpieczeństwo.
FreeSoftwareServers

Odpowiedzi:

1967

Edycja: Jeśli używasz Docker-for-mac lub Docker-for-Windows 18.03+, po prostu połącz się z usługą mysql za pomocą hosta host.docker.internal(zamiast 127.0.0.1w ciągu połączenia).

Począwszy od Docker 18.09.3, nie działa to w Docker-for-Linux. Fix został złożony w dniu 8 marca 2019 i mam nadzieję, że zostaną połączone z bazą kodu. Do tego czasu obejściem problemu jest użycie kontenera zgodnie z opisem w odpowiedzi qoomon .

2020-01: poczyniono pewne postępy . Jeśli wszystko pójdzie dobrze, powinno to wylądować w Docker 20.04


TLDR

Użyj --network="host"w swoim docker runpoleceniu, a następnie 127.0.0.1w kontenerze dokera wskaże hosta dokera.

Uwaga: Ten tryb działa tylko w systemie Docker dla systemu Linux, zgodnie z dokumentacją .


Uwaga na temat trybów pracy sieci kontenerów dokujących

Docker oferuje różne tryby sieci podczas uruchamiania kontenerów. W zależności od wybranego trybu połączenie z bazą danych MySQL działającą na hoście dokera będzie różne.

Uruchom okno dokowane --network = „most” (domyślnie)

Docker tworzy docker0domyślnie nazwany most . Zarówno host dokera, jak i kontenery dokują mają adres IP na tym moście.

na hoście Docker wpisz sudo ip addr show docker0wynik wyglądający następująco:

[vagrant@docker:~] $ sudo ip addr show docker0
4: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> 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

Więc tutaj mój host dokera ma adres IP 172.17.42.1w docker0interfejsie sieciowym.

Teraz uruchom nowy kontener i uzyskaj na nim powłokę: docker run --rm -it ubuntu:trusty bashi w obrębie typu kontenera, ip addr show eth0aby dowiedzieć się, jak jest skonfigurowany jego główny interfejs sieciowy:

root@e77f6a1b3740:/# ip addr show eth0
863: eth0: <BROADCAST,UP,LOWER_UP> 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

Tutaj mój kontener ma adres IP 172.17.1.192. Teraz spójrz na tabelę routingu:

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

Dlatego adres IP hosta dokera 172.17.42.1jest ustawiony jako domyślna trasa i jest dostępny z kontenera.

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

Uruchom okno dokowane --network = "host"

Alternatywnie możesz uruchomić kontener dokerów z ustawieniami sieci ustawionymi nahost . Taki kontener będzie dzielić stos sieciowy z hostem dokera iz punktu widzenia kontenera localhost(lub 127.0.0.1) będzie odnosił się do hosta dokera.

Należy pamiętać, że każdy port otwarty w kontenerze dokera zostanie otwarty na hoście dokera. I to bez wymagania opcji -plub-P docker run .

Konfiguracja IP na moim hoście dokera:

[vagrant@docker:~] $ ip addr show eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> 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

oraz z kontenera dokowanego w trybie hosta :

[vagrant@docker:~] $ docker run --rm -it --network=host ubuntu:trusty ip addr show eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> 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

Jak widać, zarówno host dokera, jak i kontener dokerów mają ten sam interfejs sieciowy i jako taki mają ten sam adres IP.


Łączenie się z MySQL z kontenerów

tryb pomostowy

Aby uzyskać dostęp do MySQL uruchomionego na hoście dokera z kontenerów w trybie mostu , musisz upewnić się, że usługa MySQL nasłuchuje połączeń na 172.17.42.1adresie IP.

Aby to zrobić, upewnij się, że masz albo bind-address = 172.17.42.1czy bind-address = 0.0.0.0w pliku konfiguracyjnym MySQL (my.cnf).

Jeśli musisz ustawić zmienną środowiskową z adresem IP bramy, możesz uruchomić następujący kod w kontenerze:

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

następnie w aplikacji użyj DOCKER_HOST_IPzmiennej środowiskowej, aby otworzyć połączenie z MySQL.

Uwaga: jeśli używasz bind-address = 0.0.0.0serwera MySQL, nasłuchuje połączeń na wszystkich interfejsach sieciowych. Oznacza to, że do twojego serwera MySQL można uzyskać dostęp z Internetu; upewnij się, że odpowiednio skonfigurowałeś reguły zapory.

Uwaga 2: jeśli korzystasz bind-address = 172.17.42.1z serwera MySQL, nie będziesz nasłuchiwał nawiązywania połączeń 127.0.0.1. Procesy uruchomione na hoście dokera, które chciałyby połączyć się z MySQL, musiałyby korzystać z 172.17.42.1adresu IP.

tryb hosta

Aby uzyskać dostęp do MySQL uruchomionego na hoście dokera z kontenerów w trybie hosta , możesz zachować bind-address = 127.0.0.1konfigurację MySQL, a wszystko, co musisz zrobić, to połączyć się 127.0.0.1z kontenerów:

[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>

Uwaga: używaj mysql -h 127.0.0.1i nie mysql -h localhost; w przeciwnym razie klient MySQL próbowałby połączyć się przy użyciu gniazda unix.

Thomasleveil
źródło
8
Dziękuję za tak szczegółową odpowiedź! Z tego, co zebrałem, używanie trybu hosta jest jedynym sposobem na uzyskanie tej funkcjonalności za pośrednictwem hosta lokalnego. Nie próbowałem, ale zakładam, że możesz stworzyć oddzielną sieć do łączenia kontenerów przez ich własny most, oferując im wspólny „localhost”.
Ben
26
Uwaga dla użytkowników OSX: najpierw zaloguj się na maszynie wirtualnej dokera (boot2docker), używając „domyślnej ssh maszyny dokującej”, a następnie uruchom „sudo ip addr show docker0”. Stamtąd kontynuuj instrukcje Thomasa.
Charlie Dalsass
30
Używam Docker na Maca i nie ma już 172.17.42.1, nie ma już docker0. To była 172.17.0.1 jako brama, a nawet nie możetelnet 172.17.0.1 3306
zx1986
26
Możesz zamontować gniazdo mysql w kontenerze zamiast sieci w -v /var/run/mysqld/mysqld.sock:/tmp/mysql.sockten sposób.
chx
8
Czy ktoś może rozwiązać sytuację, gdy uruchomiony Docker na komputerze Mac i nieużywający boot2docker jako takiego nie ma interfejsu docker0?
TheJKFever
350

Dla macOS i Windows

Docker przeciwko 18.03 i nowszym (od 21 marca 2018)

Użyj wewnętrznego adresu IP lub połącz się ze specjalną nazwą DNS, host.docker.internalktóra rozwiąże z wewnętrznym adresem IP używanym przez hosta.

Wsparcie dla systemu Linux w oczekiwaniu na https://github.com/docker/for-linux/issues/264

MacOS z wcześniejszymi wersjami Dockera

Docker dla komputerów Mac w wersji od 17.12 do 18.02

To samo co powyżej, ale użyj docker.for.mac.host.internalzamiast tego.

Docker dla komputerów Mac w wersji 17.06 do wersji 17.11

To samo co powyżej, ale użyj docker.for.mac.localhostzamiast tego.

Docker na komputery Mac 17.05 i starsze

Aby uzyskać dostęp do komputera hosta z kontenera dokowanego, musisz dołączyć alias IP do interfejsu sieciowego. Możesz powiązać dowolny adres IP, po prostu upewnij się, że nie używasz go do niczego innego.

sudo ifconfig lo0 alias 123.123.123.123/24

Następnie upewnij się, że Twój serwer nasłuchuje adresu IP wspomnianego powyżej lub 0.0.0.0. Jeśli nasłuchuje na localhost 127.0.0.1, nie zaakceptuje połączenia.

Następnie po prostu skieruj kontener dokujący na ten adres IP, aby uzyskać dostęp do komputera hosta!

Aby przetestować, możesz uruchomić coś takiego jak curl -X GET 123.123.123.123:3000wewnątrz kontenera.

Alias ​​zostanie zresetowany przy każdym ponownym uruchomieniu, więc w razie potrzeby utwórz skrypt startowy.

Rozwiązanie i więcej dokumentacji tutaj: https://docs.docker.com/docker-for-mac/networking/#use-cases-and-workarounds

Janne Annala
źródło
5
genialne i dzięki, to zadziałało dla mnie z pojemnika. mysql -uroot -hdocker.for.mac.localhost
Richard Frank
1
docker.for.mac.localhost To jest dokładnie to, czego szukałem. Ale to jest jednocześnie brudne jak diabli. W oknie dokowanym można się spodziewać, że hook docker.for.mac.localhost byłby ogólną nazwą wewnętrzną dokera, która byłaby poprawna dla dowolnego systemu operacyjnego, nie tylko dla komputerów Mac. Ale do celów rozwojowych jest to wystarczająco dobre.
99
Jak uzyskać dostęp do portu, który jest widoczny w powiedzmy 9093 .. Próbuję teler docker.for.mac.localhost 9093. Jest nieosiągalny, ale jeśli wyślę ping do docker.for.mac.localhost, jest osiągalny. Czy coś mi tu brakuje?
Achilleus,
1
Nazwa DNS docker.for.mac.host.internal powinna być używana zamiast docker.for.mac.localhost (wciąż ważna) do rozpoznawania hosta z kontenerów, ponieważ istnieje RFC zakazujący używania poddomen lokalnego hosta. Zobacz tools.ietf.org/html/draft-west-let-localhost-be-localhost-06 .
Jya
To mi nie działa. Kiedy ja docker run -e HOSTNAME= docker.for.mac.host.internal , kontener jest tworzony, ale nic się nie dzieje. Muszę wtedy crtl + C. Z --net=host -e HOSTNAME=localhostco najmniej tras kontenerowych i narzeka, że nie może znaleźć muszę usług (MySQL db).
Jorge Orpinel,
83

Robię włamanie podobne do powyższych postów, aby lokalny adres IP zmapować na nazwę aliasu (DNS) w kontenerze. Głównym problemem jest dynamiczne uzyskanie prostego skryptu, który działa zarówno w systemie Linux, jak i OSX na adresie IP hosta . Zrobiłem ten skrypt, który działa w obu środowiskach (nawet w dystrybucji Linuksa ze "$LANG" != "en_*"skonfigurowanym):

ifconfig | grep -E "([0-9]{1,3}\.){3}[0-9]{1,3}" | grep -v 127.0.0.1 | awk '{ print $2 }' | cut -f2 -d: | head -n1

Tak więc przy użyciu Docker Compose pełna konfiguracja będzie:

Skrypt startowy (docker-run.sh) :

export DOCKERHOST=$(ifconfig | grep -E "([0-9]{1,3}\.){3}[0-9]{1,3}" | grep -v 127.0.0.1 | awk '{ print $2 }' | cut -f2 -d: | head -n1)
docker-compose -f docker-compose.yml up

docker-compose.yml :

myapp:
  build: .
  ports:
    - "80:80"
  extra_hosts:
    - "dockerhost:$DOCKERHOST"

Następnie zmień na http://localhostna http://dockerhostw swoim kodzie.

Bardziej zaawansowany przewodnik na temat dostosowywania DOCKERHOSTskryptu znajduje się w tym poście z wyjaśnieniem, jak działa.

Mariano Ruiz
źródło
1
W zależności od przypadku użycia możesz nawet po prostu użyć tej DOCKERHOSTwartości zamiast „localhost” lub 0.0.0.0 w dowolnej usłudze, z którą kontener dokerów musi się połączyć lokalnie.
kraina krańców
2
Lekko zmodyfikowałem twoje rozwiązanie, aby było kompatybilne z sieciami niestandardowymi: export DOCKERHOST=$(docker network inspect --format='{{range .IPAM.Config}}{{.Gateway}}{{end}}' <NETWORK-NAME> | awk -F "/" 'NR==1{print $1}') gdzie <NAZWA SIECI> może być mostem lub nazwą sieci zdefiniowaną przez docker-compose (zwykle nazwa-ścieżki - nazwa_sieci ).
dieresys 26.04.17
1
Musisz dodać komentarz: użyj dockerhostjako hosta dla połączenia db (zwykle zamień na localhostw plik konfiguracyjny).
Justin
dziwne rozwiązanie, ale to jedyne, które sprawia, że ​​xdebug działa pod dokerem z php cli
Eddie
Acl przestał działać po tym roztworze w haproxy. Masz pomysł, dlaczego?
HyukHyukBoi
41

To działało dla mnie na stosie NGINX / PHP-FPM bez dotykania żadnego kodu ani sieci, do których aplikacja spodziewa się, że będzie mogła się połączyć localhost

Zamontuj mysqld.sockod hosta do wnętrza kontenera.

Znajdź lokalizację pliku mysql.sock na hoście, na którym działa mysql:
netstat -ln | awk '/mysql(.*)?\.sock/ { print $9 }'

Zamontuj ten plik w odpowiednim miejscu w oknie dokowanym:
docker run -v /hostpath/to/mysqld.sock:/containerpath/to/mysqld.sock

Możliwe lokalizacje 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
użytkownik833482
źródło
2
Jest to znacznie czystsze rozwiązanie, nie narażające MySQL na zewnątrz (jeśli nie używa się zapory ogniowej).
user1226868
5
Gniazda nie skalują się tak dobrze jak TCP, ponieważ blokują się częściej i mogą powodować dziwne zachowanie. W miarę możliwości używaj protokołu TCP.
Joel E Salas,
3
@JoelESalas Czy masz źródło tego roszczenia?
Prywatny
Uważam, że jest to najłatwiejsze rozwiązanie. Kciuki w górę user833482! Powinieneś częściej przyczyniać się do StackOverflow.
Prywatny
2
@JoelESalas Myślę, że się mylisz. Biblioteka klienta mysql domyślnie korzysta nawet z gniazd unix podczas łączenia się z localhost, a nie z połączeniem z localhost. Gniazdo unix pozwala uniknąć narzutu stosu TCP i routingu i powinno działać szybciej.
M Conrad
25

Dopóki host.docker.internalnie działa na każdej platformie, możesz użyć mojego kontenera działającego jako brama NAT bez ręcznej konfiguracji:

https://github.com/qoomon/docker-host

qoomon
źródło
5
Mogę potwierdzić, że to nie działa w Docker dla Windows 19.03.2 z kontenerem Windows.
KMC
jakiś pomysł, jak to naprawić? (Nie jestem użytkownikiem systemu Windows)
qoomon
Jeśli środowisko nie blokuje portów używanych przez mysql, możesz odwołać się do serwera po nazwie komputera, na którym jest on hostowany. Więc w swoim ciągu połączenia użyj nazwy komputera jako nazwy serwera.
KMC
24

Rozwiązanie dla systemu Linux (jądro> = 3,6).

Ok, twój serwer lokalny ma domyślny interfejs dokera0 z adresem IP 172.17.0.1 . Twój kontener zaczął od domyślnych ustawień sieciowych --net = "bridge" .

  1. Włącz route_localnet dla interfejsu docker0:
    $ sysctl -w net.ipv4.conf.docker0.route_localnet=1
  2. Dodaj te reguły do ​​iptables:
    $ iptables -t nat -I PREROUTING -i docker0 -d 172.17.0.1 -p tcp --dport 3306 -j DNAT --to 127.0.0.1:3306
    $ iptables -t filter -I INPUT -i docker0 -d 127.0.0.1 -p tcp --dport 3306 -j ACCEPT
  3. Utwórz użytkownika mysql z dostępem z „%”, co oznacza - od każdego, z wyjątkiem localhost:
    CREATE USER 'user'@'%' IDENTIFIED BY 'password';
  4. Zmień w skrypcie adres serwera mysql na 172.17.0.1


Z dokumentacji jądra :

route_localnet - BOOLEAN: Podczas routingu nie traktuj adresów sprzężenia zwrotnego jako marsjańskiego źródła lub miejsca docelowego. Umożliwia to użycie 127/8 do lokalnych celów routingu ( domyślnie FAŁSZ ).

Ray D.
źródło
1
Jaki jest cel drugiego polecenia iptable? Rozumiem, że pierwszym jest przepisanie wszystkich miejsc docelowych TCP, które pasują do 172.17.0.1:3306 do 127.0.0.1:3306, ale dlaczego konieczne jest drugie polecenie iptable?
Patrick
17

Rozwiązanie dla systemu Windows 10

Docker Community Edition 17.06.0-ce-win18 2017-06-28 (stabilny)

Możesz użyć nazwy DNS hosta docker.for.win.localhost, aby rozwiązać do wewnętrznego adresu IP. (Ostrzeżenie o niektórych źródłach wymienionych, windowsale powinno być win)

Omówienie
Musiałem zrobić coś podobnego, to znaczy połączyć się z mojego kontenera Docker z moim hostem lokalnym, na którym działało Azure Storage Emulatori CosmosDB Emulator.

Azure Storage EmulatorDomyślnie nasłuchuje na 127.0.0.1 , podczas gdy można zmienić IP jego oprawioną też szukałem rozwiązania, które będzie pracować z ustawieniami domyślnymi.

Działa to również w przypadku łączenia z mojego kontenera Docker do SQL Serveri IIS, oba działają lokalnie na moim hoście z domyślnymi ustawieniami portów.

Ralph Willgoss
źródło
13

Bardzo proste i szybkie, sprawdź adres IP hosta za pomocą ifconfig (linux) lub ipconfig (Windows), a następnie utwórz

docker-compose.yml

version: '3' # specify docker-compose version

services:
  nginx:
    build: ./ # specify the directory of the Dockerfile
    ports:
      - "8080:80" # specify port mapping
    extra_hosts:
      - "dockerhost:<yourIP>"

W ten sposób Twój kontener będzie mógł uzyskać dostęp do Twojego hosta. Podczas uzyskiwania dostępu do bazy danych pamiętaj, aby użyć nazwy podanej wcześniej, w tym przypadku „dockerhost” i portu hosta, na którym działa baza danych

Felipe Toledo
źródło
W HaProxy to rozwiązanie przestało działać z acl z jakiegoś powodu, działa tylko ustawienie domyślne.
HyukHyukBoi
1
Jedyne rozwiązanie, które działa na systemie Linux. +1
Rafik Farhad
11

Żadna z odpowiedzi nie działała dla mnie podczas korzystania z Docker Toolbox w systemie Windows 10 Home, ale 10.0.2.2 tak, ponieważ używa VirtualBox, który udostępnia hosta maszynie wirtualnej pod tym adresem.

Elad
źródło
2
To działa. Nawet nie trzeba określać --network = host. wygląda na to, że 10.0.2.2 jest ustawiony jako domyślny adres IP hosta. Dzięki.
TheManish
Ale czy mogę używać tego statycznego adresu IP we wszystkich wersjach systemu Windows i Mac?
151291
To zadziałało dla mnie. Wystarczy uruchomić ipconfig na swoim hoście (Windows) i uzyskać adres IP podEthernet adapter vEthernet (DockerNAT)
Kihats
10

W przypadku systemu Windows, zakładając, że używasz sterownika sieciowego mostu, powinieneś w szczególności powiązać MySQL z adresem IP interfejsu sieciowego hyper-v.

Odbywa się to poprzez plik konfiguracyjny w normalnie ukrytym folderze C: \ ProgramData \ MySQL.

Powiązanie z 0.0.0.0 nie będzie działać. Potrzebny adres jest również wyświetlany w konfiguracji dokera, aw moim przypadku był to 10.0.75.1.

Casey
źródło
3
Zasługujesz na medal! Pracowałem nad tym przez dwa pełne dni. Dziękujemy za pomoc!
Michael
1
Pracowałem nad tym przez dwa pełne dni. To jedyne miejsce w sieci, o którym wspominałem. Microsoft milczy na ten temat, gdy mówi o łączeniu się z MSSQL z poziomu kontenera Docker. To sprawia, że ​​zastanawiasz się, czy kiedykolwiek sprawili, że działali sami!
Contango,
8

Edycja: Skończyłem prototypowanie koncepcji na GitHub. Sprawdź: https://github.com/sivabudh/system-in-a-box


Po pierwsze, moja odpowiedź jest skierowana do 2 grup ludzi: tych, którzy używają komputera Mac i tych, którzy używają Linuksa.

Gospodarz tryb sieciowy nie działa na Macu. Musisz użyć aliasu IP, patrz: https://stackoverflow.com/a/43541681/2713729

Co to jest tryb sieci hosta? Zobacz: https://docs.docker.com/engine/reference/run/#/network-settings

Po drugie, dla tych z was, którzy używają Linuksa (moje bezpośrednie doświadczenie dotyczyło Ubuntu 14.04 LTS, a ja wkrótce aktualizuję do wersji 16.04 LTS w produkcji), tak , można sprawić, aby usługa działająca w kontenerze Docker łączyła się z localhostusługami działającymi na Host dokera (np. Laptop).

W jaki sposób?

Kluczem jest to, że kiedy uruchomisz kontener Docker, musisz go uruchomić w trybie hosta . Polecenie wygląda następująco:

docker run --network="host" -id <Docker image ID>

Kiedy zrobisz ifconfig(musisz mieć apt-get install net-toolsswój kontener, ifconfigaby można go było wywołać) wewnątrz swojego kontenera, zobaczysz, że interfejsy sieciowe są takie same jak na hoście Docker (np. Twój laptop).

Ważne jest, aby pamiętać, że jestem użytkownikiem Maca, ale uruchamiam Ubuntu pod Parallels, więc korzystanie z Maca nie jest wadą. ;-)

I w ten sposób łączysz kontener NGINX z MySQL działającym na localhost.

sivabudh
źródło
1
Należy zauważyć, że tryb hosta oferuje lepszą wydajność, ponieważ wykorzystuje stos sieciowy systemu operacyjnego.
sivabudh
2
Bardzo dobry punkt. Chociaż możliwe jest połączenie z kontenera do usługi hosta z nieużywanym adresem IP, dołącz docs.docker.com/docker-for-mac/networking . Nie jest to przyjemne rozwiązanie ... ale działa.
Xavier Huppé
Dobre rzeczy tutaj. W --network="host"jaki sposób można znaleźć się w kontenerze z mysql hosta?
Michael
1
@Buccleuch Wystarczy użyć localhost. Sprawdź mój kod źródłowy GitHub: github.com/sivabudh/system-in-a-box/blob/master/dj_host_docker/… . Wyszukaj 'HOST', zobaczysz 127.0.0.1, aby połączyć się z Postgresql.
sivabudh
Byłem w stanie uzyskać dostęp do baz danych mysql hosta, instalując wolumin zgodnie z @ user833482, a po zainstalowaniu klienta i serwera mysql na kontenerze dokera oczywiście.
Michael
7

Najprostsze rozwiązanie dla Mac OSX

Wystarczy użyć adresu IP komputera Mac. Na komputerze Mac uruchom to, aby uzyskać adres IP i użyć go z kontenera:

$ ifconfig | grep 'inet 192'| awk '{ print $2}'

Tak długo, jak serwer działający lokalnie na komputerze Mac lub w innym kontenerze dokera będzie nasłuchiwał wersji 0.0.0.0, kontener dokera będzie mógł dotrzeć do tego adresu.

Jeśli chcesz uzyskać dostęp do innego kontenera dokera, który nasłuchuje w wersji 0.0.0.0, możesz użyć 172.17.0.1

dansalmo
źródło
1
Docker dla komputerów Mac wyświetla docker.for.mac.host.internalteraz nazwę hosta.
Matt
5

To nie jest odpowiedź na rzeczywiste pytanie. W ten sposób rozwiązałem podobny problem. Rozwiązanie pochodzi całkowicie z: Zdefiniuj Docker Container Networking, aby kontenery mogły się komunikować . Dzięki Nic Raboy

Pozostawiając to tutaj innym, którzy mogą chcieć wykonywać połączenia REST między jednym kontenerem a drugim. Odpowiada na pytanie: czego używać zamiast localhost w środowisku dokera?

Zobacz, jak wygląda Twoja sieć docker network ls

Utwórz nową sieć docker network create -d my-net

Uruchom pierwszy pojemnik docker run -d -p 5000:5000 --network="my-net" --name "first_container" <MyImage1:v0.1>

Sprawdź ustawienia sieciowe dla pierwszego kontenera docker inspect first_container. „Sieci”: powinny mieć „my-net”

Uruchom drugi pojemnik docker run -d -p 6000:6000 --network="my-net" --name "second_container" <MyImage2:v0.1>

Sprawdź ustawienia sieciowe dla drugiego kontenera docker inspect second_container. „Sieci”: powinny mieć „my-net”

ssh do drugiego pojemnika docker exec -it second_container shlub docker exec -it second_container bash.

Wewnątrz drugiego kontenera możesz pingować pierwszy kontener ping first_container. Ponadto wywołania kodu, takie jak, http://localhost:5000mogą zostać zastąpione przezhttp://first_container:5000

Shirish Hirekodi
źródło
Dokładnie tego szukałem. Dzięki: D
Simar Singh,
5

Dla Windowsa,

Zmieniłem adres URL bazy danych w konfiguracji wiosennej: spring.datasource.url=jdbc:postgresql://host.docker.internal:5432/apidb

Następnie zbuduj obraz i uruchom. To zadziałało dla mnie.

Praveenkumar Beedanal
źródło
ciekawe ....
Phil
dla mnie nie działa. Mam Mac i próbuję z kontenera php połączyć się z localhost mysql. Dowolny pomysł ?
A. Zalonis,
4

Nie zgadzam się z odpowiedzią Thomasleveil.

Utworzenie mysql powiązania z 172.17.42.1 uniemożliwi innym programom korzystanie z bazy danych na hoście, aby do niej dotrzeć. Działa to tylko wtedy, gdy wszyscy użytkownicy bazy danych są zadokowani.

Zmuszenie mysql do powiązania z 0.0.0.0 spowoduje otwarcie bazy danych na świat zewnętrzny, co jest nie tylko bardzo złym posunięciem, ale także sprzeczne z tym, co autor chce zrobić z oryginalnym pytaniem. Mówi wprost: „MySql działa na localhost i nie udostępnia portu zewnętrznemu światu, więc jest związany z localhost”

Aby odpowiedzieć na komentarz od Ivant

„Dlaczego nie powiązać mysql również z dokerem0?”

To jest niemożliwe. Dokumentacja mysql / mariadb wyraźnie stwierdza, że ​​nie można powiązać kilku interfejsów. Można powiązać tylko 0, 1 lub wszystkie interfejsy.

Podsumowując, NIE znalazłem żadnego sposobu na uzyskanie dostępu do bazy danych (tylko localhost) na hoście z kontenera dokującego. To zdecydowanie wydaje się być bardzo powszechnym wzorcem, ale nie wiem, jak to zrobić.

orzel
źródło
4
z hosta dokera nadal można połączyć się z serwerem MySQL przy użyciu 172.17.42.1adresu. Ale twoja notatka ma rację inaczej. Również zredagowałem swoją odpowiedź w hosttrybie sieciowym, który pozwala utrzymać serwer MySQL związany, 127.0.0.1a kontenery mogą się z nim połączyć
Thomasleveil
nie, jak powiedziałem, nie możesz połączyć się z 172.17.42.1, jeśli mysql jest powiązany z hostem lokalnym.
orzel
4
„Utworzenie wiązania mysql z 172.17.42.1 uniemożliwi innym programom korzystanie z bazy danych na hoście, aby się do niego dostać”. - to nie jest prawda. Inne programy mogą korzystać z mysql, muszą jedynie połączyć się z 172.17.42.1 zamiast localhost / 127.0.0.1.
0x89
Rozwiązaniem problemu w tej odpowiedzi jest na ogół skłonienie serwera MySQL do połączenia się, 0.0.0.0a następnie skonfigurowania zapory ogniowej, aby db nie był dostępny z Internetu.
halfer
4

Oto moje rozwiązanie: działa w moim przypadku

  • ustaw lokalny serwer mysql na publiczny dostęp przez komentarz #bind-address = 127.0.0.1 w /etc/mysql/mysql.conf.d

  • zrestartuj serwer mysql sudo /etc/init.d/mysql restart

  • uruchom następujące polecenie, aby otworzyć dostęp użytkownika root do dowolnego hosta mysql -uroot -proot GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION; FLUSH PRIVILEGES;

  • utwórz skrypt sh: run_docker.sh

    #! bin / bash

    HOSTIP = `ip -4 addr show scope global dev eth0 | grep inet | awk '{print \ $ 2}' | cut -d / -f 1`


      docker run -it -d - nazwa aplikacji internetowej \
                  --add-host = lokalny: $ {HOSTIP} \
                  -p 8080: 8080 \
                  -e DATABASE_HOST = $ {HOSTIP} \
                  -e DATABASE_PORT = 3306 \
                  -e DATABASE_NAME = wersja demo \
                  -e DATABASE_USER = root \
                  -e DATABASE_PASSWORD = root \
                  sopheamak / springboot_docker_mysql

  
  • uruchomić z dokerem-kompozytorem

    wersja: „2.1”

    usługi:
    tomcatwar: dodatkowe hosty: - „lokalnie: 10.1.2.232” obraz: sopheamak / springboot_docker_mysql
    porty: - 8080: 8080 środowisko: - DATABASE_HOST = lokalny - DATABASE_USER = root - DATABASE_PASSWORD = root - DATABASE_NAME = wersja demonstracyjna - DATABASE_PORT = 3306

sopheamak
źródło
4

Przychodzi na myśl kilka rozwiązań:

  1. Najpierw przenieś swoje zależności do kontenerów
  2. Udostępnij swoje usługi zewnętrznie i połącz się z nimi za pomocą tego zewnętrznego adresu IP
  3. Uruchom kontenery bez izolacji sieci
  4. Unikaj łączenia się przez sieć, zamiast tego użyj gniazda zamontowanego jako wolumin

Powodem, dla którego to nie działa od razu jest fakt, że kontenery domyślnie działają z własną siecią nazw. Oznacza to, że localhost (lub 127.0.0.1 wskazujący na interfejs pętli zwrotnej) jest unikalny dla każdego kontenera. Łączenie się z tym spowoduje połączenie z samym kontenerem, a nie z usługami działającymi poza dokerem lub wewnątrz innego kontenera dokera.

Opcja 1 : Jeśli twoją zależność można przenieść do kontenera, zrobiłbym to pierwszy. Dzięki temu stos aplikacji jest przenośny, ponieważ inni próbują uruchomić Twój kontener we własnym środowisku. Nadal możesz opublikować port na hoście, na którym inne usługi, które nie zostały zmigrowane, nadal mogą do niego dotrzeć. Możesz nawet opublikować port w interfejsie localhost na hoście dokera, aby uniknąć jego zewnętrznego dostępu ze składnią typu: -p 127.0.0.1:3306:3306dla opublikowanego portu.

Opcja 2 : Istnieje wiele sposobów wykrywania adresu IP hosta z wnętrza kontenera, ale każdy z nich ma ograniczoną liczbę scenariuszy, w których działają (np. Wymagające Docker dla komputerów Mac). Najbardziej przenośną opcją jest wstrzyknięcie adresu IP hosta do kontenera za pomocą zmiennej środowiskowej lub pliku konfiguracyjnego, np .:

docker run --rm -e "HOST_IP=$(ip r s 0/0 | awk '{print $3}')" ...

Wymaga to, aby Twoja usługa nasłuchiwała na tym zewnętrznym interfejsie, co może stanowić zagrożenie bezpieczeństwa. Inne metody uzyskania adresu IP hosta z wnętrza kontenera znajdują się w tym poście .

Opcja 3 : Praca bez izolacji sieci, tj. Praca z--net host , oznacza, że ​​aplikacja działa w sieciowej przestrzeni nazw hosta. Jest to mniej izolacja dla kontenera i oznacza, że ​​nie można uzyskać dostępu do innych kontenerów za pośrednictwem wspólnej sieci dokerów z DNS (zamiast tego należy użyć opublikowanych portów, aby uzyskać dostęp do innych aplikacji w kontenerach). Ale w przypadku aplikacji, które muszą uzyskać dostęp do innych usług na hoście, które nasłuchują tylko 127.0.0.1na hoście, może to być najłatwiejsza opcja.

Opcja 4 : Różne usługi umożliwiają również dostęp przez gniazdo oparte na systemie plików. To gniazdo można zamontować w kontenerze jako wolumin zamontowany na powiązaniu, co umożliwia dostęp do usługi hosta bez konieczności łączenia się z siecią. Aby uzyskać dostęp do mechanizmu dokowania, często można zobaczyć przykłady montażu /var/run/docker.sockw kontenerze (dające dostęp rootowi kontenera do hosta). Za pomocą mysql możesz spróbować czegoś takiego, -v /var/run/mysqld/mysqld.sock:/var/run/mysqld/mysql.socka następnie połączyć się, z localhostktórym mysql konwertuje na używanie gniazda.

BMitch
źródło
3

Możesz uzyskać adres IP hosta za pomocą obrazu alpejskiego

docker run --rm alpine ip route | awk 'NR==1 {print $3}'

Byłoby to bardziej spójne, ponieważ zawsze używasz alpine do uruchomienia polecenia.

Podobnie do odpowiedzi Mariano, możesz użyć tego samego polecenia, aby ustawić zmienną środowiskową

DOCKER_HOST=$(docker run --rm alpine ip route | awk 'NR==1 {print $3}') docker-compose up
hasnat
źródło
3

W systemie Linux, w którym nie można zmienić interfejsu, z którym łączy się usługa localhost

Są dwa problemy, które musimy rozwiązać

  1. Uzyskiwanie adresu IP hosta
  2. Udostępnianie naszej usługi localhost Docker

Pierwszy problem można rozwiązać za pomocą obrazu dokera -hosta qoomon , podanego w innych odpowiedziach.

Będziesz musiał dodać ten kontener do tej samej sieci mostowej, co drugi kontener, aby uzyskać do niego dostęp. Otwórz terminal w kontenerze i upewnij się, że możesz pingować dockerhost.

bash-5.0# ping dockerhost
PING dockerhost (172.20.0.2): 56 data bytes
64 bytes from 172.20.0.2: seq=0 ttl=64 time=0.523 ms

Teraz trudniejszy problem, dzięki któremu usługa jest dostępna dla dokerów.

Możemy użyć telnetu, aby sprawdzić, czy możemy uzyskać dostęp do portu na hoście (być może trzeba go zainstalować).

Problem polega na tym, że nasz kontener będzie mógł uzyskać dostęp tylko do usług wiążących się ze wszystkimi interfejsami, takimi jak SSH:

bash-5.0# telnet dockerhost 22
SSH-2.0-OpenSSH_7.6p1 Ubuntu-4ubuntu0.3

Ale usługi powiązane tylko z hostem lokalnym będą niedostępne:

bash-5.0# telnet dockerhost 1025
telnet: can't connect to remote host (172.20.0.2): Connection refused

Właściwym rozwiązaniem byłoby tutaj powiązanie usługi z siecią mostów dokerów. Jednak ta odpowiedź zakłada, że ​​nie można tego zmienić. Więc zamiast tego użyjemyiptables .

Najpierw musimy znaleźć nazwę sieci mostów, z którą korzysta doker ifconfig. Jeśli używasz nienazwanego mostu, tak właśnie będzie docker0. Jeśli jednak używasz nazwanej sieci, będziesz mieć most zaczynający się od br-tego dokera. Mój jestbr-5cd80298d6f4 .

Po uzyskaniu nazwy tego mostu musimy zezwolić na routing z tego mostu do hosta lokalnego. Jest to domyślnie wyłączone ze względów bezpieczeństwa:

sysctl -w net.ipv4.conf.<bridge_name>.route_localnet=1

Teraz skonfiguruj naszą iptablesregułę. Ponieważ nasz kontener ma dostęp tylko do portów w sieci mostu dokującego, będziemy udawać, że nasza usługa jest faktycznie związana z portem w tej sieci.

W tym celu przekażemy wszystkie prośby <docker_bridge>:portdolocalhost:port

iptables -t nat -A PREROUTING -p tcp -i <docker_bridge_name> --dport <service_port> -j DNAT --to-destination 127.0.0.1:<service_port>

Na przykład dla mojej usługi na porcie 1025

iptables -t nat -A PREROUTING -p tcp -i br-5cd80298d6f4 --dport 1025 -j DNAT --to-destination 127.0.0.1:1025

Powinieneś teraz mieć dostęp do swojej usługi z kontenera:

bash-5.0# telnet dockerhost 1025
220 127.0.0.1 ESMTP Service Ready
JShorthouse
źródło
1
Jest to to samo, co wspomniane powyżej @ ray-d, ale jest ładnie wyjaśnione. Dziękuję Ci! Dodatkowo, gdy korzystam z docker-compose, musiałem również dodać regułę DNAT w łańcuchu PREROUTING dla wszystkich pakietów przybywających również do interfejsu docker0: ponieważ, zdaje się, że docker-compose używa docker0 podczas kompilacji (co zaskakujące): sysctl -w net.ipv4.conf.docker0.route_localnet=1iiptables -t nat -A PREROUTING -p tcp -i docker0 --dport 1025 -j DNAT --to-destination 127.0.0.1:1025
arvindd
3

Musisz znać bramę ! Moim rozwiązaniem z lokalnym serwerem było ujawnienie go poniżej 0.0.0.0:8000, a następnie uruchomienie dokera z podsiecią i uruchomienie kontenera w następujący sposób :

docker network create --subnet=172.35.0.0/16 --gateway 172.35.0.1 SUBNET35
docker run -d -p 4444:4444 --net SUBNET35 <container-you-want-run-place-here>

Teraz możesz uzyskać dostęp do pętli zwrotnej za pośrednictwem http://172.35.0.1:8000

Kirill .z
źródło
2

Grupy C i przestrzenie nazw odgrywają główną rolę w ekosystemie kontenerowym.

Przestrzeń nazw zapewnia warstwę izolacji. Każdy kontener działa w osobnej przestrzeni nazw, a jego dostęp jest ograniczony do tej przestrzeni nazw. Grupy C kontrolują wykorzystanie zasobów każdego kontenera, podczas gdy Przestrzeń nazw kontroluje to, co proces może zobaczyć i uzyskać dostęp do odpowiedniego zasobu.

Oto podstawowe zrozumienie podejścia, które możesz zastosować,

Użyj sieciowej przestrzeni nazw

Kiedy kontener odradza się z obrazu, interfejs sieciowy jest definiowany i tworzony. To daje kontenerowi unikalny adres IP i interfejs.

$ docker run -it alpine ifconfig

Zmieniając przestrzeń nazw na host, sieci cotainers nie pozostają odizolowane od swojego interfejsu, proces będzie miał dostęp do interfejsu sieciowego maszyn hosta.

$ docker run -it --net=host alpine ifconfig

Jeśli proces nasłuchuje na portach, zostaną one nasłuchane na interfejsie hosta i zmapowane do kontenera.

Użyj przestrzeni nazw PID Zmieniając przestrzeń nazw PID, umożliwia kontenerowi interakcję z innym procesem poza jego normalnym zakresem.

Ten kontener będzie działał we własnej przestrzeni nazw.

$ docker run -it alpine ps aux

Zmieniając przestrzeń nazw na host, kontener może również zobaczyć wszystkie inne procesy uruchomione w systemie.

$ docker run -it --pid=host alpine ps aux

Udostępnianie przestrzeni nazw

Jest to zła praktyka, aby to zrobić w produkcji, ponieważ wychodzisz z modelu zabezpieczeń kontenera, który może otworzyć się na luki i łatwy dostęp do podsłuchu. Służy to wyłącznie do debugowania narzędzi i niedopuszczania luk w zabezpieczeniach kontenerów.

Pierwszy kontener to serwer nginx. Spowoduje to utworzenie nowej sieci i przestrzeni nazw procesów. Ten kontener połączy się z portem 80 nowo utworzonego interfejsu sieciowego.

$ docker run -d --name http nginx:alpine

Kolejny kontener może teraz ponownie wykorzystać tę przestrzeń nazw,

$ docker run --net=container:http mohan08p/curl curl -s localhost

Ponadto ten kontener może zobaczyć interfejs z procesami we wspólnym kontenerze.

$ docker run --pid=container:http alpine ps aux

Umożliwi to przyznanie większej liczby uprawnień kontenerom bez zmiany lub ponownego uruchomienia aplikacji. W podobny sposób możesz połączyć się z mysql na hoście, uruchomić i debugować aplikację. Ale nie zaleca się, aby przejść tą drogą. Mam nadzieję, że to pomoże.

mohan08p
źródło
2

Spróbuj tego:

version: '3.5'
services:
  yourservice-here:
    container_name: container_name
    ports:
      - "4000:4000"
    extra_hosts: # <---- here
      - localhost:192.168.1.202
      - or-vitualhost.local:192.168.1.202

Aby uzyskać 192.168.1.202, używaifconfig

To zadziałało dla mnie. Mam nadzieję, że to pomoże!

Binh Ho
źródło
1

W przypadku komputera z systemem Windows: -

Uruchom poniższe polecenie, aby ujawnić losowo port dokera podczas kompilacji

$docker run -d --name MyWebServer -P mediawiki

wprowadź opis zdjęcia tutaj

wprowadź opis zdjęcia tutaj

Na powyższej liście kontenerów widać port przypisany jako 32768. Spróbuj uzyskać dostęp

localhost:32768 

Możesz zobaczyć stronę mediawiki

Lokesh S
źródło
5
Chociaż ta odpowiedź może dostarczyć użytecznych informacji niektórym użytkownikom, jest niewłaściwa ! Chodzi o dostęp do usługi uruchomionej w kontenerze z komputera hosta. Pytanie dotyczyło jednak dostępu do usługi uruchomionej na hoście z kontenera.
einjohn
1

Dopóki poprawka nie zostanie scalona z mastergałęzią, aby uzyskać adres IP hosta, wystarczy uruchomić z wnętrza kontenera:

ip -4 route list match 0/0 | cut -d' ' -f3

(zgodnie z sugestią @Mahoney tutaj ).

patryk.beza
źródło
1

Rozwiązałem to, tworząc użytkownika w MySQL dla adresu IP kontenera:

$ sudo mysql<br>
mysql> create user 'username'@'172.17.0.2' identified by 'password';<br>
Query OK, 0 rows affected (0.00 sec)

mysql> grant all privileges on database_name.* to 'username'@'172.17.0.2' with grant option;<br>
Query OK, 0 rows affected (0.00 sec)

$ sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf
<br>bind-address        = 172.17.0.1

$ sudo systemctl restart mysql.service

Następnie na pojemniku: jdbc:mysql://<b>172.17.0.1</b>:3306/database_name

Leandro
źródło
To najprostsze rozwiązanie. To zadziałało dla mnie i
poleciłem
-1

W ten sposób przekazuję adres IP hosta jako zmienną środowiskową do kontenera. Kontener następnie uzyskuje dostęp do hosta za pomocą tej zmiennej.

F. Kam
źródło
Czy możesz zilustrować, jak to robisz? Próbowałem tego podejścia, ale nie odniosłem dużego sukcesu
kmjb
`docker run -i -t -e HOST = 10.145.2.123 root Ubuntu root @ ce2a843da3ee: / tmp # ./telnet $ HOST 22 Próbowanie 10.145.2.123 ... Połączono z 10.145.2.123. Znakiem ucieczki jest „^]”. SSH-2.0-OpenSSH_7.4`
F. Kam