จากด้านในของ Docker container ฉันจะเชื่อมต่อกับ localhost ของเครื่องได้อย่างไร


1449

ดังนั้นฉันมี Nginx ที่ทำงานอยู่ภายใน container docker, ฉันมี mysql ที่ทำงานบน localhost, ฉันต้องการเชื่อมต่อ MySql จากภายใน Nginx ของฉัน MySql กำลังทำงานบน localhost และไม่เปิดเผยพอร์ตไปสู่โลกภายนอกดังนั้นมันจึงถูกผูกไว้กับ localhost ไม่ได้ถูกผูกไว้กับที่อยู่ IP ของเครื่อง

มีวิธีใดบ้างที่จะเชื่อมต่อกับ MySql นี้หรือโปรแกรมอื่น ๆ บน localhost จากภายใน container docker นี้?

คำถามนี้แตกต่างจาก "วิธีรับที่อยู่ IP ของโฮสต์นักเทียบท่าจากภายในคอนเทนเนอร์นักเทียบท่า" เนื่องจากข้อเท็จจริงที่ว่าที่อยู่ IP ของโฮสต์นักเทียบท่าอาจเป็น IP สาธารณะหรือ IP ส่วนตัวในเครือข่ายซึ่งอาจหรืออาจ ไม่สามารถเข้าถึงได้จากภายในคอนเทนเนอร์ของนักเทียบท่า (ฉันหมายถึง IP สาธารณะหากโฮสต์ที่ AWS หรือบางอย่าง) แม้ว่าคุณจะมีที่อยู่ IP ของโฮสต์นักเทียบท่า แต่ก็ไม่ได้หมายความว่าคุณสามารถเชื่อมต่อกับโฮสต์นักเทียบท่าได้จากภายในคอนเทนเนอร์เนื่องจากที่อยู่ IP เป็นเครือข่ายนักเทียบท่าของคุณอาจวางซ้อน, โฮสต์, บริดจ์, macvlan เป็นต้น ที่อยู่ IP นั้น


ทำไมไม่ผูก mysql กับ docker0 ด้วยล่ะ?
— ivant

2
สำหรับเครื่องที่ใช้ Windows: - $ นักเทียบท่าทำงาน -d - ชื่อ MyWebServer -P httpd
— Lokesh S


หากnetwork: hostคุณไม่สามารถย้อนกลับจากคอนเทนเนอร์ไปยังโฮสต์ได้ โฮสต์ไปยังคอนเทนเนอร์เท่านั้น นี่คืออุดมการณ์หลักที่อยู่เบื้องหลังภาชนะบรรจุ มันถูกแยกด้วยเหตุผลด้านความมั่นคงและความปลอดภัย
— FreeSoftwareServers

คำตอบ:


1968

แก้ไข:หากคุณใช้Docker-for-macหรือDocker-for-Windows 18.03+ เพียงเชื่อมต่อกับบริการ mysql ของคุณโดยใช้โฮสต์host.docker.internal(แทนที่จะเป็น127.0.0.1สตริงการเชื่อมต่อของคุณ)

ในฐานะของ Docker 18.09.3 สิ่งนี้ไม่สามารถใช้ได้กับ Docker-for-Linux แก้ไขได้ถูกส่งมาเมื่อวันที่ 8, 2019 และจะหวังว่าจะรวมกับฐานรหัส จนแล้ววิธีแก้ปัญหาคือการใช้ภาชนะที่อธิบายไว้ในคำตอบของ qoomon

2020-01:บางความคืบหน้าได้รับการทำ หากทุกอย่างเป็นไปด้วยดีควรลงจอดที่ Docker 20.04


TLDR

ใช้--network="host"ในdocker runคำสั่งของคุณจากนั้น127.0.0.1ในคอนเทนเนอร์นักเทียบท่าของคุณจะชี้ไปที่โฮสต์นักเทียบท่าของคุณ

หมายเหตุ: โหมดนี้จะทำงานเฉพาะในหางสำหรับลินุกซ์ต่อเอกสาร


หมายเหตุเกี่ยวกับโหมดเครือข่ายคอนเทนเนอร์นักเทียบท่า

นักเทียบท่านำเสนอโหมดเครือข่ายที่แตกต่างกันเมื่อเรียกใช้คอนเทนเนอร์ ขึ้นอยู่กับโหมดที่คุณเลือกคุณจะเชื่อมต่อกับฐานข้อมูล MySQL ของคุณทำงานบนโฮสต์นักเทียบท่าต่างกัน

นักเทียบท่าวิ่ง --network = "สะพาน" (ค่าเริ่มต้น)

นักเทียบท่าสร้างสะพานที่ตั้งชื่อdocker0ตามค่าเริ่มต้น ทั้งโฮสต์นักเทียบท่าและคอนเทนเนอร์นักเทียบท่ามีที่อยู่ IP บนบริดจ์นั้น

บนโฮสต์ Docker ให้พิมพ์sudo ip addr show docker0ผลลัพธ์ที่คุณต้องการ:

[vagrant@docker:~] $ sudo ip addr show docker0
4: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    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
    inet6 fe80::5484:7aff:fefe:9799/64 scope link
       valid_lft forever preferred_lft forever

ดังนั้นที่นี่โฮสต์นักเทียบท่าของฉันมีที่อยู่ IP 172.17.42.1บนdocker0อินเทอร์เฟซเครือข่าย

ตอนนี้เริ่มคอนเทนเนอร์ใหม่และรับเชลล์: docker run --rm -it ubuntu:trusty bashและภายในประเภทคอนเทนเนอร์ip addr show eth0เพื่อค้นหาวิธีตั้งค่าอินเตอร์เฟสเครือข่ายหลัก:

root@e77f6a1b3740:/# ip addr show eth0
863: eth0: <BROADCAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 66:32:13:f0:f1:e3 brd ff:ff:ff:ff:ff:ff
    inet 172.17.1.192/16 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::6432:13ff:fef0:f1e3/64 scope link
       valid_lft forever preferred_lft forever

172.17.1.192นี่ภาชนะของฉันมีที่อยู่ IP ตอนนี้ดูที่ตารางเส้นทาง:

root@e77f6a1b3740:/# route
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         172.17.42.1     0.0.0.0         UG    0      0        0 eth0
172.17.0.0      *               255.255.0.0     U     0      0        0 eth0

ดังนั้นที่อยู่ IP ของโฮสต์นักเทียบท่า172.17.42.1จึงถูกตั้งค่าเป็นเส้นทางเริ่มต้นและสามารถเข้าถึงได้จากคอนเทนเนอร์ของคุณ

root@e77f6a1b3740:/# ping 172.17.42.1
PING 172.17.42.1 (172.17.42.1) 56(84) bytes of data.
64 bytes from 172.17.42.1: icmp_seq=1 ttl=64 time=0.070 ms
64 bytes from 172.17.42.1: icmp_seq=2 ttl=64 time=0.201 ms
64 bytes from 172.17.42.1: icmp_seq=3 ttl=64 time=0.116 ms

นักเทียบท่าวิ่ง --network = "โฮสต์"

หรือคุณสามารถเรียกใช้ภาชนะนักเทียบท่าที่มีการตั้งค่าเครือข่ายการตั้งค่า hostคอนเทนเนอร์ดังกล่าวจะแชร์เครือข่ายสแต็คกับโฮสต์นักเทียบท่าและจากมุมมองคอนเทนเนอร์localhost(หรือ127.0.0.1) จะอ้างถึงโฮสต์นักเทียบท่า

โปรดทราบว่าพอร์ตใด ๆ ที่เปิดในคอนเทนเนอร์นักเทียบท่าของคุณจะถูกเปิดบนโฮสต์นักเทียบท่า และสิ่งนี้โดยไม่ต้องใช้-pหรือ-P docker runตัวเลือก

IP config บนโฮสต์นักเทียบท่าของฉัน:

[vagrant@docker:~] $ ip addr show eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 08:00:27:98:dc:aa brd ff:ff:ff:ff:ff:ff
    inet 10.0.2.15/24 brd 10.0.2.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:fe98:dcaa/64 scope link
       valid_lft forever preferred_lft forever

