อนุญาตให้ docker container เชื่อมต่อกับฐานข้อมูล postgres ในเครื่อง / โฮสต์


153

ฉันเพิ่งเล่นกับ Docker และ QGIS และได้ติดตั้งคอนเทนเนอร์ตามคำแนะนำในบทช่วยสอนนี้

ทุกอย่างใช้งานได้ดีแม้ว่าฉันจะไม่สามารถเชื่อมต่อกับฐานข้อมูล localhost postgres ที่มีข้อมูล GIS ทั้งหมดของฉัน ฉันคิดว่านี้เป็นเพราะฐานข้อมูล Postgres ของฉันไม่ได้กำหนดค่าให้ยอมรับการเชื่อมต่อระยะไกลและได้รับการแก้ไขไฟล์ postgres conf จะอนุญาตให้เชื่อมต่อระยะไกลโดยใช้คำแนะนำในบทความนี้

ฉันยังคงได้รับข้อความแสดงข้อผิดพลาดเมื่อฉันพยายามเชื่อมต่อกับฐานข้อมูลของฉันที่เรียกใช้ QGIS ใน Docker: ไม่สามารถเชื่อมต่อกับเซิร์ฟเวอร์ได้: Connection refused Is the server running on host "localhost" (::1) and accepting TCP/IP connections to port 5433? เซิร์ฟเวอร์ postgres กำลังทำงานอยู่และฉันได้แก้ไขไฟล์pg_hba.confของฉันเพื่ออนุญาตการเชื่อมต่อจากช่วงของ ที่อยู่ IP (172.17.0.0/32) ก่อนหน้านี้ฉันเคยสอบถามที่อยู่ IP ของคอนเทนเนอร์นักเทียบท่าโดยใช้docker psและแม้ว่าที่อยู่ IP จะเปลี่ยนไป แต่ก็อยู่ในช่วง 172.17.0.x มาโดยตลอด

มีความคิดเห็นว่าทำไมฉันถึงเชื่อมต่อกับฐานข้อมูลนี้ไม่ได้? อาจเป็นสิ่งที่ง่ายมากที่ฉันคิด!

ฉันใช้ Ubuntu 14.04; Postgres 9.3

คำตอบ:


159

TL; ดร

  1. ใช้172.17.0.0/16เป็นช่วงที่อยู่ IP 172.17.0.0/32ไม่
  2. อย่าใช้localhostเชื่อมต่อกับฐานข้อมูล PostgreSQL บนโฮสต์ของคุณ แต่เป็น IP ของโฮสต์แทน เพื่อให้คอนเทนเนอร์พกพาได้ให้เริ่มคอนเทนเนอร์ด้วย--add-host=database:<host-ip>แฟล็กและใช้databaseเป็นชื่อโฮสต์สำหรับเชื่อมต่อกับ PostgreSQL
  3. ตรวจสอบให้แน่ใจ PostgreSQL การกำหนดค่าให้ฟังสำหรับการเชื่อมต่อในทุกที่อยู่ IP ไม่เพียง localhostแต่ใน ค้นหาการตั้งค่าlisten_addressesในไฟล์คอนฟิกูเรชันของ PostgreSQL ซึ่งโดยทั่วไปจะอยู่ใน/etc/postgresql/9.3/main/postgresql.conf(เครดิตถึง @DazmoNorton)

เวอร์ชันยาว

172.17.0.0/32ไม่ใช่ช่วงของที่อยู่ IP แต่เป็นที่อยู่เดียว (นาม172.17.0.0) ไม่มีคอนเทนเนอร์ Docker ที่จะได้รับที่อยู่นั้นเนื่องจากเป็นที่อยู่เครือข่ายของdocker0อินเทอร์เฟซDocker bridge ( )

เมื่อ Docker เริ่มต้นมันจะสร้างอินเทอร์เฟซเครือข่ายบริดจ์ใหม่ที่คุณสามารถมองเห็นได้ง่ายเมื่อโทร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

