Consentire al contenitore docker di connettersi a un database postgres locale / host


143

Recentemente ho giocato con Docker e QGIS e ho installato un contenitore seguendo le istruzioni in questo tutorial .

Tutto funziona alla grande, anche se non riesco a collegarmi a un database Postgres localhost che contiene tutti i miei dati GIS. Immagino che ciò sia dovuto al fatto che il mio database Postgres non è configurato per accettare connessioni remote e ho modificato i file di configurazione di Postgres per consentire connessioni remote usando le istruzioni in questo articolo .

Ricevo ancora un messaggio di errore quando provo a connettermi al mio database con QGIS in Docker: impossibile collegarmi al server: Connection refused Is the server running on host "localhost" (::1) and accepting TCP/IP connections to port 5433? il server Postgres è in esecuzione e ho modificato il mio file pg_hba.conf per consentire connessioni da un intervallo di Indirizzi IP (172.17.0.0/32). In precedenza avevo richiesto l'indirizzo IP del contenitore docker utilizzando docker pse sebbene l'indirizzo IP cambi, finora è sempre stato nell'intervallo 172.17.0.x

Qualche idea sul perché non riesco a collegarmi a questo database? Probabilmente qualcosa di molto semplice, immagino!

Sto eseguendo Ubuntu 14.04; Postgres 9.3

Risposte:


149

TL; DR

  1. Utilizzare 172.17.0.0/16come intervallo di indirizzi IP, non 172.17.0.0/32.
  2. Non utilizzare localhostper connettersi al database PostgreSQL sul proprio host, ma al suo posto IP. Per mantenere il contenitore portatile, avviare il contenitore con il --add-host=database:<host-ip>flag e utilizzare databasecome nome host per la connessione a PostgreSQL.
  3. Assicurati che PostreSQL sia configurato per ascoltare le connessioni su tutti gli indirizzi IP, non solo localhost. Cerca l'impostazione listen_addressesnel file di configurazione di PostgreSQL, che si trova in genere in /etc/postgresql/9.3/main/postgresql.conf(crediti a @DazmoNorton).

Versione lunga

172.17.0.0/32non è un intervallo di indirizzi IP, ma un singolo indirizzo (vale a dire 172.17.0.0). A nessun contenitore Docker verrà assegnato tale indirizzo, poiché è l'indirizzo di rete dell'interfaccia bridge ( docker0) Docker .

All'avvio di Docker, verrà creata una nuova interfaccia di rete bridge, che puoi facilmente vedere quando chiami 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

Come puoi vedere, nel mio caso, l' docker0interfaccia ha l'indirizzo IP 172.17.42.1con una maschera di rete di /16(o 255.255.0.0). Ciò significa che l'indirizzo di rete è 172.17.0.0/16.

L'indirizzo IP viene assegnato in modo casuale, ma senza alcuna configurazione aggiuntiva, sarà sempre nella 172.17.0.0/16rete. Per ciascun contenitore Docker, verrà assegnato un indirizzo casuale da quell'intervallo.

Ciò significa che, se si desidera consentire l'accesso da tutti i possibili contenitori al database, utilizzare 172.17.0.0/16.


1
ehi grazie per i tuoi commenti. Ho cambiato il mio pg_hba.confall'indirizzo che mi hai suggerito, ma ricevo ancora lo stesso messaggio di errore di connessione dopo l'arresto e il riavvio del servizio Postgres. Ho aggiunto la linea sotto le mie connessioni ipv4 - c'è un altro posto in cui dovrei aggiungere l'indirizzo che mi consigliate? In alternativa, nella mia app QGIS in esecuzione su Docker, devo modificare le informazioni di connessione di Postgres? Ad esempio, se mi connetto da un contenitore docker, l'host è ancora "localhost"?
marty_c

Ah, questo è un punto importante. No, localhostnon è il sistema host all'interno del contenitore Docker. Prova a connetterti all'indirizzo IP pubblico del sistema host. Per mantenere il contenitore portatile, è anche possibile avviare il contenitore con --add-host=database:<host-ip>e semplicemente utilizzare databasecome nome host per connettersi all'host PostgreSQL dall'interno del contenitore Docker.
helmbert,

