Cómo obtener la dirección IP del host acoplable desde un contenedor acoplable

358

Como dice el título. Necesito poder recuperar la dirección IP que alojan los docker y los mapas de puertos del host al contenedor, y hacerlo dentro del contenedor.

xiamx
fuente
¿Podría explicar cómo le gustaría utilizar esta información? Dijiste "hosts docker": ¿estás ejecutando Docker en más de un host? Una vez que su contenedor conozca la dirección IP del host y los mapas de puertos, ¿qué hará?
Andy
La forma más sencilla de pasar las direcciones IP del host del acoplador al contenedor del acoplador, creo que debería hacer una llamada dentro del contenedor utilizando 'docker container exec'. Suponga que desea hacer ping al host desde el contenedor busybox, use por ejemplo: $ IP = '8.8.8.8' && docker container busybox ping $ IP 'La forma de averiguar la IP del host, use lo que más le guste.
SauloAlessandre

Respuestas:

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

Como notó @MichaelNeale, no tiene sentido usar este método Dockerfile(excepto cuando necesitamos esta IP solo durante el tiempo de compilación), porque esta IP se codificará durante el tiempo de compilación.

spinus
fuente
49
Cuando utiliza el puente acoplable (predeterminado) para los contenedores, esto generará la IP de los puentes como 172.17.42.1 en lugar de la IP del host como 192.168.1.x (supongo que su host está en un NAT doméstico). Usar la respuesta de @Magno Torres es probablemente lo que la gente quiere en tales situaciones si desea la dirección 192.168.1.x.
Programador
2
ese RUN no funcionará como espera, solo calculará la IP en el momento de la compilación, y será siempre estático después de eso, y no será útil. Será la IP del host de compilación.
Michael Neale
77
@Programster, puedo suponer que la gente quiere la conexión entre el host Docker y el contenedor, eso es lo que el IP del puente puede brindarle (por supuesto, en la instalación estándar "doméstica"). ¿Por qué alguien necesitaría una IP de host "real" si puede estar incluso fuera del Docker Bridge y puede ser inaccesible? Esta es la solución para todas las personas que acaban de instalar Docker y quieren jugar con ella en poco tiempo.
spinus
1
@MichaelNeale, como antes, supondría que la mayoría de las personas que están comenzando con Docker necesitan una conexión entre su host y el contenedor, eso es todo. Si alguien está haciendo implementaciones "adecuadas", probablemente no esté usando Docker Bridge de todos modos, está usando redes personalizadas y probablemente esté al tanto de todas las peculiaridades de la red o tenga DNS (o cualquier descubrimiento) configurado.
spinus
1
@spinus, pero esto solo será válido si se ejecuta en el host en el que se creó, en ese caso, solo puede codificarlo o buscarlo, creo que no es una respuesta útil y engañará mucho de personas: te recomiendo que lo quites. (The RUN bit)
Michael Neale
182

A partir de la versión 18.03, puede usar host.docker.internalcomo IP del host.

Funciona en Docker para Mac , Docker para Windows y quizás también en otras plataformas.

Esta es una actualización específica de Mac docker.for.mac.localhost, disponible desde la versión 17.06 y docker.for.mac.host.internaldisponible desde la versión 17.12, que también puede funcionar en esa plataforma.

Tenga en cuenta que, como en la documentación de Mac y Windows , esto es solo para fines de desarrollo.

Por ejemplo, tengo variables de entorno establecidas en mi host:

MONGO_SERVER=host.docker.internal