และจากคอนเทนเนอร์นักเทียบท่าในโหมดโฮสต์ :

[vagrant@docker:~] $ docker run --rm -it --network=host ubuntu:trusty ip addr show eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 08:00:27:98:dc:aa brd ff:ff:ff:ff:ff:ff
    inet 10.0.2.15/24 brd 10.0.2.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:fe98:dcaa/64 scope link
       valid_lft forever preferred_lft forever

ในขณะที่คุณสามารถเห็นได้ทั้งโฮสต์นักเทียบท่าและคอนเทนเนอร์นักเทียบท่าแบ่งปันอินเทอร์เฟซเครือข่ายเดียวกันแน่นอนและเช่นนั้นมีที่อยู่ IP เดียวกัน


เชื่อมต่อกับ MySQL จากคอนเทนเนอร์

โหมดบริดจ์

ในการเข้าถึง MySQL ที่ทำงานบนโฮสต์นักเทียบท่าจากตู้คอนเทนเนอร์ในโหมดบริดจ์คุณต้องแน่ใจว่าบริการ MySQL กำลังรับฟังการเชื่อมต่อที่อยู่172.17.42.1IP

ในการทำเช่นนั้นตรวจสอบให้แน่ใจว่าคุณมีไฟล์ MySQL bind-address = 172.17.42.1หรืออย่างใดอย่างหนึ่งbind-address = 0.0.0.0(my.cnf)

หากคุณต้องการตั้งค่าตัวแปรสภาพแวดล้อมด้วยที่อยู่ IP ของเกตเวย์คุณสามารถเรียกใช้รหัสต่อไปนี้ในคอนเทนเนอร์:

export DOCKER_HOST_IP=$(route -n | awk '/UG[ \t]/{print $2}')

จากนั้นในแอปพลิเคชันของคุณให้ใช้DOCKER_HOST_IPตัวแปรสภาพแวดล้อมเพื่อเปิดการเชื่อมต่อกับ MySQL

หมายเหตุ:หากคุณใช้bind-address = 0.0.0.0เซิร์ฟเวอร์ MySQL ของคุณจะรับฟังการเชื่อมต่อในทุกอินเตอร์เฟสเครือข่าย นั่นหมายความว่าเซิร์ฟเวอร์ MySQL ของคุณสามารถเข้าถึงได้จากอินเทอร์เน็ต ตรวจสอบให้แน่ใจว่าตั้งค่ากฎไฟร์วอลล์ตามนั้น

หมายเหตุ 2:ถ้าคุณใช้bind-address = 172.17.42.1เซิร์ฟเวอร์ MySQL ของคุณจะไม่ฟังการเชื่อมต่อที่เกิด127.0.0.1ขึ้น กระบวนการทำงานบนโฮสต์นักเทียบท่าที่ต้องการเชื่อมต่อกับ MySQL จะต้องใช้ที่172.17.42.1อยู่ IP

โหมดโฮสต์

ในการเข้าถึง MySQL ที่ทำงานบนโฮสต์นักเทียบท่าจากคอนเทนเนอร์ในโหมดโฮสต์คุณสามารถเก็บไว้bind-address = 127.0.0.1ในการกำหนดค่า MySQL ของคุณและสิ่งที่คุณต้องทำก็คือเชื่อมต่อกับ127.0.0.1คอนเทนเนอร์ของคุณ:

[vagrant@docker:~] $ docker run --rm -it --network=host mysql mysql -h 127.0.0.1 -uroot -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 36
Server version: 5.5.41-0ubuntu0.14.04.1 (Ubuntu)

Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

หมายเหตุ:ใช้mysql -h 127.0.0.1และไม่ใช้mysql -h localhost; มิฉะนั้นไคลเอนต์ MySQL จะพยายามเชื่อมต่อโดยใช้ซ็อกเก็ตยูนิกซ์


8
ขอบคุณสำหรับคำตอบอย่างละเอียด! จากสิ่งที่ฉันรวบรวมไว้การใช้โหมดโฮสต์เป็นวิธีเดียวที่จะทำให้การทำงานนี้ผ่าน localhost ฉันไม่ได้ลอง แต่ฉันจะสมมติว่าคุณสามารถสร้างเครือข่ายแยกต่างหากเพื่อเชื่อมต่อคอนเทนเนอร์ผ่านบริดจ์ของพวกเขาเองโดยเสนอ 'localhost' ทั่วไป
— Ben

26
หมายเหตุสำหรับผู้ใช้ OSX: ล็อกอินเข้าสู่เครื่องเสมือนนักเทียบท่าของคุณก่อน (boot2docker) โดยใช้ "ค่าเริ่มต้นของนักเทียบเครื่อง ssh" จากนั้นเรียกใช้ "sudo ip addr show docker0" ทำตามคำแนะนำของโทมัสจากที่นั่น
— Charlie Dalsass

30
ฉันใช้ Docker สำหรับ Mac และไม่มีอีก 172.17.42.1 อีกต่อไปไม่มี docker0 อีกต่อไป มันเป็น 172.17.0.1 ในฐานะเกตเวย์และไม่สามารถทำได้telnet 172.17.0.1 3306
— zx1986

26
คุณสามารถติดตั้งซ็อกเก็ต mysql ลงในคอนเทนเนอร์แทนเครือข่ายเช่น-v /var/run/mysqld/mysqld.sock:/tmp/mysql.sockนี้
— chx

8
บางคนสามารถแก้ไขสถานการณ์เมื่อคุณรัน Docker บน Mac และไม่ได้ใช้ boot2docker เพราะไม่มีอินเตอร์เฟส docker0 หรือไม่?
— TheJKFever

350

สำหรับ macOS และ Windows

นักเทียบท่า v 18.03 ขึ้นไป (ตั้งแต่วันที่ 21 มีนาคม 2561)

ใช้ที่อยู่ IP ภายในของคุณหรือเชื่อมต่อกับชื่อ DNS พิเศษ host.docker.internalที่จะแก้ไขไปยังที่อยู่ IP ภายในที่โฮสต์ใช้

การสนับสนุน Linux รอการhttps://github.com/docker/for-linux/issues/264

MacOS พร้อม Docker รุ่นก่อนหน้า

นักเทียบท่าสำหรับ Mac v 17.12 ถึง v 18.02

เหมือนข้างบน แต่ใช้docker.for.mac.host.internalแทน

นักเทียบท่าสำหรับ Mac v 17.06 ถึง v 17.11

เหมือนข้างบน แต่ใช้docker.for.mac.localhostแทน

นักเทียบท่าสำหรับ Mac 17.05 และต่ำกว่า

ในการเข้าถึงเครื่องโฮสต์จากคอนเทนเนอร์นักเทียบท่าคุณจะต้องแนบนามแฝง IP กับอินเตอร์เฟสเครือข่ายของคุณ คุณสามารถผูกสิ่งที่คุณต้องการ IP เพียงแค่ให้แน่ใจว่าคุณไม่ได้ใช้มันเพื่อสิ่งอื่นใด

sudo ifconfig lo0 alias 123.123.123.123/24

จากนั้นให้แน่ใจว่าคุณเซิร์ฟเวอร์ฟัง IP 0.0.0.0ดังกล่าวข้างต้นหรือ หากกำลังฟังบน localhost 127.0.0.1จะไม่ยอมรับการเชื่อมต่อ

จากนั้นเพียงชี้คอนเทนเนอร์นักเทียบท่าของคุณไปที่ IP นี้และคุณสามารถเข้าถึงเครื่องโฮสต์ได้!

ในการทดสอบคุณสามารถเรียกใช้บางอย่างเช่นcurl -X GET 123.123.123.123:3000ภายในคอนเทนเนอร์

นามแฝงจะรีเซ็ตทุกครั้งที่ทำการรีบูตดังนั้นสร้างสคริปต์เริ่มต้นหากจำเป็น

