2013-07-21 62 views
92

是否有可能让主机打开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 

[email protected] ~ % docker run -i -t base /bin/bash 
[email protected]:/# apt-get install nmap 
[email protected]:/# 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 

我不得不这样做的手段来得到任何互联网连接withing容器:My firewall is blocking network connections from the docker container to outside

编辑:最后,我创建一个使用pipework定制桥去并让这些服务在网桥IP上进行监听。我采用这种方法,而不是让MongoDB和RabbitMQ在Docker桥上侦听,因为它提供了更大的灵活性。

回答

35

你搬运工主机暴露了适配器所有的容器。假设你是在最近的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 

你需要告诉兔子/蒙戈以绑定到该IP(172.17.42.1)。之后,您应该能够在容器内打开与172.17.42.1的连接。

+22

容器如何知道要发送请求的IP?我可以对这个值进行硬编码(172.17.42.1这里和我的测试平台上,但总是如此),但这似乎违背了与任何主机一起工作的码头原则! –

+0

另一种选择是绑定您的主机服务(例如mongodb)以侦听所有网络接口(即0.0.0.0),配置防火墙,以便只有内部网络上的机器才能连接到相关端口,然后连接到主机机器的网络IP地址在容器内。 – Josh

+1

@Seldo:该界面是否需要配置才能显示?我使用的是Docker 1.7.1,我只有'lo'和'eth0'。 – mknecht

4

如果MongoDB和RabbitMQ在主机上运行,​​那么该端口应该已经暴露,因为它不在Docker中。

为了将端口从容器公开到主机,您不需要'-p'选项。默认情况下,所有端口都被暴露。 '-p'选项允许您将容器中的端口暴露给主机外部。

所以,我的猜测是,你并不需要“-p”在所有的,它应该做工精细:)

+0

我知道,但似乎我缺少了一点信息:见最近的编辑,因为我无法到达主机上的端口。 – JoelKuiper

+1

您需要安装rabbitmq和mongodb以便在网桥上进行监听,而不仅仅是在主网络接口上进行监听。 – creack

+7

@creack你如何让rabbitmq和mongodb在桥上聆听? –

66

一个简单但相对不安全的方法是将--net=host选项用于docker 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跳过将容器放置在单独的网络堆栈中。实质上,这个选择告诉Docker不要容器化容器的网络!虽然容器进程仍然限于自己的文件系统和进程列表以及资源限制,但快速ip addr命令将向您显示,在网络方面,它们活在Docker主机主机的“外部”,并且可以完全访问其网络接口。请注意,这不会让容器重新配置主机网络堆栈 - 这将需要--privileged = true - 但它确实允许容器进程像任何其他根进程一样打开低编号的端口。它还允许容器访问D-bus等本地网络服务。这可能会导致容器中的进程能够执行意外的事情,如重新启动计算机。您应谨慎使用此选项。

+7

对于任何不在Linux上使用docker的人(例如使用某种虚拟化),这将不起作用,因为主机将是包含的VM,而不是实际的主机OS。 –

+3

特别是在MacOS上,这个**是不可能的**(没有一些解决方法):https://docs.docker.com/docker-for-mac/networking/#i-want-to-connect-from-一个容器到服务的主机 – pje

4

你也可以创建一个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)并暴露po rt 9200与该服务。

+0

你基本上把私钥放在Docker镜像中。秘密不应该进入Docker镜像。 –

1

我有一个类似的问题,从码头集装箱访问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