2446

所以我在 docker 容器中运行了一个 Nginx,我在 localhost 上运行了一个 mysql,我想从我的 Nginx 中连接到 MySql。MySql 在 localhost 上运行并且没有向外界公开端口,因此它绑定在 localhost 上,而不是绑定在机器的 ip 地址上。

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

这个问题与“如何从 docker 容器内部获取 docker 主机的 IP 地址”不同,因为 docker 主机的 IP 地址可能是网络中的公共 IP 或私有 IP,这可能是也可能是无法从 docker 容器中访问(如果托管在 AWS 或其他地方,我的意思是公共 IP)。即使您拥有 docker 主机的 IP 地址,这并不意味着您可以从容器内连接到 docker 主机,因为您的 Docker 网络的 IP 地址可能是覆盖、主机、网桥、macvlan、none 等,这限制了那个IP地址。

4

36 回答 36

3371

编辑:

如果您使用的是Docker-for-macDocker-for-Windows 18.03+,只需使用主机host.docker.internal(而不是127.0.0.1连接字符串中的)连接到您的 mysql 服务。

如果您使用的是 Docker-for-Linux 20.10.0+,host.docker.internal 如果--add-host host.docker.internal:host-gateway您使用该选项启动 Docker 容器,您也可以使用主机。

否则,请阅读下文


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

所以这里我的 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

这里我的容器有 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

因此 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

搬运工运行--network =“主机”

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

请注意,在您的 docker 容器中打开的任何端口都将在 docker 主机上打开。这不需要-por-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

并从主机模式下的 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

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


从容器连接到 MySQL

桥接模式

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

为此,请确保您的 MySQL 配置文件 (my.cnf) 中有一个bind-address = 172.17.42.1或其中一个。bind-address = 0.0.0.0

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

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

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

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

注意 2:如果您使用bind-address = 172.17.42.1MySQL 服务器,则不会侦听与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>

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

于 2014-06-20T11:46:51.397 回答
477

适用于所有平台

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

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

在 Linux 上,添加--add-host=host.docker.internal:host-gateway到 Docker 命令以启用此功能。要在 Linux 上的 Docker Compose 中启用此功能,请将以下几行添加到容器定义中:

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

对于 Docker 的旧 macOS 和 Windows 版本

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

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

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

于 2017-04-21T11:33:46.983 回答
163

使用

host.docker.internal

代替

localhost

对我来说完美无缺。

于 2020-07-27T09:52:38.073 回答
112

我做了一个类似于上述帖子的破解,获取本地 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

因此,使用 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

码头工人-compose.yml

myapp:
  build: .
  ports:
    - "80:80"
  extra_hosts:
    - "dockerhost:$DOCKERHOST"

然后在您的代码中更改http://localhost为。http://dockerhost

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

于 2016-08-03T21:30:39.500 回答
50

这在 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
于 2015-05-27T13:36:34.697 回答
42

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)。

于 2017-09-27T13:22:52.440 回答
40

直到host.docker.internal适用于每个平台,您可以将我的容器用作 NAT 网关,而无需任何手动设置:

https://github.com/qoomon/docker-host

于 2018-10-17T15:08:44.047 回答
22

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

码头工人-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>"

这样,您的容器将能够访问您的主机。访问数据库时,请记住使用您之前指定的名称,在本例中为“dockerhost”以及运行数据库的主机端口

于 2019-03-22T02:40:19.573 回答
21

适用于 Windows 10 的解决方案

Docker 社区版 17.06.0-ce-win18 2017-06-28(稳定版)

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

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

默认情况下Azure Storage Emulator侦听127.0.0.1,虽然您也可以更改其绑定的 IP,但我正在寻找一种可以使用默认设置的解决方案。

这也适用于从我的 Docker 容器连接到SQL Serverand IIS,两者都使用默认端口设置在我的主机上本地运行。

于 2017-11-09T10:49:13.623 回答
20

想到了几个解决方案:

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

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

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

选项 2:有多种方法可以从容器内部检测主机 IP 地址,但每种方法的工作场景数量有限(例如,Mac 需要 Docker)。最便携的选项是使用环境变量或配置文件之类的东西将主机 IP 注入容器,例如:

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

