我有一个Nginx在码头集装箱里运行。我在主机系统上运行了MySql。我想从我的容器中连接到MySql。MySql仅绑定到本地主机设备。

是否有任何方法可以从这个docker容器连接到这个MySql或本地主机上的任何其他程序?

这个问题与“如何从docker容器中获取docker主机的IP地址”不同,因为docker主机IP地址可以是网络中的公共IP或私有IP,而这些IP可能在docker容器内无法访问(如果托管在AWS或其他地方,我指的是公共IP)。即使你有docker主机的IP地址,这并不意味着你可以从容器内连接到docker主机,因为你的docker网络可能是overlay、host、bridge、macvlan、none等,这限制了该IP地址的可达性。


当前回答

这在NGINX/PHP-FPM堆栈上对我有效,而无需接触任何代码或网络,应用程序只是希望能够连接到本地主机

将mysqld.sock从主机装载到容器内部。

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

将该文件装载到docker中预期的位置:docker运行-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

其他回答

编辑:我最终在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-设置

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

How?

关键是当你运行Docker容器时,你必须以主机模式运行它。命令如下所示:

docker run--network=“host”-id<docker image id>

当你在容器中执行ifconfig(你需要apt-get-install-net-tools你的容器才能调用ifconfig)时,你会看到网络接口与Docker主机上的相同(例如你的笔记本电脑)。

需要注意的是,我是Mac用户,但我在Parallels下运行Ubuntu,所以使用Mac不是缺点

这就是将NGINX容器连接到本地主机上运行的MySQL的方法。

我们想到了几种解决方案:

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

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

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

选项2:有多种方法可以从容器内部检测主机IP地址,但每个方法都有有限的工作场景(例如需要Docker for Mac)。最可移植的选项是将您的主机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 ...

主机网关是Docker 20.10中添加的一个特殊值,它会自动扩展到主机IP。有关详细信息,请参阅本请购单。

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

选项4:各种服务也允许通过基于文件系统的套接字进行访问。此套接字可以作为绑定装载卷装载到容器中,允许您在不通过网络的情况下访问主机服务。为了访问docker引擎,您经常会看到将/var/run/docker.sock装载到容器中的示例(为该容器提供对主机的根访问权限)。对于mysql,您可以尝试类似于-v/var/run/mysqld/mysqld.sock:/varrun/mysqld/mysql.sock的方式,然后连接到localhost,mysql使用套接字将其转换为localhost。

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

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

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

为docker0接口启用route_localnet:$sysctl-w net.ipv4.conf.docker0.route_localnet=1将这些规则添加到iptables:$iptables-t nat-I预路由-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创建具有从“%”访问权限的MySQL用户,这意味着-来自任何人,不包括本地主机:CREATE USER“USER”@“%”IDENTIFIED BY“password”;在脚本中将mysql服务器地址更改为172.17.0.1。

从内核文档中:

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

Windows 10解决方案

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

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

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

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

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