有可能让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桥上监听,因为它提供了更大的灵活性。


当前回答

正如其中一条评论所述,这适用于Mac(可能也适用于Windows/Linux):

我想从容器连接到主机上的服务 主机有一个不断变化的IP地址(如果没有网络访问,则没有)。我们建议您连接到特殊的DNS名称host.docker.internal,它可以解析为主机使用的内部IP地址。这是为了开发目的,不能在Mac Docker Desktop以外的生产环境中工作。 您也可以使用gateway.docker.internal到达网关。

引自https://docs.docker.com/docker-for-mac/networking/

我不需要使用——net=host。

其他回答

为什么不用稍微不同的溶液呢,像这样?

services:
  kubefwd:
    image: txn2/kubefwd
    command: ...
  app:
    image: bash
    command:
     - sleep
     - inf
    init: true
    network_mode: service:kubefwd

REF: txn2/kubefwd:本地开发的批量端口转发Kubernetes服务。

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

为了将端口从容器公开到主机,不需要使用-p选项。默认情况下,所有端口都是公开的。-p选项允许您从容器向主机外部公开一个端口。

所以,我的猜测是你根本不需要-p,它应该可以正常工作:)

您还可以创建一个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"

码头工人/ 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

ssh problem / / problem:

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

这样一来,elasticsearch就有了一个连接到服务器上运行的服务(elasticsearch, MongoDB, PostgreSQL)的隧道,并将9200端口与该服务公开。

docker主机向所有容器公开一个适配器。假设你使用的是最新的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的连接。

一个简单但相对不安全的方法是使用——net=host选项来运行docker。

此选项使容器使用主机的网络堆栈。然后,只需使用“localhost”作为主机名,就可以连接到主机上运行的服务。

这更容易配置,因为你不需要配置服务来接受来自docker容器的IP地址的连接,你也不需要告诉docker容器一个特定的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 -- Tells Docker to skip placing the container inside of a separate network stack. In essence, this choice tells Docker to not containerize the container's networking! While container processes will still be confined to their own filesystem and process list and resource limits, a quick ip addr command will show you that, network-wise, they live “outside” in the main Docker host and have full access to its network interfaces. Note that this does not let the container reconfigure the host network stack — that would require --privileged=true — but it does let container processes open low-numbered ports like any other root process. It also allows the container to access local network services like D-bus. This can lead to processes in the container being able to do unexpected things like restart your computer. You should use this option with caution.