这确实要求您的服务正在侦听该外部接口,这可能是一个安全问题。有关从容器内部获取主机 IP 地址的其他方法,请参阅这篇文章

便携性稍差就是使用host.docker.internal。这适用于当前版本的 Docker for Windows 和 Docker for Mac。在 20.10 中,当您通过以下特殊主机条目传递时,该功能已添加到 Docker for Linux:

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

host-gateway是 Docker 20.10 中添加的一个特殊值,它会自动扩展为主机 IP。有关更多详细信息,请参阅此 PR

选项 3:在没有网络隔离的情况下运行,即使用 运行--net host,意味着您的应用程序正在主机网络命名空间上运行。这对容器的隔离较少,这意味着您无法通过具有 DNS 的共享 docker 网络访问其他容器(相反,您需要使用已发布的端口来访问其他容器化应用程序)。但是对于需要访问主机上仅在主机上侦听的其他服务的应用程序127.0.0.1,这可能是最简单的选择。

选项 4:各种服务还允许通过基于文件系统的套接字进行访问。此套接字可以作为绑定安装卷安装到容器中,允许您访问主机服务而无需通过网络。对于 docker 引擎的访问,您经常会看到挂载/var/run/docker.sock到容器中的示例(授予该容器对主机的 root 访问权限)。使用 mysql,您可以尝试类似的-v /var/run/mysqld/mysqld.sock:/var/run/mysqld/mysql.sock操作,然后localhost使用套接字连接到哪个 mysql 转换为。

于 2019-06-30T15:28:42.263 回答
20

Simplest solution for Mac OSX

Just use the IP address of your Mac. On the Mac run this to get the IP address and use it from within the container:

ifconfig | grep 'inet 192'| awk '{ print $2}'

As long as the server running locally on your Mac or in another docker container is listening to 0.0.0.0, the docker container will be able to reach out at that address.

If you just want to access another docker container that is listening on 0.0.0.0 you can use 172.17.0.1

于 2017-05-17T18:15:00.100 回答
18

对于窗户,

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

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

于 2020-02-07T15:51:55.323 回答
16

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

于 2018-11-09T22:23:58.067 回答
14

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

将这里留给可能想要在一个容器和另一个容器之间进行 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

于 2019-07-13T13:12:16.290 回答
13

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

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

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

于 2016-12-10T15:53:05.203 回答
11

编辑:我最终在 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 容器中运行的服务连接到在 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 容器连接到运行在localhost.

于 2017-02-07T07:15:57.070 回答
9

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

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

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

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

bash-5.0# telnet dockerhost 22
SSH-2.0-OpenSSH_7.6p1 Ubuntu-4ubuntu0.3

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

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

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

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

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

sysctl -w net.ipv4.conf.<bridge_name>.route_localnet=1

现在来设置我们的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>

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

iptables -t nat -A PREROUTING -p tcp -i br-5cd80298d6f4 --dport 1025 -j DNAT --to-destination 127.0.0.1:1025

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

bash-5.0# telnet dockerhost 1025
220 127.0.0.1 ESMTP Service Ready
于 2019-09-07T12:12:41.230 回答
8

我不同意 Thomasleveil 的回答。

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

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

回答 ivant 的评论

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

这是不可能的。mysql/mariadb 文档明确表示无法绑定到多个接口。您只能绑定到 0、1 或所有接口。

作为结论,我还没有找到任何方法可以从 docker 容器访问主机上的(仅限本地主机)数据库。这绝对是一种非常常见的模式,但我不知道该怎么做。

于 2015-03-12T23:31:45.360 回答
6

首先查看答案,了解您必须解决此问题的选项。但是如果你使用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
...

+表示我添加的行。


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

 ---
 version: "2.2"

 services:
   php-apache:
+    network_mode: "host"
        or
+    network_mode: host
...
于 2020-11-21T13:45:01.503 回答
6

尝试这个:

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

获取192.168.1.202,使用ifconfig

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

