Permitir que el contenedor docker se conecte a una base de datos local / host de postgres

143

Recientemente he estado jugando con Docker y QGIS y he instalado un contenedor siguiendo las instrucciones de este tutorial .

Todo funciona muy bien, aunque no puedo conectarme a una base de datos localhost postgres que contiene todos mis datos SIG. Supongo que esto se debe a que mi base de datos postgres no está configurada para aceptar conexiones remotas y he estado editando los archivos conf de postgres para permitir conexiones remotas utilizando las instrucciones de este artículo .

Todavía recibo un mensaje de error cuando intento conectarme a mi base de datos que ejecuta QGIS en Docker: no se pudo conectar al servidor: Connection refused Is the server running on host "localhost" (::1) and accepting TCP/IP connections to port 5433? el servidor postgres se está ejecutando y he editado mi archivo pg_hba.conf para permitir conexiones de un rango de Direcciones IP (172.17.0.0/32). Anteriormente había consultado la dirección IP del contenedor acoplable docker psy, aunque la dirección IP cambia, hasta ahora siempre ha estado en el rango 172.17.0.x

¿Alguna idea de por qué no puedo conectarme a esta base de datos? ¡Probablemente algo muy simple, me imagino!

Estoy ejecutando Ubuntu 14.04; Postgres 9.3

marty_c
fuente

Respuestas:

149

TL; DR

  1. Usar 172.17.0.0/16como rango de direcciones IP, no 172.17.0.0/32.
  2. No lo use localhostpara conectarse a la base de datos PostgreSQL en su host, sino a la IP del host. Para mantener el contenedor portátil, inicie el contenedor con la --add-host=database:<host-ip>bandera y utilícelo databasecomo nombre de host para conectarse a PostgreSQL.
  3. Asegúrese de que PostreSQL esté configurado para escuchar conexiones en todas las direcciones IP, no solo en localhost. Busque la configuración listen_addressesen el archivo de configuración de PostgreSQL, que normalmente se encuentra en /etc/postgresql/9.3/main/postgresql.conf(créditos a @DazmoNorton).

Versión larga

172.17.0.0/32no es un rango de direcciones IP, sino una sola dirección (normalmente 172.17.0.0). Ningún contenedor Docker obtendrá esa dirección asignada, porque es la dirección de red de la docker0interfaz Docker bridge ( ).

Cuando Docker se inicie, creará una nueva interfaz de red de puente, que puede ver fácilmente al llamar ip a:

$ ip a
...
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN 
    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

Como puede ver, en mi caso, la docker0interfaz tiene la dirección IP 172.17.42.1con una máscara de red de /16(o 255.255.0.0). Esto significa que la dirección de red es 172.17.0.0/16.

La dirección IP se asigna aleatoriamente, pero sin ninguna configuración adicional, siempre estará en la 172.17.0.0/16red. Para cada contenedor Docker, se asignará una dirección aleatoria de ese rango.

Esto significa que, si desea otorgar acceso desde todos los contenedores posibles a su base de datos, use 172.17.0.0/16.

Helmbert
fuente
1
hola gracias por tus comentarios Cambié mi pg_hba.confdirección a la que sugirió, pero aún recibo el mismo mensaje de error de conexión después de detener y reiniciar el servicio postgres. Agregué la línea debajo de mis conexiones ipv4. ¿Hay algún otro lugar donde deba agregar la dirección que sugiere? Alternativamente, en mi aplicación QGIS que se ejecuta en Docker, ¿necesito cambiar la información de conexión de Postgres? Por ejemplo, si me conecto desde un contenedor acoplable, ¿el host sigue siendo 'localhost'?
marty_c
Ah, ese es un punto importante. No, localhostno es el sistema host dentro de su contenedor Docker. Intente conectarse a la dirección IP pública del sistema host. Para mantener el contenedor portátil, también puede iniciar el contenedor con el --add-host=database:<host-ip>y simplemente usarlo databasecomo nombre de host para conectarse a su host PostgreSQL desde el contenedor Docker.
helmbert
66
Necesitaba una pieza más. También tuve que editar /etc/postgresql/9.3/main/postgresql.confy agregar la eth0dirección IP de mi servidor listen_addresses. Por defecto listen_addressestiene postgres enlazar localhostsolo.
Dzamo Norton
@DzamoNorton, gracias por la pista! Actualicé mi respuesta en consecuencia.
Helmbert
@helmbert host-ipes la dirección IP de la máquina virtual o del contenedor acoplable?
Mr.D
56

Solución Docker para Mac

17.06 en adelante

Gracias al comentario de @Birchlabs, ahora es mucho más fácil con este nombre DNS especial solo para Mac disponible :

docker run -e DB_PORT=5432 -e DB_HOST=docker.for.mac.host.internal

Desde 17.12.0-cd-mac46, docker.for.mac.host.internaldebe usarse en lugar de docker.for.mac.localhost. Vea la nota de lanzamiento para más detalles.

Versión antigua

