Come ottenere l'indirizzo IP dell'host docker dall'interno di un contenitore docker


358

Come dice il titolo. Devo essere in grado di recuperare l'indirizzo IP degli host docker e le portmap dall'host al contenitore e farlo all'interno del contenitore.


Potresti approfondire come ti piacerebbe usare queste informazioni? Hai detto "host docker" - stai eseguendo Docker su più host? Una volta che il contenitore conosce l'indirizzo IP dell'host e delle portmap, cosa farà?
Andy,

Il modo più semplice per passare gli indirizzi IP dell'host docker al contenitore docker, penso che dovresti effettuare una chiamata all'interno del contenitore utilizzando "docker container exec". Supponiamo di voler eseguire il ping dell'host dall'interno del contenitore busybox, utilizzare ad esempio: $ IP = '8.8.8.8' && docker container busybox ping $ IP 'Il modo per scoprire l'IP host, utilizzare ciò che più ti piace.
SauloAlessandre,

Risposte:


314
/sbin/ip route|awk '/default/ { print $3 }'

Come notato da @MichaelNeale, non ha senso usare questo metodo Dockerfile(tranne quando abbiamo bisogno di questo IP solo durante il tempo di compilazione), perché questo IP sarà codificato durante il tempo di compilazione.


49
Quando si utilizza il docker bridge (impostazione predefinita) per i contenitori, questo genererà l'IP del bridge come 172.17.42.1 anziché l'IP dell'host come 192.168.1.x (suppongo che l'host sia su un NAT di casa). Usare la risposta di @Magno Torres è probabilmente ciò che la gente vuole in tali situazioni se si desidera l'indirizzo 192.168.1.x.
Programster,

2
quel RUN non funzionerà come previsto - calcolerà solo l'IP in fase di compilazione - e dopo sarà sempre statico e non utile. Sarà l'IP dell'host di build.
Michael Neale,

7
@Programster, posso supporre che la gente voglia la connessione tra l'host docker e il container, questo è ciò che bridge IP può darti (ovviamente nell'installazione "home" di stndard). Perché qualcuno dovrebbe aver bisogno di un "vero" host IP se può essere anche al di fuori del docker bridge e può essere inaccessibile? Questa è la soluzione per tutte le persone che hanno appena installato la finestra mobile e vogliono giocarci in breve tempo.
Spinus,

1
@MichaelNeale, come prima, suppongo che la maggior parte delle persone che iniziano con la finestra mobile hanno bisogno di una connessione tra il loro host e il contenitore, tutto qui. Se qualcuno sta eseguendo distribuzioni "appropriate", probabilmente non sta usando comunque docker bridge, sta usando reti personalizzate e probabilmente è a conoscenza di tutte le stranezze di rete o hanno DNS (o qualunque scoperta) impostato.
Spinus,

1
@spinus - ma questo sarà valido solo se gira sull'host su cui è stato costruito - in quel caso - puoi semplicemente codificarlo o cercarlo - Penso che non sia una risposta utile e fuorvierà molto di persone - ti consiglio di rimuoverlo. (The RUN bit)
Michael Neale

182

A partire dalla versione 18.03, è possibile utilizzare host.docker.internalcome IP dell'host.

Funziona in Docker per Mac , Docker per Windows e forse anche in altre piattaforme.

Questo è un aggiornamento specifico per Mac docker.for.mac.localhost, disponibile dalla versione 17.06 e docker.for.mac.host.internaldisponibile dalla versione 17.12, che potrebbe funzionare anche su quella piattaforma.

Nota, come nella documentazione per Mac e Windows , questo è solo a scopo di sviluppo.

Ad esempio, ho variabili di ambiente impostate sul mio host:

MONGO_SERVER=host.docker.internal

Nel mio docker-compose.ymlfile, ho questo:

version: '3'

services:
  api:
    build: ./api
    volumes:
      - ./api:/usr/src/app:ro
    ports:
      - "8000"
    environment:
      - MONGO_SERVER
    command: /usr/local/bin/gunicorn -c /usr/src/app/gunicorn_config.py -w 1 -b :8000 wsgi

2
@allanberry sfortunatamente la gente di Docker preferisce non darci un modo indipendente dalla piattaforma per farlo perché preferisce non abbracciare casi d'uso involontari (come accedere a qualsiasi servizio sul computer locale da un contenitore docker)
Andy