于 2020-04-25T05:26:49.220 回答
5

你需要知道网关!我使用本地服务器的解决方案是将其公开0.0.0.0:8000,然后使用子网运行 docker并运行容器,如:

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>

所以,现在你可以通过http://172.35.0.1:8000

于 2020-01-23T12:45:56.057 回答
4

这是我的解决方案:它适用于我的情况

  • #bind-address = 127.0.0.1 通过/etc/mysql/mysql.conf.d 中的注释将本地 mysql 服务器设置为公共访问

  • 重启mysql服务器 sudo /etc/init.d/mysql restart

  • 运行以下命令以打开用户 root 访问任何主机 mysql -uroot -proot GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION; FLUSH PRIVILEGES;

  • 创建 sh 脚本:run_docker.sh

    #!bin/bash

    HOSTIP=`ip -4 addr show scope global dev eth0 | grep inet | awk '{打印 \$2}' | 剪切-d / -f 1`


      docker run -it -d --name web-app \
                  --add-host=local:${HOSTIP} \
                  -p 8080:8080 \
                  -e DATABASE_HOST=${HOSTIP} \
                  -e 数据库端口=3306 \
                  -e DATABASE_NAME=演示\
                  -e DATABASE_USER=根\
                  -e DATABASE_PASSWORD=根\
                  sopheamak/springboot_docker_mysql

  
  • 使用 docker-composer 运行

    版本:'2.1'

    服务:
    汤姆猫: 额外主机: - “本地:10.1.2.232” 图片:sopheamak/springboot_docker_mysql
    端口: - 8080:8080 环境: - DATABASE_HOST=本地 - DATABASE_USER=root - DATABASE_PASSWORD=root - DATABASE_NAME=演示 - 数据库端口=3306

于 2017-07-17T07:47:55.347 回答
4

在 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 不是静态的,并且需要路由和防火墙设置,这可能不起作用。

于 2022-01-26T21:15:08.213 回答
4

连接到网关地址。

❯ docker network inspect bridge | grep Gateway
                    "Gateway": "172.17.0.1"

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

[Unit]
After=docker.service

例子

❯ python -m http.server &> /dev/null &
[1] 149976

❯ 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())" 
True
于 2021-01-22T21:39:50.163 回答
3

您可以使用 alpine 映像获取主机 ip

docker run --rm alpine ip route | awk 'NR==1 {print $3}'

这会更加一致,因为您总是使用 alpine 来运行命令。

与 Mariano 的回答类似,您可以使用相同的命令设置环境变量

DOCKER_HOST=$(docker run --rm alpine ip route | awk 'NR==1 {print $3}') docker-compose up
于 2018-06-11T08:47:06.200 回答
2

您可以简单地ifconfig在主机上检查您的主机 IP,然后从您的容器内连接到该 IP,这对我来说非常有效。

于 2020-11-30T06:27:22.603 回答
2

我通过在 MySQL 中为容器的 ip 创建一个用户来解决它:

$ sudo mysql<br>
mysql> create user 'username'@'172.17.0.2' identified by 'password';<br>
Query OK, 0 rows affected (0.00 sec)

mysql> grant all privileges on database_name.* to 'username'@'172.17.0.2' with grant option;<br>
Query OK, 0 rows affected (0.00 sec)

$ sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf
<br>bind-address        = 172.17.0.1

$ sudo systemctl restart mysql.service

然后在容器上:jdbc:mysql://<b>172.17.0.1</b>:3306/database_name

于 2019-09-27T02:32:27.000 回答
2

为了使一切正常,您需要为您的服务器(caddy、nginx)创建一个配置,其中主域将是“docker.for.mac.localhost”。为此替换“http://docker.for.mac.localhost/api”上的 baseURL“http://localhost/api”

码头工人-compose.yml