อย่างที่คุณเห็นในกรณีของฉันdocker0อินเทอร์เฟซมีที่อยู่ IP 172.17.42.1พร้อมกับ netmask เป็น/16(หรือ255.255.0.0) 172.17.0.0/16ซึ่งหมายความว่าที่อยู่เครือข่าย

ที่อยู่ IP ถูกกำหนดแบบสุ่ม แต่ไม่มีการกำหนดค่าเพิ่มเติมใด ๆ จะอยู่ใน172.17.0.0/16เครือข่ายเสมอ สำหรับคอนเทนเนอร์ Docker แต่ละอันจะมีการกำหนดแอดเดรสแบบสุ่มจากช่วงนั้น

172.17.0.0/16วิธีนี้ถ้าคุณต้องการที่จะให้สิทธิ์การเข้าถึงจากภาชนะบรรจุที่เป็นไปได้ทั้งหมดไปยังฐานข้อมูลของคุณใช้


1
เฮ้ขอบคุณสำหรับความคิดเห็นของคุณ ฉันเปลี่ยนpg_hba.confเป็นที่อยู่ที่คุณแนะนำ แต่ยังคงได้รับข้อความแสดงข้อผิดพลาดการเชื่อมต่อเหมือนเดิมหลังจากหยุดและเริ่มบริการ postgres ใหม่ ฉันได้เพิ่มบรรทัดภายใต้การเชื่อมต่อ ipv4 ของฉัน - มีที่อื่นฉันควรจะเพิ่มที่อยู่ที่คุณแนะนำหรือไม่? หรือในแอพ QGIS ของฉันที่ทำงานใน Docker ฉันจำเป็นต้องเปลี่ยนข้อมูลการเชื่อมต่อ postgres หรือไม่ ตัวอย่างเช่นหากฉันเชื่อมต่อจากภายในคอนเทนเนอร์นักเทียบท่าโฮสต์จะยังคงเป็น "localhost" อยู่หรือไม่
marty_c

อาเป็นจุดสำคัญ ไม่ใช่localhostไม่ใช่ระบบโฮสต์ภายในคอนเทนเนอร์ Docker ของคุณ ลองเชื่อมต่อกับที่อยู่ IP สาธารณะของระบบโฮสต์ เพื่อให้คอนเทนเนอร์พกพาได้คุณยังสามารถเริ่มคอนเทนเนอร์ด้วย--add-host=database:<host-ip>และใช้databaseเป็นชื่อโฮสต์เพื่อเชื่อมต่อกับโฮสต์ PostgreSQL ของคุณจากภายในคอนเทนเนอร์ Docker
helmbert

6
ฉันต้องการอีกหนึ่งชิ้น ฉันต้องแก้ไข/etc/postgresql/9.3/main/postgresql.confและเพิ่มeth0ที่อยู่ IP ของเซิร์ฟเวอร์ของฉันlisten_addressesด้วย โดยค่าเริ่มต้นlisten_addressesมีการเชื่อมโยง postgres กับlocalhostเท่านั้น
Dzamo Norton

@DzamoNorton ขอบคุณสำหรับคำใบ้! ฉันอัปเดตคำตอบตามนั้น
helmbert

@helmbert host-ipเป็นที่อยู่ IP ของเครื่องเสมือนหรือคอนเทนเนอร์นักเทียบท่า?
Mr.D

61

โซลูชัน Docker สำหรับ Mac

17.06 น. เป็นต้นไป

ขอบคุณความคิดเห็นของ @Birchlabs ตอนนี้ง่ายขึ้นมากด้วยชื่อ DNS เฉพาะ Mac ที่มีให้ :

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

ตั้งแต่ 17.12.0-cd-mac46 docker.for.mac.host.internalควรใช้แทนdocker.for.mac.localhostไฟล์. ดูรายละเอียดในบันทึกประจำรุ่น

เวอร์ชันเก่ากว่า

คำตอบของ @ helmbert อธิบายปัญหาได้ดี แต่ Docker สำหรับ Mac ไม่เปิดเผยเครือข่ายบริดจ์ดังนั้นฉันจึงต้องทำเคล็ดลับนี้เพื่อแก้ไขข้อ จำกัด :