วิธีแก้ไขปัญหาและเอกสารเพิ่มเติมที่นี่: https://docs.docker.com/docker-for-mac/networking/#use-cases-and-workarounds


5
ยอดเยี่ยมและขอบคุณสิ่งนี้ใช้ได้สำหรับฉันจากภายในคอนเทนเนอร์ mysql -uroot -hdocker.for.mac.localhost
— Richard Frank

1
docker.for.mac.localhost เป็นสิ่งที่ฉันกำลังมองหา แต่นี่สกปรกเหมือนนรกในเวลาเดียวกัน ในตัวเทียบท่าใครจะคาดหวังว่า hook docker.for.mac.localhost จะเป็นชื่อภายในตัวเทียบท่าทั่วไปที่จะใช้ได้กับระบบปฏิบัติการใด ๆ ไม่ใช่เฉพาะสำหรับ Mac แต่สำหรับวัตถุประสงค์ในการพัฒนามันก็ดีพอ
— 99Sono

ฉันจะเข้าใช้พอร์ตที่เปิดเผยได้อย่างไรที่ 9093 .. ฉันพยายาม telnet docker.for.mac.localhost 9093 มันเข้าไม่ถึง แต่ถ้าฉัน ping docker.for.mac.localhost มันสามารถเข้าถึงได้ฉันกำลังทำอะไรบางอย่างที่นี่หรือไม่
— Achilleus

1
DNS name docker.for.mac.host.internal ควรใช้แทน docker.for.mac.localhost (ยังคงใช้ได้) สำหรับการแก้ปัญหาโฮสต์จากคอนเทนเนอร์เนื่องจากมี RFC ห้ามการใช้โดเมนย่อยของ localhost ดูtools.ietf.org/html/draft-west-let-localhost-be-localhost-06
— Jya

มันไม่ได้ผลสำหรับฉัน เมื่อฉันdocker run -e HOSTNAME= docker.for.mac.host.internal ภาชนะถูกสร้างขึ้น แต่ไม่มีอะไรเกิดขึ้น ฉันต้อง crtl + C ด้วย--net=host -e HOSTNAME=localhostตู้คอนเทนเนอร์วิ่งอย่างน้อยและบ่นว่ามันไม่สามารถหาสิ่งที่ฉันจำเป็นต้องให้บริการ (MySQL DB)
— Jorge Orpinel

83

ฉันทำแฮ็คคล้ายกับโพสต์ด้านบนเพื่อรับ IP ท้องถิ่นเพื่อแมปไปยังชื่อแทน (DNS) ในคอนเทนเนอร์ ปัญหาสำคัญคือการได้รับแบบไดนามิกที่มีสคริปต์ง่ายที่ทำงานทั้งในLinux และ OSX โฮสต์ที่อยู่ ฉันทำสคริปต์นี้ที่ทำงานในทั้งสองสภาพแวดล้อม (แม้ใน Linux กระจายกับ"$LANG" != "en_*"กำหนดค่า):

ifconfig | grep -E "([0-9]{1,3}\.){3}[0-9]{1,3}" | grep -v 127.0.0.1 | awk '{ print $2 }' | cut -f2 -d: | head -n1

ดังนั้นเมื่อใช้ Docker Compose การกำหนดค่าทั้งหมดจะเป็น:

สคริปต์เริ่มต้น (docker-run.sh) :

export DOCKERHOST=$(ifconfig | grep -E "([0-9]{1,3}\.){3}[0-9]{1,3}" | grep -v 127.0.0.1 | awk '{ print $2 }' | cut -f2 -d: | head -n1)
docker-compose -f docker-compose.yml up

นักเทียบท่า-compose.yml :

myapp:
  build: .
  ports:
    - "80:80"
  extra_hosts:
    - "dockerhost:$DOCKERHOST"

จากนั้นเปลี่ยนhttp://localhostเป็นhttp://dockerhostรหัสของคุณ

สำหรับคำแนะนำเพิ่มเติมเกี่ยวกับวิธีปรับแต่งDOCKERHOSTสคริปต์ให้ดูที่โพสต์นี้พร้อมคำอธิบายวิธีการใช้งาน


1
ขึ้นอยู่กับกรณีการใช้งานของคุณคุณอาจจะใช้DOCKERHOSTค่าที่นี่แทน "localhost" หรือ 0.0.0.0 ในสิ่งที่ให้บริการคอนเทนเนอร์นักเทียบท่าของคุณจำเป็นต้องเชื่อมต่อกับท้องถิ่น
— enderland

2
ฉันได้ปรับเปลี่ยนโซลูชันของคุณเล็กน้อยเพื่อให้เข้ากันได้กับเครือข่ายที่กำหนดเอง: export DOCKERHOST=$(docker network inspect --format='{{range .IPAM.Config}}{{.Gateway}}{{end}}' <NETWORK-NAME> | awk -F "/" 'NR==1{print $1}') โดยที่<NETWORK-NAME>อาจเป็นบริดจ์หรือชื่อของเครือข่ายตามที่กำหนดโดยนักเขียนประกอบด้วย (โดยปกติคือชื่อเส้นทาง- network_name )
— dieresys

1
คุณต้องเพิ่มความคิดเห็น: ใช้dockerhostเป็นโฮสต์สำหรับการเชื่อมต่อฐานข้อมูล (ปกติแทนที่localhostในไฟล์ config)
— Justin

ทางออกที่แปลก แต่เป็นเพียงสิ่งเดียวที่ทำให้ xdebug ทำงานภายใต้นักเทียบท่ากับ php cli
— Eddie

Acl หยุดทำงานหลังจากการแก้ปัญหานี้ใน haproxy มีความคิดอะไรบ้าง
— HyukHyukBoi

41

สิ่งนี้ใช้ได้กับฉันในสแต็ก NGINX / PHP-FPM โดยไม่ต้องแตะรหัสหรือเครือข่ายใด ๆ ที่แอพคาดหวังว่าจะสามารถเชื่อมต่อกับ localhost

เมานต์mysqld.sockจากโฮสต์ไปยังภายในคอนเทนเนอร์

ค้นหาตำแหน่งของไฟล์ mysql.sock บนโฮสต์ที่ใช้งาน mysql:
netstat -ln | awk '/mysql(.*)?\.sock/ { print $9 }'

เมานต์ไฟล์นั้นไปยังตำแหน่งที่ต้องการใน Docker:
docker run -v /hostpath/to/mysqld.sock:/containerpath/to/mysqld.sock

ตำแหน่งที่เป็นไปได้ของ mysqld.sock:

/tmp/mysqld.sock
/var/run/mysqld/mysqld.sock 
/var/lib/mysql/mysql.sock
/Applications/MAMP/tmp/mysql/mysql.sock # if running via MAMP

2
นี่เป็นวิธีที่สะอาดกว่ามากไม่เปิดเผย Mysql จากภายนอก (หากไม่ได้ใช้ไฟร์วอลล์)
— user1226868

5
ซ็อกเก็ตไม่ได้ปรับขนาดเช่นเดียวกับ TCP เพราะบล็อกบ่อยขึ้นและอาจทำให้เกิดพฤติกรรมแปลก ๆ ใช้ TCP ทุกครั้งที่ทำได้
— Joel E Salas

3
@JoelESalas คุณมีแหล่งข้อมูลสำหรับการอ้างสิทธิ์นั้นหรือไม่
— ส่วนตัว

ฉันพบว่านี่เป็นทางออกที่ง่ายที่สุด ยกระดับ user833482! คุณควรมีส่วนร่วมกับ StackOverflow บ่อยขึ้น
— ส่วนตัว

2
@ JoelESalas ฉันคิดว่าคุณเข้าใจผิด ไลบรารีไคลเอนต์ mysql ใช้ซ็อกเก็ตยูนิกซ์เป็นค่าเริ่มต้นเมื่อเชื่อมต่อกับ localhost แทนที่จะทำการเชื่อมต่อกับ localhost ซ็อกเก็ตยูนิกซ์หลีกเลี่ยงโอเวอร์เฮดของสแต็ก TCP และการเราต์และควรทำงานได้เร็วขึ้น
— M Conrad