backend:
  restart: always
  image: backend
  build:
    dockerfile: backend.Dockerfile
    context: .
  environment:
    # add django setting.py os.getenv("var") to bd config and ALLOWED_HOSTS CORS_ORIGIN_WHITELIST
    DJANGO_ALLOWED_PROTOCOL: http
    DJANGO_ALLOWED_HOSTS: docker.for.mac.localhost
    POSTGRES_PASSWORD: 123456
    POSTGRES_USER: user
    POSTGRES_DB: bd_name
    WAITDB: "1"
  volumes:
    - backend_static:/app/static
    - backend_media:/app/media
  depends_on:
    - db

frontend:
  restart: always
  build:
    dockerfile: frontend.Dockerfile
    context: .
  image: frontend
  environment:
    #  replace baseURL for axios
    API_URL: http://docker.for.mac.localhost/b/api
    API_URL_BROWSER: http://docker.for.mac.localhost/b/api
    NUXT_HOST: 0.0.0.0
  depends_on:
    - backend

caddy:
  image: abiosoft/caddy
  restart: always
  volumes:
    - $HOME/.caddy:/root/.caddy
    - ./Caddyfile.local:/etc/Caddyfile
    - backend_static:/static
    - backend_media:/media
  ports:
  - 80:80
  depends_on:
    - frontend
    - backend
    - db

球童文件.local

http://docker.for.mac.localhost {

  proxy /b backend:5000 {
    header_upstream Host {host}
    header_upstream X-Real-IP {remote}
    header_upstream X-Forwarded-For {remote}
    header_upstream X-Forwarded-Port {server_port}
    header_upstream X-Forwarded-Proto {scheme}
  }

  proxy / frontend:3000 {
    header_upstream Host {host}
    header_upstream X-Real-IP {remote}
    header_upstream X-Forwarded-For {remote}
    header_upstream X-Forwarded-Port {server_port}
    header_upstream X-Forwarded-Proto {scheme}
  }

  root /

  log stdout
  errors stdout
  gzip
}

http://docker.for.mac.localhost/static {
  root /static
}

http://docker.for.mac.localhost/media {
  root /media
}

django settings.py

ALLOWED_HOSTS = [os.getenv("DJANGO_ALLOWED_HOSTS")]
    
CORS_ORIGIN_WHITELIST = [f'{os.getenv("DJANGO_ALLOWED_PROTOCOL")}://{os.getenv("DJANGO_ALLOWED_HOSTS")}']

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.postgresql_psycopg2",
        "NAME": os.getenv("POSTGRES_DB"),
        "USER": os.getenv("POSTGRES_USER"),
        "PASSWORD": os.getenv("POSTGRES_PASSWORD"),
        "HOST": "db",
        "PORT": "5432",
    }
}

nuxt.config.js(baseURL 变量将覆盖环境的 API_URL)

axios: {
  baseURL: 'http://127.0.0.1:8000/b/api'
},
于 2020-07-02T05:55:26.827 回答
2

CGroups 和命名空间在容器生态系统中扮演着重要角色。

命名空间提供了一层隔离。每个容器都在单独的命名空间中运行,并且它的访问权限仅限于该命名空间。Cgroups 控制每个容器的资源利用率,而 Namespace 控制进程可以看到和访问相应资源的内容。

这是您可以遵循的解决方案的基本理解,

使用网络命名空间

当容器从镜像中生成时,会定义并创建一个网络接口。这为容器提供了唯一的 IP 地址和接口。

$ docker run -it alpine ifconfig

通过将命名空间更改为主机,容器网络不会与其接口保持隔离,进程将可以访问主机网络接口。

$ docker run -it --net=host alpine ifconfig

如果进程侦听端口,它们将在主机接口上被侦听并映射到容器。

使用 PID 命名空间 通过更改 Pid 命名空间,容器可以与超出其正常范围的其他进程进行交互。

此容器将在其自己的命名空间中运行。

$ docker run -it alpine ps aux

通过将命名空间更改为主机,容器还可以看到系统上运行的所有其他进程。

$ docker run -it --pid=host alpine ps aux

共享命名空间

在生产环境中这样做是一种不好的做法,因为您打破了容器安全模型,这可能会导致漏洞,并且容易访问窃听者。这只是为了调试工具和低估容器安全的漏洞。

