Permitir que o contêiner do docker se conecte a um banco de dados local / host postgres

143

Recentemente, brinquei com o Docker e o QGIS e instalei um contêiner seguindo as instruções em neste tutorial .

Tudo funciona muito bem, embora eu não consiga me conectar a um banco de dados localhost postgres que contém todos os meus dados GIS. Eu acho que isso ocorre porque meu banco de dados do postgres não está configurado para aceitar conexões remotas e foi editando os arquivos conf do postgres para permitir conexões remotas usando as instruções deste artigo .

Ainda estou recebendo uma mensagem de erro quando tento me conectar ao meu banco de dados executando o QGIS no Docker: não foi possível conectar ao servidor: Connection refused Is the server running on host "localhost" (::1) and accepting TCP/IP connections to port 5433? o servidor do postgres está em execução e editei meu pg_hba.conf arquivo para permitir conexões de vários Endereços IP (172.17.0.0/32). Eu havia consultado anteriormente o endereço IP do contêiner do docker usando docker pse, embora o endereço IP tenha sido alterado, ele até agora sempre esteve no intervalo 172.17.0.x

Alguma idéia de por que não consigo me conectar a este banco de dados? Provavelmente algo muito simples, eu imagino!

Estou executando o Ubuntu 14.04; Postgres 9.3

marty_c
fonte

Respostas:

149

TL; DR

  1. Use 172.17.0.0/16como intervalo de endereços IP, não 172.17.0.0/32.
  2. Não use localhostpara se conectar ao banco de dados PostgreSQL em seu host, mas sim ao IP do host. Para manter o contêiner portátil, inicie o contêiner com o --add-host=database:<host-ip>sinalizador e use databasecomo nome de host para conectar-se ao PostgreSQL.
  3. Verifique se o PostreSQL está configurado para escutar conexões em todos os endereços IP, não apenas em localhost. Procure a configuração listen_addressesno arquivo de configuração do PostgreSQL, normalmente encontrada em /etc/postgresql/9.3/main/postgresql.conf(créditos para @DazmoNorton).

Versão longa

172.17.0.0/32não é um intervalo de endereços IP, mas um único endereço (nomeado 172.17.0.0). Nenhum contêiner do Docker receberá esse endereço, porque é o endereço de rede da docker0interface bridge ( ) do Docker .

Quando o Docker é iniciado, ele cria uma nova interface de rede de ponte, que você pode ver facilmente ao chamar 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 você pode ver, no meu caso, a docker0interface possui o endereço IP 172.17.42.1com uma máscara de rede de /16(ou 255.255.0.0). Isso significa que o endereço de rede é 172.17.0.0/16.

O endereço IP é atribuído aleatoriamente, mas sem nenhuma configuração adicional, ele sempre estará na 172.17.0.0/16rede. Para cada contêiner do Docker, um endereço aleatório desse intervalo será atribuído.

Isso significa que, se você deseja conceder acesso de todos os contêineres possíveis ao seu banco de dados, use 172.17.0.0/16.

Helmbert
fonte
1
ei, obrigado por seus comentários. Alterei meu pg_hba.confpara o endereço que você sugeriu, mas ainda recebe a mesma mensagem de erro de conexão após parar e reiniciar o serviço postgres. Adicionei a linha em minhas conexões ipv4 - existe algum outro lugar que devo adicionar o endereço que você sugere? Como alternativa, no meu aplicativo QGIS em execução no Docker, preciso alterar as informações de conexão do postgres? Por exemplo, se eu estiver conectando de dentro de um contêiner de docker, o host ainda será 'localhost'?
Marty_c 7/07
Ah, esse é um ponto importante. Não, localhostnão é o sistema host dentro do contêiner do Docker. Tente conectar-se ao endereço IP público do sistema host. Para manter o contêiner portátil, você também pode iniciá-lo com --add-host=database:<host-ip>e simplesmente usar databasecomo nome do host para conectar-se ao seu host PostgreSQL de dentro do contêiner Docker.
helmbert
6
Eu precisava de mais uma peça. Eu também tive que editar /etc/postgresql/9.3/main/postgresql.confe adicionar o eth0endereço IP do meu servidor listen_addresses. Por padrão listen_addresses, o postgres é vinculado localhostapenas.
Dzamo Norton
@DzamoNorton, obrigado pela dica! Eu atualizei minha resposta de acordo.
helmbert
@helmbert host-ipé o endereço IP da máquina virtual ou do container docker?
Mr.D
56

