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

问题描述 投票:167回答:10

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

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

更新:

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

ip addr show docker0 | grep -Po 'inet \K[\d.]+'
docker docker-container
10个回答
146
投票

在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接口。

0
投票

我已经探索了各种解决方案,我发现这是最不讨厌的解决方案:

  1. 为网关网关IP定义静态IP地址。
  2. 将网关IP添加为hosts文件中的额外条目。

唯一的缺点是如果你有多个网络或项目这样做,你必须确保他们的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”从容器内部访问主机上的端口。


201
投票

For macOS and 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


33
投票

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


11
投票

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

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

8
投票

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


5
投票

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

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


1
投票

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

  1. 方法1与公共IP 使用主机公共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

从具有专用网络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

1
投票

我们发现对所有这些网络垃圾的更简单的解决方案是只使用域套接字来进行服务。如果您正尝试连接到主机,只需将插座安装为卷,即可开始使用。对于postgresql,这很简单:

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

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


0
投票

如果您已经“创建”了两个泊坞窗图像,并且您希望将两个容器放在一起进行通信。

为此,您可以方便地使用自己的--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或等效命令。

希望这些信息可以帮助您。

© www.soinside.com 2019 - 2024. All rights reserved.