En mi docker-compose.ymlarchivo, tengo esto:

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
arándano
fuente
2
@allanberry desafortunadamente, la gente de Docker prefiere no darnos una forma independiente de la plataforma para hacer esto porque prefieren no aceptar casos de uso involuntario (como acceder a cualquier servicio en la máquina local desde un contenedor de Docker)
Andy
21
Me presentaron a Docker como Build it once, ejecutarlo en todas partes. Pero esto es extremadamente falso, ya que siempre tiene que configurar el sistema host también. Por docker.for.mac..lo tanto, es inútil ya que en la mayoría de los casos no tiene un entorno solo para Linux o Mac en su empresa. Es mixto, tienes desarrolladores que usan Linux, Mac y Windows. Este dominio no tiene sentido ya que en el 99% es un entorno de sistema operativo host mixto. No desarrollo un contenedor en macOS y lo implemento en un servidor macOS. Lo implemento en Linux. Esto es lo que todos hacen. Entonces, ¿cuál es el punto docker.for.mac..?
TheFox
1
@allanberry docker.for.mac.host.internalno importa si está utilizando Docker con o sin docker-compose. Quiero usar un host fijo en los archivos de configuración. IDK, por ejemplo, docker.host.internalque siempre apunta a la dirección IP del host. Independientemente del sistema host que esté usando. Este es el objetivo de usar Docker: quiero ser autónomo. Entiendo que es aún más complicado en macOS porque tienes otra capa entre el sistema host y el contenedor. Pero de todos modos, en mi opinión docker.for.mac.host.internales inútil si solo puedes usarlo para macOS.
TheFox
1
host.docker.internal también funciona en Docker para Windows , al menos al momento de escribir este comentario.
joanlofe
1
esto funciona perfectamente, tengo dockerCe para Windows y ejecutando jenkins en uno de los contenedores. Quería ejecutar el comando docker dentro de jenkins, pero docker no pudo conectarse en el paso agregar una nube, utilicé este tcp: //host.docker.internal: 2375 y habilité 'exponer daemon en localhost: 2375' y funciona. ahorrado mucho tiempo ¡Gracias!
Vikash
84

Actualización: en Docker para Mac , a partir de la versión 18.03, puede usar host.docker.internal como la IP del host. Ver la respuesta de allanberry . Para versiones anteriores de Docker para Mac, la siguiente respuesta puede ser útil:

En Docker para Mac, el docker0puente no existe, por lo que otras respuestas aquí pueden no funcionar. Sin embargo, todo el tráfico saliente se enruta a través de su host principal, por lo que siempre que intente conectarse a una IP, se reconocerá como sí mismo (y el contenedor del acoplador no cree que sea él mismo), debería poder conectarse. Por ejemplo, si ejecuta esto desde la máquina principal, ejecute:

ipconfig getifaddr en0

Esto debería mostrarle la IP de su Mac en su red actual y su contenedor Docker también debería poder conectarse a esta dirección. Por supuesto, esto es un problema si esta dirección IP cambia alguna vez, pero puede agregar una IP de bucle invertido personalizada a su Mac que el contenedor no cree que sea en sí misma al hacer algo como esto en la máquina principal:

sudo ifconfig lo0 alias 192.168.46.49

Luego puede probar la conexión desde el contenedor acoplable con telnet. En mi caso, quería conectarme a un servidor xdebug remoto:

telnet 192.168.46.49 9000

Ahora, cuando el tráfico ingresa a su Mac con la dirección 192.168.46.49 (y todo el tráfico que sale de su contenedor pasa a través de su Mac), su Mac asumirá que la IP es en sí misma. Cuando termine de usar esta IP, puede eliminar el alias de bucle invertido como este:

sudo ifconfig lo0 -alias 192.168.46.49

Una cosa a tener en cuenta es que el contenedor de la ventana acoplable no enviará tráfico al host principal si cree que el destino del tráfico es él mismo. Por lo tanto, compruebe la interfaz de bucle invertido dentro del contenedor si tiene problemas:

sudo ip addr show lo

En mi caso, esto mostró lo inet 127.0.0.1/8que significa que no podía usar ninguna IP en el 127.*rango. Es por eso que usé 192.168.*en el ejemplo anterior. Asegúrese de que la IP que usa no entre en conflicto con algo en su propia red.

Code Commander
fuente
¿limpiará estas configuraciones de bucle de retorno después de reiniciar el sistema?
Robbo_UK
@Robbo_UK Sí, el alias de bucle invertido desaparecerá después de reiniciar su Mac.
Code Commander
1
El uso de este nombre de host no tiene sentido ya que no funciona en Docker para Linux. ¿Por qué no lo agregaron también para Linux?
TheFox
Lo están investigando en este momento @TheFox: github.com/docker/libnetwork/pull/2348
Ivo Pereira
46

