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

新手上路,请多包涵

所以我在 docker 容器中运行了一个 Nginx,我在主机系统上运行了一个 mysql,我想从我的容器中连接到 MySql。 MySql 仅绑定到 localhost 设备。

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

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

原文由 Phil 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.9k
2 个回答

编辑:

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

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

否则,请阅读下文


TLDR

在您的 docker run 命令中使用 --network="host" ,然后在您的 127.0.0.1 容器中使用 --- 将指向您的 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主机在 docker0 网络接口上有IP地址 172.17.42.1

现在启动一个新容器并在其上安装一个 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 容器。这样的容器将与 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

并从 主机 模式下的 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.1 IP 地址上的连接。

为此,请确保您的 MySQL 配置文件 (my.cnf) 中有 bind-address = 172.17.42.1bind-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.0 您的 MySQL 服务器将侦听所有网络接口上的连接。这意味着可以从 Internet 访问您的 MySQL 服务器;确保相应地设置防火墙规则。

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

主机模式

要从 主机模式下 的容器访问在 docker 主机上运行的 MySQL,您可以在 MySQL 配置中保留 bind-address = 127.0.0.1 ,您需要做的就是从您的容器连接到 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 套接字进行连接。

原文由 Thomasleveil 发布,翻译遵循 CC BY-SA 4.0 许可协议

适用于所有平台

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

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

在 Linux 上,使用 Docker 命令,将 --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 地址或连接到特殊的 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

原文由 Janne Annala 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进