Dall’interno di un contenitore Docker, come posso connettermi al localhost della macchina?

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

C’è un modo per connettersi a questo MySql o qualsiasi altro programma su localhost all’interno di questo contenitore docker?

Modifica: se si utilizza Docker-for-mac o Docker-for-Windows 18.03+, connettersi al servizio mysql utilizzando l’host host.docker.internal .

A partire da Docker 18.04, questo non funziona su Docker-per-Linux.


TLDR

Utilizzare --net="host" nel comando di docker run , quindi 127.0.0.1 nel contenitore mobile farà riferimento all’host di docker.


Nota sulle modalità di networking del contenitore docker

Docker offre diverse modalità di rete durante l’esecuzione di container. A seconda della modalità scelta, ci si connetterebbe al database MySQL in esecuzione sull’host di docker in modo diverso.

finestra mobile run –net = “bridge” (predefinito)

Docker crea un bridge denominato docker0 per impostazione predefinita. Sia l’host di docker che i container di docker hanno un indirizzo IP su quel bridge.

sull’host Docker, digita sudo ip addr show docker0 avrai un risultato simile a:

 [[email protected]:~] $ 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 

Quindi qui il mio host di 172.17.42.1 ha l’indirizzo IP 172.17.42.1 docker0 rete docker0 .

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

 [email protected]:/# 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 

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

 [email protected]:/# 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 

Quindi l’indirizzo IP dell’host di 172.17.42.1 è impostato come route predefinita ed è accessibile dal tuo contenitore.

 [email protected]:/# 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 

finestra mobile run –net = “host”

In alternativa è ansible eseguire un contenitore finestra mobile con le impostazioni di rete impostate per l’ host . Un tale contenitore condividerà lo stack di rete con l’host di docker e dal punto di vista del contenitore, localhost (o 127.0.0.1 ) farà riferimento all’host di docker.

Tenere presente che qualsiasi porta aperta nel contenitore docker verrà aperta sull’host di docker. E questo senza richiedere l’ opzione di docker run -p o -P .

Configurazione IP sul mio host docker:

 [[email protected]:~] $ 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 

e da un contenitore finestra mobile in modalità host :

 [[email protected]:~] $ docker run --rm -it --net=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 

Come puoi vedere, sia l’host di docker che il contenitore di docker condividono la stessa identica interfaccia di rete e hanno lo stesso indirizzo IP.


Connessione a MySQL dai contenitori

Modalità Ponte

Per accedere a MySQL in esecuzione sull’host docker dai contenitori in modalità bridge , è necessario assicurarsi che il servizio MySQL stia ascoltando le connessioni 172.17.42.1 IP 172.17.42.1 .

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

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

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

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 tuo server MySQL ascolterà le connessioni su tutte le interfacce di rete. Ciò significa che il tuo server MySQL potrebbe essere raggiunto da Internet; assicurati di configurare le regole del firewall di conseguenza.

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

modalità host

Per accedere a MySQL in esecuzione sull’host docker dai contenitori in modalità host , puoi mantenere bind-address = 127.0.0.1 nella configurazione di MySQL e tutto ciò che devi fare è connetterti a 127.0.0.1 dai tuoi contenitori:

 [[email protected]:~] $ docker run --rm -it --net=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: utilizzare mysql -h 127.0.0.1 e non mysql -h localhost ; altrimenti il ​​client MySQL proverebbe a connettersi usando un socket unix.

Per macOS e Windows

Docker v 18.03 e sopra (dal 21 marzo 2018)

Usa il tuo indirizzo IP interno o connettiti allo speciale nome DNS host.docker.internal che 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 v 17.12 a v 18.02

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

Docker per Mac v 17.06 a v 17.11

Come sopra ma usa docker.for.mac.localhost .

Docker per Mac 17.05 e versioni successive

Per accedere al computer host dal contenitore docker, è necessario colbind un alias IP all’interfaccia di rete. Puoi bind qualsiasi IP che desideri, ma assicurati di non utilizzarlo per nient’altro.

sudo ifconfig lo0 alias 123.123.123.123/24

Quindi assicurati che il tuo server stia ascoltando l’IP sopra menzionato o 0.0.0.0 . Se sta ascoltando su localhost 127.0.0.1 non accetterà la connessione.

Quindi basta puntare il contenitore docker su questo IP ed è ansible accedere al computer host!

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

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

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

