Ermöglichen Sie dem Docker-Container, eine Verbindung zu einer lokalen / Host-Postgres-Datenbank herzustellen

143

Ich habe kürzlich mit Docker und QGIS herumgespielt und einen Container installiert, der den Anweisungen in diesem Tutorial folgt .

Alles funktioniert hervorragend, obwohl ich keine Verbindung zu einer localhost-Postgres-Datenbank herstellen kann, die alle meine GIS-Daten enthält. Ich denke, dies liegt daran, dass meine Postgres-Datenbank nicht für die Annahme von Remoteverbindungen konfiguriert ist und die Postgres-Conf-Dateien so bearbeitet hat, dass Remoteverbindungen gemäß den Anweisungen in diesem Artikel zugelassen werden .

Ich erhalte immer noch eine Fehlermeldung, wenn ich versuche, eine Verbindung zu meiner Datenbank Connection refused Is the server running on host "localhost" (::1) and accepting TCP/IP connections to port 5433? herzustellen , auf der QGIS in Docker ausgeführt wird: Es konnte keine Verbindung zum Server hergestellt werden: Der Postgres-Server wird ausgeführt, und ich habe meine Datei pg_hba.conf bearbeitet , um Verbindungen aus einer Reihe von Bereichen zuzulassen IP-Adressen (172.17.0.0/32). Ich hatte zuvor die IP-Adresse des Docker-Containers mit abgefragt docker psund obwohl sich die IP-Adresse ändert, lag sie bisher immer im Bereich 172.17.0.x.

Irgendwelche Ideen, warum ich keine Verbindung zu dieser Datenbank herstellen kann? Wahrscheinlich etwas sehr Einfaches, das ich mir vorstelle!

Ich verwende Ubuntu 14.04. Postgres 9.3

marty_c
quelle

Antworten:

149

TL; DR

  1. Verwenden Sie 172.17.0.0/16als IP - Adressbereich, nicht 172.17.0.0/32.
  2. Verwenden Sie nicht die localhostVerbindung zur PostgreSQL-Datenbank auf Ihrem Host, sondern die IP des Hosts. Um den Container portabel zu halten, starten Sie den Container mit dem --add-host=database:<host-ip>Flag und verwenden Sie ihn databaseals Hostnamen für die Verbindung zu PostgreSQL.
  3. Stellen Sie sicher, dass PostreSQL so konfiguriert ist, dass Verbindungen auf allen IP-Adressen überwacht werden, nicht nur auf localhost. Suchen Sie nach der Einstellung listen_addressesin der Konfigurationsdatei von PostgreSQL, die normalerweise in /etc/postgresql/9.3/main/postgresql.conf(Credits to @DazmoNorton) enthalten ist.

Lange Version

172.17.0.0/32ist kein Bereich von IP-Adressen, sondern eine einzelne Adresse (namentlich 172.17.0.0). Kein Docker-Container wird jemals diese Adresse zugewiesen bekommen, da dies die Netzwerkadresse der Docker bridge ( docker0) -Schnittstelle ist.

Wenn Docker gestartet wird, wird eine neue Bridge-Netzwerkschnittstelle erstellt, die Sie beim Aufrufen leicht sehen können 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

Wie Sie sehen können, hat die docker0Schnittstelle in meinem Fall die IP-Adresse 172.17.42.1mit einer Netzmaske von /16(oder 255.255.0.0). Dies bedeutet, dass die Netzwerkadresse lautet 172.17.0.0/16.

Die IP-Adresse wird zufällig vergeben, befindet sich jedoch ohne zusätzliche Konfiguration immer im 172.17.0.0/16Netzwerk. Für jeden Docker-Container wird eine zufällige Adresse aus diesem Bereich zugewiesen.

Dies bedeutet, wenn Sie Zugriff von allen möglichen Containern auf Ihre Datenbank gewähren möchten, verwenden Sie 172.17.0.0/16.

