Dall'interno di un contenitore Docker, come posso collegarmi al localhost della macchina?


1453

Quindi ho un Nginx in esecuzione all'interno di un contenitore docker, ho un mysql in esecuzione su localhost, voglio collegarmi al MySql dal mio Nginx. MySql è in esecuzione su localhost e non espone una porta al mondo esterno, quindi è associato a localhost, non associato all'indirizzo IP della macchina.

Esiste un modo per connettersi a questo MySql o qualsiasi altro programma su localhost dall'interno di questo contenitore docker?

Questa domanda è diversa da "Come ottenere l'indirizzo IP dell'host docker dall'interno di un contenitore docker" a causa del fatto che l'indirizzo IP dell'host docker potrebbe essere l'IP pubblico o l'IP privato nella rete che può o può non essere raggiungibile dall'interno del contenitore docker (intendo IP pubblico se ospitato su AWS o qualcosa del genere). Anche se si dispone dell'indirizzo IP dell'host docker, ciò non significa che è possibile connettersi all'host docker dall'interno del contenitore dato che l'indirizzo IP in quanto la rete Docker può essere overlay, host, bridge, macvlan, nessuno ecc. Che limita la raggiungibilità di quell'indirizzo IP.


Perché non associare mysql anche a docker0?
Ivant,

2
Per macchine Windows: - $ docker run -d --name MyWebServer -P httpd
Lokesh S


1
Senza di network: hostte non puoi tornare da un contenitore all'host. Ospita solo sul contenitore. Questa è l'ideologia principale dietro i contenitori. Sono isolati sia per motivi di stabilità che di sicurezza.
FreeSoftwareServers

Risposte:


1971

Modifica: se stai usando Docker-per-mac o Docker-per-Windows 18.03+, connettiti al tuo servizio mysql usando l'host host.docker.internal(invece che 127.0.0.1nella stringa di connessione).

A partire da Docker 18.09.3, questo non funziona su Docker-for-Linux. Una correzione è stata inviata l'8 marzo 2019 e si spera che verrà unita alla base di codice. Fino ad allora, una soluzione alternativa consiste nell'utilizzare un contenitore come descritto nella risposta di Qoomon .

2020-01: sono stati compiuti alcuni progressi . Se tutto va bene, questo dovrebbe atterrare in Docker 20.04


TLDR

Utilizzare --network="host"come docker runcomando, quindi 127.0.0.1nel contenitore della finestra mobile verrà indicato l'host della finestra mobile.

Nota: questa modalità funziona solo su Docker per Linux, secondo la documentazione .


Nota sulle modalità di rete del contenitore docker

Docker offre diverse modalità di rete durante l'esecuzione di container. A seconda della modalità scelta, ti connetteresti al database MySQL in esecuzione sull'host docker in modo diverso.

docker run --network = "bridge" (impostazione predefinita)

Docker crea un bridge denominato docker0per impostazione predefinita. Sia l'host docker che i contenitori docker hanno un indirizzo IP su quel bridge.

sull'host Docker, digitare sudo ip addr show docker0si avrà un output simile a:

