Zezwól kontenerowi Dockera na łączenie się z lokalną bazą danych postgres / hosta

143

Ostatnio bawiłem się Dockerem i QGIS i zainstalowałem kontener postępując zgodnie z instrukcjami zawartymi w tym samouczku .

Wszystko działa świetnie, chociaż nie mogę połączyć się z bazą danych postgres localhost, która zawiera wszystkie moje dane GIS. Wydaje mi się, że dzieje się tak, ponieważ moja baza danych Postgres nie jest skonfigurowana do akceptowania połączeń zdalnych i edytuję pliki conf postgres, aby umożliwić połączenia zdalne, korzystając z instrukcji zawartych w tym artykule .

Nadal otrzymuję komunikat o błędzie, gdy próbuję połączyć się z moją bazą danych z uruchomionym QGIS w Dockerze: nie można połączyć się z serwerem: Connection refused Is the server running on host "localhost" (::1) and accepting TCP/IP connections to port 5433? serwer postgres jest uruchomiony i zmodyfikowałem mój plik pg_hba.conf , aby umożliwić połączenia z zakresu Adresy IP (172.17.0.0/32). Wcześniej odpytywałem o adres IP kontenera docker za pomocą docker psi chociaż adres IP się zmienia, do tej pory zawsze znajdował się w zakresie 172.17.0.x

Jakieś pomysły, dlaczego nie mogę połączyć się z tą bazą danych? Prawdopodobnie coś bardzo prostego, jak sobie wyobrażam!

Używam Ubuntu 14.04; Postgres 9.3

marty_c
źródło

Odpowiedzi:

149

TL; DR

  1. Użyj 172.17.0.0/16jako zakresu adresów IP, a nie 172.17.0.0/32.
  2. Nie używaj localhostdo łączenia się z bazą danych PostgreSQL na hoście, ale zamiast tego użyj adresu IP hosta. Aby kontener był przenośny, uruchom go --add-host=database:<host-ip>flagą i użyj databasejako nazwy hosta do łączenia się z PostgreSQL.
  3. Upewnij się, że PostreSQL jest skonfigurowany do nasłuchiwania połączeń na wszystkich adresach IP, a nie tylko na localhost. Poszukaj ustawienia listen_addressesw pliku konfiguracyjnym PostgreSQL, zwykle znajdującym się w /etc/postgresql/9.3/main/postgresql.conf(kredyty dla @DazmoNorton).

Długa wersja

172.17.0.0/32nie jest zakresem adresów IP, ale pojedynczym adresem (nazwanym 172.17.0.0). Żaden kontener Docker nigdy nie otrzyma przypisanego adresu, ponieważ jest to adres sieciowy docker0interfejsu Docker bridge ( ).

Po uruchomieniu Docker utworzy nowy interfejs sieciowy mostu, który możesz łatwo zobaczyć podczas dzwonienia 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

Jak widać, w moim przypadku docker0interfejs ma adres IP 172.17.42.1z maską sieci /16(lub 255.255.0.0). Oznacza to, że adres sieciowy to 172.17.0.0/16.

Adres IP jest przydzielany losowo, ale bez dodatkowej konfiguracji zawsze będzie w 172.17.0.0/16sieci. Do każdego kontenera Docker zostanie przypisany losowy adres z tego zakresu.

Oznacza to, że jeśli chcesz przyznać dostęp do bazy danych ze wszystkich możliwych kontenerów, użyj 172.17.0.0/16.

Helmbert
źródło
1
hej dzięki za twoje komentarze. Zmieniłem mój pg_hba.confna adres, który zasugerowałeś, ale nadal otrzymuję ten sam komunikat o błędzie połączenia po zatrzymaniu i ponownym uruchomieniu usługi postgres. Dodałem linię pod moimi połączeniami ipv4 - czy jest gdzieś jeszcze, gdzie mam dodać sugerowany adres? Alternatywnie, czy w mojej aplikacji QGIS działającej w Dockerze muszę zmienić informacje o połączeniu postgres? Na przykład, jeśli łączę się z kontenera Dockera, czy host nadal jest „localhost”?
marty_c 07.07.15
Ach, to ważna kwestia. Nie, localhostto nie jest system hosta w kontenerze Docker. Spróbuj połączyć się z publicznym adresem IP hosta. Aby zachować przenośność kontenera, możesz również uruchomić kontener za pomocą --add-host=database:<host-ip>i po prostu użyć databasejako nazwy hosta, aby połączyć się z hostem PostgreSQL z poziomu kontenera Docker.
helmbert
6
Potrzebowałem jeszcze jednego kawałka. Musiałem również edytować /etc/postgresql/9.3/main/postgresql.confi dodać eth0adres IP mojego serwera do listen_addresses. Domyślnie listen_addressesma powiązanie localhosttylko z postgres .
Dzamo Norton
@DzamoNorton, dzięki za podpowiedź! Odpowiednio zaktualizowałem swoją odpowiedź.
helmbert
@helmbert host-ipto adres IP maszyny wirtualnej lub kontenera Dockera?
Pan D.
56