Helmbert
quelle
1
Hey, danke für deine Kommentare. Ich habe meine pg_hba.confAdresse in die von Ihnen vorgeschlagene Adresse geändert , erhalte jedoch nach dem Stoppen und Neustarten des Postgres-Dienstes immer noch dieselbe Verbindungsfehlermeldung. Ich habe die Zeile unter meinen IPv4-Verbindungen hinzugefügt. Gibt es irgendwo anders, wo ich die von Ihnen vorgeschlagene Adresse hinzufügen soll? Muss ich in meiner QGIS-App, die in Docker ausgeführt wird, alternativ die Postgres-Verbindungsinformationen ändern? Wenn ich beispielsweise eine Verbindung innerhalb eines Docker-Containers herstelle, ist der Host dann immer noch "localhost"?
Marty_c
Ah, das ist ein wichtiger Punkt. Nein, localhostbefindet sich nicht das Hostsystem in Ihrem Docker-Container? Versuchen Sie, eine Verbindung zur öffentlichen IP-Adresse des Hostsystems herzustellen. Um den Container portabel zu halten, können Sie den Container auch mit dem starten --add-host=database:<host-ip>und einfach databaseals Hostname verwenden, um über den Docker-Container eine Verbindung zu Ihrem PostgreSQL-Host herzustellen.
Helmbert
6
Ich brauchte noch ein Stück. Ich musste auch /etc/postgresql/9.3/main/postgresql.confdie eth0IP-Adresse meines Servers bearbeiten und hinzufügen listen_addresses. Standardmäßig werden listen_addressesnur Postgres gebunden localhost.
Dzamo Norton
@ DzamoNorton, danke für den Hinweis! Ich habe meine Antwort entsprechend aktualisiert.
Helmbert
@helmbert host-ipist die IP-Adresse der virtuellen Maschine oder des Docker-Containers?
Mr.D
56

Docker für Mac-Lösung

Ab 17.06

Dank des Kommentars von @Birchlabs ist es jetzt viel einfacher, diesen speziellen DNS-Namen nur für Mac zu verwenden :

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

Ab 17.12.0-cd-mac46 docker.for.mac.host.internalsollte statt verwendet werden docker.for.mac.localhost. Siehe Versionshinweis für Details.

Ältere Version

@ helmberts Antwort erklärt das Problem gut. Da Docker für Mac das Bridge-Netzwerk jedoch nicht verfügbar macht , musste ich diesen Trick ausführen, um die Einschränkung zu umgehen:

$ sudo ifconfig lo0 alias 10.200.10.1/24

Öffnen /usr/local/var/postgres/pg_hba.confSie diese Zeile und fügen Sie sie hinzu:

host    all             all             10.200.10.1/24            trust

/usr/local/var/postgres/postgresql.confÄnderung öffnen und bearbeiten listen_addresses:

listen_addresses = '*'

Laden Sie den Dienst neu und starten Sie Ihren Container:

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

Diese Problemumgehung entspricht im Wesentlichen der Antwort von @ helmbert, verwendet jedoch eine IP-Adresse, die lo0anstelle der docker0Netzwerkschnittstelle angehängt ist .

Baxang
quelle
3
Ist dies zum 4. April 2017 noch aktuell?
Petrus Theron
Ich mag diesen Weg, der keine Datenbank verfügbar macht. Übrigens, kann ich das unter CentOS verwenden? Ich habe die Fehlermeldung erhalten: alias: Unbekannter Host, als ich versucht habe, den von Ihnen angegebenen Alias-Befehl zu verwenden.
Tsung Goh
6
Unter macOS gibt es ab Docker 17.06.0-rc1-ce-mac13 (1. Juni 2017) einen besseren Weg. Container erkennen den Host docker.for.mac.localhost. Dies ist die IP Ihres Host-Computers. Suchen Sie den Eintrag in der Hosts-Datenbank des Containers wie docker run alpine /bin/sh -c 'getent hosts docker.for.mac.localhost'
folgt
@Birchlabs Das ist so toll!
Qqilihq
5
Es scheint, als hätte es sich host.docker.internalseit dem 18.03. Geändert. Andere Optionen sind noch verfügbar, aber veraltet ( Quelle ).
gseva
44