25

จนกระทั่ง host.docker.internalจะใช้งานได้กับทุกแพลตฟอร์มคุณสามารถใช้ container ของฉันทำหน้าที่เป็นเกตเวย์ NAT โดยไม่ต้องตั้งค่าด้วยตนเอง:

https://github.com/qoomon/docker-host


5
ฉันสามารถยืนยันได้ว่านี่ไม่ทำงานใน Docker สำหรับ Windows 19.03.2 ด้วย Windows container
— KMC

ความคิดใด ๆ ที่จะแก้ไขได้อย่างไร (ฉันไม่ใช่ผู้ใช้ windows)
— qoomon

หากสภาพแวดล้อมของคุณไม่ได้ปิดกั้นพอร์ต mysql คุณสามารถอ้างถึงเซิร์ฟเวอร์โดยใช้ชื่อคอมพิวเตอร์ที่โฮสต์อยู่ ดังนั้นในสตริงการเชื่อมต่อของคุณให้ใช้ชื่อคอมพิวเตอร์ของคุณเป็นชื่อเซิร์ฟเวอร์
— KMC

24

โซลูชันสำหรับ Linux (เคอร์เนล> = 3.6)

ตกลงเซิร์ฟเวอร์ localhost ของคุณมีอินเตอร์เฟซนักเทียบท่าเริ่มต้นdocker0กับที่อยู่ IP 172.17.0.1 ภาชนะของคุณเริ่มต้นด้วยการตั้งค่าเครือข่ายเริ่มต้น--net = "สะพาน"

  1. เปิดใช้งาน route_localnet สำหรับอินเตอร์เฟส docker0:
    $ sysctl -w net.ipv4.conf.docker0.route_localnet=1
  2. เพิ่มกฎนี้ไปยัง iptables:
    $ iptables -t nat -I PREROUTING -i docker0 -d 172.17.0.1 -p tcp --dport 3306 -j DNAT --to 127.0.0.1:3306
    $ iptables -t filter -I INPUT -i docker0 -d 127.0.0.1 -p tcp --dport 3306 -j ACCEPT
  3. สร้างผู้ใช้ mysql ด้วยการเข้าถึงจาก '%' นั่นหมายถึง - จากทุกคนยกเว้น localhost:
    CREATE USER 'user'@'%' IDENTIFIED BY 'password';
  4. เปลี่ยนสคริปต์ของคุณที่อยู่ mysql-server เป็น 172.17.0.1


จาก เอกสารเคอร์เนล :

route_localnet - บูลีน: อย่าพิจารณาที่อยู่ลูปแบ็คเป็นแหล่งที่มาของดาวอังคารหรือปลายทางในขณะที่กำหนดเส้นทาง สิ่งนี้ช่วยให้การใช้งานของ 127/8 สำหรับวัตถุประสงค์การจัดเส้นทางภายใน ( ค่าเริ่มต้นเป็น FALSE )


1
วัตถุประสงค์ของคำสั่ง iptable ที่สองคืออะไร? ฉันสามารถเข้าใจอันแรกคือการเขียน tcp ปลายทางทั้งหมดที่ตรงกับ 172.17.0.1:3306 ถึง 127.0.0.1:3306 แต่ทำไมคำสั่ง iptable ที่สองจำเป็น?
— Patrick

17

โซลูชันสำหรับ Windows 10

Docker Community Edition 17.06.0-ce-win18 2017-06-28 (เสถียร)

คุณสามารถใช้ชื่อ DNS ของโฮสต์docker.for.win.localhostเพื่อแก้ไข IP ภายใน (เตือนบางแหล่งที่กล่าวถึงwindowsแต่ควรเป็นwin )

ภาพรวม
ที่ผมต้องทำบางสิ่งบางอย่างที่คล้ายกันนั่นคือการเชื่อมต่อจากภาชนะหางของฉันไป localhost ของฉันซึ่งถูกเรียกใช้และAzure Storage EmulatorCosmosDB Emulator

Azure Storage Emulatorโดยค่าเริ่มต้นฟังบน127.0.0.1ในขณะที่คุณสามารถเปลี่ยน IP ของมันผูกพันเกินไปฉันกำลังมองหาวิธีการแก้ปัญหาที่จะทำงานด้วยการตั้งค่าเริ่มต้น

นอกจากนี้ยังใช้งานได้สำหรับการเชื่อมต่อจากคอนเทนเนอร์ Docker ของฉันไปที่SQL ServerและIISทั้งสองทำงานในพื้นที่บนโฮสต์ของฉันด้วยการตั้งค่าพอร์ตเริ่มต้น


13

ง่ายมากและรวดเร็วตรวจสอบ IP โฮสต์ของคุณด้วย ifconfig (linux) หรือ ipconfig (windows) แล้วสร้าง

นักเทียบท่า-compose.yml

version: '3' # specify docker-compose version

services:
  nginx:
    build: ./ # specify the directory of the Dockerfile
    ports:
      - "8080:80" # specify port mapping
    extra_hosts:
      - "dockerhost:<yourIP>"

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


ใน HaProxy โซลูชันนี้หยุดการทำงานของ acl ด้วยเหตุผลบางอย่างเฉพาะการตั้งค่าเริ่มต้นเท่านั้นที่ทำงาน
— HyukHyukBoi

1
ทางออกเดียวที่ทำงานบนระบบ linux +1
— Rafik Farhad

11

ไม่มีคำตอบใดที่เหมาะกับฉันเมื่อใช้ Docker Toolbox บน Windows 10 Home แต่ได้ทำ10.0.2.2เนื่องจากใช้ VirtualBox ซึ่งทำให้โฮสต์ไปยัง VM บนที่อยู่นี้


2
มันได้ผล. แม้ไม่จำเป็นต้องระบุ --network = host ดูเหมือนว่า 10.0.2.2 ถูกตั้งค่าเป็น IP เริ่มต้นสำหรับโฮสต์ ขอบคุณ
— TheManish

แต่ฉันสามารถใช้ IP แบบคงที่นี้กับ Windows และ Mac ทุกเวอร์ชันได้อย่างไรฉันจะจัดการกับหลายแพลตฟอร์มผ่านสคริปต์ได้อย่างไร
— 151291

สิ่งนี้ใช้ได้สำหรับฉัน เพียงแค่รัน ipconfig บนโฮสต์ของคุณ (windows) และรับที่อยู่ IP ภายใต้Ethernet adapter vEthernet (DockerNAT)
— Kihats

10

สำหรับผู้ใช้บน Windows สมมติว่าคุณใช้ไดรเวอร์เครือข่ายบริดจ์คุณจะต้องผูก MySQL กับที่อยู่ IP ของอินเทอร์เฟซเครือข่ายไฮเปอร์ - วีโดยเฉพาะ

สิ่งนี้ทำได้ผ่านไฟล์การกำหนดค่าภายใต้โฟลเดอร์ C: \ ProgramData \ MySQL ที่ซ่อนอยู่ตามปกติ

การเชื่อมต่อกับ 0.0.0.0 จะไม่ทำงาน ที่อยู่ที่ต้องการจะแสดงในการกำหนดค่านักเทียบท่าเช่นกันและในกรณีของฉันคือ 10.0.75.1


3
คุณสมควรได้รับเหรียญ! ฉันทำงานนี้มาสองวันเต็มแล้ว ขอบคุณสำหรับการช่วยเหลือ!
— ไมเคิล

1
ฉันกำลังทำสิ่งนี้อยู่สองวันเต็ม นี่เป็นที่เดียวในเว็บที่ฉันพบ Microsoft เงียบอย่างสมบูรณ์ในเรื่องนี้เมื่อพูดถึงการเชื่อมต่อกับ MSSQL จากภายในคอนเทนเนอร์ Docker มันทำให้คุณสงสัยว่าพวกเขาเคยทำงานด้วยตัวเองหรือไม่!
— Contango

8

แก้ไข: ฉันสิ้นสุดการสร้างต้นแบบแนวคิดบน GitHub ชำระเงิน: https://github.com/sivabudh/system-in-a-box


