我有一个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地址的可达性。


当前回答

我通过在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

其他回答

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

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

将容器绑定到172.17.0.1,例如-p 172.17.0.1:8080:8080(Docker网桥网络中的网关)只需访问172.17.0.1端口8080,例如curlhttp://172.17.0.1:8080/来自其他容器

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

首先将依赖项移动到容器中使您的其他服务可从外部访问,并通过该外部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。

在7年的时间里,人们提出了一个问题,要么码头工人变了,要么没有人这样做。因此,我将包括我自己的答案。

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

在主机上使用ipconfig或ifconfig,并记下所有IP地址。容器至少可以使用其中两个。我在WiFi LAN适配器上有一个固定的本地网络地址:192.168.1.101。这可能是10.0.101。结果会因路由器而异我在windows上使用WSL,它有自己的vEthernet地址:172.19.192.1使用host.docker.internal。根据操作系统的不同,大多数答案都有这种或另一种形式。这个名字表明它现在被docker全球使用。

第三种选择是使用计算机的WAN地址,或者换句话说,使用服务提供商提供的IP地址。然而,如果IP不是静态的,并且需要路由和防火墙设置,则这可能不起作用。

在修复程序未合并到主分支之前,只需从容器内部运行主机IP即可:

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

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