Cho phép bộ chứa docker kết nối với cơ sở dữ liệu postgres cục bộ / máy chủ


143

Gần đây tôi đã chơi xung quanh với Docker và QGIS và đã cài đặt một container theo hướng dẫn trong hướng dẫn này .

Mọi thứ hoạt động rất tốt, mặc dù tôi không thể kết nối với cơ sở dữ liệu postgres localhost có chứa tất cả dữ liệu GIS của tôi. Tôi nghĩ điều này là do cơ sở dữ liệu postgres của tôi không được cấu hình để chấp nhận các kết nối từ xa và đã chỉnh sửa các tệp conf postgres để cho phép kết nối từ xa bằng cách sử dụng các hướng dẫn trong bài viết này .

Tôi vẫn nhận được thông báo lỗi khi tôi thử và kết nối với cơ sở dữ liệu của mình đang chạy QGIS trong Docker: không thể kết nối với máy chủ: Connection refused Is the server running on host "localhost" (::1) and accepting TCP/IP connections to port 5433? Máy chủ postgres đang chạy và tôi đã chỉnh sửa tệp pg_hba.conf của mình để cho phép kết nối từ một phạm vi Địa chỉ IP (172.17.0.0 / 32). Trước đây tôi đã truy vấn địa chỉ IP của bộ chứa docker bằng cách sử dụng docker psvà mặc dù địa chỉ IP thay đổi, cho đến nay nó vẫn luôn nằm trong phạm vi 172,17.0.x

Bất cứ ý tưởng tại sao tôi không thể kết nối với cơ sở dữ liệu này? Có lẽ một cái gì đó rất đơn giản tôi tưởng tượng!

Tôi đang chạy Ubuntu 14.04; Hậu 9,3

Câu trả lời:


149

TL; DR

  1. Sử dụng 172.17.0.0/16như dải địa chỉ IP, không 172.17.0.0/32.
  2. Không sử dụng localhostđể kết nối với cơ sở dữ liệu PostgreQuery trên máy chủ của bạn, nhưng thay vào đó là IP của máy chủ. Để giữ cho bộ chứa di động, hãy khởi động bộ chứa với --add-host=database:<host-ip>cờ và sử dụng databaselàm tên máy chủ để kết nối với PostgreQuery.
  3. Đảm bảo PostreSQL được cấu hình để lắng nghe các kết nối trên tất cả các địa chỉ IP, không chỉ trên localhost. Tìm kiếm cài đặt listen_addressestrong tệp cấu hình của /etc/postgresql/9.3/main/postgresql.confPostgreQuery , thường được tìm thấy trong (tín dụng cho @DazmoNorton).

Phiên bản dài

172.17.0.0/32không phải là một phạm vi địa chỉ IP, mà là một địa chỉ duy nhất (namly 172.17.0.0). Không có container Docker nào được gán địa chỉ đó, vì đó là địa chỉ mạng của docker0giao diện Docker Bridge ( ).

Khi Docker khởi động, nó sẽ tạo ra một giao diện mạng cầu mới, mà bạn có thể dễ dàng nhìn thấy khi gọi 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

Như bạn có thể thấy, trong trường hợp của tôi, docker0giao diện có địa chỉ IP 172.17.42.1với một mặt nạ là/16 (hoặc 255.255.0.0). Điều này có nghĩa là địa chỉ mạng là 172.17.0.0/16.

Địa chỉ IP được gán ngẫu nhiên, nhưng không có bất kỳ cấu hình bổ sung nào, nó sẽ luôn nằm trong 172.17.0.0/16mạng. Đối với mỗi container Docker, một địa chỉ ngẫu nhiên từ phạm vi đó sẽ được chỉ định.

Điều này có nghĩa, nếu bạn muốn cấp quyền truy cập từ tất cả các container có thể vào cơ sở dữ liệu của bạn, hãy sử dụng 172.17.0.0/16.