La respuesta de @ helmbert explica bien el problema. Pero Docker para Mac no expone la red del puente , así que tuve que hacer este truco para solucionar la limitación:

$ sudo ifconfig lo0 alias 10.200.10.1/24

Abre /usr/local/var/postgres/pg_hba.confy agrega esta línea:

host    all             all             10.200.10.1/24            trust

Abrir /usr/local/var/postgres/postgresql.confy editar cambios listen_addresses:

listen_addresses = '*'

Recargue el servicio e inicie su contenedor:

$ PGDATA=/usr/local/var/postgres pg_ctl reload
$ docker run -e DB_PORT=5432 -e DB_HOST=10.200.10.1 my_app 

Lo que hace esta solución es básicamente lo mismo con la respuesta de @ helmbert, pero usa una dirección IP que está conectada en lo0lugar de docker0la interfaz de red.

baxang
fuente
3
¿Sigue vigente al 4 de abril de 2017?
Petrus Theron
Me gusta esta forma que no expondrá la base de datos. Por cierto, ¿puedo usar esto en CentOS? Obtuve el error: alias: host desconocido cuando intenté usar el comando de alias que proporcionaste.
Tsung Goh
66
Hay una mejor manera en macOS, a partir de Docker 17.06.0-rc1-ce-mac13 (1 de junio de 2017). Los contenedores reconocen al host docker.for.mac.localhost. Esta es la IP de su máquina host. busque su entrada en la base de datos de hosts del contenedor de esta manera: docker run alpine /bin/sh -c 'getent hosts docker.for.mac.localhost'
Birchlabs
@Birchlabs ¡Esto es increíble!
qqilihq
55
Parece que cambió a host.docker.internaldesde 18.03, otras opciones todavía están disponibles pero en desuso ( Fuente ).
gseva
44

Solución simple para mac:

La versión más reciente de docker (18.03) ofrece una solución integrada de reenvío de puertos. Dentro de su contenedor docker, simplemente configure el host db en host.docker.internal. Esto se enviará al host en el que se ejecuta el contenedor de Docker.

La documentación para esto está aquí: https://docs.docker.com/docker-for-mac/networking/#i-want-to-connect-from-a-container-to-a-service-on-the-host

Chris
fuente
3
¡Esta es, de lejos, la mejor respuesta ahora! mucho más fácil y cómo debería ser.
bjm88
2
se host.docker.internallimita solo a las Mac?
Dragas
@Dragas de acuerdo con los documentos, "no funcionará fuera de Mac", pero el mismo nombre DNS se menciona en los documentos de Docker para Windows, por lo que creo que se limita a "Docker para ...". De cualquier manera, es solo de desarrollo: no está destinado a enviar una imagen acoplable que use esto.
Ruibarbo
Solo funciona con Windows y Mac. En mi caso, ubuntu no funciona
Azri Zakaria
17

Solución simple

Solo agregue --network=hosta docker run. ¡Eso es todo!

Este contenedor manera utilizará la red del huésped, por lo que localhosty 127.0.0.1apuntará al host (por defecto que apuntan a un recipiente). Ejemplo:

docker run -d --network=host \
  -e "DB_DBNAME=your_db" \
  -e "DB_PORT=5432" \
  -e "DB_USER=your_db_user" \
  -e "DB_PASS=your_db_password" \
  -e "DB_HOST=127.0.0.1" \
  --name foobar foo/bar
Max Malysh
fuente
1
¡Ten cuidado! Esta solución, que es la correcta en mi opinión, no funciona para macOS. No pierdas tu tiempo tratando de descubrir por qué no funciona. Echa un vistazo a: github.com/docker/for-mac/issues/2716
jfcorugedo el
1
Funciona en Debian. Intenté cambiar postgresql.conf y pg_hba.conf pero esto es más simple y rápido.
Frmbelz
2

En Ubuntu:

Primero debe verificar que el puerto de la base de datos de Docker esté disponible en su sistema siguiendo el comando:

sudo iptables -L -n

Salida de muestra:

Chain DOCKER (1 references)
target     prot opt source               destination         
ACCEPT     tcp  --  0.0.0.0/0            172.17.0.2           tcp dpt:3306
ACCEPT     tcp  --  0.0.0.0/0            172.17.0.3           tcp dpt:80
ACCEPT     tcp  --  0.0.0.0/0            172.17.0.3           tcp dpt:22

Aquí 3306se utiliza como puerto de base de datos Docker en 172.17.0.2 IP, si este puerto no está disponible Ejecute el siguiente comando:

sudo iptables -A INPUT -p tcp --dport 3306 -j ACCEPT

Ahora, puede acceder fácilmente a la base de datos de Docker desde su sistema local siguiendo la configuración

  host: 172.17.0.2 
  adapter: mysql
  database: DATABASE_NAME
  port: 3307
  username: DATABASE_USER
  password: DATABASE_PASSWORD
  encoding: utf8

En CentOS:

Primero debe verificar si el puerto de la base de datos de Docker está disponible en su firewall siguiendo el comando:

sudo firewall-cmd --list-all