อันดับแรกคำตอบของฉันมุ่งเน้นไปที่คนสองกลุ่ม: ผู้ที่ใช้ Mac และผู้ที่ใช้ Linux

โฮสต์โหมดเครือข่ายไม่ทำงานบน Mac คุณต้องใช้ชื่อแทน IP ดู: https://stackoverflow.com/a/43541681/2713729

โหมดเครือข่ายโฮสต์คืออะไร ดู: https://docs.docker.com/engine/reference/run/#/network-settings

ประการที่สองสำหรับผู้ที่ใช้ Linux (ประสบการณ์ตรงของฉันคือกับ Ubuntu 14.04 LTS และฉันกำลังอัปเกรดเป็น 16.04 LTS ในการผลิตในเร็ว ๆ นี้) ใช่คุณสามารถทำให้บริการทำงานภายในคอนเทนเนอร์ Docker เชื่อมต่อกับlocalhostบริการที่ทำงานบน โฮสต์นักเทียบท่า (เช่นแล็ปท็อปของคุณ)

อย่างไร?

กุญแจสำคัญคือเมื่อคุณเรียกใช้คอนเทนเนอร์นักเทียบท่าคุณจะต้องเรียกใช้ด้วยโหมดโฮสต์ คำสั่งมีลักษณะดังนี้:

docker run --network="host" -id <Docker image ID>

เมื่อคุณทำifconfig(คุณจะต้องใช้apt-get install net-toolsคอนเทนเนอร์ของคุณเพื่อifconfigให้สามารถเรียกใช้ได้) ภายในคอนเทนเนอร์ของคุณคุณจะเห็นว่าส่วนต่อประสานเครือข่ายนั้นเหมือนกับที่อยู่ในโฮสต์ Docker (เช่นแล็ปท็อปของคุณ)

เป็นเรื่องสำคัญที่จะต้องทราบว่าฉันเป็นผู้ใช้ Mac แต่ฉันใช้งาน Ubuntu ภายใต้ Parallels ดังนั้นการใช้ Mac จึงไม่ใช่ข้อเสีย ;-)

และนี่คือวิธีที่คุณเชื่อมต่อ NGINX คอนเทนเนอร์ไปยัง MySQL localhostทำงานบน


1
สิ่งสำคัญคือต้องทราบว่าโหมดโฮสต์ให้ประสิทธิภาพที่ดีขึ้นเนื่องจากใช้เครือข่ายสแต็กของระบบปฏิบัติการ
— sivabudh

2
จุดที่ดีมากที่นั่น แม้ว่ามันจะเป็นไปได้ที่จะเชื่อมต่อจากภาชนะให้บริการโฮสต์ที่มี IP ที่ไม่ได้ใช้แนบdocs.docker.com/docker-for-mac/networking ไม่ใช่วิธีที่น่าพอใจ ... แต่ใช้ได้ผล
— Xavier Huppé

สิ่งที่ดีที่นี่ เมื่ออยู่ในคอนเทนเนอร์ด้วย--network="host"หนึ่งจะเชื่อมต่อกับโฮสต์ mysql ได้อย่างไร
— Michael

1
@Buccleuch localhostเพียงแค่การใช้งาน ตรวจสอบรหัสที่มาของฉัน GitHub: github.com/sivabudh/system-in-a-box/blob/master/dj_host_docker/... ค้นหา'HOST'คุณจะเห็น 127.0.0.1 เพื่อเชื่อมต่อกับ Postgresql
— sivabudh

ฉันสามารถเข้าถึงฐานข้อมูล mysql โฮสต์โดยติดตั้งไดรฟ์ตาม @ user833482 และหลังจากติดตั้งไคลเอนต์ mysql และเซิร์ฟเวอร์บนคอนเทนเนอร์นักเทียบท่าแน่นอน
— Michael

7

ทางออกที่ง่ายที่สุดสำหรับ Mac OSX

เพียงใช้ที่อยู่ IP ของ Mac ของคุณ ใน Mac เรียกใช้สิ่งนี้เพื่อรับที่อยู่ IP และใช้จากภายในคอนเทนเนอร์:

$ ifconfig | grep 'inet 192'| awk '{ print $2}'

ตราบใดที่เซิร์ฟเวอร์ที่ใช้งานอยู่บนเครื่อง Mac ของคุณหรือในที่เก็บนักเทียบท่าอื่นกำลังรับฟัง 0.0.0.0 คอนเทนเนอร์ของนักเทียบท่าจะสามารถเข้าถึงที่อยู่นั้นได้

หากคุณต้องการเข้าถึงนักเทียบท่าคอนเทนเนอร์อื่นที่กำลังฟังใน 0.0.0.0 คุณสามารถใช้ 172.17.0.1


1
Docker for Mac แสดงdocker.for.mac.host.internalชื่อโฮสต์ทันที
— แมตต์

5

นี่ไม่ใช่คำตอบสำหรับคำถามจริง นี่คือวิธีที่ฉันแก้ไขปัญหาที่คล้ายกัน วิธีการแก้ปัญหามาจากทั้งหมด: กำหนดเครือข่ายคอนเทนเนอร์ Docker เพื่อให้ผู้สื่อสารสามารถสื่อสารกันได้ ขอบคุณ Nic Raboy

ออกจากที่นี่เพื่อคนอื่นที่อาจต้องการเรียกใช้ REST ระหว่างคอนเทนเนอร์หนึ่งกับอีกคอนเทนเนอร์ ตอบคำถาม: อะไรที่จะใช้แทน localhost ในสภาพแวดล้อมของนักเทียบท่า?

ดูว่าเครือข่ายของคุณเป็นอย่างไร docker network ls

สร้างเครือข่ายใหม่ docker network create -d my-net

เริ่มคอนเทนเนอร์แรก docker run -d -p 5000:5000 --network="my-net" --name "first_container" <MyImage1:v0.1>

ตรวจสอบการตั้งค่าเครือข่ายสำหรับคอนเทนเนอร์แรก docker inspect first_containerตรวจสอบการตั้งค่าเครือข่ายสำหรับภาชนะแรก"เครือข่าย": ควรมี 'my-net'

เริ่มคอนเทนเนอร์ที่สอง docker run -d -p 6000:6000 --network="my-net" --name "second_container" <MyImage2:v0.1>

ตรวจสอบการตั้งค่าเครือข่ายสำหรับคอนเทนเนอร์ที่สอง docker inspect second_containerตรวจสอบการตั้งค่าเครือข่ายสำหรับภาชนะที่สอง"เครือข่าย": ควรมี 'my-net'

ssh ในคอนเทนเนอร์ที่สองของคุณdocker exec -it second_container shหรือdocker exec -it second_container bashหรือ

ภายในของภาชนะที่สองคุณสามารถ ping ping first_containerภาชนะบรรจุครั้งแรกโดย นอกจากนี้การเรียกรหัสของคุณเช่นhttp://localhost:5000สามารถถูกแทนที่ด้วยhttp://first_container:5000


สิ่งที่ฉันกำลังมองหา ขอบคุณ: D
— Simar Singh

5

สำหรับ windows

ฉันเปลี่ยน URL ฐานข้อมูลในการกำหนดค่าสปริง: spring.datasource.url=jdbc:postgresql://host.docker.internal:5432/apidb

จากนั้นสร้างภาพและเรียกใช้ มันใช้งานได้สำหรับฉัน


ที่น่าสนใจ ....
— ฟิล

สำหรับฉันไม่ทำงาน ฉันมี mac และลองจาก php container เพื่อเชื่อมต่อกับ localhost mysql ความคิดใด ๆ
— A. Zalonis

4

ฉันไม่เห็นด้วยกับคำตอบจาก Thomasleveil

การทำให้ mysql เชื่อมโยงกับ 172.17.42.1 จะป้องกันโปรแกรมอื่น ๆ โดยใช้ฐานข้อมูลบนโฮสต์เพื่อเข้าถึง สิ่งนี้จะใช้งานได้เฉพาะเมื่อผู้ใช้ฐานข้อมูลทั้งหมดของคุณถูกเทียบท่า