Rozwiązanie Docker dla komputerów Mac

17.06 i później

Dzięki komentarzowi @Birchlabs, teraz jest dużo łatwiej dzięki tej specjalnej nazwie DNS tylko dla komputerów Mac :

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

Od 17.12.0-cd-mac46, docker.for.mac.host.internalpowinno być używane zamiast docker.for.mac.localhost. Szczegółowe informacje można znaleźć w informacji o wersji.

Starsza wersja

Odpowiedź @ helmberta dobrze wyjaśnia problem. Ale Docker na Maca nie ujawnia sieci mostkowej , więc musiałem zrobić tę sztuczkę, aby obejść ograniczenie:

$ sudo ifconfig lo0 alias 10.200.10.1/24

Otwórz /usr/local/var/postgres/pg_hba.confi dodaj tę linię:

host    all             all             10.200.10.1/24            trust

Otwórz /usr/local/var/postgres/postgresql.confi edytuj zmianę listen_addresses:

listen_addresses = '*'

Załaduj ponownie usługę i uruchom kontener:

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

To obejście jest zasadniczo takie samo, jak odpowiedź @ helmbert, ale używa adresu IP, do którego jest dołączony lo0zamiast docker0interfejsu sieciowego.

baxang
źródło
3
Czy jest to nadal aktualne na dzień 4 kwietnia 2017 r.?
Petrus Theron
Podoba mi się ten sposób, który nie ujawnia bazy danych. BTW, czy mogę tego używać na CentOS? Pojawił się błąd: alias: nieznany host, kiedy próbowałem użyć podanego przez Ciebie polecenia aliasu.
Tsung Goh,
6
Jest lepszy sposób na macOS, od Docker 17.06.0-rc1-ce-mac13 (1 czerwca 2017). kontenery rozpoznają hosta docker.for.mac.localhost. to jest adres IP twojego komputera głównego. wyszukaj jego wpis w bazie danych hostów kontenera w następujący sposób: docker run alpine /bin/sh -c 'getent hosts docker.for.mac.localhost'
Birchlabs
@Birchlabs To jest niesamowite!
qqilihq
5
Wygląda na to, że zmienił się host.docker.internalod 18.03, inne opcje są nadal dostępne, ale są przestarzałe ( źródło ).
gseva
44

Proste rozwiązanie dla komputerów Mac:

Najnowsza wersja dockera (18.03) oferuje wbudowane rozwiązanie do przekazywania portów. Wewnątrz kontenera docker po prostu ustaw host db na host.docker.internal. Zostanie to przekazane do hosta, na którym działa kontener Dockera.

Dokumentacja na ten temat jest tutaj: https://docs.docker.com/docker-for-mac/networking/#i-want-to-connect-from-a-container-to-a-service-on-the-host

Chris
źródło
3
To zdecydowanie najlepsza odpowiedź teraz! o wiele łatwiej i jak powinno być.
bjm88
2
jest host.docker.internalograniczony tylko do komputerów Mac?
Dragas
@Dragas zgodnie z dokumentacją „nie będzie działać poza komputerem Mac”, ale ta sama nazwa DNS jest wymieniona w dokumentacji Docker dla Windows, więc myślę, że jest ograniczona do „Docker dla ...”. Tak czy inaczej, jest to tylko programowanie: nie zamierzasz wysyłać obrazu dockera, który to wykorzystuje.
Rabarbar
Działa tylko z Windows i Mac. W moim przypadku ubuntu nie działa
Azri Zakaria
16

Proste rozwiązanie

Po prostu dodaj --network=hostdo docker run. To wszystko!

W ten sposób kontener będzie korzystał z sieci hosta, localhosta więc i 127.0.0.1wskaże hosta (domyślnie wskazuje kontener). Przykład:

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
źródło
1
Bądź ostrożny! To rozwiązanie, moim zdaniem słuszne, nie działa na macOS. Nie trać czasu na zastanawianie się, dlaczego to nie działa. Spójrz na: github.com/docker/for-mac/issues/2716
jfcorugedo
Działa na Debianie. Próbowałem zmienić postgresql.conf i pg_hba.conf, ale jest to prostsze i szybsze.
frmbelz
2

W Ubuntu:

Najpierw musisz sprawdzić, czy port bazy danych Docker jest dostępny w twoim systemie, wykonując polecenie -

sudo iptables -L -n

Przykładowe WYJŚCIE:

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

Tutaj 3306jest używany jako port bazy danych Docker na adresie IP 172.17.0.2, jeśli ten port nie jest dostępny Uruchom następujące polecenie -

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