6
Avevo bisogno di un altro pezzo. Ho anche dovuto modificare /etc/postgresql/9.3/main/postgresql.confe aggiungere l' eth0indirizzo IP del mio server a listen_addresses. Di default listen_addressesPostgres si lega localhostsolo a.
Dzamo Norton,

@DzamoNorton, grazie per il suggerimento! Ho aggiornato la mia risposta di conseguenza.
helmbert,

@helmbert host-ipè l'indirizzo IP della macchina virtuale o del contenitore docker?
Mr.D,

56

Docker per soluzione Mac

17.06 in poi

Grazie al commento di @Birchlabs, ora è molto più facile con questo speciale nome DNS solo per Mac disponibile :

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

Da 17.12.0-cd-mac46, docker.for.mac.host.internaldovrebbe essere usato al posto di docker.for.mac.localhost. Vedere la nota di rilascio per i dettagli.

Versione precedente

La risposta di @ helmbert spiega bene il problema. Ma Docker per Mac non espone la rete bridge , quindi ho dovuto fare questo trucco per aggirare la limitazione:

$ sudo ifconfig lo0 alias 10.200.10.1/24

Apri /usr/local/var/postgres/pg_hba.confe aggiungi questa riga:

host    all             all             10.200.10.1/24            trust

Apri /usr/local/var/postgres/postgresql.confe modifica modifica listen_addresses:

listen_addresses = '*'

Ricarica il servizio e avvia il tuo contenitore:

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

Ciò che fa questa soluzione alternativa è sostanzialmente lo stesso con la risposta di @ helmbert, ma utilizza un indirizzo IP collegato lo0invece docker0dell'interfaccia di rete.


3
È ancora attuale al 4 aprile 2017?
Petrus Theron,

Mi piace in questo modo che non esporrà il database. A proposito, posso usarlo su CentOS? Ho ricevuto l'errore: alias: host sconosciuto quando ho provato a utilizzare il comando alias fornito.
Tsung Goh,

6
C'è un modo migliore su macOS, a partire da Docker 17.06.0-rc1-ce-mac13 (1 giugno 2017). i container riconoscono l'host docker.for.mac.localhost. questo è l'IP del tuo computer host. cerca la sua voce nel database degli host del container in questo modo: docker run alpine /bin/sh -c 'getent hosts docker.for.mac.localhost'
Birchlabs,

@Birchlabs È fantastico!
qqilihq,

5
Sembra che sia cambiato host.docker.internaldal 18.03, altre opzioni sono ancora disponibili ma deprecate ( Fonte ).
gseva,

44

Soluzione semplice per mac:

La versione più recente di docker (18.03) offre una soluzione di port forwarding integrata. All'interno del contenitore della finestra mobile è sufficiente impostare l'host db su host.docker.internal. Questo verrà inoltrato all'host su cui è in esecuzione il contenitore docker.

La documentazione per questo è qui: https://docs.docker.com/docker-for-mac/networking/#i-want-to-connect-from-a-container-to-a-service-on-the-host


3
Questa è di gran lunga la migliore risposta ora! molto più facile e come dovrebbe essere.
bjm88,

2
è host.docker.internallimitato ai mac?
Dragas,

@Dragas secondo i documenti "non funzionerà al di fuori del Mac", ma lo stesso nome DNS è menzionato nei documenti per Docker per Windows, quindi penso che sia limitato a "Docker per ...". Ad ogni modo è solo di sviluppo: non sei destinato a spedire un'immagine docker che lo utilizza.
Rabarbaro

Funziona solo con Windows e Mac. Nel mio caso Ubuntu non funziona
Azri Zakaria,

17

Soluzione semplice

Aggiungi --network=hosta docker run. È tutto!

In questo modo il contenitore utilizzerà la rete dell'host, quindi localhoste 127.0.0.1punterà all'host (per impostazione predefinita puntano a un contenitore). Esempio:

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

1
Stai attento! Questa soluzione, quella giusta secondo me, non funziona per macOS. Non perdere tempo a cercare di capire perché non funziona. Dai un'occhiata a: github.com/docker/for-mac/issues/2716
jfcorugedo

1
Funziona su Debian. Ho provato a cambiare postgresql.conf e pg_hba.conf ma questo è più semplice e veloce.
venerdì

2

