如何从docker容器访问主机端口

时间:2015-07-09 18:01:28

标签: docker docker-container

我有一个运行jenkins的docker容器。作为构建过程的一部分,我需要访问在主机上本地运行的Web服务器。有没有办法将主机Web服务器(可以配置为在端口上运行)暴露给jenkins容器?

编辑:我正在Linux机器上本地运行docker。

更新:

除了下面的@larsks答案,要从主机获取主机IP的IP地址,我还会执行以下操作:

ip addr show docker0 | grep -Po 'inet \K[\d.]+'

16 个答案:

答案 0 :(得分:181)

对于macOS和Windows

Docker v 18.03及以上(自2018年3月21日起)

使用您的内部IP地址或连接到特殊DNS名称host.docker.internal,该名称将解析为主机使用的内部IP地址。

Linux支持暂挂https://github.com/docker/for-linux/issues/264

MacOS与早期版本的Docker

Docker for Mac v 17.12至v 18.02

与上述相同,但请改用docker.for.mac.host.internal

Docker for Mac v 17.06至v 17.11

与上述相同,但请改用docker.for.mac.localhost

适用于Mac 17.05及更低版本的Docker

要从docker容器访问主机,必须将IP别名附加到网络接口。你可以绑定你想要的任何IP,只要确保你没有将它用于其他任何地方。

sudo ifconfig lo0 alias 123.123.123.123/24

然后确保您的服务器正在收听上述IP或0.0.0.0。如果它正在侦听localhost 127.0.0.1,它将不接受该连接。

然后只需将您的docker容器指向此IP,即可访问主机!

要测试,您可以在容器内运行类似curl -X GET 123.123.123.123:3000的内容。

别名将在每次重新启动时重置,因此如有必要,请创建启动脚本。

此处的解决方案和更多文档:https://docs.docker.com/docker-for-mac/networking/#use-cases-and-workarounds

答案 1 :(得分:137)

在Linux上本机运行Docker时,您可以使用docker0接口的IP地址访问主机服务。从容器内部,这将是您的默认路线。

例如,在我的系统上:

$ ip addr show docker0
7: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::f4d2:49ff:fedd:28a0/64 scope link 
       valid_lft forever preferred_lft forever

在容器内:

# ip route show
default via 172.17.0.1 dev eth0 
172.17.0.0/16 dev eth0  src 172.17.0.4 

使用简单的shell提取此IP地址相当容易 脚本:

#!/bin/sh

hostip=$(ip route show | awk '/default/ {print $3}')
echo $hostip

您可能需要修改主机上的iptables规则以允许 来自Docker容器的连接。像这样的东西会做的 特技:

# iptables -A INPUT -i docker0 -j ACCEPT

这将允许从Docker访问主机上的任何端口 容器。请注意:

  • 订购iptables规则,此规则可能会也可能不会 正确的事情取决于之前的其他规则。

  • 您将只能访问(a)的主机服务 听INADDR_ANY(又名0.0.0.0)或明确表示 在docker0界面上聆听。

答案 2 :(得分:29)

--net="host"命令中使用docker run,然后Docker容器中的localhost将指向您的泊坞主机。

答案 3 :(得分:24)

对于linux系统,您可以–从主要版本docker引擎20.04开始–现在也可以通过host.docker.internal与主机进行通信。这将自动不起作用,但是您需要提供以下运行标志:

--add-host=host.docker.internal:host-gateway

请参见

答案 4 :(得分:11)

使用docker-compose解决方案: 要访问基于主机的服务,您可以使用network_mode参数 https://docs.docker.com/compose/compose-file/#network_mode

version: '3'
services:
  jenkins:
    network_mode: host

答案 5 :(得分:7)

目前,在Mac和Windows上执行此操作的最简单方法是使用主机host.docker.internal,该主机解析为托管计算机的IP地址。不幸的是does not work on linux yet(截至2018年4月)。

答案 6 :(得分:4)

我创建了一个docker容器来完成https://github.com/qoomon/docker-host

