Desde el interior de un contenedor Docker, ¿cómo me conecto al host local de la máquina?


1455

Así que tengo un Nginx ejecutándose dentro de un contenedor docker, tengo un mysql ejecutándose en localhost, quiero conectarme a MySql desde mi Nginx. MySql se ejecuta en localhost y no expone un puerto al mundo exterior, por lo que está vinculado a localhost, no a la dirección IP de la máquina.

¿Hay alguna forma de conectarse a este MySql o cualquier otro programa en localhost desde este contenedor acoplable?

Esta pregunta es diferente de "Cómo obtener la dirección IP del host acoplable desde el interior de un contenedor acoplable" debido al hecho de que la dirección IP del host acoplador podría ser la IP pública o la privada en la red que puede o no no se puede acceder desde el contenedor de Docker (me refiero a IP pública si está alojado en AWS o algo así). Incluso si tiene la dirección IP del host docker, no significa que pueda conectarse al host docker desde el contenedor dado que la dirección IP puede estar superpuesta, host, bridge, macvlan, ninguno, etc., lo que restringe la accesibilidad de esa dirección IP


¿Por qué no vincular mysql a docker0 también?
ivant

2
Para máquinas Windows: - $ docker run -d --name MyWebServer -P httpd
Lokesh S


1
Sin network: hostti no puedes volver de un contenedor al host. Solo host al contenedor. Esta es la ideología principal detrás de los contenedores. Están aislados por razones de estabilidad y seguridad.
FreeSoftwareServers

Respuestas:


1974

Editar: Si está utilizando Docker-for-mac o Docker-for-Windows 18.03+, simplemente conéctese a su servicio mysql utilizando el host host.docker.internal(en lugar de 127.0.0.1en la cadena de conexión).

A partir de Docker 18.09.3, esto no funciona en Docker-for-Linux. Se presentó una solución el 8 de marzo de 2019 y, con suerte, se fusionará con la base del código. Hasta entonces, una solución alternativa es usar un contenedor como se describe en la respuesta de qoomon .

2020-01: se han realizado algunos progresos . Si todo va bien, esto debería aterrizar en Docker 20.04


TLDR

Úselo --network="host"en su docker runcomando, luego 127.0.0.1en su contenedor docker apuntará a su host docker.

Nota: Este modo solo funciona en Docker para Linux, según la documentación .


Nota sobre los modos de red del contenedor Docker

Docker ofrece diferentes modos de red cuando se ejecutan contenedores. Dependiendo del modo que elija, se conectaría a su base de datos MySQL que se ejecuta en el host docker de manera diferente.

docker run --network = "bridge" (predeterminado)

Docker crea un puente nombrado docker0por defecto. Tanto el host del acoplador como los contenedores del acoplador tienen una dirección IP en ese puente.

en el host Docker, escriba sudo ip addr show docker0tendrá una salida similar a:

[vagrant@docker:~] $ sudo ip addr show docker0
4: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> 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

Así que aquí mi host docker tiene la dirección IP 172.17.42.1en la docker0interfaz de red.

Ahora inicie un nuevo contenedor y obtenga un shell en él: docker run --rm -it ubuntu:trusty bashy dentro del tipo de contenedor ip addr show eth0para descubrir cómo está configurada su interfaz de red principal:

root@e77f6a1b3740:/# ip addr show eth0
863: eth0: <BROADCAST,UP,LOWER_UP> 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

Aquí mi contenedor tiene la dirección IP 172.17.1.192. Ahora mira la tabla de enrutamiento:

root@e77f6a1b3740:/# 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

Por lo tanto, la dirección IP del host docker 172.17.42.1se establece como la ruta predeterminada y se puede acceder desde su contenedor.

root@e77f6a1b3740:/# 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

docker run --network = "host"

Alternativamente, puede ejecutar un contenedor acoplable con la configuración de red establecida enhost . Dicho contenedor compartirá la pila de red con el host del acoplador y, desde el punto de vista del contenedor, localhost(o 127.0.0.1) se referirá al host del acoplador.

Tenga en cuenta que cualquier puerto abierto en su contenedor Docker se abriría en el host Docker. Y esto sin requerir la opción -pu-P docker run .

Configuración de IP en mi host docker:

[vagrant@docker:~] $ ip addr show eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> 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

y desde un contenedor acoplable en modo host :

[vagrant@docker:~] $ docker run --rm -it --network=host ubuntu:trusty ip addr show eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> 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

Como puede ver, tanto el host Docker como el contenedor Docker comparten exactamente la misma interfaz de red y, como tales, tienen la misma dirección IP.


Conectarse a MySQL desde contenedores

Modo Puente

Para acceder a MySQL que se ejecuta en el host acoplable desde contenedores en modo puente , debe asegurarse de que el servicio MySQL esté escuchando las conexiones en la 172.17.42.1dirección IP.