Einfache Lösung für Mac:

Die neueste Version von Docker (18.03) bietet eine integrierte Portweiterleitungslösung. Stellen Sie in Ihrem Docker-Container einfach den Datenbank-Host auf ein host.docker.internal. Dies wird an den Host weitergeleitet, auf dem der Docker-Container ausgeführt wird.

Die Dokumentation hierzu finden Sie hier: https://docs.docker.com/docker-for-mac/networking/#i-want-to-connect-from-a-container-to-a-service-on-the-host

Chris
quelle
3
Dies ist jetzt bei weitem die beste Antwort! viel einfacher und wie es sein sollte.
bjm88
2
ist host.docker.internalnur auf Macs beschränkt?
Dragas
@Dragas laut den Dokumenten wird es "nicht außerhalb des Mac funktionieren", aber der gleiche DNS-Name wird in den Dokumenten für Docker für Windows erwähnt, so dass ich denke, es ist auf "Docker für ..." beschränkt. In beiden Fällen ist es nur für die Entwicklung gedacht: Sie sollen kein Docker-Image versenden, das dies verwendet.
Rhabarber
Funktioniert nur mit Windows und Mac. In meinem Fall funktioniert Ubuntu nicht
Azri Zakaria
16

Einfache Lösung

Fügen Sie einfach --network=hostzu docker run. Das ist alles!

Auf diese Weise verwendet der Container das Netzwerk des Hosts localhostund 127.0.0.1zeigt auf den Host (standardmäßig zeigen sie auf einen Container). Beispiel:

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
quelle
1
Achtung! Diese Lösung, die meiner Meinung nach die richtige ist, funktioniert unter macOS nicht. Verschwenden Sie keine Zeit damit, herauszufinden, warum es nicht funktioniert.
Werfen
Arbeitet auf Debian. Es wurde versucht, postgresql.conf und pg_hba.conf zu ändern, dies ist jedoch einfacher und schneller.
Frmbelz
2

In Ubuntu:

Zuerst müssen Sie überprüfen, ob der Docker-Datenbankport in Ihrem System verfügbar ist, indem Sie den folgenden Befehl ausführen:

sudo iptables -L -n

Beispielausgabe:

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

Hier 3306wird als Docker-Datenbankport auf IP 172.17.0.2 verwendet. Wenn dieser Port nicht verfügbar ist Führen Sie den folgenden Befehl aus:

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

Jetzt können Sie von Ihrem lokalen System aus problemlos auf die Docker-Datenbank zugreifen, indem Sie die folgende Konfiguration durchführen

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

In CentOS:

Zuerst müssen Sie überprüfen, ob der Docker-Datenbankport in Ihrer Firewall verfügbar ist, indem Sie den folgenden Befehl ausführen:

sudo firewall-cmd --list-all

Beispielausgabe:

  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:

Hier 3307wird als Docker-Datenbankport auf IP 172.17.0.2 verwendet. Wenn dieser Port nicht verfügbar ist Führen Sie den folgenden Befehl aus:

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

Auf dem Server können Sie den Port dauerhaft hinzufügen

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

Mit der obigen Konfiguration können Sie jetzt problemlos von Ihrem lokalen System aus auf die Docker-Datenbank zugreifen.

Sanaulla
quelle
Ich weiß, dass dies alt ist, aber jetzt können Sie von Ihrem lokalen System aus problemlos auf die Docker-Datenbank zugreifen, indem Sie der Konfiguration folgen - Sie haben dies falsch herum. Er hat eine lokale Datenbank und eine Docker-App, die versucht, eine Verbindung zu dieser lokalen Datenbank
herzustellen,
2

Die hier veröffentlichte Lösung funktioniert bei mir nicht. Daher poste ich diese Antwort, um jemandem zu helfen, der mit einem ähnlichen Problem konfrontiert ist.