Teraz możesz łatwo uzyskać dostęp do bazy danych Docker z systemu lokalnego, wykonując konfigurację

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

W CentOS:

Najpierw musisz sprawdzić, czy port bazy danych Docker jest dostępny w zaporze, wykonując polecenie -

sudo firewall-cmd --list-all

Przykładowe WYJŚCIE:

  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:

Tutaj 3307jest używany jako port bazy danych Docker na adresie IP 172.17.0.2, jeśli ten port nie jest dostępny Uruchom następujące polecenie -

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

Na serwerze możesz dodać port na stałe

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

Teraz możesz łatwo uzyskać dostęp do bazy danych Docker z systemu lokalnego dzięki powyższej konfiguracji.

Sanaulla
źródło
Wiem, że to jest stare, ale teraz możesz łatwo uzyskać dostęp do bazy danych Docker z systemu lokalnego, postępując zgodnie z konfiguracją - masz to w niewłaściwy sposób. Ma lokalną bazę danych i aplikację docker próbującą połączyć się z lokalną bazą danych, a nie odwrotnie
Craicerjack
2

Przedstawione tutaj rozwiązanie nie działa dla mnie. Dlatego zamieszczam tę odpowiedź, aby pomóc komuś, kto ma podobny problem.

System operacyjny: Ubuntu 18
PostgreSQL: 9.5 (hostowany na Ubuntu)
Docker: Aplikacja serwerowa (która łączy się z PostgreSQL)

Do tworzenia aplikacji używam docker-compose.yml.

KROK 1: Dodajhost.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"

Aby znaleźć adres IP dockera i.e. 172.17.0.1 (in my case), możesz użyć:

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

LUB

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

KROK 2: W postgresql.conf zmień Listen_addresses nalisten_addresses = '*'

KROK 3: W pg_hba.conf dodaj tę linię

host    all             all             0.0.0.0/0               md5

KROK 4: Teraz zrestartuj usługę postgresql używając,sudo service postgresql restart

KROK 5: Użyj host.docker.internalnazwy hosta do połączenia bazy danych z aplikacji serwera.
Dawny:jdbc:postgresql://host.docker.internal:5432/bankDB

Cieszyć się!!

singhpradeep
źródło
1

dla docker-compose możesz spróbować po prostu dodać

network_mode: "host"

przykład:

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
źródło
4
dodanie networkd_mode do hosta przerywa połączenie między innymi kontenerami
Bawantha
1

Aby skonfigurować coś prostego, co pozwala na połączenie Postgresql z kontenera dockera do mojego lokalnego hosta, użyłem tego w postgresql.conf:

listen_addresses = '*'

I dodał ten pg_hba.conf:

host    all             all             172.17.0.0/16           password

Następnie uruchom ponownie. Mój klient z kontenera docker (który był pod adresem 172.17.0.2) mógł wtedy połączyć się z Postgresql działającym na moim lokalnym hoście przy użyciu hosta: hasła, bazy danych, nazwy użytkownika i hasła.

Harlin
źródło
0

Jeszcze jedna rzecz potrzebna do mojej konfiguracji to dodanie

172.17.0.1  localhost

do /etc/hosts

tak, że Docker wskazywałby 172.17.0.1jako nazwę hosta DB i nie polegał na zmieniającym się zewnętrznym adresie IP w celu znalezienia DB. Mam nadzieję, że pomoże to komuś innemu w rozwiązaniu tego problemu!

Mikko Pöri
źródło
14
To jest złe rozwiązanie. Localhost powinien zazwyczaj wskazywać na 127.0.0.1. Zmiana może mieć niepożądane konsekwencje, nawet jeśli w tym konkretnym przypadku zadziała.
Alex
2
Lepszym sposobem jest skonfigurowanie databasehosta --add-host=database:172.17.0.1przy uruchomieniu kontenera. Następnie skieruj swoją aplikację do tego hosta. Pozwala to uniknąć zakodowania adresu IP na stałe w kontenerze.
jaredsk
1
to --add-host=database:172.17.0.1jest lepsze
Luis Martins
-3

Innym rozwiązaniem jest wolumen usług. Możesz zdefiniować wolumen usługi i zamontować w nim katalog danych PostgreSQL hosta. Sprawdź podany plik tworzenia, aby uzyskać szczegółowe informacje.

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

W ten sposób inna usługa PostgreSQL będzie działać w kontenerze, ale używa tego samego katalogu danych, którego używa usługa hosta PostgreSQL.

Hrishi
źródło
1
Prawdopodobnie spowoduje to konflikty zapisu z uruchomioną usługą PostgreSQL hosta
Petrus Theron
Myślę, że zatrzymanie usługi hosta rozwiąże problem w tym przypadku.
Hrishi