1
hey cảm ơn ý kiến ​​của bạn. Tôi đã thay đổi pg_hba.confđịa chỉ mà bạn đề xuất, nhưng vẫn nhận được thông báo lỗi kết nối tương tự sau khi dừng và khởi động lại dịch vụ postgres. Tôi đã thêm dòng dưới các kết nối ipv4 của mình - có nơi nào khác tôi phải thêm địa chỉ mà bạn đề xuất không? Ngoài ra, trong ứng dụng QGIS của tôi đang chạy trong Docker, tôi có cần thay đổi thông tin kết nối của postgres không? Ví dụ: nếu tôi kết nối từ trong một container docker thì máy chủ vẫn là 'localhost'?
marty_c 7/07/2015

Ah, đó là một điểm quan trọng. Không, localhostkhông phải là hệ thống máy chủ bên trong container Docker của bạn. Hãy thử kết nối với địa chỉ IP công cộng của hệ thống máy chủ. Để giữ cho bộ chứa di động, bạn cũng có thể khởi động bộ chứa với --add-host=database:<host-ip>và chỉ cần sử dụng databaselàm tên máy chủ để kết nối với máy chủ PostgreQuery của bạn từ trong bộ chứa Docker.
helmbert 7/07/2015

6
Tôi cần thêm một mảnh nữa. Tôi cũng đã phải chỉnh sửa /etc/postgresql/9.3/main/postgresql.confvà thêm eth0địa chỉ IP của máy chủ của mình vào listen_addresses. Theo mặc định listen_addressescó postgres liên kết đến localhostchỉ.
Dzamo Norton 7/11/2015

@DzamoNorton, cảm ơn vì gợi ý! Tôi cập nhật câu trả lời của tôi cho phù hợp.
helmbert

@musbert host-iplà địa chỉ IP của máy ảo hoặc container docker ?
Mr.D

56

Docker cho giải pháp Mac

17,06 trở đi

Nhờ nhận xét của @Birchlabs, giờ đây việc tấn công dễ dàng hơn với tên DNS đặc biệt chỉ dành cho máy Mac này :

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

Từ 17.12.0-cd-mac46, docker.for.mac.host.internalnên được sử dụng thay vì docker.for.mac.localhost. Xem ghi chú phát hành để biết chi tiết.

Phiên bản cũ hơn

Câu trả lời của @ helmbert cũng giải thích vấn đề này. Nhưng Docker cho Mac không làm lộ mạng cầu , vì vậy tôi đã phải thực hiện thủ thuật này để khắc phục hạn chế:

$ sudo ifconfig lo0 alias 10.200.10.1/24

Mở /usr/local/var/postgres/pg_hba.confvà thêm dòng này:

host    all             all             10.200.10.1/24            trust

Mở /usr/local/var/postgres/postgresql.confvà chỉnh sửa thay đổi listen_addresses:

listen_addresses = '*'

Tải lại dịch vụ và khởi chạy container của bạn:

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

Cách giải quyết này về cơ bản giống với câu trả lời của @ helmbert, nhưng sử dụng địa chỉ IP được đính kèm lo0thay vì docker0giao diện mạng.


3
Đây có phải là hiện tại kể từ ngày 4 tháng 4 năm 2017?
Petrus Theron

Tôi thích cách này sẽ không làm lộ cơ sở dữ liệu. BTW, tôi có thể sử dụng cái này trên CentOS không? Tôi đã gặp lỗi: bí danh: Máy chủ không xác định khi tôi cố gắng sử dụng lệnh bí danh mà bạn cung cấp.
Tsung Goh

6
Có một cách tốt hơn trên macOS, kể từ Docker 17,06.0-rc1-ce-mac13 (ngày 1 tháng 6 năm 2017). container nhận ra máy chủ docker.for.mac.localhost. đây là IP của máy chủ của bạn tra cứu mục nhập của nó trong cơ sở dữ liệu máy chủ chứa như vậy: docker run alpine /bin/sh -c 'getent hosts docker.for.mac.localhost'
Birchlabs