Para hacerlo, asegúrese de tener uno bind-address = 172.17.42.1o bind-address = 0.0.0.0su archivo de configuración MySQL (my.cnf).

Si necesita establecer una variable de entorno con la dirección IP de la puerta de enlace, puede ejecutar el siguiente código en un contenedor:

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

luego, en su aplicación, use la DOCKER_HOST_IPvariable de entorno para abrir la conexión a MySQL.

Nota: si usa bind-address = 0.0.0.0su servidor MySQL, escuchará las conexiones en todas las interfaces de red. Eso significa que se puede acceder a su servidor MySQL desde Internet; asegúrese de configurar las reglas del firewall en consecuencia.

Nota 2: si usa bind-address = 172.17.42.1su servidor MySQL no escuchará las conexiones realizadas 127.0.0.1. Los procesos que se ejecutan en el host docker que desearían conectarse a MySQL tendrían que usar la 172.17.42.1dirección IP.

modo host

Para acceder a MySQL que se ejecuta en el host de Docker desde contenedores en modo host , puede mantener bind-address = 127.0.0.1su configuración de MySQL y todo lo que necesita hacer es conectarse 127.0.0.1desde sus contenedores:

[vagrant@docker:~] $ docker run --rm -it --network=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: usar mysql -h 127.0.0.1y no mysql -h localhost; de lo contrario, el cliente MySQL intentaría conectarse utilizando un socket Unix.


8
¡Gracias por una respuesta tan detallada! Por lo que he reunido, usar el modo host es la única forma de obtener esta funcionalidad a través de localhost. No lo he intentado, pero supongo que podría crear una red separada para conectar contenedores a través de su propio puente ofreciéndoles un 'localhost' común.
Ben

26
Nota para usuarios de OSX: primero inicie sesión en su máquina virtual docker (boot2docker), usando "docker-machine ssh default", luego ejecute "sudo ip addr show docker0". Continúa con las instrucciones de Thomas desde allí.
Charlie Dalsass 01 de

30
Estoy ejecutando Docker para Mac, y ya no hay 172.17.42.1, ya no hay docker0. Era 172.17.0.1 como puerta de enlace, y ni siquiera puedetelnet 172.17.0.1 3306
zx1986

26
Puede montar el socket mysql en el contenedor en lugar de redes como -v /var/run/mysqld/mysqld.sock:/tmp/mysql.sockesta.
chx

8
¿Alguien puede abordar la situación cuando ejecuta Docker en Mac y no utiliza boot2docker como tal, no hay una interfaz docker0?
TheJKFever

350

Para macOS y Windows

Docker v 18.03 y superior (desde el 21 de marzo de 2018)

Utilice su dirección IP interna o conéctese al nombre DNS especial host.docker.internalque se resolverá en la dirección IP interna utilizada por el host.

Soporte de Linux pendiente https://github.com/docker/for-linux/issues/264

MacOS con versiones anteriores de Docker

Docker para Mac v 17.12 a v 18.02

Igual que el anterior, pero use docker.for.mac.host.internalen su lugar.

Docker para Mac v 17.06 a v 17.11

Igual que el anterior, pero use docker.for.mac.localhosten su lugar.

Docker para Mac 17.05 y versiones inferiores

Para acceder a la máquina host desde el contenedor acoplable, debe adjuntar un alias de IP a su interfaz de red. Puede vincular la IP que desee, solo asegúrese de no usarla para nada más.

sudo ifconfig lo0 alias 123.123.123.123/24

Luego, asegúrese de que su servidor esté escuchando la IP mencionada anteriormente o 0.0.0.0. Si está escuchando en localhost 127.0.0.1, no aceptará la conexión.

¡Entonces solo apunte su contenedor acoplable a esta IP y podrá acceder a la máquina host!

Para probar puede ejecutar algo como curl -X GET 123.123.123.123:3000dentro del contenedor.

El alias se restablecerá en cada reinicio, así que cree un script de inicio si es necesario.

Solución y más documentación aquí: https://docs.docker.com/docker-for-mac/networking/#use-cases-and-workarounds


55
genial y gracias, esto funcionó para mí desde dentro del contenedor. mysql -uroot -hdocker.for.mac.localhost
Richard Frank

1
docker.for.mac.localhost es exactamente lo que estaba buscando. Pero esto es sucio como el infierno al mismo tiempo. EN docker, uno esperaría que el hook docker.for.mac.localhost sería un nombre interno genérico de docker que sería válido para cualquier sistema operativo, no solo para Mac. Pero para fines de desarrollo esto es lo suficientemente bueno.
99Sono

¿Cómo accedo a un puerto que está expuesto en digamos 9093? Estoy tratando de hacer telnet docker.for.mac.localhost 9093. Es inalcanzable pero si hago ping a docker.for.mac.localhost, es accesible. ¿Me estoy perdiendo algo aquí?
Achilleus