การทำให้ mysql ผูกติดกับ 0.0.0.0 จะเปิดฐานข้อมูลสู่โลกภายนอกซึ่งไม่เพียง แต่เป็นสิ่งที่เลวร้ายมากที่ต้องทำ แต่ยังขัดแย้งกับสิ่งที่ผู้เขียนคำถามดั้งเดิมต้องการทำ เขากล่าวอย่างชัดเจนว่า "The MySql กำลังทำงานอยู่บน localhost และไม่เปิดเผยพอร์ตสู่โลกภายนอกดังนั้นมันจึงผูกมัดกับ localhost"

เพื่อตอบความคิดเห็นจาก ivant

"ทำไมไม่ผูก mysql กับ docker0 ด้วย"

สิ่งนี้เป็นไปไม่ได้ เอกสาร mysql / mariadb บอกไว้อย่างชัดเจนว่ามันเป็นไปไม่ได้ที่จะผูกกับอินเตอร์เฟสหลายตัว คุณสามารถผูกกับ 0, 1 หรืออินเตอร์เฟสทั้งหมดเท่านั้น

โดยสรุปฉันไม่พบวิธีการเข้าถึงฐานข้อมูล (localhost เท่านั้น) บนโฮสต์จากคอนเทนเนอร์นักเทียบท่า แน่นอนว่ามันเป็นรูปแบบที่ธรรมดามาก แต่ฉันไม่รู้ว่าจะทำอย่างไร


4
จากโฮสต์นักเทียบท่าคุณยังสามารถเชื่อมต่อกับเซิร์ฟเวอร์ MySQL โดยใช้ที่172.17.42.1อยู่ แต่บันทึกย่อของคุณถูกต้องเป็นอย่างอื่น Aso ฉันแก้ไขคำตอบของฉันกับhostโหมดระบบเครือข่ายที่จะช่วยให้การ MySQL เซิร์ฟเวอร์ผูกพันกับ127.0.0.1ขณะที่ช่วยให้ภาชนะที่จะเชื่อมต่อกับมัน
— Thomasleveil

ไม่อย่างที่ฉันบอกว่าคุณไม่สามารถเชื่อมต่อกับ 172.17.42.1 หาก mysql ถูกผูกไว้กับ localhost
— orzel

4
"การทำให้ mysql เชื่อมโยงกับ 172.17.42.1 จะป้องกันโปรแกรมอื่น ๆ โดยใช้ฐานข้อมูลบนโฮสต์เพื่อเข้าถึง" - นั่นไม่เป็นความจริง โปรแกรมอื่น ๆ สามารถใช้ mysql พวกเขาเพียงแค่ต้องเชื่อมต่อกับ 172.17.42.1 แทน localhost / 127.0.0.1
— 0x89

วิธีการแก้ปัญหาในคำตอบนี้โดยทั่วไปคือการให้เซิร์ฟเวอร์ MySQL เชื่อมโยง0.0.0.0และตั้งค่าไฟร์วอลล์เพื่อให้ db ไม่สามารถเข้าถึงได้จากอินเทอร์เน็ต
— halfer

4

นี่คือทางออกของฉัน: มันใช้งานได้กับกรณีของฉัน

  • ตั้งค่าเซิร์ฟเวอร์ mysql ในพื้นที่เป็นการเข้าถึงสาธารณะโดยความคิดเห็น #bind-address = 127.0.0.1 ใน /etc/mysql/mysql.conf.d

  • รีสตาร์ทเซิร์ฟเวอร์ mysql sudo /etc/init.d/mysql restart

  • รันคำสั่งต่อไปนี้เพื่อเปิดรูทผู้ใช้เข้าถึงโฮสต์ใด ๆ mysql -uroot -proot GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION; FLUSH PRIVILEGES;

  • สร้างสคริปต์ sh: run_docker.sh

    #! bin / ทุบตี

    HOSTIP = `ip -4 addr แสดงขอบเขตทั่วโลก dev eth0 | grep inet | awk '{print \ $ 2}' | ตัด -d / -f 1`


      นักเทียบท่าวิ่ง -it -d - ชื่อเว็บแอพ \
                  - เพิ่มโฮสต์ = local: $ {HOSTIP} \
                  -p 8080: 8080 \
                  -e DATABASE_HOST = $ {HOSTIP} \
                  -e DATABASE_PORT = 3306 \
                  -e DATABASE_NAME = สาธิต \
                  -e DATABASE_USER = root \
                  -e DATABASE_PASSWORD = root \
                  sopheamak / springboot_docker_mysql

  
  • ทำงานกับนักแต่งเพลงนักเทียบท่า

    รุ่น: '2.1'

    บริการ:
    tomcatwar: extra_hosts: - "local: 10.1.2.232" ภาพ: sopheamak / springboot_docker_mysql
    พอร์ต: - 8080: 8080 สภาพแวดล้อม: - DATABASE_HOST = ท้องถิ่น - DATABASE_USER = root - DATABASE_PASSWORD = รูท - DATABASE_NAME = สาธิต - DATABASE_PORT = 3306


4

การแก้ปัญหาต่าง ๆ อยู่ในใจ:

  1. ย้ายการอ้างอิงของคุณไปยังคอนเทนเนอร์ก่อน
  2. ทำให้บริการอื่น ๆ ของคุณสามารถเข้าถึงได้จากภายนอกและเชื่อมต่อกับบริการเหล่านั้นด้วย IP ภายนอก
  3. เรียกใช้คอนเทนเนอร์ของคุณโดยไม่มีการแยกเครือข่าย
  4. หลีกเลี่ยงการเชื่อมต่อผ่านเครือข่ายใช้ซ็อกเก็ตที่ติดตั้งเป็นไดรฟ์ข้อมูลแทน

เหตุผลที่มันไม่ได้ผลอยู่ในกล่องนี้คือคอนเทนเนอร์ที่ทำงานด้วยเนมสเปซเครือข่ายของตนเองโดยค่าเริ่มต้น นั่นหมายถึง localhost (หรือ 127.0.0.1 ที่ชี้ไปยังอินเทอร์เฟซย้อนกลับ) เป็นค่าเฉพาะสำหรับแต่ละคอนเทนเนอร์ การเชื่อมต่อกับสิ่งนี้จะเชื่อมต่อกับคอนเทนเนอร์เองไม่ใช่บริการที่ทำงานนอก Docker หรือภายในคอนเทนเนอร์ที่แตกต่างกัน

ตัวเลือกที่ 1 : หากการพึ่งพาของคุณสามารถย้ายลงในคอนเทนเนอร์ฉันจะทำสิ่งนี้ก่อน มันทำให้แอปพลิเคชันของคุณพกพาสะดวกขณะที่คนอื่นพยายามเรียกใช้คอนเทนเนอร์ของคุณในสภาพแวดล้อมของตนเอง และคุณยังสามารถเผยแพร่พอร์ตบนโฮสต์ของคุณซึ่งบริการอื่น ๆ ที่ไม่ได้ถูกโยกย้ายยังสามารถเข้าถึงได้ คุณสามารถเผยแพร่พอร์ตไปยังอินเตอร์เฟส localhost บนโฮสต์นักเทียบท่าของคุณเพื่อหลีกเลี่ยงการเข้าถึงจากภายนอกด้วยไวยากรณ์เช่น: -p 127.0.0.1:3306:3306สำหรับพอร์ตที่เผยแพร่

ตัวเลือก 2 : มีหลายวิธีในการตรวจสอบที่อยู่ IP ของโฮสต์จากด้านในของคอนเทนเนอร์ แต่แต่ละสถานการณ์มีจำนวน จำกัด ในสถานการณ์ที่ใช้งานได้ (เช่นต้องการ Docker for Mac) ตัวเลือกแบบพกพาที่สุดคือการฉีด IP โฮสต์ของคุณลงในคอนเทนเนอร์ด้วยสิ่งต่าง ๆ เช่นตัวแปรสภาพแวดล้อมหรือไฟล์การกำหนดค่าเช่น:

