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.
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.
Risposte:
/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.
A partire dalla versione 18.03, è possibile utilizzare host.docker.internal
come 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.internal
disponibile 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.yml
file, 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
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..
?
docker.for.mac.host.internal
non importa se stai usando Docker con o senza docker-compose
. Voglio usare un host fisso nei file di configurazione. IDK, ad esempio, docker.host.internal
che 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.
host.docker.internal
funziona anche su Docker per Windows , almeno al momento della stesura di questo commento.
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 docker0
bridge 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/8
che 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.
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
ifconfig eth0 | grep -oP 'inet \K\S+'
L'unico modo è passare le informazioni sull'host come ambiente quando si crea un contenitore
run --env <key>=<value>
-e "DOCKER_HOST=$(ip -4 addr show docker0 | grep -Po 'inet \K[\d.]+')"
(utilizzando la risposta accettata da unix.stackexchange.com/questions/87468/… )
Il --add-host
potrebbe essere una soluzione più pulito (ma senza la parte della porta, solo l'host può essere maneggiato con questa soluzione). Quindi, al tuo docker run
comando, fai qualcosa del tipo:
docker run --add-host dockerhost:`/sbin/ip route|awk '/default/ { print $3}'` [my container]
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 ip
comando 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.co
Comando davvero utile .. Grazie :)
Se desideri un IP
indirizzo reale (non un bridge IP
) Windows
e 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 spinus
risposta 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.
Alpine Linux
? In caso contrario, controlla l'equivalente per il tuo specifico linux distribution
.
linux containers
e non sto usando windows containers
. Puoi farlo facendo clic con il tasto destro docker icon
e selezionando Switch to Linux containers
. Penso che potrebbe essere importante quando si scarica l'immagine. Se avessi windows container
verificato se l'eliminazione di una vecchia nginx
immagine e il suo nuovo download ti offriranno un altro contenitore. Se ancora non funziona per te, allora puoi provare a installarlo nslookup
in ash
.
host.docker.internal
) dall'interno del contenitore
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
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.
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
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.-H
tcp://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/cgroup
file 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
.
HostPort
possono essere utili informazioni qui, sfortunatamente HostIp
potrebbero essere0.0.0.0
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]
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
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.
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'/.$//'`
hostname -I
avvertire di non "fare ipotesi sull'ordine dell'output".
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);
})
Se si esegue un contenitore Windows su un cluster di Service Fabric, l'indirizzo IP dell'host è disponibile tramite la variabile di ambiente Fabric_NodeIPOrFQDN
. Variabili d'ambiente di Service Fabric
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.
Forse anche il contenitore che ho creato è utile https://github.com/qoomon/docker-host
È possibile semplicemente utilizzare il nome contenitore dns per accedere al sistema host, ad esempio curl http: // dockerhost: 9200 , quindi non è necessario seccarsi con nessun indirizzo IP.
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
Prova questo
docker run --rm -i --net = host alpine ifconfig
Su Ubuntu, il hostname
comando può essere utilizzato con le seguenti opzioni:
-i
, --ip-address
indirizzi per il nome host-I
, --all-ip-addresses
tutti gli indirizzi per l'hostPer esempio:
$ hostname -i
172.17.0.2
Per assegnare alla variabile, è possibile utilizzare la seguente riga singola:
IP=$(hostname -i)
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