从Docker容器内部,如何连接到本机的本地主机?

Phi*_*hil 1176 reverse-proxy nginx docker docker-networking

所以我在Docker容器中运行了一个Nginx,我在localhost上运行了一个mysql,我想从我的Nginx中连接到MySql.MySql在localhost上运行,而不是将端口暴露给外部世界,所以它绑定在localhost上,而不是绑定在机器的ip地址上.

有没有办法从这个docker容器中连接到这个MySql或localhost上的任何其他程序?

Tho*_*eil 1638

编辑:如果您使用的是Docker-for-macDocker-for-Windows 18.03+,只需使用主机连接到您的mysql服务即可host.docker.internal.

从Docker 18.04开始,这不适用于Docker-for-Linux.但是,使用qoomon的答案中描述的容器,您可以使其工作.


TLDR

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

注意:根据文档,此模式仅适用于Docker for Linux .


关于docker容器网络模式的注意事项

Docker 在运行容器时提供不同的网络模式.根据您选择的模式,您将以不同方式连接到在docker主机上运行的MySQL数据库.

docker run --network ="bridge"(默认)

Docker创建一个docker0默认命名的网桥.docker主机和docker容器都在该网桥上有一个IP地址.

在Docker主机上输入sudo ip addr show docker0你会看到如下输出:

[vagrant@docker:~] $ sudo ip addr show docker0
4: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 56:84:7a:fe:97:99 brd ff:ff:ff:ff:ff:ff
    inet 172.17.42.1/16 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::5484:7aff:fefe:9799/64 scope link
       valid_lft forever preferred_lft forever
Run Code Online (Sandbox Code Playgroud)

所以这里我的docker主机172.17.42.1docker0网络接口上有IP地址.

现在启动一个新容器并在其上获取一个shell:docker run --rm -it ubuntu:trusty bash并在容器类型ip addr show eth0中发现它的主网络接口是如何设置的:

root@e77f6a1b3740:/# ip addr show eth0
863: eth0: <BROADCAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 66:32:13:f0:f1:e3 brd ff:ff:ff:ff:ff:ff
    inet 172.17.1.192/16 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::6432:13ff:fef0:f1e3/64 scope link
       valid_lft forever preferred_lft forever
Run Code Online (Sandbox Code Playgroud)

这里我的容器有IP地址172.17.1.192.现在看一下路由表:

root@e77f6a1b3740:/# route
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         172.17.42.1     0.0.0.0         UG    0      0        0 eth0
172.17.0.0      *               255.255.0.0     U     0      0        0 eth0
Run Code Online (Sandbox Code Playgroud)

因此,docker主机的IP地址172.17.42.1被设置为默认路由,可以从容器中访问.

root@e77f6a1b3740:/# ping 172.17.42.1
PING 172.17.42.1 (172.17.42.1) 56(84) bytes of data.
64 bytes from 172.17.42.1: icmp_seq=1 ttl=64 time=0.070 ms
64 bytes from 172.17.42.1: icmp_seq=2 ttl=64 time=0.201 ms
64 bytes from 172.17.42.1: icmp_seq=3 ttl=64 time=0.116 ms
Run Code Online (Sandbox Code Playgroud)

docker run --network ="host"

或者,您可以运行设置为的网络设置host的docker容器.这样的容器将与docker主机共享网络堆栈,并且从容器的角度来看,localhost(或127.0.0.1)将引用docker主机.

请注意,Docker容器中打开的任何端口都将在docker主机上打开.这不需要-p-P docker run选择.

我的docker主机上的IP配置:

[vagrant@docker:~] $ ip addr show eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 08:00:27:98:dc:aa brd ff:ff:ff:ff:ff:ff
    inet 10.0.2.15/24 brd 10.0.2.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:fe98:dcaa/64 scope link
       valid_lft forever preferred_lft forever
Run Code Online (Sandbox Code Playgroud)

主机模式的docker容器:

[vagrant@docker:~] $ docker run --rm -it --network=host ubuntu:trusty ip addr show eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 08:00:27:98:dc:aa brd ff:ff:ff:ff:ff:ff
    inet 10.0.2.15/24 brd 10.0.2.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:fe98:dcaa/64 scope link
       valid_lft forever preferred_lft forever
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,docker主机和docker容器共享完全相同的网络接口,因此具有相同的IP地址.


从容器连接到MySQL

桥接模式

要在桥接模式下从容器访问在docker主机上运行的MySQL ,您需要确保MySQL服务正在侦听172.17.42.1IP地址上的连接.

为此,请确保您具有bind-address = 172.17.42.1bind-address = 0.0.0.0在MySQL配置文件(my.cnf)中.

如果需要使用网关的IP地址设置环境变量,则可以在容器中运行以下代码:

export DOCKER_HOST_IP=$(route -n | awk '/UG[ \t]/{print $2}')
Run Code Online (Sandbox Code Playgroud)

然后在您的应用程序中,使用DOCKER_HOST_IP环境变量打开与MySQL的连接.

注意:如果您使用bind-address = 0.0.0.0MySQL服务器将侦听所有网络接口上的连接.这意味着可以从Internet访问您的MySQL服务器; 确保相应地设置防火墙规则.

注2:如果你使用bind-address = 172.17.42.1你的MySQL服务器将不会监听连接127.0.0.1.在docker主机上运行的想要连接MySQL的进程必须使用172.17.42.1IP地址.

主机模式

要从主机模式下的容器访问在docker主机上运行的MySQL ,您可以保留bind-address = 127.0.0.1MySQL配置,您需要做的就是127.0.0.1从容器连接到:

[vagrant@docker:~] $ docker run --rm -it --network=host mysql mysql -h 127.0.0.1 -uroot -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 36
Server version: 5.5.41-0ubuntu0.14.04.1 (Ubuntu)

Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>
Run Code Online (Sandbox Code Playgroud)