docker run --rm -e "HOST_IP=$(ip r s 0/0 | awk '{print $3}')" ...

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

ตัวเลือก 3 : ทำงานโดยไม่มีการแยกเครือข่ายเช่นทำงานด้วย--net hostหมายความว่าแอปพลิเคชันของคุณกำลังทำงานบนเนมสเปซเครือข่ายโฮสต์ นี่คือการแยกน้อยกว่าสำหรับคอนเทนเนอร์และหมายความว่าคุณไม่สามารถเข้าถึงคอนเทนเนอร์อื่น ๆ ผ่านเครือข่ายนักเทียบท่าที่ใช้ร่วมกันกับ DNS (แทนคุณต้องใช้พอร์ตที่เผยแพร่เพื่อเข้าถึงแอปพลิเคชันที่บรรจุอื่น ๆ ) แต่สำหรับแอปพลิเคชั่นที่ต้องการเข้าถึงบริการอื่น ๆ บนโฮสต์ที่รับฟังเฉพาะ127.0.0.1ในโฮสต์นี่เป็นตัวเลือกที่ง่ายที่สุด

ตัวเลือก 4 : บริการต่าง ๆ ยังอนุญาตให้เข้าถึงผ่านซ็อกเก็ตที่ใช้ระบบไฟล์ ซ็อกเก็ตนี้สามารถติดตั้งในคอนเทนเนอร์เป็นไดรฟ์ข้อมูลผูกติดตั้งช่วยให้คุณสามารถเข้าถึงบริการโฮสต์โดยไม่ต้องผ่านเครือข่าย สำหรับการเข้าถึงเครื่องมือนักเทียบท่าคุณมักจะเห็นตัวอย่างของการติดตั้ง/var/run/docker.sockลงในคอนเทนเนอร์ (ให้สิทธิ์เข้าถึงรูทคอนเทนเนอร์ไปยังโฮสต์) ด้วย mysql คุณสามารถลองทำสิ่งที่ชอบ-v /var/run/mysqld/mysqld.sock:/var/run/mysqld/mysql.sockแล้วเชื่อมต่อกับlocalhostmysql ที่แปลงเป็นการใช้ซ็อกเก็ต


3

คุณสามารถรับโฮสต์ IP โดยใช้ภาพอัลไพน์

docker run --rm alpine ip route | awk 'NR==1 {print $3}'

สิ่งนี้จะสอดคล้องกันมากขึ้นเนื่องจากคุณใช้อัลไพน์เพื่อเรียกใช้คำสั่งเสมอ

เช่นเดียวกับคำตอบของ Mariano คุณสามารถใช้คำสั่งเดียวกันเพื่อตั้งค่าตัวแปรสภาพแวดล้อม

DOCKER_HOST=$(docker run --rm alpine ip route | awk 'NR==1 {print $3}') docker-compose up

3

สำหรับ Linux ซึ่งคุณไม่สามารถเปลี่ยนอินเตอร์เฟสได้เซอร์วิส localhost จะเชื่อมโยงกับ

มีสองปัญหาที่เราต้องแก้ไข

  1. รับ IP ของโฮสต์
  2. ทำให้บริการโฮสต์ในพื้นที่ของเราพร้อมใช้งานสำหรับนักเทียบท่า

ปัญหาแรกสามารถแก้ไขได้โดยใช้อิมเมจ docker -hostของ qoomon ตามคำตอบอื่น ๆ

คุณจะต้องเพิ่มคอนเทนเนอร์นี้ไปยังเครือข่ายบริดจ์เดียวกันกับคอนเทนเนอร์อื่นของคุณเพื่อให้สามารถเข้าถึงได้ เปิดเทอร์มินัลภายในคอนเทนเนอร์ของคุณและตรวจสอบให้แน่ใจว่าคุณสามารถปิงdockerhostได้

bash-5.0# ping dockerhost
PING dockerhost (172.20.0.2): 56 data bytes
64 bytes from 172.20.0.2: seq=0 ttl=64 time=0.523 ms

ตอนนี้ปัญหาที่ยากขึ้นทำให้นักเข้าถึงบริการสามารถเข้าถึงได้

เราสามารถใช้ telnet เพื่อตรวจสอบว่าเราสามารถเข้าถึงพอร์ตบนโฮสต์ (คุณอาจต้องติดตั้งนี้)

ปัญหาคือว่าคอนเทนเนอร์ของเราจะสามารถเข้าถึงบริการที่ผูกกับอินเทอร์เฟซทั้งหมดเท่านั้นเช่น SSH:

bash-5.0# telnet dockerhost 22
SSH-2.0-OpenSSH_7.6p1 Ubuntu-4ubuntu0.3

แต่บริการที่ผูกไว้กับ localhost จะไม่สามารถเข้าถึงได้:

bash-5.0# telnet dockerhost 1025
telnet: can't connect to remote host (172.20.0.2): Connection refused

ทางออกที่เหมาะสมที่นี่คือการผูกบริการกับนักเทียบท่าสะพานเครือข่าย อย่างไรก็ตามคำตอบนี้ถือว่าคุณไม่สามารถเปลี่ยนแปลงได้ iptablesดังนั้นเราจะใช้แทน

ifconfigอันดับแรกเราต้องไปหาชื่อของเครือข่ายสะพานที่นักเทียบท่าที่ใช้กับ หากคุณกำลังใช้บริดจ์ที่ไม่มีชื่อนี่จะเป็นdocker0เช่นนั้น อย่างไรก็ตามหากคุณใช้เครือข่ายที่มีชื่อคุณจะมีบริดจ์ที่เริ่มต้นด้วยbr-นักเทียบท่านั้นจะใช้แทน br-5cd80298d6f4เหมือง

เมื่อเรามีชื่อของบริดจ์นี้แล้วเราต้องอนุญาตการกำหนดเส้นทางจากบริดจ์นี้ไปยังโลคอลโฮสต์ สิ่งนี้ถูกปิดใช้งานโดยค่าเริ่มต้นด้วยเหตุผลด้านความปลอดภัย:

sysctl -w net.ipv4.conf.<bridge_name>.route_localnet=1

ตอนนี้เพื่อตั้งiptablesกฎของเรา เนื่องจากคอนเทนเนอร์ของเราสามารถเข้าถึงพอร์ตบนเครือข่ายบริดจ์นักเทียบท่าเท่านั้นเราจึงจะแกล้งทำเป็นว่าบริการของเราถูกผูกไว้กับพอร์ตบนเครือข่ายนี้จริง ๆ

ในการทำเช่นนี้เราจะส่งต่อคำขอทั้งหมดไป<docker_bridge>:portที่localhost:port

iptables -t nat -A PREROUTING -p tcp -i <docker_bridge_name> --dport <service_port> -j DNAT --to-destination 127.0.0.1:<service_port>

ตัวอย่างเช่นสำหรับบริการของฉันที่พอร์ต 1025

iptables -t nat -A PREROUTING -p tcp -i br-5cd80298d6f4 --dport 1025 -j DNAT --to-destination 127.0.0.1:1025

ตอนนี้คุณควรจะสามารถเข้าถึงบริการของคุณจากคอนเทนเนอร์:

bash-5.0# telnet dockerhost 1025
220 127.0.0.1 ESMTP Service Ready

1
นี่เป็นสิ่งเดียวกับที่ @ ray-d พูดถึงข้างต้น แต่ได้รับการอธิบายอย่างดี ขอบคุณ! นอกจากนี้เมื่อใช้นักเทียบท่าเขียนฉันต้องเพิ่มกฎ DNAT ในห่วงโซ่ PREROUTING สำหรับแพ็คเก็ตทั้งหมดที่มาถึงอินเทอร์เฟซ docker0 ด้วยเช่นกันเพราะดูเหมือนว่านักเขียน Docker-compos จะใช้ docker0 ในระหว่างการสร้างsysctl -w net.ipv4.conf.docker0.route_localnet=1และiptables -t nat -A PREROUTING -p tcp -i docker0 --dport 1025 -j DNAT --to-destination 127.0.0.1:1025
— arvindd