然后您可以简单地使用容器名称dns来访问主机系统,例如 curl http://dockerhost:9200

答案 7 :(得分:3)

对于docker-compose,使用网桥网络在容器之间创建专用网络,使用docker0的已接受解决方案不起作用,因为来自容器的出口接口不是docker0,而是一个随机生成的接口ID,例如:

$ ifconfig

br-02d7f5ba5a51: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.32.1  netmask 255.255.240.0  broadcast 192.168.47.255

不幸的是,随机ID是不可预测的,并且每次compose必须重新创建网络时(例如在主机重启时),随机ID都会改变。我的解决方案是在已知子网中创建专用网络,并将iptables配置为接受该范围:

撰写文件摘要:

version: "3.7"

services:
  mongodb:
    image: mongo:4.2.2
    networks:
    - mynet
    # rest of service config and other services removed for clarity

networks:
  mynet:
    name: mynet
    ipam:
      driver: default
      config:
      - subnet: "192.168.32.0/20"

如果您的环境需要,可以更改子网。我通过使用192.168.32.0/20任意选择了docker network inspect来查看默认情况下创建的内容。

在主机上配置iptables,以允许专用子网作为源:

$ iptables -I INPUT 1 -s 192.168.32.0/20 -j ACCEPT

这是最简单的iptables规则。您可能希望添加其他限制,例如按目标端口。当您对iptables规则感到满意时,别忘了坚持。

此方法的优点是可重复且因此可自动化。我使用ansible的template模块来部署带有变量替换的撰写文件,然后分别使用iptablesshell模块来配置和保留防火墙规则。

答案 8 :(得分:2)

这是一个古老的问题,有很多答案,但是没有一个适合我的情况。就我而言,这些容器非常瘦,并且不包含从容器内部提取主机ip地址所需的任何联网工具。

此外,在--net="host"方法中使用的方法是一种非常粗糙的方法,当要使用多个容器进行良好隔离的网络配置时,该方法不适用。

因此,我的方法是提取主机侧的主机地址,然后使用--add-host参数将其传递到容器:

$ docker run --add-host=docker-host:`ip addr show docker0 | grep -Po 'inet \K[\d.]+'` image_name

或者,将主机的IP地址保存在环境变量中,以后再使用该变量:

$ DOCKERIP=`ip addr show docker0 | grep -Po 'inet \K[\d.]+'`
$ docker run --add-host=docker-host:$DOCKERIP image_name

然后将docker-host添加到容器的hosts文件中,然后可以在数据库连接字符串或API URL中使用它。

答案 9 :(得分:1)

我们发现,针对所有这些网络垃圾的更简单解决方案是仅将域套接字用于服务。如果仍然尝试连接到主机,只需将套接字作为卷安装,就可以了。对于postgresql,这很简单:

docker run -v /var/run/postgresql:/var/run/postgresql

然后,我们只是将数据库连接设置为使用套接字而不是网络。从字面上看很容易。

答案 10 :(得分:1)

