Dall'interno di un contenitore Docker, come faccio a connettermi al localhost della macchina?
Quindi ho un Nginx in esecuzione all'interno di un contenitore docker, ho un mysql in esecuzione su localhost, voglio connettermi al MySql dall'interno del mio Nginx. Il MySql è in esecuzione su localhost e non espone una porta al mondo esterno, quindi è legato a localhost, non legato all'indirizzo ip della macchina.
C'è un modo per connettersi a questo MySql o a 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 della rete che potrebbe o meno essere raggiungibile dall'interno del contenitore docker (intendo IP pubblico se ospitato su AWS o qualcosa del genere). Anche se hai l'indirizzo IP dell'host docker non significa che puoi connetterti all'host docker dall'interno del contenitore dato quell'indirizzo IP poiché la tua rete Docker potrebbe essere overlay, host, bridge, macvlan, nessuno ecc che limita la raggiungibilità di quell'indirizzo IP.
Modifica: Se state usando Docker-for-mac o Docker-for-Windows 18.03+, connettetevi semplicemente al vostro servizio mysql usando l'host
host.docker.internal
.A partire da Docker 18.09.3, questo non funziona su Docker-for-Linux. Una correzione è stata presentata l'8 marzo 2019 e si spera che venga unita alla base del codice. Fino ad allora, un workaround è quello di utilizzare un contenitore come descritto in qoomon'risposta.
TLDR
Usa
--network="host"
nel tuo comandodocker run
, quindi127.0.0.1
nel tuo contenitore docker punterà al tuo host docker.Nota: Questa modalità funziona solo su Docker per Linux, secondo la documentazione.
Nota sulle modalità di rete dei container docker
Docker offre diverse modalità di rete quando si eseguono i container. A seconda della modalità scelta ci si connette al database MySQL in esecuzione sull'host docker in modo diverso.
docker run --network="bridge" (predefinito)
Docker crea un bridge chiamato
docker0
per impostazione predefinita. Sia l'host docker che i contenitori docker hanno un indirizzo IP su quel ponte.Sull'host Docker, digitate
sudo ip addr show docker0
e avrete un output simile a questo:Quindi qui il mio host docker ha l'indirizzo IP
172.17.42.1
sull'interfaccia di retedocker0
.Ora avvia un nuovo contenitore e crea una shell su di esso:
docker run --rm -it ubuntu:trusty bash
e all'interno del contenitore digitateip addr show eth0
per scoprire come è impostata la sua interfaccia di rete principale:Qui il mio contenitore ha l'indirizzo IP
172.17.1.192
. Ora guarda la tabella di routing:Quindi l'indirizzo IP dell'host docker
172.17.42.1
è impostato come percorso predefinito ed è accessibile dal tuo contenitore.docker run --network="host"
In alternativa si può eseguire un contenitore docker con impostazioni di rete impostate su
host
. Tale contenitore condividerà lo stack di rete con l'host docker e dal punto di vista del contenitore,localhost
(o127.0.0.1
) si riferirà all'host docker.Siate consapevoli che qualsiasi porta aperta nel vostro contenitore docker verrebbe aperta sull'host docker. E questo senza richiedere l'opzione
-p
o-P
docker run
.Configurazione IP sul mio host docker:
e da un contenitore docker in modalità host:
Come potete vedere sia l'host docker che il contenitore docker condividono la stessa identica interfaccia di rete e come tale hanno lo stesso indirizzo IP.
Connessione a MySQL dai container
modalità bridge
Per accedere a MySQL in esecuzione sull'host docker dai container in modalità ponte, è necessario assicurarsi che il servizio MySQL sia in ascolto per le connessioni sull'indirizzo IP
172.17.42.1
.Per farlo, assicurati di avere o
bind-address = 172.17.42.1
obind-address = 0.0.0.0
nel tuo file di configurazione di MySQL (my.cnf).Se hai bisogno di impostare una variabile d'ambiente con l'indirizzo IP del gateway, puoi eseguire il seguente codice in un contenitore :
poi nella tua applicazione, usa la variabile d'ambiente
DOCKER_HOST_IP
per aprire la connessione a MySQL.Nota: se usi
bind-address = 0.0.0.0
il tuo server MySQL ascolterà le connessioni su tutte le interfacce di rete. Questo significa che il tuo server MySQL potrebbe essere raggiunto da Internet; assicurati di impostare le regole del firewall di conseguenza.Nota 2: se usi
bind-address = 172.17.42.1
il tuo server MySQL non ascolterà le connessioni fatte a127.0.0.1
. I processi in esecuzione sull'host docker che vorrebbero connettersi a MySQL dovrebbero usare l'indirizzo IP172.17.42.1
.modalità host
Per accedere a MySQL in esecuzione sull'host docker dai container in modalità host, puoi mantenere
bind-address = 127.0.0.1
nella tua configurazione di MySQL e tutto quello che devi fare è connetterti a127.0.0.1
dai tuoi container:nota: Usare
mysql -h 127.0.0.1
e nonmysql -h localhost
; altrimenti il client MySQL cercherà di connettersi usando un socket unix.Questo ha funzionato per me su uno stack NGINX/PHP-FPM senza toccare alcun codice o rete dove l'applicazione si aspetta solo di potersi connettere a
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 dove ci si aspetta di trovarlo nel docker:
docker run -v /hostpath/to/mysqld.sock:/containerpath/to/mysqld.sock
.Possibili posizioni di mysqld.sock:
Non sono d'accordo con la risposta di Thomasleveil.
Fare il bind di mysql a 172.17.42.1 impedirà ad altri programmi che usano il database sull'host di raggiungerlo. Questo funzionerà solo se tutti gli utenti del tuo database sono dockerizzati.
Fare mysql bind a 0.0.0.0 aprirà il db al mondo esterno, che non è solo una cosa molto brutta da fare, ma anche contraria a ciò che l'autore della domanda originale vuole fare. Dice esplicitamente "Il MySql è in esecuzione su localhost e non espone una porta al mondo esterno, quindi è legato su localhost"
Per rispondere al commento di ivant
" "Perché non legare mysql anche a docker0?
Questo non è possibile. La documentazione di mysql/mariadb dice esplicitamente che non è possibile legarsi a più interfacce. È possibile solo legarsi a 0, 1, o a tutte le interfacce.
Come conclusione, NON ho trovato alcun modo per raggiungere il database (solo localhost) sull'host da un contenitore docker. Questo sembra sicuramente un modello molto molto comune, ma non so come farlo.