注意:不要使用mysql -h 127.0.0.1,而不是mysql -h localhost; 否则MySQL客户端将尝试使用unix套接字进行连接.

  • 我正在运行Docker for Mac,而且再也没有172.17.42.1了,没有docker0了.作为网关是172.17.0.1,甚至不能`telnet 172.17.0.1 3306` (29认同)
  • OSX用户注意事项:首先登录docker虚拟机(boot2docker),使用"docker-machine ssh default",然后运行"sudo ip addr show docker0".继续托马斯的指示. (25认同)
  • 您可以将mysql套接字安装到容器中,而不是像`-v /var/run/mysqld/mysqld.sock:/ tmp/mysql.sock`这样的网络. (24认同)
  • 谢谢你这么详细的解答!根据我的收集,使用主机模式是通过localhost获得此功能的唯一方法.我没有尝试,但我认为你可以创建一个单独的网络,通过他们自己的桥连接容器,为他们提供一个共同的'localhost'. (7认同)
  • 当你在Mac上运行Docker并且不使用boot2docker时,有人可以解决这种情况吗?没有docker0接口? (7认同)
  • 对于尝试连接到主机服务并运行Docker for Mac的任何人。有一个特殊的Mac专用DNS名称`docker.for.mac.host.internal`,它解析为主机使用的内部IP地址。[源代码](https://docs.docker.com/docker-for-mac/networking/#known-limitations-use-cases-and-workarounds) (3认同)
  • 最新版本的Docker支持`host.docker.internal`作为容器中的域名(根据@Janne Annala的最新更新[答案](/sf/answers/3047917701/) ).展望未来,当您仍希望容器和主机网络之间存在某种程度的隔离时,这似乎是更通用的解决方案. (3认同)
  • @funseiki注意到对于docker 18.04.0-ce`host.docker.internal`不适用于Linux.它仅适用于docker-for-Windows和docker-for-mac.请参阅https://github.com/docker/for-linux/issues/264 (3认同)
  • 对于桥接模式情况,您是否需要配置iptables以接受来自容器的传入流量? (3认同)
  • 在https://docs.docker.com/articles/networking/上也有关于高级网络的指南。 (2认同)
  • 他们没有尝试简化这一点是有原因的。最好也对所有依赖项都进行docker化,这可以让您回避整个问题。 (2认同)
  • --net = host中断了已发布的端口转换,因此,如果容器公开端口80(使用--publish XXX:80或更简单地使用-p XXX:80,则主机上的服务已绑定到端口80(泊坞窗实例或主机本机服务),则容器将无法绑定端口80。因此,在任何情况下均不理想。 (2认同)
  • 一个提交给host.docker.internal在Linux上运行的[fix](https://github.com/docker/libnetwork/pull/2348)已提交。希望它将合并 (2认同)
  • “一次编写,随处可用”就到此为止了。 (2认同)

Jan*_*ala 302

对于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

  • 非常好,谢谢,这在容器内对我有用.`mysql -uroot -hdocker.for.mac.localhost` (5认同)
  • 看起来在 Linux 上,只有当容器位于默认的 docker “bridge” 网络“172.17.0.0”(即“docker0”接口使用的网络)上时,此功能才有效。如果您创建一个新网络并向其中添加容器,这将不起作用。 (4认同)
  • docker.for.mac.localhost 正是我要找的。但这同时又脏得要命。在 docker 中,人们会期望钩子 docker.for.mac.localhost 将是一个通用的 docker 内部名称,它对任何操作系统都有效,而不仅仅是对 Mac。但出于开发目的,这已经足够了。 (2认同)
  • 这个答案在 Debian 11 上对我不起作用。我已将 `host.docker.internal:host-gateway` 添加到 `extra_hosts`,并且在容器的 `/etc/hosts/` 中我可以看到 `172.17.0.1 主机。 docker.internal`,但从容器内我仍然得到“无法连接到远程主机(172.17.0.1):连接被拒绝”。 (2认同)
  • @aSemy 您是否使用自定义网络而不是默认的 docker 网络?不幸的是,在这种情况下,它无法在 Linux 上运行。 (2认同)

Dey*_*een 121

使用

host.docker.internal
Run Code Online (Sandbox Code Playgroud)

代替

localhost
Run Code Online (Sandbox Code Playgroud)

作品完美的我。

  • 也许这个答案可以扩展和澄清一点?这是否意味着您仍然可以使用桥接模式? (10认同)
  • @ArnoldRoa 这只适用于 Mac/Windows,不适用于 Linux (7认同)
  • 自 2021 年 4 月 26 日起不再运行。host.docker.internal 解析为空。 (5认同)
  • 有关使用 docker-compose 设置 host.docker.internal,请参阅 /sf/answers/4701074871/ (5认同)
  • 在 Windows 10 上运行 WSL2(启用了 WSL 后端的 Docker 桌面)。这是行不通的。 (2认同)

Mar*_*uiz 75

我做了一个类似于以上帖子的hack,让本地IP映射到容器中的别名(DNS).主要问题是使用一个简单的脚本动态获取,该脚本在Linux和OSX中都可以使用主机IP地址.我做了这个在两种环境中都有效的脚本(即使在已"$LANG" != "en_*"配置的Linux发行版中):

ifconfig | grep -E "([0-9]{1,3}\.){3}[0-9]{1,3}" | grep -v 127.0.0.1 | awk '{ print $2 }' | cut -f2 -d: | head -n1
Run Code Online (Sandbox Code Playgroud)

因此,使用Docker Compose,完整配置将是:

启动脚本(docker-run.sh):

export DOCKERHOST=$(ifconfig | grep -E "([0-9]{1,3}\.){3}[0-9]{1,3}" | grep -v 127.0.0.1 | awk '{ print $2 }' | cut -f2 -d: | head -n1)
docker-compose -f docker-compose.yml up
Run Code Online (Sandbox Code Playgroud)

docker-compose.yml:

myapp:
  build: .
  ports:
    - "80:80"
  extra_hosts:
    - "dockerhost:$DOCKERHOST"
Run Code Online (Sandbox Code Playgroud)

然后在代码中更改http://localhosthttp://dockerhost.

有关如何自定义DOCKERHOST脚本的更高级指南,请查看此文章并解释其工作原理.

  • 我对您的解决方案进行了少许修改,使其与自定义网络兼容:`export DOCKERHOST = $(docker network inspect --format ='{{range .IPAM.Config}} {{。Gateway}} {{end}}'&lt;NETWORK -NAME&gt; | awk -F“ /”'NR == 1 {print $ 1}')`其中_ &lt;NETWORK-NAME&gt; _可以是_bridge_或docker-compose定义的网络名称(通常是_path-name_ **-**_网络名字_)。 (2认同)

小智 38

这对我来说非常适合NGINX/PHP-FPM堆栈而无需触及应用程序只是希望能够连接到的任何代码或网络 localhost

安装mysqld.sock从主机到容器内.

在运行mysql的主机上找到mysql.sock文件的位置:
netstat -ln | awk '/mysql(.*)?\.sock/ { print $9 }'

将该文件挂载到docker中的预期位置:
docker run -v /hostpath/to/mysqld.sock:/containerpath/to/mysqld.sock

mysqld.sock的可能位置:

/tmp/mysqld.sock
/var/run/mysqld/mysqld.sock 
/var/lib/mysql/mysql.sock
/Applications/MAMP/tmp/mysql/mysql.sock # if running via MAMP
Run Code Online (Sandbox Code Playgroud)

  • 套接字不像TCP那样扩展,因为它们更频繁地阻塞并且可能导致奇怪的行为.尽可能使用TCP. (5认同)
  • @JoelESalas你有这个说法的来源吗? (3认同)
  • 这是一个更清洁的解决方案,不会将Mysql暴露给外部(如果不使用防火墙). (2认同)
  • @JoelESalas我想你错了。默认情况下,mysql客户端库甚至在连接到本地主机时甚至使用unix套接字,而不是实际连接到本地主机。Unix套接字避免了TCP堆栈和路由的开销,并且应运行得更快。 (2认同)

BMi*_*tch 19

想到了几种解决方案:

  1. 首先将您的依赖项移动到容器中
  2. 使您的其他服务可从外部访问并使用该外部 IP 连接到它们
  3. 在没有网络隔离的情况下运行您的容器
  4. 避免通过网络连接,而是使用作为卷安装的套接字

这不是开箱即用的原因是容器默认使用自己的网络命名空间运行。这意味着 localhost(或指向环回接口的 127.0.0.1)对于每个容器都是唯一的。连接到此将连接到容器本身,而不是在 docker 外部或不同 docker 容器内部运行的服务。

选项 1:如果您的依赖项可以移动到容器中,我会先执行此操作。它使您的应用程序堆栈可移植,因为其他人尝试在他们自己的环境中运行您的容器。并且您仍然可以在您的主机上发布端口,其他尚未迁移的服务仍然可以访问它。您甚至可以将端口发布到 docker 主机上的 localhost 接口,以避免使用以下语法从外部访问它:-p 127.0.0.1:3306:3306对于已发布的端口。

Option 2: There are a variety of ways to detect the host IP address from inside of the container, but each have a limited number of scenarios where they work (e.g. requiring Docker for Mac). The most portable option is to inject your host IP into the container with something like an environment variable or configuration file, e.g.:

docker run --rm -e "HOST_IP=$(ip route get 1 | sed -n 's/^.*src \([0-9.]*\) .*$/\1/p')" ...
Run Code Online (Sandbox Code Playgroud)

This does require that your service is listening on that external interface, which could be a security concern. For other methods to get the host IP address from inside of the container, see this post.

Slightly less portable is to use host.docker.internal. This works in current versions of Docker for Windows and Docker for Mac. And in 20.10, the capability has been added to Docker for Linux when you pass a special host entry with:

docker run --add-host host.docker.internal:host-gateway ...
Run Code Online (Sandbox Code Playgroud)

The host-gateway is a special value added in Docker 20.10 that automatically expands to a host IP. For more details see this PR.

Option 3: Running without network isolation, i.e. running with --net host, means your application is running on the host network namespace. This is less isolation for the container, and it means you cannot access other containers over a shared docker network with DNS (instead, you need to use published ports to access other containerized applications). But for applications that need to access other services on the host that are only listening on 127.0.0.1 on the host, this can be the easiest option.

Option 4: Various services also allow access over a filesystem based socket. This socket can be mounted into the container as a bind mounted volume, allowing you to access the host service without going over the network. For access to the docker engine, you often see examples of mounting /var/run/docker.sock into the container (giving that container root access to the host). With mysql, you can try something like -v /var/run/mysqld/mysqld.sock:/var/run/mysqld/mysql.sock and then connect to localhost which mysql converts to using the socket.


小智 18

Linux解决方案(内核> = 3.6).

好的,您的localhost服务器具有默认的docker接口docker0,其IP地址为172.17.0.1.您的容器以默认网络设置--net ="bridge"启动.

  1. 为docker0接口启用route_localnet:
    $ sysctl -w net.ipv4.conf.docker0.route_localnet=1
  2. 将此规则添加到iptables:
    $ iptables -t nat -I PREROUTING -i docker0 -d 172.17.0.1 -p tcp --dport 3306 -j DNAT --to 127.0.0.1:3306
    $ iptables -t filter -I INPUT -i docker0 -d 127.0.0.1 -p tcp --dport 3306 -j ACCEPT
  3. 创建具有来自'%'的访问权限的mysql用户 - 来自任何人,不包括localhost:
    CREATE USER 'user'@'%' IDENTIFIED BY 'password';
  4. 将脚本中的mysql-server地址更改为172.17.0.1


内核文档:

route_localnet - BOOLEAN:路由时不要将环回地址视为火星源或目的地.这使得127/8可用于本地路由(默认为FALSE).

  • 第二个 iptable 命令的用途是什么?我可以理解第一个是将 172.17.0.1:3306 匹配的所有 tcp 目标重写为 127.0.0.1:3306 但为什么需要第二个 iptable 命令? (3认同)

qoo*_*mon 18

直到host.docker.internal为每个平台工作,您可以使用我的容器充当NAT网关而无需任何手动设置https://github.com/qoomon/docker-host

  • 我可以确认这在具有Windows容器的Windows 19.03.2的Docker中不起作用。 (3认同)
  • 我可以确认这在 Docker for Windows v. 20.10.5 上不起作用。真令人气愤。主机(来自容器)的 IP 随机变化。当主机 IP 在运行时发生变化并且 host.docker.internal 解析为空时,我到底该如何部署连接字符串? (2认同)

Pra*_*nal 17

对于窗户,

我在 spring 配置中更改了数据库 url: spring.datasource.url=jdbc:postgresql://host.docker.internal:5432/apidb

然后构建镜像并运行。它对我有用。


小智 16

如果您使用 --net=host 运行,则 localhost 应该可以正常工作。如果您使用默认网络,请使用静态 IP 172.17.0.1。

看到这个 - /sf/answers/3398295211/


Ral*_*oss 15

Windows 10的解决方案

Docker Community Edition 17.06.0-ce-win18 2017-06-28(稳定)

您可以使用主机的DNS名称docker.for.win.localhost来解析内部IP.(警告一些消息来源,windows但它应该是win)

概述
我需要做类似的事情,即从我的Docker容器连接到我的localhost,它正在运行Azure Storage EmulatorCosmosDB Emulator.

Azure Storage Emulator在默认情况下侦听127.0.0.1,而你可以改变它的束缚太多,我一直在寻找,将使用默认设置工作的解决方案的IP.

这也适用于从我的Docker容器连接到SQL ServerIIS我在主机上本地运行的默认端口设置.


Shi*_*odi 13

这不是对实际问题的回答。这就是我解决类似问题的方法。解决方案完全来自:Define Docker Container Networking so Containers can Communicate。感谢 Nic Raboy

留在这里给其他可能想要在一个容器和另一个容器之间进行 REST 调用的人。回答这个问题:在 docker 环境中用什么来代替 localhost?

了解您的网络是什么样的 docker network ls

创建新网络 docker network create -d my-net

启动第一个容器 docker run -d -p 5000:5000 --network="my-net" --name "first_container" <MyImage1:v0.1>

检查第一个容器的网络设置docker inspect first_container。“网络”:应该有“我的网”

启动第二个容器 docker run -d -p 6000:6000 --network="my-net" --name "second_container" <MyImage2:v0.1>

检查第二个容器的网络设置docker inspect second_container。“网络”:应该有“我的网”

ssh 到您的第二个容器docker exec -it second_container shdocker exec -it second_container bash.

在第二个容器内,您可以通过 ping 第一个容器ping first_container。此外,您的代码调用,例如http://localhost:5000可以替换为http://first_container:5000


Ehs*_*n88 12

首先查看答案以获取解决此问题的选项。但如果您使用,docker-compose您可以添加network_mode: host到您的服务,然后用于127.0.0.1连接到本地主机。这只是上面答案中描述的选项之一。您可以在下面找到我的修改docker-compose.yml方法https://github.com/geerlingguy/php-apache-container.git

 ---
 version: "3"
 services:
   php-apache:
+    network_mode: host
     image: geerlingguy/php-apache:latest
     container_name: php-apache
...
Run Code Online (Sandbox Code Playgroud)

+表示我添加的行。


[附加信息] 这也适用于版本2.2。和“主机”或只是“主机”都在docker-compose.

 ---
 version: "2.2"

 services:
   php-apache:
+    network_mode: "host"
        or
+    network_mode: host
...
Run Code Online (Sandbox Code Playgroud)


Cas*_*sey 10

对于那些在Windows上,假设您正在使用桥接网络驱动程序,您将需要专门将MySQL绑定到hyper-v网络接口的IP地址.

这是通过通常隐藏的C:\ ProgramData\MySQL文件夹下的配置文件完成的.

绑定到0.0.0.0将不起作用.所需的地址也显示在docker配置中,在我的例子中是10.0.75.1.

  • 你值得一枚奖牌!我已经整整工作了两天.谢谢你的帮助! (3认同)

orz*_*zel 8

我不同意 Thomasleveil 的回答。

将 mysql 绑定到 172.17.42.1 将阻止其他使用主机上的数据库的程序访问它。这仅在您的所有数据库用户都已 dockerized 时才有效。

将mysql绑定到0.0.0.0会向外界打开db,这不仅是一件非常糟糕的事情,而且与原问题作者想要做的相反。他明确表示“MySql 在本地主机上运行,​​并且没有向外界公开端口,因此它绑定在本地主机上”

回答 ivant 的评论

“为什么不将 mysql 也绑定到 docker0?”

这不可能。mysql/mariadb 文档明确指出不可能绑定到多个接口。您只能绑定到 0、1 或所有接口。

总之,我还没有找到任何方法来从 docker 容器访问主机上的(仅限本地主机)数据库。这绝对看起来是一个非常非常常见的模式,但我不知道该怎么做。

  • “将 mysql 绑定到 172.17.42.1 将阻止其他使用主机上的数据库的程序访问它。” - 那不是真的。其他程序可以使用 mysql,它们只需要连接到 172.17.42.1 而不是 localhost/127.0.0.1。 (5认同)
  • 从 docker 主机,您仍然可以使用“172.17.42.1”地址连接到 MySQL 服务器。但是你的笔记是正确的。Aso,我使用“主机”网络模式编辑了我的答案,该模式允许将 MySQL 服务器绑定到“127.0.0.1”,同时允许容器连接到它 (4认同)

siv*_*udh 8

编辑:我最终在GitHub上对该概念进行了原型设计.查看: https ://github.com/sivabudh/system-in-a-box


首先,我的答案是面向两组人:使用Mac的人和使用Linux的人.

主机的网络模式不会在Mac上运行.您必须使用IP别名,请参阅:https://stackoverflow.com/a/43541681/2713729

什么是主机网络模式?请参阅:https://docs.docker.com/engine/reference/run/#/network-settings

其次,对于那些使用Linux的人(我的直接经验是使用Ubuntu 14.04 LTS并且我很快就会升级到16.04 LTS),是的,你可以让服务在Docker容器内运行连接到localhost运行在Docker主机(例如您的笔记本电脑).

怎么样?

关键是当您运行Docker容器时,必须使用主机模式运行它.该命令如下所示:

docker run --network="host" -id <Docker image ID>

当您在容器内执行ifconfig(您需要apt-get install net-tools容器ifconfig可以调用)时,您将看到网络接口与Docker主机(例如您的笔记本电脑)上的网络接口相同.

重要的是要注意我是Mac用户,但我在Parallels下运行Ubuntu,因此使用Mac并不是一个缺点.;-)

这就是你如何将NGINX容器连接到运行在MySQL上的MySQL localhost.

  • 那里非常好.虽然可以使用未使用的IP连接从容器连接到主机服务https://docs.docker.com/docker-for-mac/networking/.不是一个愉快的解决方案......但是有效 (2认同)

Yıl*_*maz 7

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

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

  • 在您的主机上使用ipconfigifconfig并记下所有 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 不是静态的,并且需要路由和防火墙设置,则这可能不起作用。


dan*_*lmo 6

Mac OSX最简单的解决方案

只需使用Mac的IP地址即可。在Mac上,运行此命令以获取IP地址并在容器中使用它:

$ ifconfig | grep 'inet 192'| awk '{ print $2}'
Run Code Online (Sandbox Code Playgroud)

只要在Mac上本地运行的服务器或另一个Docker容器中的服务器正在侦听0.0.0.0,该Docker容器就可以访问该地址。

如果您只想访问正在监听0.0.0.0的另一个Docker容器,则可以使用172.17.0.1

  • Docker for Mac 现在公开了“docker.for.mac.host.internal”主机名。 (5认同)

小智 6

非常简单快速,请使用ifconfig(linux)或ipconfig(windows)检查主机IP,然后创建一个

docker-compose.yml

version: '3' # specify docker-compose version

services:
  nginx:
    build: ./ # specify the directory of the Dockerfile
    ports:
      - "8080:80" # specify port mapping
    extra_hosts:
      - "dockerhost:<yourIP>"
Run Code Online (Sandbox Code Playgroud)

这样,您的容器将能够访问您的主机。访问数据库时,请记住使用之前指定的名称,在这种情况下,请使用“ dockerhost”和运行数据库的主机的端口


Ela*_*lad 5

在Windows 10 Home上使用Docker Toolbox时,没有任何答案对我有用,但是10.0.2.2可以使用,因为它使用VirtualBox将该主机暴露给该地址上的VM。

  • 有用。甚至无需指定--network = host。看起来10.0.2.2已设置为主机的默认IP。谢谢。 (2认同)

JSh*_*use 5

对于 Linux,您无法更改 localhost 服务绑定到的接口

我们需要解决两个问题

  1. 获取主机IP
  2. 使我们的 localhost 服务可用于 Docker

第一个问题可以使用 qoomon 的 docker -host image 解决,正如其他答案所给出的。

您需要将此容器添加到与其他容器相同的桥接网络,以便您可以访问它。在您的容器内打开一个终端并确保您可以 ping dockerhost

bash-5.0# ping dockerhost
PING dockerhost (172.20.0.2): 56 data bytes
64 bytes from 172.20.0.2: seq=0 ttl=64 time=0.523 ms
Run Code Online (Sandbox Code Playgroud)

现在,更难的问题是使 docker 可以访问该服务。

我们可以使用 telnet 来检查我们是否可以访问主机上的端口(您可能需要安装它)。

问题是我们的容器将只能访问绑定到所有接口的服务,例如 SSH:

bash-5.0# telnet dockerhost 22
SSH-2.0-OpenSSH_7.6p1 Ubuntu-4ubuntu0.3
Run Code Online (Sandbox Code Playgroud)

但是仅绑定到 localhost 的服务将无法访问:

bash-5.0# telnet dockerhost 1025
telnet: can't connect to remote host (172.20.0.2): Connection refused
Run Code Online (Sandbox Code Playgroud)

这里正确的解决方案是将服务绑定到 dockers 网桥网络。但是,此答案假定您无法更改此设置。所以我们将改为使用iptables.

首先,我们需要找到 docker 正在使用的桥接网络的名称ifconfig。如果您使用的是未命名的网桥,这将是docker0. 但是,如果您使用的是命名网络,您将拥有一个以br-该 docker开头的网桥。我的是br-5cd80298d6f4

一旦我们有了这个网桥的名字,我们就需要允许从这个网桥到本地主机的路由。出于安全原因,默认情况下禁用此功能:

sysctl -w net.ipv4.conf.<bridge_name>.route_localnet=1
Run Code Online (Sandbox Code Playgroud)

现在来设置我们的iptables规则。由于我们的容器只能访问 docker bridge 网络上的端口,我们将假装我们的服务实际上绑定到该网络上的一个端口。

为此,我们会将所有请求转发<docker_bridge>:portlocalhost:port

iptables -t nat -A PREROUTING -p tcp -i <docker_bridge_name> --dport <service_port> -j DNAT --to-destination 127.0.0.1:<service_port>
Run Code Online (Sandbox Code Playgroud)

例如,对于我在端口 1025 上的服务

iptables -t nat -A PREROUTING -p tcp -i br-5cd80298d6f4 --dport 1025 -j DNAT --to-destination 127.0.0.1:1025
Run Code Online (Sandbox Code Playgroud)

您现在应该能够从容器访问您的服务:

bash-5.0# telnet dockerhost 1025
220 127.0.0.1 ESMTP Service Ready
Run Code Online (Sandbox Code Playgroud)

  • 这与@ray-d 上面提到的相同,但解释得很好。谢谢你!此外,当使用 docker-compose 时,我还必须在 PREROUTING 链中为到达 docker0 接口的所有数据包添加 DNAT 规则:因为,docker-compose 似乎在构建期间使用 docker0(令人惊讶的是,不是在运行期间): `sysctl -w net.ipv4.conf.docker0.route_localnet=1` 和 `iptables -t nat -A PREROUTING -p tcp -i docker0 --dport 1025 -j DNAT --to-destination 127.0.0.1:1025` (2认同)

sto*_*nth 5

你需要知道网关!我与本地服务器的解决办法是将其暴露下0.0.0.0:8000,与当时的运行码头工人子网运行容器,如:

docker network create --subnet=172.35.0.0/16 --gateway 172.35.0.1 SUBNET35
docker run -d -p 4444:4444 --net SUBNET35 <container-you-want-run-place-here>
Run Code Online (Sandbox Code Playgroud)

所以,现在您可以通过以下方式访问您的环回 http://172.35.0.1:8000


Bin*_* Ho 5

尝试这个:

version: '3.5'
services:
  yourservice-here:
    container_name: container_name
    ports:
      - "4000:4000"
    extra_hosts: # <---- here
      - localhost:192.168.1.202
      - or-vitualhost.local:192.168.1.202
Run Code Online (Sandbox Code Playgroud)

为了得到192.168.1.202,使用ifconfig

这对我有用。希望这有帮助!


bal*_*lki 5

连接到网关地址。

\n
\xe2\x9d\xaf docker network inspect bridge | grep Gateway\n                    "Gateway": "172.17.0.1"\n
Run Code Online (Sandbox Code Playgroud)\n

确保主机上的进程正在侦听此接口或所有接口,并且在 docker 之后启动。如果使用 systemd,您可以添加以下内容以确保它在 docker 之后启动。

\n
[Unit]\nAfter=docker.service\n
Run Code Online (Sandbox Code Playgroud)\n
\n

例子

\n
\xe2\x9d\xaf python -m http.server &> /dev/null &\n[1] 149976\n\n\xe2\x9d\xaf docker run --rm python python -c  "from urllib.request import urlopen;print(b'Directory listing for' in urlopen('http://172.17.0.1:8000').read())" \nTrue\n
Run Code Online (Sandbox Code Playgroud)\n