[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

Quindi qui il mio host docker ha l'indirizzo IP 172.17.42.1sull'interfaccia di docker0rete.

Ora avvia un nuovo contenitore e ottieni una shell su di esso: docker run --rm -it ubuntu:trusty bashe all'interno del tipo di contenitore ip addr show eth0per scoprire come è impostata la sua interfaccia di rete principale:

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

Qui il mio contenitore ha l'indirizzo IP 172.17.1.192. Ora guarda la tabella di routing:

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

Pertanto, l'indirizzo IP dell'host docker 172.17.42.1è impostato come route predefinita ed è accessibile dal contenitore.

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"

In alternativa è possibile eseguire un contenitore finestra mobile con le impostazioni di rete impostate suhost . Tale contenitore condividerà lo stack di rete con l'host docker e dal punto di vista del contenitore localhost(o 127.0.0.1) farà riferimento all'host docker.

Tenere presente che qualsiasi porta aperta nel contenitore della finestra mobile verrà aperta sull'host della finestra mobile. E questo senza richiedere l' opzione -po-P docker run .

Configurazione IP sul mio host docker:

[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

e da un contenitore finestra mobile in modalità host :

[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

Come puoi vedere, sia l'host docker che il container docker condividono esattamente la stessa interfaccia di rete e come tali hanno lo stesso indirizzo IP.


Connessione a MySQL dai contenitori

Modalità Ponte

Per accedere a MySQL in esecuzione sull'host docker da contenitori in modalità bridge , è necessario assicurarsi che il servizio MySQL sia in ascolto delle connessioni sull'indirizzo 172.17.42.1IP.

Per fare ciò, assicurati di avere uno bind-address = 172.17.42.1o bind-address = 0.0.0.0nel tuo file di configurazione MySQL (my.cnf).

Se è necessario impostare una variabile di ambiente con l'indirizzo IP del gateway, è possibile eseguire il seguente codice in un contenitore:

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

quindi nella tua applicazione, usa la DOCKER_HOST_IPvariabile d'ambiente per aprire la connessione a MySQL.

Nota: se si utilizza bind-address = 0.0.0.0il server MySQL, ascolterà le connessioni su tutte le interfacce di rete. Ciò significa che il tuo server MySQL potrebbe essere raggiunto da Internet; assicurarsi di impostare le regole del firewall di conseguenza.

Nota 2: se si utilizza bind-address = 172.17.42.1il server MySQL non ascolterà le connessioni effettuate 127.0.0.1. I processi in esecuzione sull'host docker che desiderano connettersi a MySQL dovrebbero utilizzare l' 172.17.42.1indirizzo IP.

modalità host

Per accedere a MySQL in esecuzione sull'host docker da contenitori in modalità host , è possibile mantenere bind-address = 127.0.0.1la configurazione MySQL e tutto ciò che è necessario fare è connettersi 127.0.0.1dai contenitori:

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

nota: usare mysql -h 127.0.0.1e non mysql -h localhost; altrimenti il ​​client MySQL proverebbe a connettersi usando un socket unix.


8
Grazie per una risposta così dettagliata! Da quello che ho raccolto, l'uso della modalità host è l'unico modo per ottenere questa funzionalità tramite localhost. Non ho provato, ma suppongo che potresti creare una rete separata per connettere i container sul proprio bridge offrendo loro un 'localhost' comune.
Ben

26
Nota per gli utenti OSX: accedere prima alla macchina virtuale docker (boot2docker), utilizzando "docker-machine ssh default", quindi eseguire "sudo ip addr show docker0". Continua con le istruzioni di Thomas da lì.
Charlie Dalsass,

30
Sto eseguendo Docker per Mac e non c'è più 172.17.42.1, né docker0 più. Era 172.17.0.1 come gateway e non può nemmenotelnet 172.17.0.1 3306
zx1986

26
È possibile montare il socket mysql nel contenitore invece di collegarsi in rete in -v /var/run/mysqld/mysqld.sock:/tmp/mysql.sockquesto modo.
chx,

8
Qualcuno può affrontare la situazione quando si esegue Docker su Mac e non si utilizza boot2docker in quanto tale non esiste un'interfaccia docker0?
TheJKFever

350

Per macOS e Windows

Docker v 18.03 e versioni successive (dal 21 marzo 2018)

Usa il tuo indirizzo IP interno o connettiti al nome DNS speciale host.docker.internalche si risolverà all'indirizzo IP interno utilizzato dall'host.

Supporto Linux in sospeso https://github.com/docker/for-linux/issues/264

MacOS con versioni precedenti di Docker

Docker per Mac dalla 17.12 alla 18.02

Come sopra ma usare docker.for.mac.host.internal invece.

Docker per Mac dalla 17.06 alla v 17.11

Come sopra ma usare docker.for.mac.localhost invece.

Docker per Mac 17.05 e versioni precedenti

Per accedere al computer host dal contenitore della finestra mobile è necessario collegare un alias IP all'interfaccia di rete. Puoi associare qualsiasi IP tu voglia, assicurati solo di non usarlo per nient'altro.

sudo ifconfig lo0 alias 123.123.123.123/24

Quindi assicurati che il tuo server stia ascoltando l'IP di cui sopra o 0.0.0.0. Se è in ascolto su localhost127.0.0.1 , non accetterà la connessione.

Quindi punta il contenitore della finestra mobile a questo IP e puoi accedere al computer host!

Per testare puoi eseguire qualcosa come curl -X GET 123.123.123.123:3000all'interno del contenitore.

L'alias verrà reimpostato ad ogni riavvio, quindi creare uno script di avvio, se necessario.

Soluzione e altra documentazione qui: https://docs.docker.com/docker-for-mac/networking/#use-cases-and-workarounds


5
geniale e grazie, questo ha funzionato per me dall'interno del contenitore. mysql -uroot -hdocker.for.mac.localhost
Richard Frank,

1
docker.for.mac.localhost È esattamente quello che stavo cercando. Ma questo è sporco da morire allo stesso tempo. Nella finestra mobile, ci si aspetterebbe che l'hook docker.for.mac.localhost fosse un nome interno docker generico che sarebbe valido per qualsiasi sistema operativo, non solo per Mac. Ma ai fini dello sviluppo questo è abbastanza buono.
99

Come posso accedere a una porta che è esposta a dire 9093 .. Sto provando a telnet docker.for.mac.localhost 9093. È irraggiungibile, ma se eseguo il ping docker.for.mac.localhost, è raggiungibile. Mi manca qualcosa qui?
Achilleus,

1
Il nome DNS docker.for.mac.host.internal dovrebbe essere usato al posto di docker.for.mac.localhost (ancora valido) per la risoluzione dell'host dai container, poiché esiste un RFC che vieta l'uso dei sottodomini di localhost. Vedi tools.ietf.org/html/draft-west-let-localhost-be-localhost-06 .
Jya,

Questo non funziona per me. Quando I docker run -e HOSTNAME= docker.for.mac.host.internal , il contenitore viene creato ma non succede nulla. Devo quindi crtl + C. Con --net=host -e HOSTNAME=localhostalmeno il contenitore funziona e si lamenta che non riesce a trovare il servizio di cui ho bisogno (MySQL db).
Jorge Orpinel,

83

Sto facendo un hack simile ai post precedenti per ottenere l'IP locale da mappare a un nome alias (DNS) nel contenitore. Il problema principale è ottenere dinamicamente con un semplice script che funziona sia in Linux che in OSX l'indirizzo IP dell'host . Ho fatto questo script che funziona in entrambi gli ambienti (anche nella distribuzione Linux con "$LANG" != "en_*"configurato):

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

Quindi, usando Docker Compose, la configurazione completa sarà:

Script di avvio (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"

Quindi passare http://localhosta http://dockerhostnel tuo codice.

Per una guida più avanzata su come personalizzare lo DOCKERHOSTscript, dai un'occhiata a questo post con una spiegazione di come funziona.


1
A seconda del tuo caso d'uso, potresti anche semplicemente usare il DOCKERHOSTvalore qui invece di "localhost" o 0.0.0.0 in qualunque servizio il tuo contenitore docker debba connettersi localmente.
Enderland

2
Ho leggermente modificato la tua soluzione per renderla compatibile con le reti personalizzate: export DOCKERHOST=$(docker network inspect --format='{{range .IPAM.Config}}{{.Gateway}}{{end}}' <NETWORK-NAME> | awk -F "/" 'NR==1{print $1}') dove <NETWORK-NAME> potrebbe essere bridge o il nome della rete come definito da docker-compose (di solito nome-percorso - nome_sistema ).
Dieresys,

1
Devi aggiungere un commento: usa dockerhostcome host per la connessione db (normalmente sostituisci localhostnel file di configurazione).
Giustino, il

soluzione strana, ma è l'unico che fa funzionare xdebug sotto docker con php cli
Eddie

Acl ha smesso di funzionare dopo questa soluzione in haproxy. Qualche idea sul perché?
HyukHyukBoi,

41

Questo ha funzionato per me su uno stack NGINX / PHP-FPM senza toccare alcun codice o rete in cui l'app si aspetta solo di essere in grado di connettersi localhost

Montare mysqld.sock dall'host all'interno del contenitore.

Trova la posizione del file mysql.sock sull'host che esegue mysql:
netstat -ln | awk '/mysql(.*)?\.sock/ { print $9 }'

Montare quel file nel punto previsto nella finestra mobile:
docker run -v /hostpath/to/mysqld.sock:/containerpath/to/mysqld.sock

Possibili posizioni di 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

2
Questa è una soluzione molto più pulita, che non espone Mysql all'esterno (se non si utilizza un firewall).
user1226868

5
I socket non si adattano bene come TCP perché si bloccano più spesso e possono causare comportamenti strani. Usa TCP quando possibile.
Joel E Salas,

3
@JoelESalas Hai una fonte per tale richiesta?
Privato

Ho trovato che questa è la soluzione più semplice. Pollice in su user833482! Dovresti contribuire più spesso a StackOverflow.
Privato

2
@JoelESalas Penso che ti sbagli. La libreria client mysql utilizza anche socket unix per impostazione predefinita quando ci si connette a localhost anziché effettuare effettivamente una connessione a localhost. Un socket unix evita il sovraccarico dello stack e del routing TCP e dovrebbe essere eseguito più velocemente.
M Conrad,

25

Fino a quando non host.docker.internalfunziona per ogni piattaforma, è possibile utilizzare il mio contenitore che funge da gateway NAT senza alcuna configurazione manuale:

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


5
Posso confermare che non funziona in Docker per Windows 19.03.2 con contenitore Windows.
KMC,

qualche idea su come risolverlo? (Non sono un utente Windows)
Qoomon,

Se l'ambiente non blocca la porta utilizzata da mysql, è possibile fare riferimento al server con il nome del computer in cui è ospitato. Quindi nella tua stringa di connessione, usa il nome del tuo computer come nome del server.
KMC

24

Soluzione per Linux (kernel> = 3.6).

Ok, il tuo server localhost ha un'interfaccia docker predefinita docker0 con indirizzo IP 172.17.0.1 . Il contenitore è iniziato con le impostazioni di rete predefinite --net = "bridge" .

  1. Abilita route_localnet per l'interfaccia docker0:
    $ sysctl -w net.ipv4.conf.docker0.route_localnet=1
  2. Aggiungi queste regole a 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. Crea un utente mysql con accesso da '%' che significa - da chiunque, escluso localhost:
    CREATE USER 'user'@'%' IDENTIFIED BY 'password';
  4. Cambia nel tuo script l'indirizzo mysql-server in 172.17.0.1


Dalla documentazione del kernel :

route_localnet - BOOLEAN: non considerare gli indirizzi di loopback come sorgente o destinazione marziana durante il routing. Ciò consente l'uso di 127/8 per scopi di routing locale ( impostazione predefinita FALSE ).


1
Qual è lo scopo del secondo comando iptable? Posso capire che il primo è quello di riscrivere tutta la destinazione tcp che corrisponda da 172.17.0.1:3306 a 127.0.0.1:3306 ma perché è necessario il secondo comando iptable?
Patrick,

17

Soluzione per Windows 10

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

È possibile utilizzare il nome DNS dell'host docker.for.win.localhostper risolvere l'IP interno. (Avvertendo alcune fonti menzionate, windowsma dovrebbe esserewin )

Panoramica
Avevo bisogno di fare qualcosa di simile, ovvero connettermi dal mio contenitore Docker al mio localhost, che eseguiva Azure Storage Emulatore CosmosDB Emulator.

L' Azure Storage Emulatorascolto di default su 127.0.0.1 , mentre è possibile modificare anche l'IP associato, stavo cercando una soluzione che funzionasse con le impostazioni predefinite.

Questo funziona anche per la connessione dal mio contenitore Docker a SQL Servere IIS, entrambi in esecuzione localmente sul mio host con le impostazioni di porta predefinite.


13

Molto semplice e veloce, controlla il tuo IP host con ifconfig (linux) o ipconfig (windows) e quindi crea un

finestra mobile-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>"

In questo modo, il tuo contenitore sarà in grado di accedere al tuo host. Quando accedi al tuo DB, ricorda di usare il nome specificato in precedenza, in questo caso "dockerhost" e la porta del tuo host in cui il DB è in esecuzione


In HaProxy, questa soluzione ha smesso di funzionare per gli acl per qualche motivo, funziona solo l'impostazione predefinita.
HyukHyukBoi,

1
L'unica soluzione che funziona su un sistema Linux. +1
Rafik Farhad,

11

Nessuna delle risposte ha funzionato per me quando ho utilizzato Docker Toolbox su Windows 10 Home, ma 10.0.2.2 ha funzionato, poiché utilizza VirtualBox che espone l'host alla VM su questo indirizzo.


2
Funziona. Neanche la necessità di specificare --network = host. sembra che 10.0.2.2 sia impostato come IP predefinito per l'host. Grazie.
TheManish

Ma posso usare questo IP statico per tutte le versioni di Windows e Mac? Come posso gestirlo per più piattaforme tramite script?
151291

Questo ha funzionato per me. Basta eseguire ipconfig sul tuo host (windows) e ottenere l'indirizzo IP sottoEthernet adapter vEthernet (DockerNAT)
Kihats

10

Per quelli su Windows, supponendo che tu stia utilizzando il driver di rete bridge, ti consigliamo di associare MySQL specificatamente all'indirizzo IP dell'interfaccia di rete hyper-v.

Questo viene fatto tramite il file di configurazione nella cartella C: \ ProgramData \ MySQL normalmente nascosta.

Il binding a 0.0.0.0 non funzionerà. L'indirizzo necessario è indicato anche nella configurazione della finestra mobile, e nel mio caso era 10.0.75.1.


3
Ti meriti una medaglia! Ci sto lavorando da due giorni interi. Grazie per l'aiuto!
Michael,

1
Ci stavo anche lavorando da due giorni interi. Questo è l'unico posto sul web che ho trovato menzionato. Microsoft è completamente silenziosa al riguardo quando parla della connessione a MSSQL da un contenitore Docker. Ti viene da chiedersi se l'hanno mai fatto funzionare da soli!
Contango,

8

Modifica: ho finito per prototipare il concetto su GitHub. Dai un'occhiata a: https://github.com/sivabudh/system-in-a-box


Innanzitutto, la mia risposta è rivolta a 2 gruppi di persone: quelli che usano un Mac e quelli che usano Linux.

La modalità di rete host non funziona su un Mac. Devi usare un alias IP, vedi: https://stackoverflow.com/a/43541681/2713729

Che cos'è una modalità di rete host? Vedere: https://docs.docker.com/engine/reference/run/#/network-settings

In secondo luogo, per quelli di voi che usano Linux (la mia esperienza diretta è stata con Ubuntu 14.04 LTS e presto aggiornerò a 16.04 LTS in produzione), , è possibile rendere il servizio in esecuzione all'interno di un contenitore Docker a cui connettersilocalhost servizi in esecuzione sul Docker host (es. Il tuo laptop).

Come?

La chiave è quando si esegue il contenitore Docker, è necessario eseguirlo con la modalità host . Il comando è simile al seguente:

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

Quando esegui un ifconfig(avrai bisogno del apt-get install net-toolstuo contenitore per ifconfigessere richiamabile) all'interno del tuo contenitore, vedrai che le interfacce di rete sono le stesse dell'host Docker (es. Il tuo laptop).

È importante notare che sono un utente Mac, ma eseguo Ubuntu sotto Parallels, quindi l'utilizzo di un Mac non è uno svantaggio. ;-)

Ed è così che colleghi il contenitore NGINX a MySQL in esecuzione su un localhost.


1
È importante notare che la modalità host offre prestazioni migliori poiché utilizza lo stack di rete del sistema operativo.
sivabudh,

2
Ottimo punto lì. Sebbene sia possibile connettersi da un contenitore a un servizio host con IP non utilizzato, allegare docs.docker.com/docker-for-mac/networking . Non è una soluzione piacevole ... ma funziona.
Xavier Huppé,

Roba buona qui. Una volta all'interno del contenitore con --network="host", come si può connettersi al mysql host per esempio?
Michael,

1
@Buccleuch Basta usare localhost. Dai un'occhiata al mio codice sorgente GitHub: github.com/sivabudh/system-in-a-box/blob/master/dj_host_docker/… . Cerca 'HOST', vedrai 127.0.0.1 per connetterti a Postgresql.
sivabudh,

Sono stato in grado di accedere ai database mysql host montando il volume come per @ user833482 e, dopo aver ovviamente installato mysql-client e server sul contenitore docker.
Michael,

7

La soluzione più semplice per Mac OSX

Usa semplicemente l'indirizzo IP del tuo Mac. Sul Mac esegui questo per ottenere l'indirizzo IP e utilizzarlo dal contenitore:

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

Finché il server in esecuzione localmente sul Mac o in un altro contenitore docker è in ascolto di 0.0.0.0, il contenitore docker sarà in grado di raggiungere tale indirizzo.

Se si desidera solo accedere a un altro contenitore docker in ascolto su 0.0.0.0, è possibile utilizzare 172.17.0.1


1
Docker per Mac docker.for.mac.host.internalora espone il nome host.
Matt

5

Questa non è una risposta alla domanda reale. Ecco come ho risolto un problema simile. La soluzione proviene totalmente da: Definire la rete di container Docker in modo che i container possano comunicare . Grazie a Nic Raboy

Lasciandolo qui per gli altri che potrebbero voler effettuare chiamate REST tra un contenitore e l'altro. Risponde alla domanda: cosa usare al posto di localhost in un ambiente docker?

Scopri come appare la tua rete docker network ls

Crea una nuova rete docker network create -d my-net

Avvia il primo contenitore docker run -d -p 5000:5000 --network="my-net" --name "first_container" <MyImage1:v0.1>

Controlla le impostazioni di rete per il primo container docker inspect first_container . "Reti": dovrebbe avere "my-net"

Avvia il secondo contenitore docker run -d -p 6000:6000 --network="my-net" --name "second_container" <MyImage2:v0.1>

Controlla le impostazioni di rete per il secondo contenitore docker inspect second_container . "Reti": dovrebbe avere "my-net"

ssh nel tuo secondo contenitore docker exec -it second_container shodocker exec -it second_container bash .

All'interno del secondo contenitore, è possibile eseguire il ping del primo contenitore vicino ping first_container. Inoltre, le tue chiamate in codice come http://localhost:5000possono essere sostituite dahttp://first_container:5000


Esattamente quello che stavo cercando. Grazie: D
Simar Singh,

5

Per windows,

Ho modificato l'URL del database nella configurazione di primavera: spring.datasource.url=jdbc:postgresql://host.docker.internal:5432/apidb

Quindi crea l'immagine ed esegui. Ha funzionato per me.


interessante ....
Phil

per me non funziona. Ho mac e provo da un contenitore PHP per connettersi a mysql localhost. Qualche idea ?
A. Zalonis,

4

Non sono d'accordo con la risposta di Thomasleveil.

Fare in modo che mysql si leghi a 172.17.42.1 impedirà ad altri programmi di utilizzare il database sull'host per raggiungerlo. Funzionerà solo se tutti gli utenti del database sono ancorati.

Fare in modo che mysql si leghi a 0.0.0.0 aprirà il db al mondo esterno, il che non è solo una brutta cosa da fare, ma è anche contrario a ciò che l'autore della domanda originale vuole fare. Dice esplicitamente "MySql è in esecuzione su localhost e non espone una porta al mondo esterno, quindi è legato a localhost"

Per rispondere al commento di Ivant

"Perché non associare mysql anche a docker0?"

Non è possibile. La documentazione mysql / mariadb afferma esplicitamente che non è possibile eseguire il binding a più interfacce. È possibile associare solo 0, 1 o tutte le interfacce.

In conclusione, NON ho trovato alcun modo per raggiungere il database (solo localhost) sull'host da un contenitore docker. Sembra sicuramente un modello molto comune, ma non so come farlo.


4
dall'host docker è comunque possibile connettersi al server MySQL utilizzando l' 172.17.42.1indirizzo. Ma la tua nota è giusta altrimenti. Inoltre, ho modificato la mia risposta con la hostmodalità di rete che consente di mantenere vincolato il server MySQL 127.0.0.1consentendo ai contenitori di connettersi ad esso
Thomasleveil

no, come ho detto, non è possibile connettersi a 172.17.42.1 se mysql è associato a localhost.
Orzel

4
"Rendere mysql associato a 172.17.42.1 impedirà ad altri programmi che utilizzano il database sull'host di raggiungerlo." - quello non è vero. Altri programmi possono usare mysql, devono solo connettersi a 172.17.42.1 invece di localhost / 127.0.0.1.
0x89

La soluzione al problema in questa risposta è in genere quella di far legare il server MySQL 0.0.0.0e quindi impostare un firewall in modo che il db non sia accessibile da Internet.
halfer

4

Ecco la mia soluzione: funziona per il mio caso

  • imposta il server mysql locale su accesso pubblico commentando #bind-address = 127.0.0.1 in /etc/mysql/mysql.conf.d

  • riavvia il server mysql sudo /etc/init.d/mysql restart

  • eseguire il comando seguente per aprire l'accesso root dell'utente a qualsiasi host mysql -uroot -proot GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION; FLUSH PRIVILEGES;

  • crea sh script: 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 --name web-app \
                  --add-host = local: $ {HOSTIP} \
                  -p 8080: 8080 \
                  -e DATABASE_HOST = $ {HOSTIP} \
                  -e DATABASE_PORT = 3306 \
                  -e DATABASE_NAME = demo \
                  -e DATABASE_USER = root \
                  -e DATABASE_PASSWORD = root \
                  sopheamak / springboot_docker_mysql

  
  • eseguito con docker-compositore

    versione: '2.1'

    Servizi:
    tomcatwar: extra_hosts: - "locale: 10.1.2.232" immagine: sopheamak / springboot_docker_mysql
    porti: - 8080: 8080 ambiente: - DATABASE_HOST = locale - DATABASE_USER = root - DATABASE_PASSWORD = root - DATABASE_NAME = demo - DATABASE_PORT = 3306


4

Vengono in mente diverse soluzioni:

  1. Sposta prima le tue dipendenze in contenitori
  2. Rendi i tuoi altri servizi accessibili dall'esterno e connettiti ad essi con quell'IP esterno
  3. Esegui i contenitori senza isolamento di rete
  4. Evitare la connessione in rete, utilizzare invece un socket montato come volume

Il motivo per cui questo non funziona immediatamente è che i contenitori vengono eseguiti con il proprio spazio dei nomi di rete per impostazione predefinita. Ciò significa che localhost (o 127.0.0.1 che punta all'interfaccia di loopback) è unico per container. La connessione a questo si connetterà al contenitore stesso e non ai servizi in esecuzione all'esterno della finestra mobile o all'interno di un contenitore finestra mobile diverso.

Opzione 1 : se la tua dipendenza può essere spostata in un contenitore, lo farei prima. Rende portatile lo stack dell'applicazione mentre altri tentano di eseguire il contenitore nel proprio ambiente. E puoi ancora pubblicare la porta sul tuo host dove altri servizi che non sono stati migrati possono ancora raggiungerla. Puoi persino pubblicare la porta sull'interfaccia localhost sul tuo docker host per evitare che sia accessibile esternamente con una sintassi come: -p 127.0.0.1:3306:3306per la porta pubblicata.

Opzione 2 : esistono diversi modi per rilevare l'indirizzo IP dell'host dall'interno del contenitore, ma ognuno di essi ha un numero limitato di scenari in cui funziona (ad es. Richiede Docker per Mac). L'opzione più portatile è quella di iniettare l'IP dell'host nel contenitore con qualcosa come una variabile di ambiente o un file di configurazione, ad esempio:

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

Ciò richiede che il servizio sia in ascolto su quell'interfaccia esterna, il che potrebbe costituire un problema di sicurezza. Per altri metodi per ottenere l'indirizzo IP dell'host dall'interno del contenitore, vedere questo post .

Opzione 3 : l'esecuzione senza isolamento della rete, ovvero l'esecuzione con --net host, indica che l'applicazione è in esecuzione nello spazio dei nomi della rete host. Questo è meno isolamento per il container e significa che non è possibile accedere ad altri container su una rete docker condivisa con DNS (invece, è necessario utilizzare le porte pubblicate per accedere ad altre applicazioni containerizzate). Ma per le applicazioni che devono accedere ad altri servizi sull'host che stanno solo ascoltando 127.0.0.1sull'host, questa può essere l'opzione più semplice.

Opzione 4 : vari servizi consentono anche l'accesso tramite un socket basato su filesystem. Questo socket può essere montato nel contenitore come volume montato su bind, consentendo di accedere al servizio host senza passare attraverso la rete. Per l'accesso al motore docker, vengono spesso visualizzati esempi di montaggio /var/run/docker.socknel contenitore (che consente a tale contenitore di accedere all'host come root). Con mysql, puoi provare qualcosa di simile -v /var/run/mysqld/mysqld.sock:/var/run/mysqld/mysql.socke quindi connetterti a localhostquale mysql si converte utilizzando il socket.


3

È possibile ottenere l'IP host utilizzando l'immagine alpina

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

Ciò sarebbe più coerente poiché usi sempre alpine per eseguire il comando.

Simile alla risposta di Mariano, puoi usare lo stesso comando per impostare una variabile d'ambiente

DOCKER_HOST=$(docker run --rm alpine ip route | awk 'NR==1 {print $3}') docker-compose up

3

Per Linux, dove non è possibile modificare l'interfaccia a cui si lega il servizio localhost

Ci sono due problemi che dobbiamo risolvere

  1. Ottenere l'IP dell'host
  2. Rendere il nostro servizio localhost disponibile per Docker

Il primo problema può essere risolto utilizzando l'immagine docker -host di qoomon , come indicato da altre risposte.

Sarà necessario aggiungere questo contenitore alla stessa rete bridge dell'altro contenitore in modo da potervi accedere. Apri un terminale all'interno del tuo contenitore e assicurati di poter eseguire il ping 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

Ora, il problema più difficile, rendendo il servizio accessibile alla finestra mobile.

Possiamo usare telnet per verificare se possiamo accedere a una porta sull'host (potrebbe essere necessario installarlo).

Il problema è che il nostro container sarà in grado di accedere solo ai servizi che si legano a tutte le interfacce, come SSH:

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

Ma i servizi associati solo a localhost saranno inaccessibili:

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

La soluzione corretta qui sarebbe quella di associare il servizio alla rete bridge dockers. Tuttavia, questa risposta presuppone che non sia possibile modificarlo. Quindi useremo invece iptables.

Innanzitutto, dobbiamo trovare il nome della rete bridge utilizzata dalla docker ifconfig. Se stai usando un bridge senza nome, questo sarà solo docker0. Tuttavia, se si utilizza una rete denominata, si avrà invece un bridge che inizia con br-quella finestra mobile. Il mio è br-5cd80298d6f4.

Una volta che abbiamo il nome di questo bridge, dobbiamo consentire il routing da questo bridge a localhost. Questo è disabilitato di default per motivi di sicurezza:

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

Ora per impostare la nostra iptablesregola. Poiché il nostro contenitore può accedere solo alle porte sulla rete del docker bridge, faremo finta che il nostro servizio sia effettivamente associato a una porta su questa rete.

Per fare ciò, inoltreremo tutte le richieste <docker_bridge>:portalocalhost: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>

Ad esempio, per il mio servizio sulla porta 1025

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

Ora dovresti essere in grado di accedere al tuo servizio dal contenitore:

bash-5.0# telnet dockerhost 1025
220 127.0.0.1 ESMTP Service Ready

1
Questo è lo stesso di quello che @ ray-d ha menzionato sopra, ma è ben spiegato. Grazie! Inoltre, quando si utilizza docker-compose, ho dovuto aggiungere anche una regola DNAT nella catena PREROUTING per tutti i pacchetti che arrivano anche sull'interfaccia docker0: perché, docker-compose sembra usare docker0 durante le build (non durante le esecuzioni, sorprendentemente): sysctl -w net.ipv4.conf.docker0.route_localnet=1eiptables -t nat -A PREROUTING -p tcp -i docker0 --dport 1025 -j DNAT --to-destination 127.0.0.1:1025
arvindd il

3

Devi conoscere il gateway ! La mia soluzione con il server locale era di esporla in 0.0.0.0:8000, quindi eseguire docker con sottorete ed eseguire container come:

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>

Quindi, ora puoi accedere al tuo loopback http://172.35.0.1:8000


3

Prova questo:

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

Per ottenere 192.168.1.202, usaifconfig

Questo ha funzionato per me. Spero che questo aiuto!


2

I CGroup e gli spazi dei nomi stanno giocando un ruolo importante nell'ecosistema container.

Lo spazio dei nomi fornisce un livello di isolamento. Ogni contenitore viene eseguito in uno spazio dei nomi separato e il suo accesso è limitato a quello spazio dei nomi. Cgroups controlla l'utilizzo delle risorse di ciascun contenitore, mentre Namespace controlla ciò che un processo può vedere e accedere alla rispettiva risorsa.

Ecco la comprensione di base dell'approccio di soluzione che potresti seguire,

Usa lo spazio dei nomi di rete

Quando un container viene generato dall'immagine, viene definita e creata un'interfaccia di rete. Ciò fornisce al contenitore un indirizzo IP e un'interfaccia univoci.

$ docker run -it alpine ifconfig

Modificando lo spazio dei nomi in host, le reti cotainer non rimangono isolate alla sua interfaccia, il processo avrà accesso all'interfaccia di rete delle macchine host.

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

Se il processo è in ascolto sulle porte, verranno ascoltate sull'interfaccia host e mappate sul contenitore.

Usa spazio dei nomi PID Modificando lo spazio dei nomi Pid, ​​un contenitore può interagire con altri processi oltre il suo normale ambito.

Questo contenitore verrà eseguito nel proprio spazio dei nomi.

$ docker run -it alpine ps aux

Modificando lo spazio dei nomi sull'host, il contenitore può anche vedere tutti gli altri processi in esecuzione sul sistema.

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

Condivisione dello spazio dei nomi

Questa è una cattiva pratica per farlo in produzione perché stai uscendo dal modello di sicurezza del container che potrebbe aprirsi per le vulnerabilità e un facile accesso a intercettazioni. Questo è solo per gli strumenti di debug e per minimizzare le lacune nella sicurezza dei container.

Il primo contenitore è il server nginx. Ciò creerà una nuova rete ed elaborerà lo spazio dei nomi. Questo contenitore si legherà alla porta 80 dell'interfaccia di rete appena creata.

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

Un altro contenitore ora può riutilizzare questo spazio dei nomi,

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

Inoltre, questo contenitore può vedere l'interfaccia con i processi in un contenitore condiviso.

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

Ciò consentirà di assegnare più privilegi ai contenitori senza modificare o riavviare l'applicazione. Allo stesso modo è possibile connettersi a mysql sull'host, eseguire ed eseguire il debug dell'applicazione. Ma non è consigliabile seguire questa strada. Spero che sia d'aiuto.


1

Per macchine Windows: -

Eseguire il comando seguente per esporre la porta finestra mobile in modo casuale durante il tempo di compilazione

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

inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine

Nell'elenco contenitore sopra puoi vedere la porta assegnata come 32768. Prova ad accedere

localhost:32768 

Puoi vedere la pagina di mediawiki


5
Sebbene questa risposta possa fornire informazioni utili ad alcuni utenti, è la strada sbagliata ! Si tratta di accedere a un servizio in esecuzione nel contenitore dal computer host. La domanda, tuttavia, riguardava l'accesso a un servizio in esecuzione sull'host dal contenitore.
einjohn

1

Fino a quando la correzione non viene unita nel masterramo, per ottenere l'IP host basta eseguirlo dall'interno del contenitore:

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

(come suggerito da @Mahoney qui ).


1

L'ho risolto creando un utente in MySQL per l'ip del contenitore:

$ 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

Quindi sul contenitore: jdbc:mysql://<b>172.17.0.1</b>:3306/database_name


Questa è la soluzione più semplice. Ha funzionato per me e ne ho
parlato

-1

Il modo in cui lo faccio è passare l'IP host come variabile d'ambiente al contenitore. Il contenitore quindi accede all'host tramite quella variabile.


Puoi illustrarmi come lo fai? Avevo tentato questo approccio ma non ho trovato molto successo
kmjb,

`docker run -i -t -e HOST = 10.145.2.123 ubuntu root @ ce2a843da3ee: / tmp # ./telnet $ HOST 22 Prova 10.145.2.123 ... Connesso a 10.145.2.123. Il carattere di escape è '^]'. SSH-2.0-OpenSSH_7.4`
F. Kam
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.