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




subir ejecutar (15)

Entonces tengo un Nginx corriendo dentro de un contenedor docker, tengo un mysql corriendo en localhost, quiero conectarme al MySql desde mi Nginx. El MySql se ejecuta en localhost y no está exponiendo un puerto al mundo exterior, por lo que está vinculado en localhost, no en la dirección IP de la máquina.

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


Answers

Edit: terminé haciendo un prototipo del concepto en GitHub. Echa un vistazo a: 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 del host no funciona en una Mac. Debe utilizar un alias de IP, consulte: https://stackoverflow.com/a/43541681/2713729

¿Qué es un modo de red host? Consulte: 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 pronto estaré actualizando a 16.04 LTS en producción), , puede hacer que el servicio que se ejecuta dentro de un contenedor Docker se conecte a los servicios de localhost el host Docker (por ejemplo, su computadora portátil).

¿Cómo?

La clave es cuando ejecutas el contenedor Docker, debes ejecutarlo con el modo de host . El comando se ve así:

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

Cuando realice un ifconfig (necesitará apt-get install net-tools su contenedor para que el ifconfig sea ​​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 bajo 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 host localhost .


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.localhost para resolver la IP interna. (Advertencia algunas fuentes mencionan windows pero debería ser win )

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

El Azure Storage Emulator escucha de forma predeterminada el 127.0.0.1 , mientras que también puede cambiar la IP de su límite, estaba buscando una solución que funcionara con la configuración predeterminada.

Esto también funciona para conectar desde mi contenedor Docker a SQL Server e IIS , ambos ejecutándose localmente en mi host con la configuración de puerto predeterminada.


No estoy de acuerdo con la respuesta de Thomasleveil.

Hacer que mysql se enlace a 172.17.42.1 evitará que otros programas utilicen la base de datos en el host para alcanzarlo. Esto solo funcionará si todos los usuarios de la base de datos están acoplados.

Hacer que mysql se una a 0.0.0.0 abrirá el db 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. Dice explícitamente "El MySql se está ejecutando en localhost y no está exponiendo un puerto al mundo exterior, por lo que está vinculado a localhost"

Para responder el comentario de ivant.

"¿Por qué no enlazar 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 se puede enlazar a 0, 1 o todas las interfaces.

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


Estoy haciendo un truco similar a las publicaciones anteriores de obtener la IP local para asignar un nombre de alias (DNS) en el contenedor. El principal problema es obtener dinámicamente con un script simple que funciona tanto en Linux como en OSX, la dirección IP del host . Hice este script que funciona en ambos entornos (incluso en la distribución de 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, utilizando 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://localhost a http://dockerhost en su código.

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


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

  • configurar el servidor mysql local para acceso público mediante el 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 usuario root acceda a cualquier host mysql -uroot -proot GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION; FLUSH PRIVILEGES; mysql -uroot -proot GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION; FLUSH PRIVILEGES;

  • crear sh script: run_docker.sh

    #!bin/bash

    HOSTIP=`ip -4 addr show scope global dev eth0 | grep inet | awk '{print \$2}' | cut -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 DATABASE_USER=root \
                  -e DATABASE_PASSWORD=root \
                  sopheamak/springboot_docker_mysql

  
  • correr con docker-compositor

    version: '2.1'
    
    

    services:
    tomcatwar: extra_hosts: - "local:10.1.2.232" image: sopheamak/springboot_docker_mysql
    ports: - 8080:8080 environment: - DATABASE_HOST=local - DATABASE_USER=root - DATABASE_PASSWORD=root - DATABASE_NAME=demo - DATABASE_PORT=3306


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

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

  1. Habilitar route_localnet para la interfaz docker0:
    $ sysctl -w net.ipv4.conf.docker0.route_localnet=1
  2. Agrega 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 '%' que significa - 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 núcleo :

route_localnet - BOOLEAN: no considere las direcciones de bucle invertido como origen o destino marciano mientras enruta. Esto permite el uso de 127/8 para propósitos de enrutamiento local ( valor predeterminado FALSO ).


Puedes obtener la ip del host usando imagen alpina

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

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

Similar a la respuesta de Mariano, puedes 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

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


Esto me funcionó en una pila NGINX / PHP-FPM sin tocar ningún código o red en la que la aplicación solo espera poder conectarse a localhost

Monte mysqld.sock desde el host al interior del contenedor.

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

Monte ese archivo a 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

Edición: 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 .

A partir de Docker 18.04, esto no funciona en Docker para Linux.

TLDR

Use --network="host" en su comando de docker run --network="host" docker run , luego 127.0.0.1 en su contenedor de la ventana acoplable apuntará a su host de la ventana acoplable.

Nota sobre los modos de red de contenedores docker

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

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

Docker crea un puente denominado docker0 de forma predeterminada. Tanto el host de la ventana acoplable como los contenedores de la ventana acoplable tienen una dirección IP en ese puente.

en el host de Docker, escriba sudo ip addr show docker0 tendrá una salida con el siguiente aspecto:

[[email protected]:~] $ 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.1 en la interfaz de red docker0 .

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

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

[email protected]:/# route
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         172.17.42.1     0.0.0.0         UG    0      0        0 eth0
172.17.0.0      *               255.255.0.0     U     0      0        0 eth0

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

[email protected]:/# ping 172.17.42.1
PING 172.17.42.1 (172.17.42.1) 56(84) bytes of data.
64 bytes from 172.17.42.1: icmp_seq=1 ttl=64 time=0.070 ms
64 bytes from 172.17.42.1: icmp_seq=2 ttl=64 time=0.201 ms
64 bytes from 172.17.42.1: icmp_seq=3 ttl=64 time=0.116 ms

docker run --network = "host"

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

Tenga en cuenta que cualquier puerto abierto en el contenedor de la ventana acoplable se abrirá en el host de la ventana acoplable. Y esto sin requerir la opción de docker run -P docker run -p o -P .

Configuración de IP en mi host docker:

[[email protected]:~] $ 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 docker en modo host :

[[email protected]:~] $ 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, el host de la ventana acoplable y el contenedor de la ventana acoplable comparten exactamente la misma interfaz de red y, como tal, tienen la misma dirección IP.

Conexión a MySQL desde contenedores

Modo Puente

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

Para hacerlo, asegúrese de tener bind-address = 172.17.42.1 o bind-address = 0.0.0.0 en su archivo de configuración de 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 variable de entorno DOCKER_HOST_IP para abrir la conexión a MySQL.

Nota: si usa bind-address = 0.0.0.0 su 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 de firewall en consecuencia.

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

modo host

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

[[email protected]:~] $ 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: use mysql -h 127.0.0.1 y no mysql -h localhost ; de lo contrario, el cliente MySQL intentaría conectarse utilizando un socket Unix.


La solución más simple para Mac OSX

Solo usa la dirección IP de tu Mac. En la Mac, ejecute esto para obtener la dirección IP y utilícela desde dentro del contenedor:

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

Mientras el servidor que se ejecuta localmente en su Mac o en otro contenedor de la ventana acoplable escuche 0.0.0.0, el contenedor de la ventana acoplable podrá comunicarse con esa dirección.

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


Para macOS y Windows

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

Use su dirección IP interna o conéctese al nombre de DNS especial host.docker.internal que se resolverá con la dirección IP interna que usa 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.internal en docker.for.mac.host.internal lugar.

Docker para Mac v 17.06 a v 17.11

Igual que el anterior, pero usa docker.for.mac.localhost en docker.for.mac.localhost lugar.

Docker para Mac 17.05 e inferior

Para acceder a la máquina host desde el contenedor de la ventana acoplable, debe adjuntar un alias de IP a su interfaz de red. Puede enlazar cualquier 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.

Luego simplemente apunte su contenedor de la ventana acoplable a esta IP y podrá acceder a la máquina host

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

El alias se reiniciará 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


Puede usar ngrok para crear un túnel seguro para su máquina localhost y luego exponer ese túnel a su contenedor docker.

ngrok es de uso gratuito a partir del 22/05/2017.

Pasos:

1) ir a ngrok

2) download el cliente ngrok y siga las instrucciones de instalación

3) INSCRÍBASE para obtener una cuenta y le proporcionarán un token de autenticación. Es necesario registrarse porque ngrok solo le otorga el túnel de puerto tcp después de registrarse. No hay costo o tarjeta de crédito requerida para registrarse.

4) En su terminal haga ngrok tcp 3306 . 3306 es el puerto que mysql ejecuta en mi local, también puede hacerlo con cualquier otro puerto.

5) Recibirá una dirección del paso 4 como esta: tcp://0.tcp.ngrok.io:10117 . Esta es la conexión del túnel a su máquina local. 0.tcp.ngrok.io se asigna a su 0.tcp.ngrok.io localhost y el puerto 10117 se asigna a su puerto 3306 local. Ahora puede acceder a su puerto localhost 3306 desde cualquier lugar con esta dirección, incluido cualquier contenedor acoplable que se ejecute en esta máquina. En su contenedor docker (donde sea que esté), asumiendo que ya tiene instalado el cliente mysql, haga lo siguiente:

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

¡Podrá iniciar sesión en su cuenta root de su máquina local desde dentro del contenedor de la ventana acoplable!

He blogeado sobre esta solución, vea más detalles here


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. El 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 el 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 y una interfaz únicas.

$ docker run -it alpine ifconfig

Al cambiar el espacio de nombres a host, las redes de cotainers no permanecen aisladas en 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 otros procesos 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

Esta es una mala práctica para hacer esto en producción porque está saliendo del modelo de seguridad del contenedor, lo que podría abrirse a vulnerabilidades y un fácil acceso a la escucha. Esto es solo para las herramientas de depuración y para subestimar las lagunas en la seguridad de los contenedores.

El primer contenedor es el servidor nginx. Esto creará una nueva red y espacio de nombres de proceso. Este contenedor se vinculará 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 la misma manera, puede conectarse a mysql en el host, ejecutar y depurar su aplicación. Pero, no es recomendable ir por este camino. Espero eso ayude.


Para agregar a la solución iptables respuesta aceptada , tuve que ejecutar dos comandos más en el host para abrirlo al mundo exterior.

HOST> iptables -t nat -A DOCKER -p tcp --dport 443 -j DNAT --to-destination 172.17.0.2:443
HOST> iptables -t nat -A POSTROUTING -j MASQUERADE -p tcp --source 172.17.0.2 --destination 172.17.0.2 --dport https
HOST> iptables -A DOCKER -j ACCEPT -p tcp --destination 172.17.0.2 --dport https

Nota: estaba abriendo el puerto https (443), mi IP interna de la 172.17.0.2 acoplable era 172.17.0.2

Nota 2: Estas reglas son temporales y solo durarán hasta que se reinicie el contenedor





nginx docker reverse-proxy docker-networking