1
Se debe usar el nombre DNS docker.for.mac.host.internal en lugar de docker.for.mac.localhost (aún válido) para la resolución del host desde los contenedores, ya que existe un RFC que prohíbe el uso de subdominios de localhost. Ver tools.ietf.org/html/draft-west-let-localhost-be-localhost-06 .
Jya

Esto no funciona para mi. Cuando yo docker run -e HOSTNAME= docker.for.mac.host.internal , el contenedor se crea pero no sucede nada. Entonces tengo que crtl + C. Con --net=host -e HOSTNAME=localhostal menos el contenedor se ejecuta y se queja de que no puede encontrar el servicio que necesito (MySQL db).
Jorge Orpinel

83

Estoy haciendo un truco similar a las publicaciones anteriores para obtener la IP local para asignar a un nombre de alias (DNS) en el contenedor. El principal problema es obtener dinámicamente con un script simple que funcione tanto en Linux como en OSX la dirección IP del host . Hice este script que funciona en ambos entornos (incluso en distribución Linux con "$LANG" != "en_*"configurado):

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

Entonces, usando Docker Compose, la configuración completa será:

Script de inicio (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"

Luego cambie http://localhosta http://dockerhosten su código.

Para obtener una guía más avanzada sobre cómo personalizar el DOCKERHOSTscript, eche un vistazo a esta publicación con una explicación de cómo funciona.


1
Dependiendo de su caso de uso, incluso podría salirse con la suya usando el DOCKERHOSTvalor aquí en lugar de "localhost" o 0.0.0.0 en cualquier servicio al que su contenedor acoplable necesite conectarse localmente.
enderland

2
He modificado ligeramente su solución para que sea compatible con redes personalizadas: export DOCKERHOST=$(docker network inspect --format='{{range .IPAM.Config}}{{.Gateway}}{{end}}' <NETWORK-NAME> | awk -F "/" 'NR==1{print $1}') donde <NETWORK-NAME> podría ser bridge o el nombre de la red según lo definido por docker-compose (generalmente nombre de ruta - nombre_de_redicación ).
dieresys

1
Debe agregar un comentario: utilícelo dockerhostcomo host para la conexión de base de datos (generalmente, reemplácelo localhosten el archivo de configuración).
Justin

solución extraña, pero es la única que hace que xdebug funcione bajo docker con php cli
Eddie

Acl dejó de funcionar después de esta solución en haproxy. ¿Alguna idea de por qué?
HyukHyukBoi

41

Esto funcionó para mí en una pila NGINX / PHP-FPM sin tocar ningún código o red donde la aplicación solo espera poder conectarse localhost

Montar mysqld.sockdesde el host al interior del contenedor.

Encuentre la ubicación del archivo mysql.sock en el host que ejecuta mysql:
netstat -ln | awk '/mysql(.*)?\.sock/ { print $9 }'

Monte ese archivo donde se espera en la ventana acoplable:
docker run -v /hostpath/to/mysqld.sock:/containerpath/to/mysqld.sock

Posibles ubicaciones de 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

2
Esta es una solución mucho más limpia, que no expone Mysql al exterior (si no usa un firewall).
user1226868

55
Los sockets no se escalan tan bien como TCP porque se bloquean con más frecuencia y pueden causar un comportamiento extraño. Use TCP siempre que sea posible.
Joel E Salas

3
@JoelESalas ¿Tiene una fuente para ese reclamo?
Privado

He encontrado que esta es la solución más fácil. ¡Pulgares arriba user833482! Debería contribuir con más frecuencia a StackOverflow.
Privado

2
@ JoelESalas Creo que te equivocas. La biblioteca del cliente mysql incluso usa sockets de Unix por defecto cuando se conecta a localhost en lugar de hacer una conexión a localhost. Un socket Unix evita la sobrecarga de la pila TCP y el enrutamiento, y debería ejecutarse más rápido.
M Conrad

25

Hasta host.docker.internalque funcione para cada plataforma, puede usar mi contenedor actuando como una puerta de enlace NAT sin ninguna configuración manual:

https://github.com/qoomon/docker-host


55
Puedo confirmar que esto no funciona en Docker para Windows 19.03.2 con el contenedor de Windows.
KMC

¿Alguna idea de como arreglarlo? (No soy un usuario de Windows)
qoomon

Si su entorno no bloquea el uso de puerto mysql, puede referirse al servidor por el nombre de la computadora que está alojado. Entonces, en su cadena de conexión, use el nombre de su computadora como nombre del servidor.
KMC

24

Solución para Linux (kernel> = 3.6).

Ok, su servidor localhost tiene la interfaz docker predeterminada docker0 con la dirección IP 172.17.0.1 . Su contenedor comenzó con la configuración de red predeterminada --net = "bridge" .

  1. Habilite route_localnet para la interfaz docker0:
    $ sysctl -w net.ipv4.conf.docker0.route_localnet=1
  2. Agregue estas reglas 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. Cree un usuario mysql con acceso desde '%', es decir, desde cualquier persona, excluyendo localhost:
    CREATE USER 'user'@'%' IDENTIFIED BY 'password';
  4. Cambie en su script la dirección del servidor mysql a 172.17.0.1


De la documentación del kernel :

route_localnet - BOOLEAN: no considere las direcciones de bucle invertido como origen o destino marciano durante el enrutamiento. Esto permite el uso de 127/8 para fines de enrutamiento local ( predeterminado FALSO ).


1
¿Cuál es el propósito del segundo comando iptable? Puedo entender que el primero es reescribir todos los destinos tcp que coinciden con 172.17.0.1:3306 a 127.0.0.1:3306, pero ¿por qué es necesario el segundo comando iptable?
Patrick

17

Solución para Windows 10

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

Puede usar el nombre DNS del host docker.for.win.localhostpara resolver la IP interna. (Advertencia algunas fuentes mencionadas windowspero debería ser win)

Descripción general
Necesitaba hacer algo similar, es decir, conectarme desde mi contenedor Docker a mi host local, que ejecutaba el Azure Storage Emulatory CosmosDB Emulator.

Por Azure Storage Emulatordefecto, escucha en 127.0.0.1 , aunque también puede cambiar la dirección IP, estaba buscando una solución que funcionara con la configuración predeterminada.

Esto también funciona para conectarse desde mi contenedor Docker a , SQL Servery IISambos se ejecutan localmente en mi host con la configuración de puerto predeterminada.


13

Muy simple y rápido, verifique la IP de su host con ifconfig (linux) o ipconfig (windows) y luego cree un

docker-compose.yml

version: '3' # specify docker-compose version

services:
  nginx:
    build: ./ # specify the directory of the Dockerfile
    ports:
      - "8080:80" # specify port mapping
    extra_hosts:
      - "dockerhost:<yourIP>"

De esta manera, su contenedor podrá acceder a su host. Al acceder a su base de datos, recuerde usar el nombre que especificó anteriormente, en este caso "dockerhost" y el puerto de su host en el que se ejecuta la base de datos


En HaProxy, esta solución ha dejado de funcionar en las acl por alguna razón, solo funciona la configuración predeterminada.
HyukHyukBoi

1
La única solución que funciona en un sistema Linux. +1
Rafik Farhad

11

Ninguna de las respuestas funcionó para mí cuando usé Docker Toolbox en Windows 10 Home, pero 10.0.2.2 sí, ya que usa VirtualBox que expone el host a la VM en esta dirección.


2
Funciona. Incluso no es necesario especificar --network = host. parece que 10.0.2.2 está configurado como una IP predeterminada para el host. Gracias.
TheManish

Pero, ¿puedo usar esta IP estática para todas las versiones de Windows y Mac ?, ¿cómo puedo manejarla para múltiples plataformas mediante script?
151291

Esto funcionó para mí. Simplemente ejecute ipconfig en su host (windows) y obtenga la dirección IP enEthernet adapter vEthernet (DockerNAT)
Kihats

10

Para aquellos en Windows, suponiendo que esté utilizando el controlador de red de puente, querrá vincular específicamente MySQL a la dirección IP de la interfaz de red Hyper-V.

Esto se realiza a través del archivo de configuración en la carpeta C: \ ProgramData \ MySQL normalmente oculta.

El enlace a 0.0.0.0 no funcionará. La dirección necesaria también se muestra en la configuración de la ventana acoplable, y en mi caso fue 10.0.75.1.


3
Te mereces una medalla! He estado trabajando en esto durante dos días completos. ¡Gracias por ayudar!
Michael

1
También estuve trabajando en esto durante dos días completos. Este es el único lugar en la web que he encontrado mencionado. Microsoft no dice nada al respecto cuando habla de conectarse a MSSQL desde un contenedor Docker. ¡Te hace preguntarte si alguna vez lo hicieron funcionar ellos mismos!
Contango

8

Editar: terminé creando prototipos del concepto en GitHub. Echa un vistazo: https://github.com/sivabudh/system-in-a-box


Primero, mi respuesta está dirigida a 2 grupos de personas: aquellos que usan una Mac y aquellos que usan Linux.

El modo de red host no funciona en una Mac. Debe usar un alias de IP, consulte: https://stackoverflow.com/a/43541681/2713729

¿Qué es un modo de red host? Ver: https://docs.docker.com/engine/reference/run/#/network-settings

En segundo lugar, para aquellos de ustedes que están usando Linux (mi experiencia directa fue con Ubuntu 14.04 LTS y estoy actualizando a 16.04 LTS en producción pronto), , pueden hacer que el servicio que se ejecuta dentro de un contenedor Docker se conecte a los localhostservicios que se ejecutan en el Docker host (por ejemplo, su computadora portátil).

¿Cómo?

La clave es que cuando ejecuta el contenedor Docker, debe ejecutarlo con el modo host . El comando se ve así:

docker run --network="host" -id <Docker image ID>

Cuando haga un ifconfig(necesitará que apt-get install net-toolssu contenedor ifconfigsea ​​invocable) dentro de su contenedor, verá que las interfaces de red son las mismas que las del host Docker (por ejemplo, su computadora portátil).

Es importante tener en cuenta que soy un usuario de Mac, pero ejecuto Ubuntu en Parallels, por lo que usar una Mac no es una desventaja. ;-)