$ sudo ifconfig lo0 alias 10.200.10.1/24

เปิด/usr/local/var/postgres/pg_hba.confและเพิ่มบรรทัดนี้:

host    all             all             10.200.10.1/24            trust

เปิด/usr/local/var/postgres/postgresql.confและแก้ไขการเปลี่ยนแปลงlisten_addresses:

listen_addresses = '*'

โหลดบริการใหม่และเปิดคอนเทนเนอร์ของคุณ:

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

วิธีแก้ปัญหานี้โดยพื้นฐานแล้วจะเหมือนกันกับคำตอบของ @ helmbert แต่ใช้ที่อยู่ IP ที่เชื่อมต่อlo0แทนdocker0อินเทอร์เฟซเครือข่าย


3
ปัจจุบันยังเป็นวันที่ 4 เมษายน 2560 หรือไม่
Petrus Theron

ฉันชอบวิธีนี้ซึ่งจะไม่เปิดเผยฐานข้อมูล BTW ฉันสามารถใช้สิ่งนี้บน CentOS ได้หรือไม่ ฉันได้รับข้อผิดพลาด: alias: Unknown host เมื่อฉันพยายามใช้คำสั่งนามแฝงที่คุณระบุ
Tsung Goh

6
มีวิธีที่ดีกว่าบน macOS เช่น Docker 17.06.0-rc1-ce-mac13 (1 มิถุนายน 2017) docker.for.mac.localhostภาชนะบรรจุที่รู้จักโฮสต์ นี่คือ IP ของเครื่องโฮสต์ของคุณ ค้นหารายการในฐานข้อมูลโฮสต์ของคอนเทนเนอร์ดังนี้: docker run alpine /bin/sh -c 'getent hosts docker.for.mac.localhost'
Birchlabs

@Birchlabs นี่มันสุดยอดมาก!
qqilihq

5
ดูเหมือนว่าจะเปลี่ยนเป็นhost.docker.internalตั้งแต่ 18.03 เป็นต้นไปตัวเลือกอื่น ๆ ยังคงพร้อมใช้งาน แต่เลิกใช้แล้ว ( ที่มา )
gseva

48

วิธีง่ายๆสำหรับ mac:

Docker เวอร์ชันใหม่ล่าสุด (18.03) นำเสนอโซลูชันการส่งต่อพอร์ตในตัว ภายในคอนเทนเนอร์นักเทียบท่าของคุณเพียงแค่ตั้งค่าโฮสต์ฐานข้อมูลเป็นhost.docker.internal. สิ่งนี้จะถูกส่งต่อไปยังโฮสต์ที่ Docker container กำลังทำงานอยู่

เอกสารสำหรับสิ่งนี้อยู่ที่นี่: https://docs.docker.com/docker-for-mac/networking/#i-want-to-connect-from-a-container-to-a-service-on-the-host


3
นี่คือคำตอบที่ดีที่สุดในตอนนี้! วิธีที่ง่ายขึ้นและควรจะเป็นอย่างไร
bjm88

2
จะถูกhost.docker.internalจำกัด ให้แม็คเท่านั้น?
Dragas

@Dragas ตามเอกสารจะ "ไม่ทำงานนอก Mac" แต่มีการกล่าวถึงชื่อ DNS เดียวกันในเอกสารสำหรับ Docker สำหรับ Windows ดังนั้นฉันคิดว่า จำกัด เฉพาะ "Docker for ... " ไม่ว่าจะเป็นวิธีการพัฒนาเท่านั้น: คุณไม่ได้ตั้งใจที่จะส่งภาพนักเทียบท่าที่ใช้สิ่งนี้
Rhubarb

ใช้งานได้กับ windows และ mac เท่านั้น ในกรณีของฉัน ubuntu ไม่ทำงาน
Azri Zakaria

20

วิธีแก้ปัญหาง่ายๆ