Para aquellos que ejecutan Docker en AWS, los metadatos de instancia para el host todavía están disponibles desde el interior del contenedor.

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

Por ejemplo:

$ 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
Nate Fox
fuente
Este es un método súper conveniente para quienes usan AWS. Lo uso para configurar las direcciones de enlace y cliente de los agentes de Consul. Es ideal cuando se encuentra en situaciones en las que no puede utilizar la red de host (como implementar contenedores en Elastic Beanstalk y ECS).
Richard Clayton
Esto es un salvavidas, gracias. Estaba teniendo problemas para descubrir cómo manejar la comunicación entre contenedores en mi clúster ECS.
Brennan
En Phusion basimage (basado en ubuntu), tuve que cambiar un poco su comando:ifconfig eth0 | grep -oP 'inet \K\S+'
Meuoi
25

La única forma es pasar la información del host como entorno cuando crea un contenedor

run --env <key>=<value>
Magno Torres
fuente
19
Más específicamente, la dirección IP del puente se puede pasar usando una opción de línea de comando como: -e "DOCKER_HOST=$(ip -4 addr show docker0 | grep -Po 'inet \K[\d.]+')"(usando la respuesta aceptada de unix.stackexchange.com/questions/87468/… )
ncoghlan
77
Creo que no funciona en Docker para Mac / Windows. (la IP del puente)
zx1986
22

El --add-hostpodría ser una solución más limpia (pero sin la parte de puerto, sólo el anfitrión puede ser manejado con esta solución). Entonces, bajo tu docker runmando, haz algo como:

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

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

Augunrik
fuente
Dije "hecho para esto" cuando alguien más quería una entrada en / etc / hosts; en esta pregunta no es realmente cierto. También OP solicitó "host y portmaps" y solo ha cubierto el host.
Bryan
Okay. Estaba un poco confundido ya que la solución aceptada solo cubre la parte del host también. Y creo que su solución es superior a la de spinus.
Augunrik
esto no funciona si quieres usar dind - docker-in-docker. La ventana acoplable interna tendrá una IP diferente
ruidosa
12

La mejor práctica estándar para la mayoría de las aplicaciones que buscan hacer esto automáticamente es: no lo hace . En su lugar, haga que la persona que ejecuta el contenedor inyecte un nombre de host externo / dirección IP como configuración, por ejemplo, como una variable de entorno o un archivo de configuración. Permitir que el usuario inyecte esto le brinda el diseño más portátil.

¿Por qué sería tan difícil? Debido a que los contenedores, por diseño, aislarán la aplicación del entorno del host. La red tiene un espacio de nombres solo para ese contenedor de forma predeterminada, y los detalles del host están protegidos del proceso que se ejecuta dentro del contenedor, que puede no ser totalmente confiable.


Existen diferentes opciones según su situación específica:

Si su contenedor se está ejecutando con redes de host, puede mirar la tabla de enrutamiento en el host directamente para ver la ruta predeterminada. De esta pregunta, lo siguiente funciona para mí, por ejemplo:

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

Un ejemplo que muestra esto con la red de host en un contenedor se ve así:

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

Para algunas versiones de Docker Desktop, inyectaron una entrada DNS en la VM incorporada:

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

Si está ejecutando en un entorno de nube, puede verificar el servicio de metadatos del proveedor de la nube, por ejemplo, el de AWS:

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

Si desea su dirección externa / de internet, puede consultar un servicio remoto como:

curl ifconfig.co

Cada uno de estos tiene limitaciones y solo funciona en escenarios específicos. La opción más portátil aún es ejecutar su contenedor con la dirección IP inyectada como configuración, por ejemplo, aquí hay una opción que ejecuta el ipcomando anterior en el host y lo inyecta como una variable de entorno:

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
BMitch
fuente
curl ifconfig.coComando realmente útil ... Gracias :)
MadAboutProgramming
8

