Chuyển tiếp cổng máy chủ đến container docker


166

Có thể có một cổng truy cập container Docker được mở bởi máy chủ không? Cụ thể là tôi có MongoDB và RabbitMQ đang chạy trên máy chủ và tôi muốn chạy một quy trình trong bộ chứa Docker để lắng nghe hàng đợi và (tùy chọn) ghi vào cơ sở dữ liệu.

Tôi biết rằng tôi có thể chuyển tiếp một cổng từ container sang máy chủ (thông qua tùy chọn -p) và có kết nối với thế giới bên ngoài (tức là internet) từ bên trong container Docker nhưng tôi không muốn lộ các cổng RabbitMQ và MongoDB từ chủ nhà đến thế giới bên ngoài.

EDIT: một số làm rõ:

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

Tôi đã phải thực hiện thủ thuật này để có được bất kỳ kết nối internet nào với container: Tường lửa của tôi đang chặn các kết nối mạng từ container docker ra bên ngoài

EDIT : Cuối cùng, tôi đã tạo ra một cây cầu tùy chỉnh bằng cách sử dụng pipework và có các dịch vụ lắng nghe IP của cây cầu. Tôi đã thực hiện theo cách tiếp cận này thay vì nghe MongoDB và RabbitMQ trên cầu docker vì nó cho phép linh hoạt hơn.

Câu trả lời:


53

Máy chủ docker của bạn hiển thị một bộ chuyển đổi cho tất cả các container. Giả sử bạn đang ở trên Ubuntu gần đây, bạn có thể chạy

ip addr

Điều này sẽ cung cấp cho bạn một danh sách các bộ điều hợp mạng, một trong số đó sẽ trông giống như

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

Bạn sẽ cần bảo thỏ / mongo liên kết với IP đó (172.17.42.1). Sau đó, bạn sẽ có thể mở các kết nối tới 172.17.42.1 từ trong các thùng chứa của mình.


35
Làm thế nào để container biết IP nào để gửi yêu cầu? Tôi có thể mã hóa giá trị (172.17.42.1 ở đây và trên thiết bị thử nghiệm của mình, nhưng điều đó có luôn đúng không?), Nhưng điều đó dường như đi ngược lại các nguyên tắc làm việc với docker!
JP.

2
@Seldo: Giao diện đó có cần cấu hình để hiển thị không? Tôi đang sử dụng docker 1.7.1, và tôi chỉ có loeth0.
mknecht

8
Có thể làm điều này bằng cách nào đó, nếu máy chủ chỉ nghe trên 127.0.0.1?
HansHarhoff

5
"Bạn sẽ cần yêu cầu thỏ / mongo liên kết với IP đó (172.17.42.1). Sau đó, bạn sẽ có thể mở các kết nối tới 172.17.42.1 từ trong các thùng chứa của mình." Sẽ thật tuyệt nếu bạn giải thích cách làm điều đó
Novaterata

1
Như @Novaterata đã đề cập, ai đó có thể vui lòng giải thích quá trình đó không?
keskinsaf

121

Một cách đơn giản nhưng tương đối không an toàn sẽ là sử dụng --net=hosttùy chọn này docker run.

Tùy chọn này làm cho nó để container sử dụng ngăn xếp mạng của máy chủ. Sau đó, bạn có thể kết nối với các dịch vụ đang chạy trên máy chủ bằng cách sử dụng "localhost" làm tên máy chủ.

Điều này dễ cấu hình hơn vì bạn sẽ không phải định cấu hình dịch vụ để chấp nhận kết nối từ địa chỉ IP của bộ chứa docker của bạn và bạn sẽ không phải nói với bộ chứa docker một địa chỉ IP hoặc tên máy chủ cụ thể để kết nối, chỉ cần một cảng.

Ví dụ: bạn có thể kiểm tra nó bằng cách chạy lệnh sau, giả sử hình ảnh của bạn được gọi my_image, hình ảnh của bạn bao gồm telnettiện ích và dịch vụ bạn muốn kết nối nằm trên cổng 25:

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

Nếu bạn xem xét thực hiện theo cách này, vui lòng xem cảnh báo về bảo mật trên trang này:

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

Nó nói rằng:

--net = host - Yêu cầu Docker bỏ qua việc đặt container bên trong ngăn xếp mạng riêng biệt. Về bản chất, lựa chọn này nói với Docker không được chứa mạng của người chứa! Mặc dù các quy trình vùng chứa vẫn sẽ bị giới hạn trong hệ thống tệp và danh sách quy trình và giới hạn tài nguyên của riêng chúng, nhưng lệnh addr ip nhanh sẽ cho bạn thấy rằng, thông thái mạng, chúng sống trực tiếp bên ngoài trên máy chủ Docker chính và có quyền truy cập đầy đủ vào giao diện mạng của nó . Lưu ý rằng điều này không cho phép bộ chứa cấu hình lại ngăn xếp mạng máy chủ - sẽ yêu cầu --privileged = true - nhưng nó cho phép các bộ xử lý container mở các cổng được đánh số thấp như bất kỳ quy trình gốc nào khác. Nó cũng cho phép container truy cập các dịch vụ mạng cục bộ như D-bus. Điều này có thể dẫn đến các quy trình trong container có thể thực hiện những việc không mong muốn như khởi động lại máy tính của bạn.


12
Đối với bất kỳ ai không sử dụng docker trên Linux (ví dụ: sử dụng một số ảo hóa) thì điều này sẽ không hoạt động, vì máy chủ sẽ là VM chứa chứ không phải HĐH máy chủ thực tế.
Sebastian Graf

13
Đặc biệt, trên MacOS, điều này là không thể (không có một số cách giải quyết): docs.docker.com/docker-for-mac/networking/ Lỗi
pje

15
Trên MacOS, --net=hostkhông hoạt động để cho phép quá trình chứa của bạn kết nối với máy chủ của bạn bằng cách sử dụng localhost. Thay vào đó, hãy để container của bạn kết nối với tên máy chủ chỉ dành cho MacOS docker.for.mac.host.internalthay vì localhost. Không có tham số bổ sung là cần thiết docker runđể làm việc này. Bạn có thể chuyển cái này dưới dạng var env bằng cách sử dụng -enếu bạn muốn giữ cho nền tảng container của bạn không biết gì. Bằng cách đó, bạn có thể kết nối với máy chủ có tên trong var env và truyền docker.for.mac.host.internaltrên MacOS và localhosttrên Linux.
hoa tulip

18
tên máy chủ mới nhất cho mac là host.docker.internal, xem doc
xysun

Tương tự cho Windows docker run --rm -it --net=host postgres bashrồipsql -h host.docker.internal -U postgres
Leo Cavalcante

12

Bạn cũng có thể tạo một đường hầm 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

Bằng cách elasticsearchnày, có một đường hầm đến máy chủ với dịch vụ đang chạy (Elaticsearch, MongoDB, PostgreQuery) và hiển thị cổng 9200 với dịch vụ đó.


8
Về cơ bản, bạn đang đặt khóa riêng trong hình ảnh Docker. Bí mật không bao giờ nên có được vào một hình ảnh Docker.
Teoh Han Hui

2
Đây là giải pháp lành mạnh duy nhất có thể sử dụng cho đến nay.
trực thăng

5

Tôi gặp vấn đề tương tự khi truy cập LDAP-Server từ bộ chứa docker. Tôi đặt IP cố định cho vùng chứa và thêm quy tắc tường lửa.

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

quy tắc iptables:

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

Bên trong container dockerhost:portnumberOnHost


3

Nếu MongoDB và RabbitMQ đang chạy trên Máy chủ, thì cổng sẽ được hiển thị vì nó không nằm trong Docker.

Bạn không cần -ptùy chọn để hiển thị các cổng từ container sang máy chủ. Theo mặc định, tất cả các cổng được tiếp xúc. Các -ptùy chọn cho phép bạn để lộ một cổng từ container ra bên ngoài của máy chủ.

Vì vậy, tôi đoán là bạn hoàn toàn không cần -pvà nó sẽ hoạt động tốt :)


1
Tôi biết điều đó, nhưng dường như tôi đang thiếu một chút thông tin: xem bản chỉnh sửa gần đây, vì tôi không thể truy cập vào các cổng trên máy chủ.
JoelKuiper

2
Bạn cần thiết lập rabbitmq và mongodb để nghe trên cầu và không chỉ trên giao diện mạng chính của bạn.
creack

13
@creack làm thế nào để bạn có được rabbitmq và mongodb để nghe trên cầu?
Ryan Walls
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.