3

คุณต้องรู้ประตู ! วิธีแก้ปัญหาของฉันกับเซิร์ฟเวอร์ภายในคือการเปิดเผยภายใต้0.0.0.0:8000แล้วเรียกใช้นักเทียบท่ากับเครือข่ายย่อยและเรียกใช้คอนเทนเนอร์เช่น:

docker network create --subnet=172.35.0.0/16 --gateway 172.35.0.1 SUBNET35
docker run -d -p 4444:4444 --net SUBNET35 <container-you-want-run-place-here>

ดังนั้นตอนนี้คุณสามารถเข้าถึงลูปแบ็คได้แล้ว http://172.35.0.1:8000


3

ลองสิ่งนี้:

version: '3.5'
services:
  yourservice-here:
    container_name: container_name
    ports:
      - "4000:4000"
    extra_hosts: # <---- here
      - localhost:192.168.1.202
      - or-vitualhost.local:192.168.1.202

ที่จะได้รับ 192.168.1.202ใช้ifconfig

สิ่งนี้ใช้ได้สำหรับฉัน หวังว่าจะช่วยได้!


2

กลุ่ม CG และ Namespaces กำลังมีบทบาทสำคัญในระบบนิเวศคอนเทนเนอร์

เนมสเปซเป็นชั้นของการแยก แต่ละคอนเทนเนอร์จะทำงานในเนมสเปซที่แยกต่างหากและการเข้าถึงจะ จำกัด เฉพาะเนมสเปซนั้น กลุ่ม Cg ควบคุมการใช้ทรัพยากรของแต่ละภาชนะในขณะที่ Namespace ควบคุมสิ่งที่กระบวนการสามารถดูและเข้าถึงทรัพยากรที่เกี่ยวข้อง

นี่คือความเข้าใจพื้นฐานของวิธีการแก้ปัญหาที่คุณสามารถติดตามได้

ใช้เนมสเปซเครือข่าย

เมื่อคอนเทนเนอร์วางไข่ออกจากภาพอินเทอร์เฟซเครือข่ายจะถูกกำหนดและสร้าง สิ่งนี้จะให้ที่อยู่ IP และอินเตอร์เฟสที่ไม่ซ้ำกันของคอนเทนเนอร์

$ docker run -it alpine ifconfig

โดยการเปลี่ยนเนมสเปซเป็นโฮสต์เครือข่าย cotainers จะไม่แยกออกจากอินเตอร์เฟสกระบวนการจะสามารถเข้าถึงอินเตอร์เฟสเครือข่ายของเครื่องโฮสต์ได้

$ docker run -it --net=host alpine ifconfig

หากกระบวนการฟังพอร์ตพวกเขาจะฟังบนโฮสต์อินเตอร์เฟสและแมปไปยังคอนเทนเนอร์

ใช้ PID เนมสเปซโดยการเปลี่ยน Pid เนมสเปซอนุญาตให้คอนเทนเนอร์โต้ตอบกับกระบวนการอื่นนอกเหนือจากขอบเขตปกติ

คอนเทนเนอร์นี้จะทำงานในเนมสเปซของตนเอง

$ docker run -it alpine ps aux

โดยการเปลี่ยนเนมสเปซเป็นโฮสต์คอนเทนเนอร์ยังสามารถเห็นกระบวนการอื่น ๆ ทั้งหมดที่ทำงานบนระบบ

$ docker run -it --pid=host alpine ps aux

การแบ่งปัน Namespace

นี่เป็นวิธีปฏิบัติที่ไม่ดีที่จะทำเช่นนี้เนื่องจากคุณกำลังทำลายโมเดลการรักษาความปลอดภัยของคอนเทนเนอร์ซึ่งอาจเปิดช่องโหว่และเข้าถึง eavesdropper ได้ง่าย นี่เป็นเพียงเครื่องมือในการดีบักและทำความเข้าใจช่องโหว่ในความปลอดภัยของคอนเทนเนอร์

คอนเทนเนอร์แรกคือเซิร์ฟเวอร์ nginx สิ่งนี้จะสร้างเนมสเปซเครือข่ายและกระบวนการใหม่ คอนเทนเนอร์นี้จะผูกตัวเองกับพอร์ต 80 ของอินเตอร์เฟสเครือข่ายที่สร้างขึ้นใหม่

$ docker run -d --name http nginx:alpine

คอนเทนเนอร์อื่นสามารถใช้ namespace นี้ซ้ำได้

$ docker run --net=container:http mohan08p/curl curl -s localhost

นอกจากนี้คอนเทนเนอร์นี้สามารถเห็นอินเตอร์เฟสกับกระบวนการในคอนเทนเนอร์ที่แชร์

$ docker run --pid=container:http alpine ps aux

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


1

สำหรับเครื่อง Windows: -

เรียกใช้คำสั่งด้านล่างเพื่อแสดงพอร์ตนักเทียบท่าแบบสุ่มระหว่างเวลาสร้าง

$docker run -d --name MyWebServer -P mediawiki

ป้อนคำอธิบายรูปภาพที่นี่

ป้อนคำอธิบายรูปภาพที่นี่

ในรายการคอนเทนเนอร์ด้านบนคุณสามารถดูพอร์ตที่กำหนดเป็น 32768 ลองเข้าถึง

localhost:32768 

คุณสามารถดูหน้ามีเดียวิกิ


5
แม้ว่าคำตอบนี้อาจให้ข้อมูลที่เป็นประโยชน์แก่ผู้ใช้บางคน แต่เป็นวิธีที่ผิด ! มันเกี่ยวกับการเข้าถึงบริการที่ทำงานอยู่ในคอนเทนเนอร์จากเครื่องโฮสต์ อย่างไรก็ตามคำถามเกี่ยวกับการเข้าถึงบริการที่ทำงานอยู่บนโฮสต์จากภาชนะ
— einjohn

1

จนกว่าการแก้ไขจะไม่ถูกรวมเข้ากับmasterสาขาเพื่อรับ IP โฮสต์เพียงแค่เรียกใช้จากด้านในของคอนเทนเนอร์:

ip -4 route list match 0/0 | cut -d' ' -f3

(ตามที่แนะนำโดย@Mhoney ที่นี่ )


1

ฉันแก้ไขมันโดยการสร้างผู้ใช้ใน MySQL สำหรับ ip ของคอนเทนเนอร์:

$ sudo mysql<br>
mysql> create user 'username'@'172.17.0.2' identified by 'password';<br>
Query OK, 0 rows affected (0.00 sec)

mysql> grant all privileges on database_name.* to 'username'@'172.17.0.2' with grant option;<br>
Query OK, 0 rows affected (0.00 sec)

$ sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf
<br>bind-address        = 172.17.0.1

$ sudo systemctl restart mysql.service

จากนั้นในภาชนะบรรจุ: jdbc:mysql://<b>172.17.0.1</b>:3306/database_name


นี่เป็นทางออกที่ง่ายที่สุด มันได้ผลสำหรับฉันและฉันได้อ้างอิงหลายคน
— Sopia Alfred

-1

วิธีที่ฉันทำคือส่ง IP ของโฮสต์เป็นตัวแปรสภาพแวดล้อมไปยังคอนเทนเนอร์ คอนเทนเนอร์จากนั้นเข้าถึงโฮสต์โดยตัวแปรนั้น


คุณช่วยอธิบายวิธีการทำสิ่งนี้ได้ไหม ฉันได้ลองวิธีนี้ แต่ไม่พบความสำเร็จมากนัก
— kmjb

`นักเทียบท่าเรียกใช้ -i -t -e HOST = 10.145.2.123 ubuntu root @ ce2a843da3ee: / tmp # ./telnet $ HOST 22 กำลังพยายาม 10.145.2.123 ... เชื่อมต่อกับ 10.145.2.123 ตัวละคร Escape คือ '^]' SSH-2.0-OpenSSH_7.4`
— F. Kam
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.