551

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

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

更新:

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

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

18 回答 18

658

适用于所有平台

Docker v 20.10 及更高版本(自 2020 年 12 月 14 日起)

在 Linux 上,添加--add-host=host.docker.internal:host-gateway到 Docker 命令以启用此功能。(有关 Docker Compose 配置,请参见下文。)

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

要在 Linux 上的 Docker Compose 中启用此功能,请将以下几行添加到容器定义中:

extra_hosts:
- "host.docker.internal:host-gateway"

适用于 macOS 和 Windows

Docker v 18.03 及更高版本(自 2018 年 3 月 21 日起)

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

Linux 支持待定https://github.com/docker/for-linux/issues/264

带有早期版本 Docker 的 MacOS

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

于 2017-04-21T11:36:02.207 回答
344

在 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接口的主机服务。


如果您在MacOSWindows 18.03+ 上使用 Docker,则可以连接到神奇的主机名host.docker.internal


最后,在 Linux 下,您可以通过设置在主机网络命名空间中运行容器--net=host;在这种情况下localhost,您的主机上与容器内部相同localhost,因此容器化服务将像非容器化服务一样运行,无需任何额外配置即可访问。

于 2015-07-09T20:54:28.943 回答
148

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

于 2018-02-15T12:08:02.900 回答
72

对于 linux 系统,您可以 - 从20.04docker 引擎的主要版本开始 - 现在还可以通过host.docker.internal. 这不会自动工作,但您需要提供以下运行标志:

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

于 2020-04-25T10:56:32.687 回答
45

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

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

编辑 2020-04-27:建议仅在本地开发环境中使用。

编辑 2021-09-21:IHaveHandedInMyResignation 写道它不适用于 Mac 和 Windows。选项仅支持 Linux

于 2018-06-14T21:11:16.150 回答
35

我的谷歌搜索把我带到了这里,在挖掘评论后我发现它是来自 Docker 容器内部的副本,我如何连接到机器的本地主机?. 我投票赞成将此作为重复关闭,但由于人们(包括我自己!)经常向下滚动答案而不是仔细阅读评论,所以这里有一个简短的答案。

TL;博士:

替换http://127.0.0.1或。http://localhost_ http://host.docker.internal来源

于 2021-04-26T19:01:19.793 回答
26

我创建了一个 docker 容器来完全做到这一点https://github.com/qoomon/docker-host

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

于 2018-08-06T08:36:00.577 回答
24

目前在 Mac 和 Windows 上执行此操作的最简单方法是使用 host host.docker.internal,它解析为主机的 IP 地址。不幸的是,它还不能在 linux 上运行(截至 2018 年 4 月)。

于 2018-04-20T19:47:18.680 回答
14

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

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

然后我们只是设置我们的数据库连接以使用套接字而不是网络。字面意思就是这么简单。

于 2019-05-07T17:19:37.987 回答
14

我探索了各种解决方案,我发现这是最简单的解决方案:

  1. 为网桥网关 IP 定义一个静态 IP 地址。
  2. extra_hosts将网关 IP 添加为指令中的额外条目。

唯一的缺点是如果您有多个网络或项目这样做,您必须确保它们的 IP 地址范围不冲突。

这是一个 Docker Compose 示例:

version: '2.3'

services:
  redis:
    image: "redis"
    extra_hosts:
      - "dockerhost:172.20.0.1"

networks:
  default:
    ipam:
      driver: default
      config:
      - subnet: 172.20.0.0/16
        gateway: 172.20.0.1

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

于 2018-09-06T14:09:11.313 回答
10

对于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 必须重新创建网络时(例如在主机重新启动时)都会改变。我对此的解决方案是在已知子网中创建专用网络并配置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模块来部署我的带有变量替换的 compose 文件,然后分别使用iptablesshell模块来配置和持久化防火墙规则。

于 2020-01-01T16:37:00.417 回答
5

这是一个老问题,有很多答案,但没有一个适合我的上下文。就我而言,容器非常精简,不包含从容器中提取主机 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其添加到容器的主机文件中,您可以在数据库连接字符串或 API URL 中使用它。

于 2020-03-24T17:59:08.700 回答
4

对我来说(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 设置为桥接(如果您想维护端口转发;如果不使用host):
    version: '3.7' services: server: build: . ports: - "5000:5000" network_mode: bridge 或者:--net="bridge"如果您不使用 docker-compose 则使用(类似于https://stackoverflow.com/a/48806927/7924573
    正如前面的答案所指出的:这只应该在本地开发环境中使用
    有关更多信息,请阅读:https ://docs.docker.com/compose/compose-file/#network_mode和https://docs.docker.com/docker-for-windows/networking/#use-cases-and-workarounds
于 2020-06-02T08:27:17.147 回答
3

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

  1. 使用公共 IP 的方法 1

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

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

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

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

从具有私有网络 IP 地址的 Ubuntu docker 容器访问 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
于 2019-04-09T05:47:55.957 回答
1

对我有用的最简单的选项是,我使用本地网络上机器的 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地址。这对我来说可以连接我机器上的任何端口。

于 2021-04-22T15:41:33.857 回答
0

我运行 Jenkins 的 Dockerfile:

FROM jenkins/jenkins:2.333-jdk11
USER root

USER jenkins

https://github.com/dylanops/docker-jenkins

于 2022-03-02T11:01:37.953 回答
0

在将近 7 年的时间里,有人问了这个问题,要么是 docker 改变了,要么没有人尝试过这种方式。所以我将包括我自己的答案。

我发现所有答案都使用复杂的方法。今天,我需要这个,并找到了2个非常简单的方法:

  • 在您的主机上使用ipconfigorifconfig并记下所有 IP 地址。容器至少可以使用其中的两个。

    • 我在 WiFi LAN 适配器上有一个固定的本地网络地址:192.168.1.101. 这可能是10.0.1.101。结果将根据您的路由器而改变
    • 我在 Windows 上使用 WSL,它有自己的vEthernet地址:172.19.192.1
  • 使用host.docker.internal. 大多数答案都有这种或另一种形式,具体取决于操作系统。顾名思义,它现在被 docker 全局使用。

第三种选择是使用机器的 WAN 地址,或者换句话说,由服务提供商提供的 IP。但是,如果 IP 不是静态的,并且需要路由和防火墙设置,这可能不起作用。


PS:虽然和这里的这个问题非常相似,并且我在那里发布了这个答案,但我首先找到了这篇文章,所以我也将它发布在这里,因为可能会忘记我自己的答案。

于 2022-01-26T21:23:56.237 回答
-2

当您“已经”创建了两个 docker 映像并且您想要放置两个容器以相互通信时。

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

当您处于像我这样的场景中时,这是您的

docker build -t "centos7/someApp" someApp/ 

当你尝试

curl http://172.17.0.1:localPort/fileIWouldLikeToDownload.tar.gz > dump.tar.gz

并且你被困在“curl/wget”上,没有返回“到主机的路由”。

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

以下文档中对此进行了详细说明。

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

提供了两种快速解决方法,通过降低网络安全性来帮助您开始行动。

最简单的选择就是关闭防火墙 - 或全部允许。这意味着运行必要的命令,可以是 systemctl stop firewalld、iptables -F 或等效命令。

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

于 2016-11-16T21:47:23.857 回答