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


当前回答

我遇到了类似的问题,从docker容器访问LDAP-Server。 我为容器设置了固定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

其他回答

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

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

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

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的连接。

TLDR;

只适用于本地发展,请采取以下措施:

在笔记本电脑/电脑/PC/Mac上启动服务或SSH隧道。 构建/运行Docker镜像/容器以连接到主机名host.docker.internal:<hostPort>

注意:还有gateway.docker.internal,我没有尝试过。

END_TLDR;

例如,如果你在你的容器中使用这个:

PGPASSWORD=password psql -h localhost -p 5432 -d mydb -U myuser

改成这样:

PGPASSWORD=password psql -h host.docker.internal -p 5432 -d mydb -U myuser

这将神奇地连接到主机上运行的服务。不需要使用——net=host或-p "hostPort:ContainerPort"或-p

背景

详情见:https://docs.docker.com/docker-for-mac/networking/#use-cases-and-workarounds

我将此与SSH隧道一起使用到Windows 10上的AWS RDS Postgres实例。我只需要在容器中使用localhost:containerPort更改为host.docker.internal:hostPort。

正如其中一条评论所述,这适用于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服务。