Si desea una IPdirección real (no un puente IP) Windowsy tiene docker 18.03(o más reciente), haga lo siguiente:

Ejecute bash en el contenedor desde el host donde está el nombre de la imagen nginx(funciona Alpine Linux distribution):

 docker run -it nginx /bin/ash

Luego corre dentro del contenedor

/ # nslookup host.docker.internal

Name:      host.docker.internal
Address 1: 192.168.65.2

192.168.65.2es la IP del host, no la IP del puente como en la spinusrespuesta aceptada.

Estoy usando aquí host.docker.internal :

El host tiene una dirección IP cambiante (o ninguna si no tiene acceso a la red). A partir del 18.03 en adelante, nuestra recomendación es conectarse al nombre DNS especial host.docker.internal, que se resuelve en la dirección IP interna utilizada por el host. Esto es para fines de desarrollo y no funcionará en un entorno de producción fuera de Docker para Windows.

Kamil Witkowski
fuente
2
Intenté su solución y parece que no se puede encontrar el comando nslookup
Sergey
@Sergey ¿Se basa su imagen Alpine Linux? Si no, entonces verifique el equivalente para su específico linux distribution.
Kamil Witkowski
No, uso exactamente su comando - docker run -it nginx / bin / ash
Sergey
Ok, si está en Windows, entonces cambié a linux containersy no estoy usando windows containers. Puede hacerlo haciendo clic derecho en docker icony seleccionando Switch to Linux containers. Creo que eso podría ser importante cuando estás descargando una imagen. Si ha windows containercomprobado si al eliminar una nginximagen anterior y descargarla nuevamente obtendrá otro contenedor. Si aún así no funciona, puede intentar instalarlo nslookupen el ash.
Kamil Witkowski
Si no puede hacer nslookup, simplemente haga ping. Mostrará la IP resuelta. Para mí, esta respuesta funciona, y solo estoy usando este nombre de host ( host.docker.internal) desde el interior del contenedor
Dmitry Minkovsky
7

TLDR para Mac y Windows

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

... imprime la dirección IP del host ...

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

Name:      host.docker.internal
Address 1: 192.168.65.2

Detalles

En Mac y Windows , puede usar el nombre DNS especial host.docker.internal.

El host tiene una dirección IP cambiante (o ninguna si no tiene acceso a la red). A partir del 18.03 en adelante, nuestra recomendación es conectarse al nombre DNS especial host.docker.internal, que se resuelve en la dirección IP interna utilizada por el host. Esto es para fines de desarrollo y no funcionará en un entorno de producción fuera de Docker Desktop para Mac.

Nick Grealy
fuente
1
Por favor no agregue la misma respuesta a múltiples preguntas . Responda al mejor y marque el resto como duplicados, una vez que gane suficiente reputación. Si no es un duplicado, adapte la publicación a la pregunta y marque la opción de eliminación.
Bhargav Rao
6

Docker para Mac Quiero conectarme desde un contenedor a un servicio en el host

El host tiene una dirección IP cambiante (o ninguna si no tiene acceso a la red). A partir del 18.03 en adelante, nuestra recomendación es conectarse al nombre DNS especial host.docker.internal, que se resuelve en la dirección IP interna utilizada por el host.

También se puede acceder a la puerta de enlace como gateway.docker.internal. https://docs.docker.com/docker-for-mac/networking/#use-cases-and-workarounds

BSCheshir
fuente
5

Si habilitó la API remota de Docker (a través de, por ejemplo) y conoce el nombre de host o la dirección IP de la máquina host, esto se puede hacer con mucho bash.-Htcp://0.0.0.0:4243

Dentro del usuario de mi contenedor 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 segunda línea toma la ID del contenedor de su /proc/self/cgrouparchivo local .

La tercera línea se enrolla en la máquina host (suponiendo que esté utilizando 4243 como puerto del acoplador) y luego usa el nodo para analizar el JSON devuelto para el DESIRED_PORT.

ICas
fuente
Esto solo se aplica cuando utiliza el reenvío de puertos. De hecho, HostPortpuede ser información útil aquí, desafortunadamente HostIppodría ser0.0.0.0
Arnout Engelen
4

