ส่งต่อพอร์ตโฮสต์ไปยังคอนเทนเนอร์นักเทียบท่า


167

เป็นไปได้หรือไม่ที่จะเปิดพอร์ตการเข้าถึงคอนเทนเนอร์ Docker โดยโฮสต์? เป็นรูปธรรมฉันมี MongoDB และ RabbitMQ ทำงานบนโฮสต์และฉันต้องการเรียกใช้กระบวนการในคอนเทนเนอร์ Docker เพื่อฟังคิวและ (เป็นทางเลือก) เขียนไปยังฐานข้อมูล

ฉันรู้ว่าฉันสามารถส่งต่อพอร์ตจากคอนเทนเนอร์ไปยังโฮสต์ (ผ่านตัวเลือก -p) และมีการเชื่อมต่อกับโลกภายนอก (เช่นอินเทอร์เน็ต) จากภายในคอนเทนเนอร์ Docker แต่ฉันไม่ต้องการเปิดเผย RabbitMQ และ MongoDB พอร์ต จากโฮสต์สู่โลกภายนอก

แก้ไข: ชี้แจงบางส่วน:

Starting Nmap 5.21 ( http://nmap.org ) at 2013-07-22 22:39 CEST
Nmap scan report for localhost (127.0.0.1)
Host is up (0.00027s latency).
PORT     STATE SERVICE
6311/tcp open  unknown

joelkuiper@vps20528 ~ % docker run -i -t base /bin/bash
root@f043b4b235a7:/# apt-get install nmap
root@f043b4b235a7:/# nmap 172.16.42.1 -p 6311 # IP found via docker inspect -> gateway

Starting Nmap 6.00 ( http://nmap.org ) at 2013-07-22 20:43 UTC
Nmap scan report for 172.16.42.1
Host is up (0.000060s latency).
PORT     STATE    SERVICE
6311/tcp filtered unknown
MAC Address: E2:69:9C:11:42:65 (Unknown)

Nmap done: 1 IP address (1 host up) scanned in 13.31 seconds

ฉันต้องทำเคล็ดลับนี้เพื่อให้ได้รับการเชื่อมต่ออินเทอร์เน็ตภายในคอนเทนเนอร์: ไฟร์วอลล์ของฉันกำลังบล็อกการเชื่อมต่อเครือข่ายจากคอนเทนเนอร์ docker ไปยังภายนอก

แก้ไข : ในที่สุดฉันก็ไปกับการสร้างสะพานที่กำหนดเองโดยใช้งานปิเปตและให้บริการฟังบน IP ของบริดจ์ ฉันใช้วิธีนี้แทนการให้ MongoDB และ RabbitMQ ฟังบน docker bridge เพราะมันให้ความยืดหยุ่นมากกว่า

คำตอบ:


54

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

ip addr

นี่จะให้รายการอะแดปเตอร์เครือข่ายแก่คุณซึ่งหนึ่งในนั้นจะมีลักษณะดังนี้

3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP
link/ether 22:23:6b:28:6b:e0 brd ff:ff:ff:ff:ff:ff
inet 172.17.42.1/16 scope global docker0
inet6 fe80::a402:65ff:fe86:bba6/64 scope link
   valid_lft forever preferred_lft forever

คุณจะต้องบอกให้ Rabbit / mongo จับ IP นั้น (172.17.42.1) หลังจากนั้นคุณควรจะสามารถเปิดการเชื่อมต่อไปยัง 172.17.42.1 จากภายในคอนเทนเนอร์ของคุณ


36
คอนเทนเนอร์ทราบได้อย่างไรว่า IP ใดที่ส่งคำขอไป ฉันสามารถ hardcode ค่า (172.17.42.1 ที่นี่และบนอุปกรณ์ทดสอบของฉัน แต่มันเป็นเรื่องจริงเสมอ?) แต่ดูเหมือนว่าจะขัดกับหลักการนักเทียบท่าของการทำงานกับโฮสต์ใด ๆ !
เจพี

2
@Seldo: อินเทอร์เฟซนั้นต้องการการกำหนดค่าให้แสดงผลหรือไม่? ฉันใช้นักเทียบท่า 1.7.1 และฉันมีเพียงและlo eth0
mknecht

8
เป็นไปได้ไหมที่จะทำเช่นนี้หากโฮสต์นั้นรับฟังบน 127.0.0.1 เท่านั้น?
HansHarhoff

5
"คุณจะต้องบอกให้ Rabbit / mongo เชื่อมโยงกับ IP นั้น (172.17.42.1) หลังจากนั้นคุณจะสามารถเปิดการเชื่อมต่อไปยัง 172.17.42.1 ภายในคอนเทนเนอร์ของคุณได้" จะดีถ้าคุณอธิบายวิธีการทำ
Novaterata

1
ตามที่ @Novaterata พูดถึงใครช่วยอธิบายกระบวนการนั้นได้ไหม
keskinsaf

122

วิธีที่เรียบง่าย แต่ค่อนข้างไม่ปลอดภัยที่จะใช้ตัวเลือกในการ--net=hostdocker run

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

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

ตัวอย่างเช่นคุณสามารถทดสอบโดยใช้คำสั่งต่อไปนี้ซึ่งถือว่าภาพของคุณเรียกว่าmy_imageภาพของคุณรวมถึงtelnetยูทิลิตี้และบริการที่คุณต้องการเชื่อมต่ออยู่ในพอร์ต 25:

docker run --rm -i -t --net=host my_image telnet localhost 25

หากคุณพิจารณาที่จะทำเช่นนี้โปรดดูข้อควรระวังเกี่ยวกับความปลอดภัยในหน้านี้:

https://docs.docker.com/articles/networking/

มันบอกว่า:

--net = host - บอกนักเทียบท่าเพื่อข้ามการวางคอนเทนเนอร์ไว้ภายในสแต็กเครือข่ายแยกต่างหาก ตัวเลือกนี้บอกให้ Docker ไม่สร้างเครือข่ายของคอนเทนเนอร์! ในขณะที่กระบวนการคอนเทนเนอร์จะยังคงถูก จำกัด อยู่ที่ระบบไฟล์ของตัวเองและรายการกระบวนการและข้อ จำกัด ทรัพยากรคำสั่ง ip addr อย่างรวดเร็วจะแสดงให้คุณเห็นว่าเครือข่ายฉลาดพวกเขาอาศัยอยู่“ นอก” ในโฮสต์ Docker หลักและเข้าถึงอินเทอร์เฟซเครือข่าย . โปรดทราบว่าสิ่งนี้ไม่อนุญาตให้คอนเทนเนอร์กำหนดค่าสแต็กเครือข่ายโฮสต์ใหม่ซึ่งจะต้องมี --privileged = true - แต่จะอนุญาตให้กระบวนการคอนเทนเนอร์เปิดพอร์ตที่มีหมายเลขต่ำเช่นเดียวกับกระบวนการรูทอื่น ๆ นอกจากนี้ยังอนุญาตให้คอนเทนเนอร์เข้าถึงบริการเครือข่ายท้องถิ่นเช่น D-bus สิ่งนี้สามารถนำไปสู่กระบวนการในคอนเทนเนอร์ที่สามารถทำสิ่งที่ไม่คาดคิดเช่นรีสตาร์ทคอมพิวเตอร์ของคุณ


12
สำหรับทุกคนที่ไม่ได้ใช้นักเทียบท่าบน Linux (เช่นใช้การจำลองเสมือนจริง) สิ่งนี้จะไม่ทำงานเนื่องจากโฮสต์จะเป็น VM ที่มีอยู่ไม่ใช่โฮสต์ระบบปฏิบัติการจริง
Sebastian Graf

13
โดยเฉพาะอย่างยิ่งใน MacOS สิ่งนี้เป็นไปไม่ได้ (ไม่มีการแก้ไขปัญหาบางอย่าง): docs.docker.com/docker-for-mac/networking/ ......
pje

15
บน MacOS, ไม่ทำงานเพื่อให้กระบวนการคอนเทนเนอร์ของคุณเพื่อเชื่อมต่อกับเครื่องโฮสต์ของคุณโดยใช้--net=host localhostแต่มีคอนเทนเนอร์ของคุณเชื่อมต่อกับ MacOS พิเศษเพียงชื่อโฮสต์แทนdocker.for.mac.host.internal localhostไม่จำเป็นต้องใช้พารามิเตอร์เพิ่มเติมเพื่อdocker runให้สามารถใช้งานได้ คุณสามารถส่งสิ่งนี้เป็น env var โดยใช้-eหากคุณต้องการทำให้แพลตฟอร์มคอนเทนเนอร์ของคุณไม่เชื่อเรื่องพระเจ้า ด้วยวิธีนี้คุณสามารถเชื่อมต่อกับโฮสต์ที่มีชื่อใน env var และ pass docker.for.mac.host.internalบน MacOS และlocalhostบน Linux
ทิว.

18
ชื่อโฮสต์ล่าสุดสำหรับ mac คือhost.docker.internalดูdoc
xysun

เช่นเดียวกันสำหรับ Windows docker run --rm -it --net=host postgres bashแล้วpsql -h host.docker.internal -U postgres
Leo Cavalcante

12

คุณสามารถสร้างอุโมงค์ SSH

docker-compose.yml:

---

version: '2'

services:
  kibana:
    image: "kibana:4.5.1"
    links:
      - elasticsearch
    volumes:
      - ./config/kibana:/opt/kibana/config:ro

  elasticsearch:
    build:
      context: .
      dockerfile: ./docker/Dockerfile.tunnel
    entrypoint: ssh
    command: "-N elasticsearch -L 0.0.0.0:9200:localhost:9200"

docker/Dockerfile.tunnel:

FROM buildpack-deps:jessie

RUN apt-get update && \
    DEBIAN_FRONTEND=noninteractive \
    apt-get -y install ssh && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

COPY ./config/ssh/id_rsa /root/.ssh/id_rsa
COPY ./config/ssh/config /root/.ssh/config
COPY ./config/ssh/known_hosts /root/.ssh/known_hosts
RUN chmod 600 /root/.ssh/id_rsa && \
    chmod 600 /root/.ssh/config && \
    chown $USER:$USER -R /root/.ssh

config/ssh/config:

# Elasticsearch Server
Host elasticsearch
    HostName jump.host.czerasz.com
    User czerasz
    ForwardAgent yes
    IdentityFile ~/.ssh/id_rsa

วิธีนี้elasticsearchจะมีอุโมงค์ไปยังเซิร์ฟเวอร์ที่มีบริการที่ทำงานอยู่ (Elasticsearch, MongoDB, PostgreSQL) และแสดงพอร์ต 9200 ด้วยบริการดังกล่าว


8
คุณกำลังวางคีย์ส่วนตัวในภาพนักเทียบท่า ความลับไม่ควรเป็นภาพนักเทียบท่า
Teoh Han Hui

2
นี่เป็นวิธีแก้ปัญหาที่มีประโยชน์เพียงอย่างเดียวจนถึงตอนนี้
helvete

5

ฉันมีปัญหาคล้ายกันในการเข้าถึงเซิร์ฟเวอร์ LDAP จากที่เก็บข้อมูลนักเทียบท่า ฉันตั้งค่า IP คงที่สำหรับคอนเทนเนอร์และเพิ่มกฎไฟร์วอลล์

docker-compose.yml:

version: '2'
services:
  containerName:
    image: dockerImageName:latest
    extra_hosts:
      - "dockerhost:192.168.50.1"
    networks:
      my_net:
        ipv4_address: 192.168.50.2
networks:
  my_net:
    ipam:
      config:
      - subnet: 192.168.50.0/24

กฎ iptables:

iptables -A INPUT -j ACCEPT -p tcp -s 192.168.50.2 -d $192.168.50.1 --dport portnumberOnHost

ภายในช่องทางเข้า dockerhost:portnumberOnHost


3

หาก MongoDB และ RabbitMQ กำลังทำงานอยู่บนโฮสต์ดังนั้นพอร์ตควรจะปรากฏขึ้นเนื่องจากไม่ได้อยู่ใน Docker

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

ดังนั้นฉันเดาว่าคุณไม่จำเป็น-pเลยและควรจะทำงานได้ดี :)


1
ฉันรู้ว่า แต่ดูเหมือนว่าฉันไม่มีข้อมูลสักหน่อย: ดูการแก้ไขล่าสุดเนื่องจากฉันไม่สามารถเข้าถึงพอร์ตบนโฮสต์ได้
JoelKuiper

2
คุณต้องตั้งค่า rabbitmq และ mongodb เพื่อฟังบนบริดจ์และไม่เพียง แต่บนอินเทอร์เฟซเครือข่ายหลักของคุณ
creack

13
@creack คุณจะได้รับ rabbitmq และ mongodb เพื่อฟังบนสะพานได้อย่างไร?
Ryan Walls
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.