จากด้านในของ 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.