Faccio un hack simile ai post precedenti di ottenere l’IP locale da mappare a un nome alias (DNS) nel contenitore. Il problema principale è quello di ottenere dynamicmente un semplice script che funziona sia su Linux che su 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 modificare http://localhost in http://dockerhost nel codice.

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

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

Monta mysqld.sock dall’host all’interno del contenitore.

Trova il percorso del file mysql.sock sull’host su cui è in esecuzione mysql:
netstat -ln | awk '/mysql(.*)?\.sock/ { print $9 }'

Montare il file nel punto in cui è 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 

Soluzione per Windows 10

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

È ansible utilizzare il nome DNS dell’host docker.for.win.localhost , per risolvere l’IP interno. (Attenzione alcune fonti hanno menzionato windows ma dovrebbe essere win )

Panoramica
Avevo bisogno di fare qualcosa di simile, ovvero connettermi dal mio contenitore Docker al mio localhost, che stava eseguendo l’ Azure Storage Emulator e CosmosDB Emulator .

L’ Azure Storage Emulator di default è in ascolto su 127.0.0.1 , mentre puoi modificare anche l’indirizzo IP, stavo cercando una soluzione che funzionasse con le impostazioni predefinite.

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

Per quelli su Windows, supponendo che si stia utilizzando il driver di rete bridge, si vorrà associare in modo specifico MySQL all’indirizzo IP dell’interfaccia di rete hyper-v.

Ciò avviene tramite il file di configurazione nella cartella C: \ ProgramData \ MySQL normalmente nascosta.

Il collegamento a 0.0.0.0 non funzionerà. L’indirizzo necessario è mostrato anche nella configurazione della finestra mobile e nel mio caso era 10.0.75.1.

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


Innanzitutto, la mia risposta è rivolta a 2 gruppi di persone: quelli che usano un Mac e coloro 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

Cos’è una modalità di rete host? Vedi: https://docs.docker.com/engine/reference/run/#/network-settings

In secondo luogo, per quelli di voi che usano Linux (la mia esperienza diretta era con Ubuntu 14.04 LTS e sto aggiornando presto a 16.04 LTS in produzione), , potete far funzionare il servizio all’interno di un contenitore Docker connettendolo ai servizi localhost esecuzione su l’host di Docker (ad esempio il tuo laptop).

Come?

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

docker run --network="host" -id

Quando si esegue un ifconfig (sarà necessario apt-get install net-tools il contenitore per ifconfig da chiamare) all’interno del contenitore, si vedrà che le interfacce di rete sono uguali a quella sull’host Docker (ad esempio il proprio laptop ).

È importante notare che sono un utente Mac, ma eseguo Ubuntu sotto Parallels, quindi l’utilizzo di un Mac non è uno svantaggio. 😉

E questo è il modo in cui connetti il ​​contenitore NGINX al MySQL in esecuzione su un localhost .

Soluzione per Linux (kernel> = 3.6).

Ok, il tuo server localhost ha l’interfaccia mobile docker0 predefinita con indirizzo IP 172.17.0.1 . Il tuo contenitore è stato avviato 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 utente mysql con accesso da ‘%’ che significa – da chiunque, escludendo 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 fonte o destinazione marziana durante il routing. Ciò consente l’utilizzo di 127/8 per scopi di routing locale ( predefinito FALSE ).