Y así es como se conecta el contenedor NGINX al MySQL que se ejecuta en un localhost.


1
Es importante tener en cuenta que el modo host ofrece un mejor rendimiento, ya que utiliza la pila de red del sistema operativo.
sivabudh

2
Muy buen punto allí. Aunque ES posible conectarse desde un contenedor a un servicio host con conexión de IP no utilizada docs.docker.com/docker-for-mac/networking . No es una solución agradable ... pero funciona.
Xavier Huppé

Cosas buenas aquí. Una vez dentro del contenedor con --network="host", ¿cómo se conecta uno al host mysql, por ejemplo?
Michael

1
@Buccleuch Solo usa localhost. Consulte mi código fuente de GitHub: github.com/sivabudh/system-in-a-box/blob/master/dj_host_docker/… . Busque 'HOST', verá 127.0.0.1 para conectarse a Postgresql.
sivabudh

Pude obtener acceso a las bases de datos mysql del host montando el volumen según @ user833482 y, por supuesto, después de instalar mysql-client y server en el contenedor docker.
Michael

7

La solución más simple para Mac OSX

Simplemente use la dirección IP de su Mac. En Mac, ejecute esto para obtener la dirección IP y usarla desde el contenedor:

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

Mientras el servidor que se ejecuta localmente en su Mac o en otro contenedor acoplable esté escuchando 0.0.0.0, el contenedor acoplable podrá comunicarse con esa dirección.