เพียงแค่เพิ่มการ--network=host docker runนั่นคือทั้งหมด!

วิธีนี้คอนเทนเนอร์จะใช้เครือข่ายของโฮสต์ดังนั้นlocalhostและ127.0.0.1จะชี้ไปที่โฮสต์ (โดยค่าเริ่มต้นจะชี้ไปที่คอนเทนเนอร์) ตัวอย่าง:

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

3
ระวัง! วิธีนี้เป็นวิธีที่ถูกต้องในความคิดของฉันใช้ไม่ได้กับ macOS อย่าเสียเวลากับการพยายามหาสาเหตุว่าทำไมมันถึงไม่ได้ผล ลองดูที่: github.com/docker/for-mac/issues/2716
jfcorugedo

1
ทำงานบน Debian พยายามเปลี่ยน postgresql.conf และ pg_hba.conf แต่ทำได้ง่ายและเร็วกว่า
frmbelz

6

วิธีแก้ปัญหาที่โพสต์ไว้ที่นี่ใช้ไม่ได้กับฉัน ดังนั้นฉันจึงโพสต์คำตอบนี้เพื่อช่วยให้ผู้ที่ประสบปัญหาคล้ายกัน

ระบบปฏิบัติการ: Ubuntu 18
PostgreSQL: 9.5 (Hosted on Ubuntu)
Docker: Server Application (ซึ่งเชื่อมต่อกับ PostgreSQL)

ฉันใช้ docker-compose.yml เพื่อสร้างแอปพลิเคชัน

ขั้นตอนที่ 1:โปรดเพิ่มhost.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"

ในการค้นหา IP ของนักเทียบท่าi.e. 172.17.0.1 (in my case)คุณสามารถใช้:

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

หรือ

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

ขั้นตอนที่ 2:ใน postgresql.conf ให้เปลี่ยน listen_addresses เป็นlisten_addresses = '*'

ขั้นตอนที่ 3:ใน pg_hba.conf ให้เพิ่มบรรทัดนี้

host    all             all             0.0.0.0/0               md5

ขั้นตอนที่ 4:ตอนนี้เริ่มบริการ postgresql ใหม่โดยใช้sudo service postgresql restart

ขั้นตอนที่ 5:โปรดใช้host.docker.internalชื่อโฮสต์เพื่อเชื่อมต่อฐานข้อมูลจาก Server Application
เช่น:jdbc:postgresql://host.docker.internal:5432/bankDB

สนุก!!


3

สำหรับนักเทียบท่าคุณสามารถลองเพิ่มได้

network_mode: "host"

ตัวอย่าง:

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


4
การเพิ่ม networkd_mode เพื่อให้โฮสต์ทำลายการเชื่อมต่อระหว่างคอนเทนเนอร์อื่น
Bawantha

2

ใน Ubuntu:

ก่อนอื่นคุณต้องตรวจสอบว่าเป็นพอร์ตฐานข้อมูล Docker ที่มีอยู่ในระบบของคุณโดยทำตามคำสั่ง -

sudo iptables -L -n

เอาท์พุทตัวอย่าง:

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

ที่นี่3306ใช้เป็น Docker Database Port บน 172.17.0.2 IP หากไม่มีพอร์ตนี้ให้รันคำสั่งต่อไปนี้ -

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

ตอนนี้คุณสามารถเข้าถึงฐานข้อมูล Docker ได้อย่างง่ายดายจากระบบภายในของคุณโดยทำตามการกำหนดค่า

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

ใน CentOS:

ก่อนอื่นคุณต้องตรวจสอบว่าเป็นพอร์ต Docker Database ที่มีอยู่ในไฟร์วอลล์ของคุณโดยทำตามคำสั่ง -

sudo firewall-cmd --list-all

เอาท์พุทตัวอย่าง:

  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:

ที่นี่3307ใช้เป็น Docker Database Port บน 172.17.0.2 IP หากไม่มีพอร์ตนี้ให้รันคำสั่งต่อไปนี้ -

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