In Ubuntu:

Per prima cosa devi verificare che la porta del database Docker sia disponibile nel tuo sistema seguendo il comando -

sudo iptables -L -n

USCITA campione:

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

Qui 3306viene utilizzato come porta del database Docker su IP 172.17.0.2, se questa porta non è disponibile Eseguire il comando seguente -

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

Ora puoi accedere facilmente al database Docker dal tuo sistema locale seguendo la configurazione

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

In CentOS:

Per prima cosa devi verificare che la porta del database Docker sia disponibile nel firewall seguendo il comando -

sudo firewall-cmd --list-all

USCITA campione:

  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:

Qui 3307viene utilizzato come porta del database Docker su IP 172.17.0.2, se questa porta non è disponibile Eseguire il comando seguente -

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

Nel server, è possibile aggiungere la porta in modo permanente

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

Ora puoi accedere facilmente al database Docker dal tuo sistema locale con la configurazione sopra.


So che questo è vecchio, ma ora puoi accedere facilmente al database Docker dal tuo sistema locale seguendo la configurazione : hai sbagliato tutto. Ha un database locale e un'app docker che cerca di connettersi a quel db locale non viceversa
Craicerjack il

2

La soluzione pubblicata qui non funziona per me. Pertanto, sto pubblicando questa risposta per aiutare qualcuno con problemi simili.

Sistema operativo: Ubuntu 18
PostgreSQL: 9.5 (ospitato su Ubuntu)
Docker: Applicazione server (che si collega a PostgreSQL)

Sto usando docker-compose.yml per creare un'applicazione.

PASSAGGIO 1: aggiungihost.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"

Per trovare l'IP della finestra mobile i.e. 172.17.0.1 (in my case)è possibile utilizzare:

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

PASSAGGIO 2: in postgresql.conf, modifica hear_addresses inlisten_addresses = '*'

PASSAGGIO 3: in pg_hba.conf, aggiungi questa riga

host    all             all             0.0.0.0/0               md5

PASSAGGIO 4: Ora riavvia il servizio postgresql usando,sudo service postgresql restart

PASSAGGIO 5: utilizzare il host.docker.internalnome host per connettere il database dall'applicazione server.
Ex:jdbc:postgresql://host.docker.internal:5432/bankDB

Godere!!



1

Per impostare qualcosa di semplice che consenta una connessione Postgresql dal contenitore docker al mio localhost, l'ho usato in postgresql.conf:

listen_addresses = '*'

E ha aggiunto questo pg_hba.conf:

host    all             all             172.17.0.0/16           password

Quindi fare un riavvio. Il mio client dal contenitore docker (che era al 172.17.0.2) poteva quindi connettersi a Postgresql in esecuzione sul mio localhost usando host: password, database, nome utente e password.


0

Un'altra cosa necessaria per la mia installazione è stata l'aggiunta

172.17.0.1  localhost

per /etc/hosts

in modo che Docker indichi 172.17.0.1come nome host del DB e non faccia affidamento su un IP esterno che cambia per trovare il DB. Spero che questo aiuti qualcun altro a questo problema!


14
Questa è una cattiva soluzione. Localhost dovrebbe in genere puntare a 127.0.0.1. La sua modifica potrebbe avere conseguenze indesiderate, anche se in questo caso particolare funziona.
Alex,

2
Un modo migliore è configurare un databasehost con --add-host=database:172.17.0.1quando si esegue il contenitore. Quindi punta la tua app su quell'host. Ciò evita di codificare in modo rigido un indirizzo IP all'interno di un contenitore.
Jaredsk,

1
la --add-host=database:172.17.0.1è preferibile
Luis Martins

-3

Un'altra soluzione è il volume del servizio, è possibile definire un volume del servizio e montare la directory dei dati PostgreSQL dell'host in quel volume. Controlla il file di composizione fornito per i dettagli.

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

In questo modo, un altro servizio PostgreSQL verrà eseguito nel contenitore ma utilizza la stessa directory di dati utilizzata dal servizio PostgreSQL host.


1
Ciò probabilmente causerà conflitti di scrittura con un servizio PostgreSQL host in esecuzione
Petrus Theron

Penso che l'interruzione del servizio host risolverà il problema in quel caso.
Hrishi,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.