问:

所以我在 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地址。

答1:

huntsbot.com高效搞钱,一站式跟进超10+任务平台外包需求

编辑:

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

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

否则,请阅读下文

TLDR

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

注意:此模式仅适用于 Docker for Linux,per the documentation。

docker 容器网络模式注意事项

Docker 在运行容器时提供 different networking modes。根据您选择的模式,您将连接到在 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:  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:  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 主机 172.17.42.1 的 IP 地址被设置为默认路由,并且可以从您的容器中访问。

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 =“主机”

或者,您可以使用 network settings set to host 运行 docker 容器。这样的容器将与 docker 主机共享网络堆栈,从容器的角度来看,localhost(或 127.0.0.1)将引用 docker 主机。

请注意,在您的 docker 容器中打开的任何端口都将在 docker 主机上打开。这不需要 -p or -P docker run option。

我的 docker 主机上的 IP 配置:

[vagrant@docker:~] $ ip addr show eth0
2: eth0:  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:  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.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.0,您的 MySQL 服务器将侦听所有网络接口上的连接。这意味着可以从 Internet 访问您的 MySQL 服务器;确保相应地设置防火墙规则。

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

主机模式

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

谢谢你这么详细的回答!根据我收集到的信息,使用主机模式是通过 localhost 获得此功能的唯一方法。我还没有尝试过,但我假设您可以创建一个单独的网络来通过它们自己的网桥连接容器,为它们提供一个通用的“本地主机”。

OSX 用户注意事项:首先使用“docker-machine ssh default”登录到您的 docker 虚拟机(boot2docker),然后运行“sudo ip addr show docker0”。从那里继续托马斯的指示。

我正在为 Mac 运行 Docker,不再有 172.17.42.1,也没有 docker0。它是 172.17.0.1 作为网关,甚至不能telnet 172.17.0.1 3306

您可以将 mysql 套接字挂载到容器中,而不是像 -v /var/run/mysqld/mysqld.sock:/tmp/mysql.sock 这样的网络。

当您在 Mac 上运行 Docker 而没有使用 boot2docker 时,有人可以解决这种情况,因为没有 docker0 接口?

答2:

huntsbot.com聚合了超过10+全球外包任务平台的外包需求,寻找外包任务与机会变的简单与高效。

适用于所有平台

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

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

在 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 地址或连接到将解析为主机使用的内部 IP 地址的特殊 DNS 名称 host.docker.internal。

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

docker.for.mac.localhost 正是我想要的。但这同时也是肮脏的。在 docker 中,人们会期望钩子 docker.for.mac.localhost 是一个通用的 docker 内部名称,它适用于任何操作系统,而不仅仅是 Mac。但出于开发目的,这已经足够了。

应该使用 DNS 名称 docker.for.mac.host.internal 而不是 docker.for.mac.localhost(仍然有效)从容器解析主机,因为有一个 RFC 禁止使用 localhost 的子域。请参阅tools.ietf.org/html/draft-west-let-localhost-be-localhost-06。

这对我不起作用。当我 docker run -e HOSTNAME= docker.for.mac.host.internal 时,容器已创建,但没有发生任何事情。我必须然后crtl + C。至少使用 --net=host -e HOSTNAME=localhost 容器运行并抱怨它找不到我需要的服务(MySQL db)。

如此快速和有用。谢谢!

答3:

huntsbot.com高效搞钱,一站式跟进超10+任务平台外包需求

使用

host.docker.internal

代替

localhost

对我来说完美无缺。 👍

也许这个答案可以扩展和澄清一点?这是否意味着您仍然可以使用桥接模式?

@ArnoldRoa 这仅适用于 Mac/Windows 而不是 Linux

自 2021 年 4 月 26 日起无效。 host.docker.internal 解析为空。

如需使用 docker-compose 设置 host.docker.internal,请参阅 stackoverflow.com/a/67158212/243392

谢谢@DeyaEldeen,这非常适合mac

答4:

保持自己快人一步,享受全网独家提供的一站式外包任务、远程工作、创意产品订阅服务–huntsbot.com

我做了一个类似于上述帖子的破解,获取本地 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 脚本的更高级指南,请查看 this post 并解释其工作原理。

根据您的用例,您甚至可以在 docker 容器需要本地连接的任何服务中使用 DOCKERHOST 值而不是“localhost”或 0.0.0.0。

我稍微修改了您的解决方案以与自定义网络兼容:export DOCKERHOST=$(docker network inspect --format='{{range .IPAM.Config}}{{.Gateway}}{{end}}' | awk -F "/" 'NR==1{print $1}') 其中 可以是 bridge 或 docker 定义的网络名称-compose(通常是 path-name-network_name)。

您需要添加注释:使用 dockerhost 作为 db 连接的主机(通常替换配置文件中的 localhost)。

奇怪的解决方案,但它是唯一使 xdebug 在 docker 下使用 php cli 工作的解决方案

在 haproxy 中此解决方案后,Acl 停止工作。知道为什么吗?

答5:

保持自己快人一步,享受全网独家提供的一站式外包任务、远程工作、创意产品订阅服务–huntsbot.com

这在 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

这是一个更清洁的解决方案,不会将 Mysql 暴露在外部(如果不使用防火墙)。

套接字的伸缩性不如 TCP,因为它们阻塞的频率更高,并且可能导致奇怪的行为。尽可能使用 TCP。

@JoelESalas 你有这个说法的来源吗?

我发现这是最简单的解决方案。竖起大拇指用户833482!您应该更频繁地为 StackOverflow 做出贡献。

@JoelESalas 我认为你错了。 mysql 客户端库在连接到 localhost 时甚至默认使用 unix 套接字,而不是实际连接到 localhost。 unix 套接字避免了 TCP 堆栈和路由的开销,并且应该运行得更快。

答6:

一个优秀的自由职业者,应该有对需求敏感和精准需求捕获的能力,而huntsbot.com提供了这个机会

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

好的,您的 localhost 服务器有一个 IP 地址为 172.17.0.1 的默认 docker 接口 docker0。您的容器以默认网络设置 --net=“bridge” 启动。

为 docker0 接口启用 route_localnet: $ sysctl -w net.ipv4.conf.docker0.route_localnet=1 将这些规则添加到 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 Create MySQL user with access from ‘%’ 这意味着 - 从任何人,不包括 localhost:CREATE USER ‘user’@‘%’ IDENTIFIED BY ‘password’;在脚本中将 mysql-server 地址更改为 172.17.0.1。

从 kernel documentation:

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

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

这件事情让我感到很快乐!感谢你的分享

最后。我努力寻找正确的 IP 地址。我不知道 docker 有默认界面。

奇怪的是,这对我来说并不稳定,至少在最新的 CentOS 7 上运行内核 3.10 和 Docker 19.03.15。它最初工作,然后在一段时间后停止工作。

答7:

HuntsBot周刊–不定时分享成功产品案例,学习他们如何成功建立自己的副业–huntsbot.com

在 host.docker.internal 适用于所有平台之前,您可以将我的容器用作 NAT 网关,而无需任何手动设置:

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

我可以确认这在带有 Windows 容器的 Windows 19.03.2 的 Docker 中不起作用。

知道如何解决吗? (我不是windows用户)

如果您的环境不阻止 mysql 使用的端口,则可以通过托管的计算机名称来引用服务器。因此,在您的连接字符串中,使用您的计算机名称作为服务器名称。

我可以确认这不适用于 Docker for Windows v. 20.10.5。真让人生气。主机(来自容器)的 IP 随机变化。当主机 IP 在运行时更改并且 host.docker.internal 解析为空时,我到底应该如何部署连接字符串?

@Triynko 你可以运行以下命令并告诉我这些命令是否成功? docker run --rm alpine ping host.docker.internal docker run --rm alpine ping docker.for.win.localhost docker run --rm alpine ping gateway.docker.internal

答8:

huntsbot.com洞察每一个产品背后的需求与收益,从而捕获灵感

非常简单快捷,使用 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:"

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

在 HaProxy 中,此解决方案由于某种原因停止了 acl 的工作,只有默认设置有效。

答9:

huntsbot.com洞察每一个产品背后的需求与收益,从而捕获灵感

适用于 Mac OSX 的最简单解决方案

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

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

只要在您的 Mac 或另一个 docker 容器中本地运行的服务器正在侦听 0.0.0.0,docker 容器就能够访问该地址。

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

Docker for Mac 现在公开 docker.for.mac.host.internal 主机名。

host.docker.internal 在 Mac 上可用。更多信息:docs.docker.com/desktop/networking/…

答10:

huntsbot.com全球7大洲远程工作机会,探索不一样的工作方式

适用于 Windows 10 的解决方案

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

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

概述我需要做类似的事情,即从我的 Docker 容器连接到运行 Azure Storage Emulator 和 CosmosDB Emulator 的本地主机。

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

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

答11:

huntsbot.com汇聚了国内外优秀的初创产品创意,可按收入、分类等筛选,希望这些产品与实践经验能给您带来灵感。

想到了几个解决方案:

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

这不能开箱即用的原因是容器默认使用自己的网络命名空间运行。这意味着 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 地址的其他方法,see this post。

使用 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。有关详细信息,请参阅 this PR。

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

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

对于选项 2(所有答案中唯一有效的方法):以下命令获取 osx 和 linux 上除本地主机以外的接口的 IP 地址:ifconfig | grep 'inet ' | grep -v 127.0.0.1 | awk '{ print $2 }' | head -1 | sed -n 's/[^0-9]*\([0-9\.]*\)/\1/p'

--add-host host.docker.internal:host-gateway 是金色的

原文链接:https://www.huntsbot.com/qa/Pd34/from-inside-of-a-docker-container-how-do-i-connect-to-the-localhost-of-the-mach?lang=zh_CN&from=csdn

huntsbot.com – 程序员副业首选,一站式外包任务、远程工作、创意产品分享订阅平台。

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