ในเซิร์ฟเวอร์คุณสามารถเพิ่มพอร์ตได้อย่างถาวร

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

ตอนนี้คุณสามารถเข้าถึงฐานข้อมูล Docker จากระบบภายในของคุณได้อย่างง่ายดายด้วยการกำหนดค่าข้างต้น


2
ฉันรู้ว่านี่เก่า แต่ตอนนี้คุณสามารถเข้าถึงฐานข้อมูล Docker จากระบบภายในของคุณได้อย่างง่ายดายโดยทำตามการกำหนดค่า - คุณมีวิธีนี้ผิด เขามีฐานข้อมูลในเครื่องและแอปนักเทียบท่าที่พยายามเชื่อมต่อกับฐานข้อมูลท้องถิ่นนั้นไม่ใช่วิธีอื่น
Craicerjack

1

ในการตั้งค่าสิ่งง่ายๆที่อนุญาตให้มีการเชื่อมต่อ Postgresql จากคอนเทนเนอร์นักเทียบท่าไปยังโฮสต์ท้องถิ่นของฉันฉันใช้สิ่งนี้ใน postgresql.conf:

listen_addresses = '*'

และเพิ่ม pg_hba.conf นี้:

host    all             all             172.17.0.0/16           password

จากนั้นทำการรีสตาร์ท ไคลเอนต์ของฉันจากคอนเทนเนอร์นักเทียบท่า (ซึ่งอยู่ที่ 172.17.0.2) สามารถเชื่อมต่อกับ Postgresql ที่ทำงานบนโลคัลโฮสต์ของฉันโดยใช้โฮสต์: รหัสผ่านฐานข้อมูลชื่อผู้ใช้และรหัสผ่าน


0

อีกสิ่งหนึ่งที่จำเป็นสำหรับการตั้งค่าของฉันคือการเพิ่ม

172.17.0.1  localhost

ถึง /etc/hosts

เพื่อให้ Docker ชี้ไป172.17.0.1ที่ชื่อโฮสต์ DB และไม่ต้องพึ่งพา ip ภายนอกที่เปลี่ยนแปลงเพื่อค้นหา DB หวังว่านี่จะช่วยคนอื่นเกี่ยวกับปัญหานี้!


15
นี่เป็นทางออกที่ไม่ดี Localhost ควรชี้ไปที่ 127.0.0.1 การเปลี่ยนอาจส่งผลที่ไม่ต้องการแม้ว่าในกรณีนี้จะได้ผลก็ตาม
Alex

2
วิธีที่ดีกว่าคือตั้งค่าdatabaseโฮสต์ด้วย--add-host=database:172.17.0.1เมื่อเรียกใช้คอนเทนเนอร์ จากนั้นชี้แอปของคุณไปที่โฮสต์นั้น วิธีนี้หลีกเลี่ยงการเข้ารหัสที่อยู่ IP อย่างหนักในคอนเทนเนอร์
jaredsk

1
--add-host=database:172.17.0.1เป็นที่นิยม
หลุยส์มาร์ติน

-3

อีกวิธีหนึ่งคือปริมาณบริการคุณสามารถกำหนดปริมาณบริการและติดตั้งไดเร็กทอรี PostgreSQL Data ของโฮสต์ในไดรฟ์ข้อมูลนั้น ตรวจสอบไฟล์เขียนที่ระบุเพื่อดูรายละเอียด

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

เมื่อทำเช่นนี้บริการ PostgreSQL อื่นจะทำงานภายใต้คอนเทนเนอร์ แต่ใช้ไดเร็กทอรีข้อมูลเดียวกันกับที่โฮสต์บริการ PostgreSQL ใช้อยู่


1
สิ่งนี้อาจทำให้เกิดข้อขัดแย้งในการเขียนกับบริการ PostgreSQL ของโฮสต์ที่ทำงานอยู่
Petrus Theron

ฉันคิดว่าการหยุดบริการโฮสต์จะช่วยแก้ปัญหาได้ในกรณีนั้น
Hrishi
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.