@Birchlabs Điều này thật tuyệt vời!
qqilihq

5
Có vẻ như nó đã thay đổi host.docker.internaltừ ngày 18.03, các tùy chọn khác vẫn có sẵn nhưng không dùng nữa ( Nguồn ).
gseva

44

Giải pháp đơn giản cho mac:

Phiên bản mới nhất của docker (18.03) cung cấp giải pháp chuyển tiếp cổng tích hợp. Trong thùng chứa docker của bạn chỉ cần đặt máy chủ db thành host.docker.internal. Điều này sẽ được chuyển tiếp đến máy chủ chứa container đang chạy.

Tài liệu cho việc này có tại đây: https://docs.docker.com/docker-for-mac/networking/#i-want-to-connect-from-a-container-to-a-service-on-the-host


3
Đây là câu trả lời tốt nhất bây giờ! cách dễ dàng hơn và làm thế nào nó nên được.
bjm88

2
được host.docker.internalgiới hạn chỉ Mac?
Dragas

@Dragas theo các tài liệu, nó sẽ "không hoạt động bên ngoài máy Mac", nhưng cùng một tên DNS được đề cập trong các tài liệu cho Docker cho Windows, vì vậy tôi nghĩ rằng nó bị giới hạn ở "Docker cho ...". Dù bằng cách nào thì nó chỉ phát triển: bạn không có ý định gửi một hình ảnh docker sử dụng điều này.
hoàng

Chỉ làm việc với windows và mac. Trong trường hợp của tôi, Ubuntu không hoạt động
Azri Zakaria

16

Giải pháp đơn giản

Chỉ cần thêm --network=hostvào docker run. Đó là tất cả!

Bằng cách này, container sẽ sử dụng mạng của máy chủ, vì vậy localhost127.0.0.1sẽ trỏ đến máy chủ (theo mặc định chúng trỏ đến một container). Thí dụ:

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
Hãy cẩn thận! Theo tôi, giải pháp này là một giải pháp phù hợp, không hoạt động với macOS. Đừng lãng phí thời gian của bạn để cố gắng tìm hiểu tại sao nó không hoạt động. Hãy xem: github.com/docker/for-mac/issues/2716
jfcorugedo

Hoạt động trên Debian. Đã thử thay đổi postgresql.conf và pg_hba.conf nhưng việc này đơn giản và nhanh hơn.
frmbelz

2

Trong Ubuntu:

Trước tiên, bạn phải kiểm tra xem cổng Cơ sở dữ liệu Docker có sẵn trong hệ thống của bạn không bằng lệnh sau -

sudo iptables -L -n

Mẫu đầu ra:

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

Ở đây 3306được sử dụng làm Cổng cơ sở dữ liệu Docker trên IP 172.17.0.2, Nếu cổng này không khả dụng Chạy lệnh sau -

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

Giờ đây, bạn có thể dễ dàng truy cập Cơ sở dữ liệu Docker từ hệ thống cục bộ của mình bằng cách cấu hình sau

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

Trong CentOS:

Trước tiên, bạn phải kiểm tra xem cổng Cơ sở dữ liệu Docker có sẵn trong tường lửa của bạn không bằng lệnh sau -

sudo firewall-cmd --list-all

Mẫu đầu ra:

  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:

Ở đây 3307được sử dụng làm Cổng cơ sở dữ liệu Docker trên IP 172.17.0.2, Nếu cổng này không khả dụng Chạy lệnh sau -

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

Trong máy chủ, Bạn có thể thêm cổng vĩnh viễn

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

Giờ đây, bạn có thể dễ dàng truy cập Cơ sở dữ liệu Docker từ hệ thống cục bộ của mình bằng cấu hình trên.


