将主机端口转发到docker容器

Joe*_*per 143 linux port networking docker

是否可以让主机打开Docker容器访问端口?具体来说,我在主机上运行MongoDB和RabbitMQ,我想在Docker容器中运行一个进程来监听队列并(可选)写入数据库.

我知道我可以将一个端口从容器转发到主机(通过-p选项)并从Docker容器中连接到外部世界(即Internet),但我不希望暴露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
Run Code Online (Sandbox Code Playgroud)

我不得不这样做以获得与容器的任何互联网连接:我的防火墙阻止从docker容器到外部的网络连接

编辑:最后我使用管道工程创建了一个自定义桥接器,让服务监听桥接IP.我采用这种方法而不是让MongoDB和RabbitMQ在docker桥上监听,因为它提供了更大的灵活性.

Dav*_*son 102

一种简单但相对不安全的方法是使用--net=host选项docker run.

此选项使容器使用主机的网络堆栈.然后,您只需使用"localhost"作为主机名即可连接到主机上运行的服务.

这更容易配置,因为您不必将服务配置为接受来自docker容器的IP地址的连接,并且您不必告知docker容器要连接的特定IP地址或主机名,一个港口.

例如,您可以通过运行以下命令来测试它,该命令假设您的图像被调用my_image,您的图像包含该telnet实用程序,并且您要连接的服务位于端口25上:

docker run --rm -i -t --net=host my_image telnet localhost 25
Run Code Online (Sandbox Code Playgroud)

如果您考虑这样做,请在此页面上查看有关安全性的警告:

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

它说:

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

  • 在MacOS上,` - net = host`不能用于允许容器进程使用`localhost`连接到主机.相反,让您的容器连接到特殊的MacOS主机名`docker.for.mac.host.internal`而不是`localhost`."docker run"不需要额外的参数来实现此功能.如果要保持容器平台不可知,可以使用`-e`将其作为env var传递.这样你就可以连接到env var中命名的主机,并在MacOS上传递`docker.for.mac.host.internal`,在Linux上传递`localhost`. (11认同)
  • 对于没有在Linux上使用docker的人(例如使用某种虚拟化),这将无法工作,因为主机将是包含VM,而不是实际的主机OS. (10认同)
  • 特别是在MacOS上,**是不可能的**(没有一些解决方法):https://docs.docker.com/docker-for-mac/networking/#i-want-to-connect-from-a -container到一个服务 - 上的主机 (10认同)
  • mac的最新主机名是`host.docker.internal`,参见[doc](https://docs.docker.com/docker-for-mac/networking/#use-cases-and-workarounds) (9认同)
  • 对于 Windows 来说,同样是 `docker run --rm -it --net=host postgres bash` 然后 `psql -h host.docker.internal -U postgres` (2认同)

Sel*_*ldo 50

您的docker主机向所有容器公开适配器.假设你是最近的ubuntu,你可以运行

ip addr
Run Code Online (Sandbox Code Playgroud)

这将为您提供一个网络适配器列表,其中一个看起来像

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
Run Code Online (Sandbox Code Playgroud)

你需要告诉rabbit/mongo绑定到那个IP(172.17.42.1).之后,您应该能够从容器中打开到172.17.42.1的连接.

  • 容器如何知道发送请求的IP是什么?我可以对这个值进行硬编码(这里和我的测试装备上的172.17.42.1,但总是如此吗?),但这似乎违背了与任何主机一起工作的码头工作原理! (32认同)
  • 如果主机只监听127.0.0.1,是否有可能以某种方式执行此操作? (7认同)
  • “您将需要告诉Rabbit / mongo绑定到该IP(172.17.42.1)。在那之后,您应该能够从容器中打开与172.17.42.1的连接。” 如果您解释了如何做到这一点会很好 (3认同)
  • @Seldo:该界面是否需要显示配置?我使用的是docker 1.7.1,我只有`lo`和`eth0`. (2认同)
  • 需要记住的一件有价值的事情是运行“ip -br -ca”。需要一段时间才能习惯,但对于一般日常使用来说它要好得多。 (2认同)

b01*_*b01 13

太长了;

仅对于本地开发,请执行以下操作:

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

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

END_TLDR;

例如,如果您在容器中使用它:

PGPASSWORD=password psql -h localhost -p 5432 -d mydb -U myuser
Run Code Online (Sandbox Code Playgroud)

将其更改为:

PGPASSWORD=password psql -h host.docker.internal -p 5432 -d mydb -U myuser
Run Code Online (Sandbox Code Playgroud)

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

背景

有关详细信息,请参阅:https://docs.docker.com/docker-for-mac/networking/#use-cases-and-workarounds

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


cze*_*asz 10

您还可以创建一个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"
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

config/ssh/config:

# Elasticsearch Server
Host elasticsearch
    HostName jump.host.czerasz.com
    User czerasz
    ForwardAgent yes
    IdentityFile ~/.ssh/id_rsa
Run Code Online (Sandbox Code Playgroud)

这样elasticsearch,通过运行服务(Elasticsearch,MongoDB,PostgreSQL)与服务器建立隧道,并使用该服务公开端口9200.

  • 你基本上把私钥放在Docker镜像中.秘密永远不应该进入Docker镜像. (8认同)
  • 这是迄今为止唯一可用的理智解决方案。 (2认同)

war*_*iuc 8

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

我想从容器连接到主机上的服务

主机有一个不断变化的 IP 地址(如果您没有网络访问权限,则没有)。我们建议您连接到host.docker.internal解析为主机使用的内部 IP 地址的特殊 DNS 名称。这是出于开发目的,不适用于 Docker Desktop for Mac 之外的生产环境。

您也可以使用 到达网关gateway.docker.internal

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

这对我有用而不使用--net=host.

  • 这适用于 Windows,但不适用于 Linux(问题是专门针对 Linux 的)。在具有足够新版本的 Docker 的 Linux 上,有一个解决方法:/sf/answers/4370181581/ (4认同)
  • Windows 的好解决方案。在这里工作 (3认同)

Ari*_*ion 7

我在从 docker 容器访问 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
Run Code Online (Sandbox Code Playgroud)

iptables 规则:

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

进入容器内部 dockerhost:portnumberOnHost