21
Mi è stato presentato Docker come Build it once, eseguirlo ovunque. Ma questo è assolutamente falso poiché devi sempre configurare anche il sistema host. Quindi docker.for.mac..è inutile poiché nella maggior parte dei casi non hai un ambiente solo Linux o Mac nella tua azienda. È misto, hai sviluppatori che usano Linux, Mac e Windows. Questo dominio non ha senso poiché nel 99% è un ambiente con sistema operativo host misto. Non sviluppo un contenitore sotto macOS e non lo distribuisco su un server macOS. Lo distribuisco su Linux. Questo è quello che fanno tutti. Allora, qual è anche il punto docker.for.mac..?
TheFox

1
@allanberry docker.for.mac.host.internalnon importa se stai usando Docker con o senza docker-compose. Voglio usare un host fisso nei file di configurazione. IDK, ad esempio, docker.host.internalche punta sempre all'indirizzo IP dell'host. Indipendentemente dal sistema host che sto usando. Questo è il punto centrale dell'utilizzo di Docker: voglio essere autonomo. Capisco che è ancora più complicato su macOS perché hai un altro livello tra il sistema host e il contenitore. Ma comunque, secondo me docker.for.mac.host.internalè inutile se puoi usarlo solo per macOS.
TheFox

1
host.docker.internal funziona anche su Docker per Windows , almeno al momento della stesura di questo commento.
joanlofe,

1
funziona perfettamente, ho dockerCe per Windows e jenkins in esecuzione in uno dei contenitori. Volevo eseguire il comando docker all'interno di jenkins ma docker non era in grado di connettersi al passaggio di aggiunta di una nuvola, ho usato questo tcp: //host.docker.internal: 2375 e abilitato 'expose daemon on localhost: 2375' e funziona. risparmiato un sacco di tempo. Grazie!
Vikash,

84

Aggiornamento: su Docker per Mac , a partire dalla versione 18.03, è possibile utilizzare host.docker.internal come IP dell'host. Vedi la risposta di Allanberry . Per le versioni precedenti di Docker per Mac, potrebbe essere utile la seguente risposta:

Su Docker per Mac il docker0bridge non esiste, quindi altre risposte potrebbero non funzionare. Tutto il traffico in uscita, tuttavia, viene instradato attraverso l'host principale, quindi finché si tenta di connettersi a un IP che riconosce come se stesso (e il contenitore docker non pensa di essere se stesso), si dovrebbe essere in grado di connettersi. Ad esempio, se lo esegui dall'esecuzione della macchina padre:

ipconfig getifaddr en0

Questo dovrebbe mostrare l'IP del tuo Mac sulla sua rete attuale e il tuo contenitore docker dovrebbe essere in grado di connettersi anche a questo indirizzo. Questo ovviamente è un problema se questo indirizzo IP cambia mai, ma puoi aggiungere un IP di loopback personalizzato al tuo Mac che il contenitore non pensa sia esso stesso facendo qualcosa di simile sul computer principale:

sudo ifconfig lo0 alias 192.168.46.49

È quindi possibile testare la connessione dall'interno del contenitore docker con telnet. Nel mio caso volevo collegarmi a un server xdebug remoto:

telnet 192.168.46.49 9000

Ora quando il traffico arriva sul tuo Mac indirizzato a 192.168.46.49 (e tutto il traffico che esce dal tuo contenitore passa attraverso il tuo Mac) il tuo Mac supporrà che l'IP sia esso stesso. Quando hai finito di usare questo IP, puoi rimuovere l'alias di loopback in questo modo:

sudo ifconfig lo0 -alias 192.168.46.49

Una cosa a cui prestare attenzione è che il contenitore della finestra mobile non invierà traffico all'host principale se ritiene che la destinazione del traffico sia essa stessa. Quindi controlla l'interfaccia di loopback all'interno del contenitore se hai problemi:

sudo ip addr show lo

Nel mio caso, ciò ha dimostrato inet 127.0.0.1/8che non potevo usare alcun IP 127.*nell'intervallo. Ecco perché ho usato 192.168.*nell'esempio sopra. Assicurati che l'IP che usi non sia in conflitto con qualcosa sulla tua rete.