第一个容器是 nginx 服务器。这将创建一个新的网络和进程命名空间。这个容器将自己绑定到新创建的网络接口的 80 端口。

$ docker run -d --name http nginx:alpine

另一个容器现在可以重用这个命名空间,

$ docker run --net=container:http mohan08p/curl curl -s localhost

此外,此容器可以看到与共享容器中的进程的接口。

$ docker run --pid=container:http alpine ps aux

这将允许您在不更改或重新启动应用程序的情况下为容器提供更多权限。以类似的方式,您可以连接到主机上的 mysql,运行和调试您的应用程序。但是,不建议走这条路。希望能帮助到你。

于 2017-09-06T12:05:22.750 回答
1

直到修复未合并到master分支中,才能从容器内部运行主机 IP:

ip -4 route list match 0/0 | cut -d' ' -f3

(正如@Mahoney 在这里所建议的那样)。

于 2019-03-22T14:10:42.210 回答
1

尽管有很多长而令人困惑的答案,但答案很短。如果您的 docker bridge 网络是 172.17.0.0/16,请执行以下操作:

  1. 将您的容器绑定到 172.17.0.1 例如。-p 172.17.0.1:8080:8080 (无论你的 Docker 桥接网络中的网关是什么)
  2. 只需访问 172.17.0.1 端口 8080 例如。curl http://172.17.0.1:8080/来自其他容器
于 2021-05-25T19:00:14.943 回答
1

主机上的服务器正在侦听端口 5000;它将response from host返回一个字符串作为响应

echo "response from host" | nc -l -p 5000

docker 默认以桥接模式运行(这比在主机网络模式下运行更安全);docker 中的进程获取主机上不是 127.0.0.1 的第一个网络接口的 ipv4 地址;这个 ipv4 地址通过环境变量 HOSTIP 传递给 docker;在 docker 里面有一个 nc 命令连接到主机 ip 和端口 5000 上的服务器;该命令还读取服务器的响应。

HOST=$(ifconfig | grep 'inet ' | grep -v 127.0.0.1 | awk '{ print $2 }' | head -1 | sed -n 's/[^0-9]*\([0-9\.]*\)/\1/p'); docker run -e HOSTIP="${HOST}" --rm -it alpine /bin/sh -c 'echo "greetings from container" | nc $HOSTIP 5000 -v'

计算第一个列出的接口的 ipv4 地址的表达式在 osx 和 linux 上有效:

HOST=$(ifconfig | grep 'inet ' | grep -v 127.0.0.1 | awk '{ print $2 }' | head -1 | sed -n 's/[^0-9]*\([0-9\.]*\)/\1/p')

使其更加通用:您可以在另一个 docker 容器中运行服务器,如下所示:

docker run --expose 5000 -p :5000:5000 --rm -it alpine /bin/sh -c 'echo "response from host" | nc -l -p 5000'

--expose 5000 docker 容器可以接受端口 5000 上的连接

-p :5000:5000 主机端的 docker 引擎正在侦听任何接口上的端口 5000,并将连接转发到容器网络上的端口 5000(运行 nc)。

于 2021-03-23T10:19:02.667 回答
1

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

看到这个 - https://stackoverflow.com/a/48547074/14120621

于 2022-02-04T12:03:02.420 回答
0

对于 Windows 机器:-

在构建期间运行以下命令以随机公开 docker 端口

$docker run -d --name MyWebServer -P mediawiki

在此处输入图像描述

在此处输入图像描述

在上面的容器列表中,您可以看到分配为 32768 的端口。尝试访问

localhost:32768 

您可以查看 mediawiki 页面

于 2018-09-17T15:18:21.630 回答
0

如果你使用 docker-compose,也许它可以工作:

iptables -I INPUT ! -i eth0 -p tcp --dport 8001 -j ACCEPT

eth0是您连接互联网的网络接口,以及8081主机服务器端口

iptables 规则的最佳方式是 iptables TRACE

于 2020-07-15T01:25:21.283 回答
0

我这样做的方式是将主机 IP 作为环境变量传递给容器。容器然后通过该变量访问主机。

于 2020-02-06T04:00:30.543 回答