Tengo Ubuntu 16.03. Para mi

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

no no trabajar (ip estaba generando mal)

Mi solución de trabajo fue que:

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

Aquí hay otra opción para aquellos que ejecutan Docker en AWS. Esta opción evita tener que usar apk para agregar el paquete de rizos y ahorra los preciosos 7mb de espacio. Use el wget incorporado (parte del binario monolítico BusyBox):

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

AFAIK, en el caso de Docker para Linux (distribución estándar), la dirección IP del host siempre será 172.17.0.1 .

La forma más fácil de obtenerlo es a través de ifconfig(interface docker0) desde el host:

ifconfig

Desde el interior de una ventana acoplable, el siguiente comando desde una ventana acoplable: ip -4 route show default | cut -d" " -f3

Puede ejecutarlo rápidamente en una ventana acoplable con la siguiente línea de 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"

Espero que ayude.

Nek
fuente
2

En linux puedes correr

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

En macOS, su máquina host no es el host Docker. Docker instalará su sistema operativo host en VirtualBox.

HOST_IP=`docker run busybox ping -c 1 docker.for.mac.localhost | awk 'FNR==2 {print $4}' | sed s'/.$//'`
Aref Aslani
fuente
1
El primer bloque de código tomará la IP del contenedor y no la IP del host
Ari
mandoc de hostname -Iadvierte que no "haga suposiciones sobre el orden de la salida".
cannot_mutably_borrow
1

Esta es una implementación minimalista en Node.js para quién ejecuta el host en instancias de AWS EC2 , utilizando la instancia de metadatos de EC2 mencionada anteriormente.

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

y usado como

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

Si está ejecutando un contenedor de Windows en un clúster de Service Fabric, la dirección IP del host está disponible a través de la variable de entorno Fabric_NodeIPOrFQDN. Variables de entorno de Service Fabric

Aaron Marten
fuente
0

Así es como lo hago. En este caso, agrega una entrada de hosts en / etc / hosts dentro de la imagen del acoplador apuntando taurus-host a la IP de mi máquina local:

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

Luego, desde el contenedor Docker, el script puede usar el nombre de host taurus-host para acceder a mi máquina local que aloja el contenedor docker.

djangofan
fuente
0

La solución que uso se basa en un "servidor" que devuelve la dirección externa del host Docker cuando recibe una solicitud http.

En el "servidor":

1) Inicie jwilder / nginx-proxy

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

2) Inicie el contenedor ipify

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

Ahora, cuando un contenedor envía una solicitud http al servidor, p. Ej.

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

ipify devuelve la dirección IP del host Docker a través del encabezado http "X-Fordered-For"

Ejemplo (el servidor ipify tiene el nombre "ipify.example.com" y se ejecuta en el puerto 80, el host docker tiene 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

Dentro del contenedor ahora puede llamar:

# curl http://ipify.example.com
10.20.30.40
ramazotto
fuente
0

Prueba esto

docker run --rm -i --net = host ifconfig alpino

Oleksandr Dudnyk
fuente
-2

En Ubuntu, el hostnamecomando se puede usar con las siguientes opciones:

  • -i, --ip-address direcciones para el nombre de host
  • -I, --all-ip-addressestodas las direcciones para el host

Por ejemplo:

$ hostname -i
172.17.0.2

Para asignar a la variable, se puede usar la siguiente línea:

IP=$(hostname -i)
kenorb
fuente
Esto le dará la dirección IP del contenedor Docker, no del host
Mario Camou
-7

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

a) $ docker-machine ip

b) Obtenga la dirección IP de una o más máquinas.

  $ docker-machine ip host_name

  $ docker-machine ip host_name1 host_name2
kalyani chaudhari
fuente
10
Esto recupera la IP de la máquina virtual que ejecuta los contenedores acoplables, no la IP del host en el que se ejecutan los contenedores.
Spencer Williams
2
Esto solo se aplica a docker que se ejecuta en docker-machine. El nuevo docker para mac no se ejecuta en la máquina docker.
thomas.han