Salida de muestra:

  target: default
  icmp-block-inversion: no
  interfaces: eno79841677
  sources: 
  services: dhcpv6-client ssh
  **ports: 3307/tcp**
  protocols: 
  masquerade: no
  forward-ports: 
  sourceports: 
  icmp-blocks: 
  rich rules:

Aquí 3307se utiliza como puerto de base de datos Docker en 172.17.0.2 IP, si este puerto no está disponible Ejecute el siguiente comando:

sudo firewall-cmd --zone=public --add-port=3307/tcp

En el servidor, puede agregar el puerto permanentemente

sudo firewall-cmd --permanent --add-port=3307/tcp
sudo firewall-cmd --reload

Ahora, puede acceder fácilmente a la base de datos Docker desde su sistema local mediante la configuración anterior.

Sanaulla
fuente
Sé que esto es antiguo, pero ahora, puede acceder fácilmente a la base de datos de Docker desde su sistema local siguiendo la configuración : tiene esto al revés. Tiene una base de datos local y una aplicación acoplable que intenta conectarse a esa base de datos local y no al revés
Craicerjack
2

La solución publicada aquí no funciona para mí. Por lo tanto, estoy publicando esta respuesta para ayudar a alguien que enfrenta un problema similar.

SO: Ubuntu 18
PostgreSQL: 9.5 (Alojado en Ubuntu)
Docker: Aplicación de servidor (que se conecta a PostgreSQL)

Estoy usando docker-compose.yml para compilar la aplicación.

PASO 1: agreguehost.docker.internal:<docker0 IP>

version: '3'
services:
  bank-server:
    ...
    depends_on:
      ....
    restart: on-failure
    ports:
      - 9090:9090
    extra_hosts:
      - "host.docker.internal:172.17.0.1"

Para encontrar la IP de la ventana acoplable i.e. 172.17.0.1 (in my case)puede usar:

$> ifconfig docker0
docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255

O

$> ip a
1: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever

PASO 2: en postgresql.conf, cambie listen_addresses alisten_addresses = '*'

PASO 3: en pg_hba.conf, agregue esta línea

host    all             all             0.0.0.0/0               md5

PASO 4: Ahora reinicie el servicio postgresql usando,sudo service postgresql restart

PASO 5: utilice el host.docker.internalnombre de host para conectar la base de datos desde la aplicación del servidor.
Ex:jdbc:postgresql://host.docker.internal:5432/bankDB

¡¡Disfrutar!!

singhpradeep
fuente
1

para docker-compose puedes intentar simplemente agregar

network_mode: "host"

ejemplo:

version: '2'
services:
  feedx:
    build: web
    ports:
    - "127.0.0.1:8000:8000"
    network_mode: "host"

https://docs.docker.com/compose/compose-file/#network_mode

Sarath Ak
fuente
44
agregando networkd_mode al host interrumpe la conexión entre otros contenedores
Bawantha
1

Para configurar algo simple que permita una conexión Postgresql desde el contenedor docker a mi host local, utilicé esto en postgresql.conf:

listen_addresses = '*'

Y agregó este pg_hba.conf:

host    all             all             172.17.0.0/16           password

Luego reinicia. Mi cliente desde el contenedor docker (que estaba en 172.17.0.2) podría conectarse a Postgresql que se ejecuta en mi localhost usando host: contraseña, base de datos, nombre de usuario y contraseña.

Harlin
fuente
0

Una cosa más que necesitaba para mi configuración era agregar

172.17.0.1  localhost

a /etc/hosts

para que Docker apunte 172.17.0.1como el nombre de host de la base de datos y no confíe en una IP externa cambiante para encontrar la base de datos. ¡Espero que esto ayude a alguien más con este problema!

Mikko Pöri
fuente
14
Esta es una mala solución. Localhost normalmente debería apuntar a 127.0.0.1. Cambiarlo podría tener consecuencias no deseadas, incluso si en este caso particular funciona.
Alex
2
Una mejor manera es configurar un databasehost con --add-host=database:172.17.0.1cuando se ejecuta el contenedor. Luego, apunte su aplicación a ese host. Esto evita codificar una dirección IP dentro de un contenedor.
jaredsk
1
el --add-host=database:172.17.0.1es preferible
Luis Martins
-3

La otra solución es el volumen de servicio. Puede definir un volumen de servicio y montar el directorio de datos PostgreSQL del host en ese volumen. Echa un vistazo al archivo de composición dado para más detalles.

version: '2'
services:
  db:   
    image: postgres:9.6.1
    volumes:
      - "/var/lib/postgresql/data:/var/lib/postgresql/data" 
    ports:
      - "5432:5432"

Al hacer esto, otro servicio PostgreSQL se ejecutará en un contenedor, pero usa el mismo directorio de datos que el servicio host PostgreSQL está usando.

Hrishi
fuente
1
Esto probablemente causará conflictos de escritura con un servicio PostgreSQL de host en ejecución
Petrus Theron
Creo que detener el servicio de host resolverá el problema en ese caso.
Hrishi