Solução Docker para Mac

17.06 em diante

Graças ao comentário do @Birchlabs, agora é muito mais fácil com este nome DNS especial somente para Mac disponível :

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

A partir de 17.12.0-cd-mac46, docker.for.mac.host.internaldeve ser usado em vez de docker.for.mac.localhost. Consulte a nota de lançamento para obter detalhes.

Versão mais antiga

A resposta de @ helmbert explica bem o problema. Mas o Docker para Mac não expõe a rede da ponte , então tive que fazer esse truque para solucionar a limitação:

$ sudo ifconfig lo0 alias 10.200.10.1/24

Abra /usr/local/var/postgres/pg_hba.confe adicione esta linha:

host    all             all             10.200.10.1/24            trust

Abrir /usr/local/var/postgres/postgresql.confe editar alterações listen_addresses:

listen_addresses = '*'

Recarregue o serviço e inicie seu contêiner:

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

O que essa solução alternativa faz é basicamente o mesmo com a resposta do @ helmbert, mas usa um endereço IP anexado ao lo0invés da docker0interface de rede.

Baxang
fonte
3
Ainda é atual a partir de 4 de abril de 2017?
Pe Theron
Eu gosto dessa maneira que não expõe o banco de dados. BTW, posso usar isso no CentOS? Eu recebi o erro: alias: host desconhecido quando tentei usar o comando alias que você fornece.
Tsung Goh
6
Existe uma maneira melhor no macOS, a partir do Docker 17.06.0-rc1-ce-mac13 (1º de junho de 2017). contêineres reconhecem o host docker.for.mac.localhost. esse é o IP da sua máquina host. procure sua entrada no banco de dados de hosts do contêiner da seguinte forma: docker run alpine /bin/sh -c 'getent hosts docker.for.mac.localhost'
Birchlabs
@Birchlabs Isso é tão incrível!
Qqilihq 5/05
5
Parece que foi alterado para host.docker.internaldesde 18.03, outras opções ainda estão disponíveis, mas estão obsoletas ( Origem ).
precisa saber é
44

Solução simples para mac:

A versão mais recente do docker (18.03) oferece uma solução integrada de encaminhamento de porta. Dentro do contêiner do docker, basta definir o host db host.docker.internal. Isso será encaminhado para o host no qual o contêiner do docker está sendo executado.

A documentação para isso está aqui: https://docs.docker.com/docker-for-mac/networking/#i-want-to-connect-from-a-container-to-a-service-on-the-host

Chris
fonte
3
Esta é de longe a melhor resposta agora! muito mais fácil e como deveria ser.
Bjm88 7/07
2
é host.docker.internallimitado apenas a macs?
Dragas
@Dragas de acordo com os documentos "ele não funcionará fora do Mac", mas o mesmo nome DNS é mencionado nos documentos do Docker para Windows, então acho que está limitado ao "Docker for ...". De qualquer forma, é apenas para desenvolvimento: você não pretende enviar uma imagem do docker que use isso.
Ruibarbo
Trabalhando apenas com Windows e Mac. No meu caso, o ubuntu não está funcionando
Azri Zakaria 27/04
16

Solução simples

Basta adicionar --network=hosta docker run. Isso é tudo!

Este recipiente maneira usará rede do host, então localhoste 127.0.0.1irá apontar para o host (por padrão, eles apontam para um recipiente). Exemplo:

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
fonte
1
Seja cuidadoso! Esta solução, que é a correta na minha opinião, não funciona no macOS. Não perca seu tempo tentando descobrir por que não está funcionando. Dê uma olhada em: github.com/docker/for-mac/issues/2716
jfcorugedo
Funciona no Debian. Tentei mudar o postgresql.conf e o pg_hba.conf, mas isso é mais simples e rápido.
frmbelz 14/01
2

No Ubuntu:

Primeiro, você deve verificar se a porta do banco de dados do Docker está disponível no sistema seguindo o comando -

sudo iptables -L -n

Saída de amostra:

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

Aqui 3306é usado como porta do banco de dados do Docker no IP 172.17.0.2, se essa porta não estiver disponível Execute o seguinte comando -

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