Si solo desea acceder a otro contenedor acoplable que está escuchando en 0.0.0.0, puede usar 172.17.0.1


1
Docker para Mac expone el docker.for.mac.host.internalnombre de host ahora.
Matt

5

Esta no es una respuesta a la pregunta real. Así es como resolví un problema similar. La solución proviene totalmente de: Definir la red de contenedores Docker para que los contenedores puedan comunicarse . Gracias a Nic Raboy

Dejando esto aquí para otros que quieran hacer llamadas REST entre un contenedor y otro. Responde a la pregunta: ¿qué usar en lugar de localhost en un entorno acoplable?

Obtenga cómo se ve su red docker network ls

Crea una nueva red docker network create -d my-net

Comience el primer contenedor docker run -d -p 5000:5000 --network="my-net" --name "first_container" <MyImage1:v0.1>

Consulte la configuración de red para el primer contenedor docker inspect first_container. "Redes": debería tener 'my-net'

Comience el segundo contenedor docker run -d -p 6000:6000 --network="my-net" --name "second_container" <MyImage2:v0.1>

Consulte la configuración de red para el segundo contenedor docker inspect second_container. "Redes": debería tener 'my-net'

ssh en su segundo contenedor docker exec -it second_container sho docker exec -it second_container bash.

Dentro del segundo contenedor, puede hacer ping al primer contenedor ping first_container. Además, sus llamadas de código como http://localhost:5000pueden ser reemplazadas porhttp://first_container:5000


Exactamente lo que estaba buscando. Gracias: D
Simar Singh

5

Para ventanas,

He cambiado la URL de la base de datos en la configuración de primavera: spring.datasource.url=jdbc:postgresql://host.docker.internal:5432/apidb

Luego construye la imagen y corre. Funcionó para mi.


interesante ...
Phil

para mí no funciona Tengo mac e intento desde un contenedor php para conectarse a localhost mysql. Alguna idea ?
A. Zalonis

4

No estoy de acuerdo con la respuesta de Thomasleveil.

Hacer que mysql se vincule a 172.17.42.1 evitará que otros programas usen la base de datos en el host para llegar a él. Esto solo funcionará si todos los usuarios de su base de datos están acoplados.

Hacer que mysql se una a 0.0.0.0 abrirá la base de datos al mundo exterior, lo que no solo es algo muy malo, sino también contrario a lo que el autor de la pregunta original quiere hacer. Él dice explícitamente "MySql se ejecuta en localhost y no expone un puerto al mundo exterior, por lo que está vinculado a localhost"

Para responder el comentario de ivant

"¿Por qué no vincular mysql a docker0 también?"

Esto no es posible. La documentación de mysql / mariadb dice explícitamente que no es posible enlazar a varias interfaces. Solo puede enlazar a 0, 1 o todas las interfaces.