pulirà queste impostazioni di loopback dopo il riavvio del sistema?
Robbo_UK

@Robbo_UK Sì, l'alias di loopback sparirà dopo il riavvio del mac.
Codice comandante

1
L'uso di questo nome host non ha senso poiché non funziona con Docker per Linux. Perché non l'hanno aggiunto anche per Linux?
TheFox,

Lo stanno esaminando in questo momento @TheFox: github.com/docker/libnetwork/pull/2348
Ivo Pereira,

46

Per coloro che eseguono Docker in AWS, i metadati dell'istanza per l'host sono ancora disponibili all'interno del contenitore.

curl http://169.254.169.254/latest/meta-data/local-ipv4

Per esempio:

$ docker run alpine /bin/sh -c "apk update ; apk add curl ; curl -s http://169.254.169.254/latest/meta-data/local-ipv4 ; echo"
fetch http://dl-cdn.alpinelinux.org/alpine/v3.3/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.3/community/x86_64/APKINDEX.tar.gz
v3.3.1-119-gb247c0a [http://dl-cdn.alpinelinux.org/alpine/v3.3/main]
v3.3.1-59-g48b0368 [http://dl-cdn.alpinelinux.org/alpine/v3.3/community]
OK: 5855 distinct packages available
(1/4) Installing openssl (1.0.2g-r0)
(2/4) Installing ca-certificates (20160104-r2)
(3/4) Installing libssh2 (1.6.0-r1)
(4/4) Installing curl (7.47.0-r0)
Executing busybox-1.24.1-r7.trigger
Executing ca-certificates-20160104-r2.trigger
OK: 7 MiB in 15 packages
172.31.27.238

$ ifconfig eth0 | grep -oP 'inet addr:\K\S+'
172.31.27.238

Questo è un metodo super conveniente per coloro che usano AWS. Lo uso per configurare gli indirizzi client e bind degli agenti della console. È ideale quando ci si trova in situazioni in cui non è possibile utilizzare la rete host (come la distribuzione di contenitori in Elastic Beanstalk ed ECS).
Richard Clayton,

Questo è un vero toccasana, grazie. Ho avuto difficoltà a capire come gestire la comunicazione tra container nel mio cluster ECS.
Brennan,

Su Phusion Basimage (basato su Ubuntu), ho dovuto cambiare un po 'il tuo comando:ifconfig eth0 | grep -oP 'inet \K\S+'
Meuoi,

25

L'unico modo è passare le informazioni sull'host come ambiente quando si crea un contenitore

run --env <key>=<value>

19
Più specificamente, l'indirizzo IP del bridge può essere passato utilizzando un'opzione della riga di comando come: -e "DOCKER_HOST=$(ip -4 addr show docker0 | grep -Po 'inet \K[\d.]+')"(utilizzando la risposta accettata da unix.stackexchange.com/questions/87468/… )
ncoghlan,

7
Penso che non funzioni in Docker per Mac / Windows. (the bridge IP)
zx1986

22

Il --add-hostpotrebbe essere una soluzione più pulito (ma senza la parte della porta, solo l'host può essere maneggiato con questa soluzione). Quindi, al tuo docker runcomando, fai qualcosa del tipo:

docker run --add-host dockerhost:`/sbin/ip route|awk '/default/ { print  $3}'` [my container]

(Da https://stackoverflow.com/a/26864854/127400 )


Ho detto "fatto per questo" quando qualcun altro voleva una voce in / etc / hosts; in questa domanda non è proprio vero. Anche OP ha richiesto "host e portmaps" e hai coperto solo l'host.
Bryan,

Ok. Ero un po 'confuso perché la soluzione accettata copre solo la parte host. E penso che la tua soluzione sia superiore a quella di spinus.
Augunrik,

questo non funziona se si desidera utilizzare dind - docker-in-docker. La finestra interna avrà un IP diverso
rumoroso il

12

La best practice standard per la maggior parte delle app che cercano di farlo automaticamente è: no . Invece hai la persona che esegue il contenitore inietta un nome host esterno / indirizzo IP come configurazione, ad es. Come variabile di ambiente o file di configurazione. Consentire all'utente di iniettare questo ti dà il design più portatile.

Perché sarebbe così difficile? Perché, in base alla progettazione, i contenitori isoleranno l'applicazione dall'ambiente host. La rete è assegnata ai nomi solo a quel contenitore per impostazione predefinita e i dettagli dell'host sono protetti dal processo in esecuzione all'interno del contenitore che potrebbe non essere completamente attendibile.


Esistono diverse opzioni a seconda della situazione specifica:

Se il contenitore è in esecuzione con la rete host, è possibile esaminare direttamente la tabella di routing sull'host per visualizzare la route predefinita. Da questa domanda il seguente funziona per me ad esempio:

ip route get 1 | sed -n 's/^.*src \([0-9.]*\) .*$/\1/p'

Un esempio che mostra questo con la rete host in un contenitore è simile a:

docker run --rm --net host busybox /bin/sh -c \
  "ip route get 1 | sed -n 's/^.*src \([0-9.]*\) .*$/\1/p'"

Per alcune versioni di Docker Desktop, hanno iniettato una voce DNS nella VM incorporata:

getent hosts host.docker.internal | awk '{print $1}'

Se si esegue in un ambiente cloud, è possibile controllare il servizio metadati dal provider cloud, ad esempio quello AWS:

curl http://169.254.169.254/latest/meta-data/local-ipv4

Se si desidera il proprio indirizzo esterno / Internet, è possibile eseguire una query su un servizio remoto come:

curl ifconfig.co

Ognuno di questi ha limitazioni e funziona solo in scenari specifici. L'opzione più portatile è ancora quella di eseguire il contenitore con l'indirizzo IP inserito come configurazione, ad es. Ecco un'opzione che esegue il ipcomando precedente sull'host e lo inietta come variabile d'ambiente:

export HOST_IP=$(ip route get 1 | sed -n 's/^.*src \([0-9.]*\) .*$/\1/p')
docker run --rm -e HOST_IP busybox printenv HOST_IP

curl ifconfig.coComando davvero utile .. Grazie :)
MadAboutProgramming

8

Se desideri un IPindirizzo reale (non un bridge IP) Windowse hai una finestra mobile 18.03(o più recente), procedi come segue:

Esegui bash sul contenitore dall'host dove si trova il nome dell'immagine nginx(funziona su Alpine Linux distribution):

 docker run -it nginx /bin/ash

Quindi eseguire all'interno del contenitore

/ # nslookup host.docker.internal

Name:      host.docker.internal
Address 1: 192.168.65.2

192.168.65.2è l'IP dell'host, non l'IP del bridge come nella spinusrisposta accettata.

Sto usando qui host.docker.internal :

L'host ha un indirizzo IP che cambia (o nessuno se non si ha accesso alla rete). Dal 18.03 in poi la nostra raccomandazione è quella di connettersi al nome DNS speciale host.docker.internal, che si risolve nell'indirizzo IP interno utilizzato dall'host. Questo è a scopo di sviluppo e non funzionerà in un ambiente di produzione al di fuori di Docker per Windows.


2
Ho provato la tua soluzione e sembra che il comando nslookup non sia stato trovato
Sergey l'

@Sergey La tua immagine è basata Alpine Linux? In caso contrario, controlla l'equivalente per il tuo specifico linux distribution.
Kamil Witkowski l'

No, utilizzo esattamente il tuo comando - Esegui finestra mobile -it nginx / bin / ash
Sergey

Ok - se sei su Windows, allora sono passato a linux containerse non sto usando windows containers. Puoi farlo facendo clic con il tasto destro docker icone selezionando Switch to Linux containers. Penso che potrebbe essere importante quando si scarica l'immagine. Se avessi windows containerverificato se l'eliminazione di una vecchia nginximmagine e il suo nuovo download ti offriranno un altro contenitore. Se ancora non funziona per te, allora puoi provare a installarlo nslookupin ash.
Kamil Witkowski il

Se non riesci a fare nslookup, esegui solo il ping. Mostrerà l'IP risolto. Per me questa risposta funziona e sto solo usando questo hostname ( host.docker.internal) dall'interno del contenitore
Dmitry Minkovsky

7

TLDR per Mac e Windows

docker run -it --rm alpine nslookup host.docker.internal

... stampa l'indirizzo IP dell'host ...

nslookup: can't resolve '(null)': Name does not resolve

Name:      host.docker.internal
Address 1: 192.168.65.2

Dettagli

Su Mac e Windows , è possibile utilizzare il nome DNS speciale host.docker.internal.

L'host ha un indirizzo IP che cambia (o nessuno se non si ha accesso alla rete). Dal 18.03 in poi la nostra raccomandazione è quella di connettersi al nome DNS speciale host.docker.internal, che si risolve nell'indirizzo IP interno utilizzato dall'host. Questo è a scopo di sviluppo e non funzionerà in un ambiente di produzione al di fuori di Docker Desktop per Mac.


1
Si prega di non aggiungere la stessa risposta a più domande . Rispondi a quello migliore e contrassegna il resto come duplicati, una volta guadagnata una reputazione sufficiente. Se non è un duplicato, adatta il post alla domanda e contrassegna l'annullamento.
Bhargav Rao

6

Docker per Mac Voglio connettermi da un contenitore a un servizio sull'host

L'host ha un indirizzo IP che cambia (o nessuno se non si ha accesso alla rete). Dal 18.03 in poi la nostra raccomandazione è quella di connettersi al nome DNS speciale host.docker.internal, che si risolve nell'indirizzo IP interno utilizzato dall'host.

Il gateway è anche raggiungibile come gateway.docker.internal. https://docs.docker.com/docker-for-mac/networking/#use-cases-and-workarounds


5

Se hai abilitato l' API remota docker (tramite ad esempio) e conosci il nome host o l'indirizzo IP della macchina host, questo può essere fatto con molta bash.-Htcp://0.0.0.0:4243

All'interno dell'utente del mio container bashrc:

export hostIP=$(ip r | awk '/default/{print $3}')
export containerID=$(awk -F/ '/docker/{print $NF;exit;}' /proc/self/cgroup)
export proxyPort=$(
  curl -s http://$hostIP:4243/containers/$containerID/json |
  node -pe 'JSON.parse(require("fs").readFileSync("/dev/stdin").toString()).NetworkSettings.Ports["DESIRED_PORT/tcp"][0].HostPort'
)

La seconda riga prende l'ID contenitore dal tuo /proc/self/cgroupfile locale .

La terza riga si arriccia sul computer host (supponendo che tu stia utilizzando 4243 come porta della finestra mobile) quindi usa il nodo per analizzare il JSON restituito per il DESIRED_PORT.


Questo vale solo quando si utilizza il port forwarding. In effetti HostPortpossono essere utili informazioni qui, sfortunatamente HostIppotrebbero essere0.0.0.0
Arnout Engelen,

4

Ho Ubuntu 16.03. Per me

docker run --add-host dockerhost:`/sbin/ip route|awk '/default/ { print  $3}'` [image]

non non funziona (IP errato è stato generando)

La mia soluzione di lavoro era che:

docker run --add-host dockerhost:`docker network inspect --format='{{range .IPAM.Config}}{{.Gateway}}{{end}}' bridge` [image]

3

Ecco un'altra opzione per coloro che eseguono Docker in AWS. Questa opzione evita di usare apk per aggiungere il pacchetto arricciatura e salva il prezioso spazio 7mb. Usa il wget integrato (parte del binario monolitico BusyBox):

wget -q -O - http://169.254.169.254/latest/meta-data/local-ipv4

3

AFAIK, nel caso di Docker per Linux (distribuzione standard), l'indirizzo IP dell'host sarà sempre 172.17.0.1 .

Il modo più semplice per ottenerlo è tramite ifconfig(interfaccia docker0) dall'host:

ifconfig

Dall'interno di una finestra mobile, il seguente comando da una finestra mobile: ip -4 route show default | cut -d" " -f3

È possibile eseguirlo rapidamente in una finestra mobile con la seguente riga di comando:

# 1. Run an ubuntu docker
# 2. Updates dependencies (quietly)
# 3. Install ip package   (quietly)
# 4. Shows (nicely) the ip of the host
# 5. Removes the docker (thanks to `--rm` arg)
docker run -it --rm ubuntu:19.10 bash -c "apt-get update && apt-get install iproute2 -y && ip -4 route show default | cut -d' ' -f3"

Spero possa essere d'aiuto.


2

In Linux puoi eseguire

HOST_IP=`hostname -I | awk '{print $1}'`

In macOS il tuo computer host non è l'host Docker. Docker installerà il suo SO host in VirtualBox.

HOST_IP=`docker run busybox ping -c 1 docker.for.mac.localhost | awk 'FNR==2 {print $4}' | sed s'/.$//'`

1
Il primo blocco di codice prenderà l'IP del contenitore e non l'IP dell'host
Ari,

mandato di hostname -Iavvertire di non "fare ipotesi sull'ordine dell'output".
cannot_mutably_borrow il

1

Questa è un'implementazione minimalista in Node.js per chi esegue l'host su istanze AWS EC2 , utilizzando l' istanza di metadati EC2 sopra menzionata

const cp = require('child_process');
const ec2 = function (callback) {
    const URL = 'http://169.254.169.254/latest/meta-data/local-ipv4';
    // we make it silent and timeout to 1 sec
    const args = [URL, '-s', '--max-time', '1'];
    const opts = {};
    cp.execFile('curl', args, opts, (error, stdout) => {
        if (error) return callback(new Error('ec2 ip error'));
        else return callback(null, stdout);
    })
        .on('error', (error) => callback(new Error('ec2 ip error')));
}//ec2

e usato come

ec2(function(err, ip) {
        if(err) console.log(err)
        else console.log(ip);
    })


0

Ecco come lo faccio. In questo caso, aggiunge una voce hosts in / etc / hosts all'interno dell'immagine docker che punta taurus-host al mio IP di macchina locale::

TAURUS_HOST=`ipconfig getifaddr en0`
docker run -it --rm -e MY_ENVIRONMENT='local' --add-host "taurus-host:${TAURUS_HOST}" ...

Quindi, all'interno del contenitore Docker, lo script può utilizzare il nome host taurus-host per uscire dal mio computer locale che ospita il contenitore docker.



0

La soluzione che utilizzo si basa su un "server" che restituisce l'indirizzo esterno dell'host Docker quando riceve una richiesta http.

Sul "server":

1) Avvia jwilder / nginx-proxy

# docker run -d -p <external server port>:80 -v /var/run/docker.sock:/tmp/docker.sock:ro jwilder/nginx-proxy

2) Avviare il contenitore ipify

# docker run -e VIRTUAL_HOST=<external server name/address> --detach --name ipify osixia/ipify-api:0.1.0

Ora quando un container invia una richiesta http al server, ad es

# curl http://<external server name/address>:<external server port>

l'indirizzo IP dell'host Docker viene restituito da ipify tramite l'intestazione http "X-Forwarded-For"

Esempio (il server ipify ha il nome "ipify.example.com" e funziona sulla porta 80, l'host docker ha IP 10.20.30.40):

# docker run -d -p 80:80 -v /var/run/docker.sock:/tmp/docker.sock:ro jwilder/nginx-proxy
# docker run -e VIRTUAL_HOST=ipify.example.com --detach --name ipify osixia/ipify-api:0.1.0

All'interno del contenitore ora puoi chiamare:

# curl http://ipify.example.com
10.20.30.40


-2

Su Ubuntu, il hostnamecomando può essere utilizzato con le seguenti opzioni:

  • -i, --ip-address indirizzi per il nome host
  • -I, --all-ip-addressestutti gli indirizzi per l'host

Per esempio:

$ hostname -i
172.17.0.2

Per assegnare alla variabile, è possibile utilizzare la seguente riga singola:

IP=$(hostname -i)

Questo ti darà l'indirizzo IP del container Docker, non dell'host
Mario Camou,

-7

Con https://docs.docker.com/machine/install-machine/

a) $ docker-machine ip

b) Ottieni l'indirizzo IP di una o più macchine.

  $ docker-machine ip host_name

  $ docker-machine ip host_name1 host_name2

10
In questo modo viene recuperato l'IP della macchina virtuale che esegue i contenitori della finestra mobile, non l'IP dell'host in cui sono in esecuzione i contenitori.
Spencer Williams

2
Questo vale solo per la finestra mobile in esecuzione sulla finestra mobile. La nuova finestra mobile per mac non funziona sulla finestra mobile.
Thomas.
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.