Betriebssystem: Ubuntu 18
PostgreSQL: 9.5 (gehostet unter Ubuntu)
Docker: Serveranwendung (die eine Verbindung zu PostgreSQL herstellt)

Ich verwende docker-compose.yml, um eine Anwendung zu erstellen.

SCHRITT 1: Bitte hinzufügenhost.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"

Um die IP des Dockers zu finden i.e. 172.17.0.1 (in my case), können Sie Folgendes verwenden:

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

ODER

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

SCHRITT 2: Ändern Sie in postgresql.conf listen_addresses inlisten_addresses = '*'

SCHRITT 3: Fügen Sie in pg_hba.conf diese Zeile hinzu

host    all             all             0.0.0.0/0               md5

SCHRITT 4: Starten Sie nun den postgresql-Dienst neu mit:sudo service postgresql restart

SCHRITT 5: Verwenden Sie den host.docker.internalHostnamen, um die Datenbank über die Serveranwendung zu verbinden.
Ex:jdbc:postgresql://host.docker.internal:5432/bankDB

Genießen!!

singhpradeep
quelle
1

Für Docker-Compose können Sie versuchen, einfach hinzuzufügen

network_mode: "host"

Beispiel:

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
quelle
4
Durch Hinzufügen von networkd_mode zum Host wird die Verbindung zwischen anderen Containern
unterbrochen
1

Um etwas Einfaches einzurichten, das eine Postgresql-Verbindung vom Docker-Container zu meinem lokalen Host ermöglicht , habe ich dies in postgresql.conf verwendet:

listen_addresses = '*'

Und fügte diese pg_hba.conf hinzu:

host    all             all             172.17.0.0/16           password

Führen Sie dann einen Neustart durch. Mein Client aus dem Docker-Container (Stand 172.17.0.2) konnte dann eine Verbindung zu Postgresql herstellen, das auf meinem lokalen Host ausgeführt wird, und zwar unter Verwendung des Hosts: Kennwort, Datenbank, Benutzername und Kennwort.

Harlin
quelle
0

Eine weitere Sache, die für mein Setup benötigt wurde, war das Hinzufügen

172.17.0.1  localhost

zu /etc/hosts

Damit Docker auf 172.17.0.1den DB-Hostnamen verweist und sich nicht auf eine sich ändernde äußere IP-Adresse verlässt, um die DB zu finden. Hoffe das hilft jemand anderem bei diesem Problem!

Mikko Pöri
quelle
14
Dies ist eine schlechte Lösung. Localhost sollte normalerweise auf 127.0.0.1 verweisen. Das Ändern kann unerwünschte Folgen haben, auch wenn es in diesem speziellen Fall funktioniert.
Alex
2
Eine bessere Möglichkeit besteht darin, beim Ausführen des Containers einen databaseHost einzurichten --add-host=database:172.17.0.1. Zeigen Sie dann mit Ihrer App auf diesen Host. Dadurch wird vermieden, dass eine IP-Adresse in einem Container fest codiert wird.
Jaredsk
1
das --add-host=database:172.17.0.1ist vorzuziehen
Luis Martins
-3

Die andere Lösung ist das Service-Volume. Sie können ein Service-Volume definieren und das PostgreSQL-Datenverzeichnis des Hosts in dieses Volume einbinden. Überprüfen Sie die angegebene Erstellungsdatei für Details.

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

Auf diese Weise wird ein anderer PostgreSQL-Dienst unter Container ausgeführt, verwendet jedoch dasselbe Datenverzeichnis, das der PostgreSQL-Host-Dienst verwendet.

Hrishi
quelle
1
Dies wird wahrscheinlich Schreibkonflikte mit einem laufenden Host-PostgreSQL-Dienst verursachen
Petrus Theron
Ich denke, das Stoppen des Host-Dienstes wird das Problem in diesem Fall lösen.
Hrishi