Tôi biết điều này đã cũ nhưng Bây giờ, Bạn có thể dễ dàng truy cập Cơ sở dữ liệu Docker từ hệ thống cục bộ của mình bằng cách làm theo cấu hình - bạn có cách này sai. Anh ta có một cơ sở dữ liệu cục bộ và một ứng dụng docker đang cố gắng kết nối với db cục bộ đó chứ không phải cách khác
Craicerjack

2

Các giải pháp được đăng ở đây không làm việc cho tôi. Do đó, tôi đang đăng câu trả lời này để giúp ai đó đối mặt với vấn đề tương tự.

HĐH: Ubuntu 18
PostgreSQL: 9.5 (Được lưu trữ trên Ubuntu)
Docker: Ứng dụng máy chủ (kết nối với PostgreQuery)

Tôi đang sử dụng docker-compose.yml để xây dựng ứng dụng.

BƯỚC 1: Vui lòng thêmhost.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"

Để tìm IP của docker, i.e. 172.17.0.1 (in my case)bạn có thể sử dụng:

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

HOẶC LÀ

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

BƯỚC 2: Trong postgresql.conf, thay đổi list_addresses thànhlisten_addresses = '*'

BƯỚC 3: Trong pg_hba.conf, thêm dòng này

host    all             all             0.0.0.0/0               md5

BƯỚC 4: Bây giờ khởi động lại dịch vụ postgresql bằng cách sử dụng,sudo service postgresql restart

BƯỚC 5: Vui lòng sử dụng host.docker.internaltên máy chủ để kết nối cơ sở dữ liệu từ Ứng dụng máy chủ.
Ví dụ:jdbc:postgresql://host.docker.internal:5432/bankDB

Thưởng thức!!



1

Để thiết lập một cái gì đó đơn giản cho phép kết nối Postgresql từ bộ chứa docker đến localhost của tôi, tôi đã sử dụng cái này trong postgresql.conf:

listen_addresses = '*'

Và đã thêm pg_hba.conf này:

host    all             all             172.17.0.0/16           password

Sau đó thực hiện khởi động lại. Máy khách của tôi từ bộ chứa docker (lúc đó là 172.17.0.2) sau đó có thể kết nối với Postgresql chạy trên localhost của tôi bằng cách sử dụng máy chủ: mật khẩu, cơ sở dữ liệu, tên người dùng và mật khẩu.


0

Một điều nữa cần thiết cho thiết lập của tôi là thêm

172.17.0.1  localhost

đến /etc/hosts

để Docker sẽ trỏ đến 172.17.0.1tên máy chủ DB và không dựa vào ip bên ngoài thay đổi để tìm DB. Hy vọng điều này sẽ giúp người khác với vấn đề này!


14
Đây là một giải pháp tồi. Localhost thường nên trỏ đến 127.0.0.1. Thay đổi nó có thể có hậu quả không mong muốn, ngay cả trong trường hợp cụ thể này nó hoạt động.
Alex

2
Một cách tốt hơn là thiết lập một databasemáy chủ lưu trữ --add-host=database:172.17.0.1khi chạy container. Sau đó trỏ ứng dụng của bạn đến máy chủ đó. Điều này tránh mã hóa cứng một địa chỉ IP bên trong một container.
jaredsk

1
những --add-host=database:172.17.0.1là một lợi thế
Luis Martins

-3

Giải pháp khác là khối lượng dịch vụ, Bạn có thể xác định khối lượng dịch vụ và gắn thư mục Dữ liệu PostgreQuery của máy chủ lưu trữ trong khối đó. Kiểm tra các tập tin soạn cho trước để biết chi tiết.

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

Bằng cách này, một dịch vụ PostgreQuery khác sẽ chạy trong vùng chứa nhưng sử dụng cùng thư mục dữ liệu mà máy chủ dịch vụ PostgreQuery đang sử dụng.


1
Điều này có thể sẽ gây ra xung đột ghi với dịch vụ PostgreSQL đang chạy
Petrus Theron

Tôi nghĩ rằng dừng dịch vụ lưu trữ sẽ giải quyết vấn đề trong trường hợp đó.
Hrishi
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.