Ecco la mia soluzione: funziona per il mio caso

  • imposta al server mysql locale l’accesso pubblico tramite il commento #bind-address = 127.0.0.1 in /etc/mysql/mysql.conf.d

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

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

  • creare sh script: run_docker.sh

     #! Bin / bash

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


       finestra mobile run -it -d --name web-app \
                   --add-host = locale: $ {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

  
  • eseguire 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 = local
    – DATABASE_USER = root
    – DATABASE_PASSWORD = root
    – DATABASE_NAME = demo
    – DATABASE_PORT = 3306

Non sono d’accordo con la risposta di Thomasleveil.

Fare mysql bind su 172.17.42.1 impedirà ad altri programmi di usare il database sull’host per raggiungerlo. Funzionerà solo se tutti gli utenti del database sono ancorati.

Facendo mysql bind a 0.0.0.0 si aprirà il db al mondo esterno, che non è solo una cosa molto brutta da fare, ma anche contrariamente 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 a localhost”

Per rispondere al commento di Ivant

“Perché non associare anche mysql a docker0?”

Non è ansible. La documentazione di mysql / mariadb dice esplicitamente che non è ansible collegarsi a più interfacce. Puoi solo associare a 0, 1 o tutte le interfacce.

In conclusione, NON ho trovato alcun modo per raggiungere il database (localhost only) sull’host da un container. Questo sembra decisamente un modello molto comune, ma non so come farlo.

CGroups e Namespaces stanno giocando un ruolo importante nell’ecosistema contenitore.

Namespace fornisce uno strato di isolamento. Ogni contenitore viene eseguito in uno spazio dei nomi separato e il relativo accesso è limitato a tale spazio dei nomi. I Cgroup controllano l’utilizzo delle risorse di ogni contenitore, mentre Namespace controlla ciò che un processo può vedere e accedere alla rispettiva risorsa.

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

Utilizza lo spazio dei nomi di rete

Quando un contenitore esce da un’immagine, viene definita e creata un’interfaccia di rete. Ciò conferisce al contenitore un indirizzo IP e un’interfaccia univoci.

 $ docker run -it alpine ifconfig 

Modificando lo spazio dei nomi sull’host, le reti dei cotainer non rimangono isolate sulla 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 nell’interfaccia host e mappate al contenitore.

Usa spazio dei nomi PID La modifica dello spazio dei nomi Pid consente a un contenitore di interagire con altri processi oltre il 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ò vedere anche tutti gli altri processi in esecuzione sul sistema.

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

Condivisione dello spazio dei nomi

Questa è una ctriggers pratica per farlo in produzione perché stai uscendo dal modello di sicurezza del contenitore che potrebbe aprirsi per vulnerabilità e un facile accesso alle intercettazioni. Questo è solo per strumenti di debug e sottovalutare le lacune nella sicurezza del contenitore.

Il primo contenitore è il server nginx. Questo creerà un nuovo spazio dei nomi di rete e processo. Questo contenitore si collegherà alla porta 80 dell’interfaccia di rete appena creata.

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

Un altro contenitore può ora 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 concedere più privilegi ai contenitori senza modificare o riavviare l’applicazione. In modo simile puoi connetterti a mysql su host, eseguire ed eseguire il debug dell’applicazione. Ma non è consigliabile andare da questa parte. Spero che sia d’aiuto.

Puoi ottenere l’IP dell’host usando l’immagine alpina

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

Ciò sarebbe più coerente in quanto utilizzi sempre Alpine per eseguire il comando.

Simile alla risposta di Mariano è ansible utilizzare lo stesso comando per impostare una variabile di ambiente

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

La soluzione più semplice per Mac OSX

Basta usare l’indirizzo IP del tuo Mac. Su Mac esegui questo per ottenere l’indirizzo IP e usarlo dal contenitore:

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

Finché il server in esecuzione in locale sul tuo Mac o in un altro contenitore docker sta ascoltando 0.0.0.0, il contenitore docker sarà in grado di raggiungere tale indirizzo.

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

È ansible utilizzare ngrok per creare un tunnel sicuro per la macchina localhost e quindi esporre quel tunnel al contenitore docker.

ngrok è gratuito da utilizzare a partire dal 22/05/2017.

passi:

1) vai su ngrok

2) scaricare il client ngrok e seguire le istruzioni di installazione

3) REGISTRATI per un account e forniranno un token di autenticazione. La registrazione è necessaria perché ngrok ti offre solo tunnel porta TCP dopo aver effettuato l’iscrizione. Non è richiesto alcun costo o carta di credito per registrarsi.

4) nel terminale do ngrok tcp 3306 . 3306 è la porta che mysql gira sul mio locale, puoi farlo anche con qualsiasi altra porta.

5) Riceverai un indirizzo dal punto 4 come questo: tcp://0.tcp.ngrok.io:10117 . Questa è la connessione tunnel al tuo computer locale. 0.tcp.ngrok.io è mappato sul tuo localhost e la porta 10117 è mappata sulla tua porta locale 3306 . Ora puoi accedere alla tua porta localhost 3306 da qualsiasi luogo usando questo indirizzo, incluso qualsiasi contenitore docker in esecuzione su questa macchina. Nel tuo contenitore docker (dovunque sia), supponendo che tu abbia già installato il client mysql, procedi come segue:

mysql --host 0.tcp.ngrok.io --port 10117 -u root

Sarai in grado di accedere al tuo account di root della tua macchina locale dall’interno del contenitore docker!

Ho bloggato su questa soluzione per vedere maggiori dettagli qui