对我来说(Windows 10,Docker Engine v19.03.8)是https://stackoverflow.com/a/43541732/7924573https://stackoverflow.com/a/50866007/7924573的混合。

  1. 将主机/ ip更改为 host.docker.internal
    例如:LOGGER_URL =“ http://host.docker.internal:8085/log
  2. 将network_mode设置为 bridge (如果要维护端口转发;如果不使用 host ):
    version: '3.7' services: server: build: . ports: - "5000:5000" network_mode: bridge 或者,如果您不使用docker-compose(类似于https://stackoverflow.com/a/48806927/7924573),请使用--net="bridge"
    如先前的答案所指出:只能在本地开发环境中使用
    有关更多信息,请阅读:https://docs.docker.com/compose/compose-file/#network_modehttps://docs.docker.com/docker-for-windows/networking/#use-cases-and-workarounds

答案 11 :(得分:0)

如果你有两个码头图片&#34;已经&#34;已创建,您希望将两个容器放在一起进行通信。

为此,您可以方便地使用自己的--name运行每个容器,并使用--link标志启用它们之间的通信。但是在docker build期间你没有得到这个。

当你处于像我一样的场景中时,它就是你的

docker build -t "centos7/someApp" someApp/ 

当你尝试

时会中断
curl http://172.17.0.1:localPort/fileIWouldLikeToDownload.tar.gz > dump.tar.gz

你会被困在&#34; curl / wget&#34;没有&#34;路由到主持人&#34;。

原因是docker设置的安全性,默认情况下禁止从容器到主机或主机上运行的其他容器的通信。 这对我来说是非常令人惊讶的,我必须说,你会期望在本地机器上运行的docker机器的echosystem只是完美无缺地可以互相访问而没有太多障碍。

以下文档中详细介绍了对此的解释。

http://www.dedoimedo.com/computers/docker-networking.html

通过降低网络安全性,可以提供两种快速解决方法,帮助您实现目标。

  

最简单的替代方案就是关闭防火墙 - 或者允许所有防火墙。这意味着运行必要的命令,可以是systemctl stop firewalld,iptables -F或等效命令。

希望这些信息对您有所帮助。

答案 12 :(得分:0)

我已经研究了各种解决方案,并且发现这是最不容易破解的解决方案:

  1. 为网桥网关IP定义一个静态IP地址。
  2. 在主机文件中添加网关IP作为额外条目。

唯一的缺点是,如果您有多个网络或项目正在执行此操作,则必须确保其IP地址范围不会冲突。

这是一个Docker Compose示例:

operator<=>

然后您可以使用主机名“ dockerhost”从容器内部访问主机上的端口。

答案 13 :(得分:0)

您可以通过两种方式访问​​在主机上运行的本地网络服务器。

  1. 使用公开IP的方法1

    使用主机的公共IP地址访问Jenkins docker容器中的Web服务器。

  2. 使用主机网络的方法2

    使用“ --net host”将Jenkins docker容器添加到主机的网络堆栈中。部署在主机堆栈上的容器可以完全访问主机接口。您可以使用主机的私有IP地址访问docker容器中的本地Web服务器。

NETWORK ID          NAME                      DRIVER              SCOPE
b3554ea51ca3        bridge                    bridge              local
2f0d6d6fdd88        host                      host                local
b9c2a4bc23b2        none                      null                local

使用主机网络启动容器 Eg: docker run --net host -it ubuntu并运行ifconfig列出可从Docker容器访问的所有可用网络IP地址。

例如:我在本地主机上启动了nginx服务器,并且能够从Ubuntu docker容器访问nginx网站URL。

docker run --net host -it ubuntu

$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
a604f7af5e36        ubuntu              "/bin/bash"         22 seconds ago      Up 20 seconds                           ubuntu_server

从Ubuntu Docker容器访问具有私有网络IP地址的Nginx Web服务器(在本地主机上运行)。

root@linuxkit-025000000001:/# curl 192.168.x.x -I
HTTP/1.1 200 OK
Server: nginx/1.15.10
Date: Tue, 09 Apr 2019 05:12:12 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 26 Mar 2019 14:04:38 GMT
Connection: keep-alive
ETag: "5c9a3176-264"
Accept-Ranges: bytes

答案 14 :(得分:0)

对我有用的最简单的选择是, 我在本地网络上使用了我机器的IP地址(由路由器分配)

您可以使用 ifconfig 命令找到它

例如

ifconfig

en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        options=400<CHANNEL_IO>
        ether f0:18:98:08:74:d4 
        inet 192.168.178.63 netmask 0xffffff00 broadcast 192.168.178.255
        media: autoselect
        status: active

然后使用 inet 地址。这对我来说可以连接我机器上的任何端口。

答案 15 :(得分:-1)

我的谷歌搜索将我带到这里,在挖掘评论后我发现它与 From inside of a Docker container, how do I connect to the localhost of the machine? 重复。我投票赞成关闭这个重复,但由于人们(包括我自己!)经常向下滚动答案而不是仔细阅读评论,这里是一个简短的答案。

TL;DR:

http://127.0.0.1http://localhost 替换为 http://host.docker.internal。 (Source)