Como conclusión, NO he encontrado ninguna manera de llegar a la base de datos (solo localhost) en el host desde un contenedor acoplable. Eso definitivamente parece un patrón muy común, pero no sé cómo hacerlo.


44
desde el host docker, aún puede conectarse al servidor MySQL utilizando la 172.17.42.1dirección. Pero su nota es correcta de lo contrario. host127.0.0.1
Además

no, como dije, no puedes conectarte a 172.17.42.1 si mysql está vinculado a localhost.
orzel

44
"Hacer que mysql se vincule a 172.17.42.1 evitará que otros programas usen la base de datos en el host para llegar a él". - eso no es verdad. Otros programas pueden usar mysql, solo tienen que conectarse a 172.17.42.1 en lugar de localhost / 127.0.0.1.
0x89

La solución al problema en esta respuesta generalmente es hacer que el servidor MySQL se enlace 0.0.0.0y luego configure un firewall para que no se pueda acceder a la base de datos desde Internet.
halfer

4

Aquí está mi solución: funciona para mi caso

  • configura el servidor mysql local para acceso público por comentario #bind-address = 127.0.0.1 en /etc/mysql/mysql.conf.d

  • reiniciar el servidor mysql sudo /etc/init.d/mysql restart

  • ejecute el siguiente comando para abrir el acceso raíz del usuario a cualquier host mysql -uroot -proot GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION; FLUSH PRIVILEGES;

  • crear script sh: run_docker.sh

    #! bin / bash

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


      docker run -it -d --name web-app \
                  --add-host = local: $ {HOSTIP} \
                  -p 8080: 8080 \
                  -e DATABASE_HOST = $ {HOSTIP} \
                  -e DATABASE_PORT = 3306 \
                  -e DATABASE_NAME = demo \
                  -e BASE DE DATOS_USUARIO = root \
                  -e DATABASE_PASSWORD = root \
                  sopheamak / springboot_docker_mysql

  
  • correr con docker-compositor

    versión: '2.1'

    servicios:
    tomcatwar: extra_hosts: - "local: 10.1.2.232" imagen: sopheamak / springboot_docker_mysql
    puertos: - 8080: 8080 medio ambiente: - DATABASE_HOST = local - DATABASE_USER = root - DATABASE_PASSWORD = root - DATABASE_NAME = demo - DATABASE_PORT = 3306


4

Se me ocurren varias soluciones:

  1. Mueva sus dependencias a contenedores primero
  2. Haga que sus otros servicios sean accesibles externamente y conéctese a ellos con esa IP externa
  3. Ejecute sus contenedores sin aislamiento de red
  4. Evite conectarse a través de la red, utilice un zócalo montado como volumen

La razón por la que esto no funciona es que los contenedores se ejecutan con su propio espacio de nombres de red de forma predeterminada. Eso significa que localhost (o 127.0.0.1 apuntando a la interfaz loopback) es único por contenedor. Conectarse a esto se conectará al contenedor en sí y no a los servicios que se ejecutan fuera de la ventana acoplable o dentro de un contenedor de ventana acoplable diferente.

Opción 1 : si su dependencia se puede mover a un contenedor, lo haría primero. Hace que su pila de aplicaciones sea portátil mientras otros intentan ejecutar su contenedor en su propio entorno. Y aún puede publicar el puerto en su host donde otros servicios que no se han migrado aún pueden llegar a él. Incluso puede publicar el puerto en la interfaz localhost en su host docker para evitar que sea accesible externamente con una sintaxis como: -p 127.0.0.1:3306:3306para el puerto publicado.

Opción 2 : hay una variedad de formas de detectar la dirección IP del host desde el interior del contenedor, pero cada una tiene un número limitado de escenarios donde funcionan (por ejemplo, requieren Docker para Mac). La opción más portátil es inyectar su IP de host en el contenedor con algo así como una variable de entorno o un archivo de configuración, por ejemplo:

docker run --rm -e "HOST_IP=$(ip r s 0/0 | awk '{print $3}')" ...

Esto requiere que su servicio esté escuchando en esa interfaz externa, lo que podría ser un problema de seguridad. Para otros métodos para obtener la dirección IP del host desde el interior del contenedor, consulte esta publicación .

Opción 3 : ejecutar sin aislamiento de red, es decir, ejecutar con --net host, significa que su aplicación se ejecuta en el espacio de nombres de la red host. Esto es menos aislamiento para el contenedor, y significa que no puede acceder a otros contenedores a través de una red acoplada compartida con DNS (en su lugar, debe usar puertos publicados para acceder a otras aplicaciones en contenedores). Pero para las aplicaciones que necesitan acceder a otros servicios en el host que solo escuchan 127.0.0.1en el host, esta puede ser la opción más fácil.