Agora, você pode acessar facilmente o banco de dados do Docker a partir do sistema local seguindo a configuração

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

No CentOS:

Primeiro, verifique se a porta do banco de dados do Docker está disponível no firewall seguindo o comando -

sudo firewall-cmd --list-all

Saída de amostra:

  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:

Aqui 3307é usado como porta do banco de dados do Docker no IP 172.17.0.2, se essa porta não estiver disponível Execute o seguinte comando -

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

No servidor, você pode adicionar a porta permanentemente

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

Agora, você pode acessar facilmente o banco de dados do Docker a partir do seu sistema local pela configuração acima.

Sanaulla
fonte
Sei que isso é antigo, mas agora, você pode acessar facilmente o banco de dados do Docker a partir do sistema local seguindo a configuração - você tem isso errado. Ele tem um banco de dados local e um aplicativo docker tentando conectar-se ao banco de dados local, e não o contrário
Craicerjack
2

A solução postada aqui não funciona para mim. Portanto, estou postando esta resposta para ajudar alguém que enfrenta um problema semelhante.

OS: Ubuntu 18
PostgreSQL: 9.5 (Hospedado no Ubuntu)
Docker: Aplicativo de Servidor (que se conecta ao PostgreSQL)

Estou usando o docker-compose.yml para criar aplicativos.

PASSO 1: Por favor, adicionehost.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 o IP da janela de encaixe, i.e. 172.17.0.1 (in my case)você pode 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

OU

$> 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

PASSO 2: No postgresql.conf, altere listen_addresses paralisten_addresses = '*'

PASSO 3: No pg_hba.conf, adicione esta linha

host    all             all             0.0.0.0/0               md5

PASSO 4: Agora reinicie o serviço postgresql usando,sudo service postgresql restart

ETAPA 5: Por favor, use o host.docker.internalnome do host para conectar o banco de dados a partir do Aplicativo do Servidor.
Ex:jdbc:postgresql://host.docker.internal:5432/bankDB

Aproveitar!!

singhpradeep
fonte
1

para docker-compor você pode tentar apenas adicionar

network_mode: "host"

exemplo:

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
fonte
4
adicionando networkd_mode ao hospedeiro quebrar a ligação entre outros recipientes
Bawantha
1

Para configurar algo simples que permita uma conexão Postgresql do contêiner do docker ao meu host local, usei isso no postgresql.conf:

listen_addresses = '*'

E adicionou este pg_hba.conf:

host    all             all             172.17.0.0/16           password

Depois, reinicie. Meu cliente do contêiner do docker (que estava em 172.17.0.2) pôde se conectar ao Postgresql em execução no meu host local usando o host: senha, banco de dados, nome de usuário e senha.

Harlin
fonte
0

Mais uma coisa necessária para a minha configuração foi adicionar

172.17.0.1  localhost

para /etc/hosts

para que o Docker aponte 172.17.0.1como o nome do host do banco de dados e não dependa de um IP externo alterado para encontrar o banco de dados. Espero que isso ajude alguém com esse problema!

Mikko Pöri
fonte
14
Esta é uma solução ruim. O host local normalmente deve apontar para 127.0.0.1. Mudá-lo pode ter consequências indesejadas, mesmo que neste caso específico funcione.
22417 Alex
2
Uma maneira melhor é configurar um databasehost --add-host=database:172.17.0.1ao executar o contêiner. Em seguida, aponte seu aplicativo para esse host. Isso evita a codificação embutida de um endereço IP dentro de um contêiner.
precisa saber é o seguinte
1
o --add-host=database:172.17.0.1é preferível
Luis Martins
-3

A outra solução é o volume de serviço. Você pode definir um volume de serviço e montar o diretório de dados PostgreSQL do host nesse volume. Confira o arquivo de composição fornecido para obter detalhes.

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

Ao fazer isso, outro serviço PostgreSQL será executado no contêiner, mas usa o mesmo diretório de dados que o serviço PostgreSQL host está usando.

Hrishi
fonte
1
Este, provavelmente, causar conflitos de gravação com um serviço de PostgreSQL host executando
Petrus Theron
Acho que interromper o serviço host resolverá o problema nesse caso.
precisa saber é o seguinte