Opción 4 : varios servicios también permiten el acceso a través de un socket basado en un sistema de archivos. Este zócalo se puede montar en el contenedor como un volumen montado de enlace, lo que le permite acceder al servicio de host sin pasar por la red. Para acceder al motor del acoplador, a menudo ve ejemplos de montaje /var/run/docker.socken el contenedor (que le da acceso a la raíz del contenedor al host). Con mysql, puede probar algo como -v /var/run/mysqld/mysqld.sock:/var/run/mysqld/mysql.socky luego conectarse a lo localhostque mysql convierte para usar el socket.


3

Puede obtener la ip del host usando la imagen alpina

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

Esto sería más consistente ya que siempre está usando alpine para ejecutar el comando.

Similar a la respuesta de Mariano, puede usar el mismo comando para establecer una variable de entorno

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

3

Para Linux, donde no puede cambiar la interfaz a la que se une el servicio localhost

Hay dos problemas que necesitamos resolver

  1. Obtener la IP del host
  2. Hacer que nuestro servicio localhost esté disponible para Docker

El primer problema se puede resolver utilizando la imagen docker-host de qoomon , como lo dan otras respuestas.

Deberá agregar este contenedor a la misma red de puente que su otro contenedor para poder acceder a él. Abra una terminal dentro de su contenedor y asegúrese de poder hacer ping dockerhost.

bash-5.0# ping dockerhost
PING dockerhost (172.20.0.2): 56 data bytes
64 bytes from 172.20.0.2: seq=0 ttl=64 time=0.523 ms

Ahora, el problema más difícil es hacer que el servicio sea accesible para Docker.

Podemos usar telnet para verificar si podemos acceder a un puerto en el host (es posible que deba instalarlo).

El problema es que nuestro contenedor solo podrá acceder a servicios que se unen a todas las interfaces, como SSH:

bash-5.0# telnet dockerhost 22
SSH-2.0-OpenSSH_7.6p1 Ubuntu-4ubuntu0.3

Pero los servicios vinculados solo a localhost serán inaccesibles:

bash-5.0# telnet dockerhost 1025
telnet: can't connect to remote host (172.20.0.2): Connection refused

La solución adecuada aquí sería vincular el servicio a la red de puentes de Dockers. Sin embargo, esta respuesta supone que no es posible cambiar esto. Entonces, en su lugar, usaremos iptables.

En primer lugar, tenemos que encontrar el nombre de la red de puente que se está utilizando con ventana acoplable ifconfig. Si está utilizando un puente sin nombre, esto será así docker0. Sin embargo, si está utilizando una red con nombre, tendrá un puente que comienza con br-ese acoplador que utilizará en su lugar. El mío es br-5cd80298d6f4.

Una vez que tengamos el nombre de este puente, debemos permitir el enrutamiento desde este puente a localhost. Esto está deshabilitado de forma predeterminada por razones de seguridad:

sysctl -w net.ipv4.conf.<bridge_name>.route_localnet=1

Ahora para configurar nuestra iptablesregla. Dado que nuestro contenedor solo puede acceder a los puertos en la red de Docker Bridge, vamos a pretender que nuestro servicio está realmente vinculado a un puerto en esta red.

Para hacer esto, enviaremos todas las solicitudes <docker_bridge>:portalocalhost:port

iptables -t nat -A PREROUTING -p tcp -i <docker_bridge_name> --dport <service_port> -j DNAT --to-destination 127.0.0.1:<service_port>

Por ejemplo, para mi servicio en el puerto 1025

iptables -t nat -A PREROUTING -p tcp -i br-5cd80298d6f4 --dport 1025 -j DNAT --to-destination 127.0.0.1:1025

Ahora debería poder acceder a su servicio desde el contenedor:

bash-5.0# telnet dockerhost 1025
220 127.0.0.1 ESMTP Service Ready

1
Esto es lo mismo que @ ray-d ha mencionado anteriormente, pero está bien explicado. ¡Gracias! Además, al usar docker-compose, también tuve que agregar una regla DNAT en la cadena PREROUTING para todos los paquetes que llegan a la interfaz docker0: porque, docker-compose parece estar usando docker0 durante las compilaciones (sorprendentemente): sysctl -w net.ipv4.conf.docker0.route_localnet=1yiptables -t nat -A PREROUTING -p tcp -i docker0 --dport 1025 -j DNAT --to-destination 127.0.0.1:1025
arvindd

3

¡Necesitas conocer la puerta de entrada ! Mi solución con el servidor local fue exponerlo debajo 0.0.0.0:8000, luego ejecutar docker con subred y ejecutar contenedor como:

docker network create --subnet=172.35.0.0/16 --gateway 172.35.0.1 SUBNET35
docker run -d -p 4444:4444 --net SUBNET35 <container-you-want-run-place-here>

Entonces, ahora puedes acceder a tu loopback a través de http://172.35.0.1:8000


3

Prueba esto:

version: '3.5'
services:
  yourservice-here:
    container_name: container_name
    ports:
      - "4000:4000"
    extra_hosts: # <---- here
      - localhost:192.168.1.202
      - or-vitualhost.local:192.168.1.202

Para obtener 192.168.1.202, utilizaifconfig

Esto funcionó para mí. ¡Espero que esto ayude!


2

Los CGroups y los espacios de nombres están jugando un papel importante en el ecosistema de contenedores.

El espacio de nombres proporciona una capa de aislamiento. Cada contenedor se ejecuta en un espacio de nombres separado y su acceso está limitado a ese espacio de nombres. Cgroups controla la utilización de recursos de cada contenedor, mientras que Namespace controla lo que un proceso puede ver y acceder al recurso respectivo.

Aquí está la comprensión básica del enfoque de solución que podría seguir,

Usar espacio de nombres de red

Cuando un contenedor se genera fuera de la imagen, se define y crea una interfaz de red. Esto le da al contenedor una dirección IP e interfaz únicas.

$ docker run -it alpine ifconfig

Al cambiar el espacio de nombres a host, las redes cotainers no quedan aisladas de su interfaz, el proceso tendrá acceso a la interfaz de red de las máquinas host.

$ docker run -it --net=host alpine ifconfig

Si el proceso escucha en los puertos, se escucharán en la interfaz del host y se asignarán al contenedor.

Usar el espacio de nombres PID Al cambiar el espacio de nombres Pid, ​​un contenedor puede interactuar con otro proceso más allá de su alcance normal.

Este contenedor se ejecutará en su propio espacio de nombres.

$ docker run -it alpine ps aux

Al cambiar el espacio de nombres al host, el contenedor también puede ver todos los demás procesos que se ejecutan en el sistema.

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

Compartir espacio de nombres

Es una mala práctica hacer esto en producción porque está rompiendo el modelo de seguridad del contenedor que podría abrir vulnerabilidades y facilitar el acceso a espías. Esto es solo para depurar herramientas y subestimar las lagunas en la seguridad del contenedor.

El primer contenedor es el servidor nginx. Esto creará una nueva red y procesará el espacio de nombres. Este contenedor se unirá al puerto 80 de la interfaz de red recién creada.

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

Otro contenedor ahora puede reutilizar este espacio de nombres,

$ docker run --net=container:http mohan08p/curl curl -s localhost

Además, este contenedor puede ver la interfaz con los procesos en un contenedor compartido.

$ docker run --pid=container:http alpine ps aux

Esto le permitirá otorgar más privilegios a los contenedores sin cambiar o reiniciar la aplicación. De manera similar, puede conectarse a mysql en el host, ejecutar y depurar su aplicación. Pero, no es recomendable ir por este camino. Espero eso ayude.


1

Para la máquina de Windows: -

Ejecute el siguiente comando para exponer el puerto acoplable al azar durante el tiempo de compilación

$docker run -d --name MyWebServer -P mediawiki

ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

En la lista de contenedores anterior puede ver el puerto asignado como 32768. Intente acceder

localhost:32768 

Puedes ver la página de mediawiki


55
Aunque esta respuesta puede proporcionar información útil para algunos usuarios, ¡es al revés ! Se trata de acceder a un servicio que se ejecuta en el contenedor desde la máquina host. Sin embargo, la pregunta era sobre el acceso a un servicio que se ejecuta en el host desde el contenedor.
Einjohn

1

Hasta que el arreglo no se fusione en la masterrama, para obtener la IP del host simplemente ejecute desde el interior del contenedor:

ip -4 route list match 0/0 | cut -d' ' -f3

(como lo sugiere @Mahoney aquí ).


1

Lo resolví creando un usuario en MySQL para la ip del contenedor:

$ sudo mysql<br>
mysql> create user 'username'@'172.17.0.2' identified by 'password';<br>
Query OK, 0 rows affected (0.00 sec)

mysql> grant all privileges on database_name.* to 'username'@'172.17.0.2' with grant option;<br>
Query OK, 0 rows affected (0.00 sec)

$ sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf
<br>bind-address        = 172.17.0.1

$ sudo systemctl restart mysql.service

Luego en el contenedor: jdbc:mysql://<b>172.17.0.1</b>:3306/database_name


Esta es la solución más simple. Me ha funcionado y me he referido a muchos
Sopia Alfred

-1

La forma en que lo hago es pasar la IP del host como variable de entorno al contenedor. El contenedor luego accede al host por esa variable.


¿Puedes ilustrar cómo haces esto?
Intenté

`docker run -i -t -e HOST = 10.145.2.123 ubuntu root @ ce2a843da3ee: / tmp # ./telnet $ HOST 22 Intentando 10.145.2.123 ... Conectado a 10.145.2.123. El carácter de escape es '^]'. SSH-2.0-OpenSSH_7.4`
F. Kam
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.