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


当前回答

CGroups和Namespaces在容器生态系统中发挥着重要作用。

命名空间提供了一层隔离。每个容器都在一个单独的命名空间中运行,其访问权限仅限于该命名空间。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,运行并调试应用程序。但是,不建议这样做。希望有帮助。

其他回答

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

我不同意托马斯列维尔的回答。

将mysql绑定到172.17.42.1将阻止其他程序使用主机上的数据库来访问它。只有在所有数据库用户都已固定的情况下,这才有效。

将mysql绑定到0.0.0.0将向外部世界打开数据库,这不仅是一件非常糟糕的事情,而且与最初的问题作者想要做的相反

回答ivant的评论

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

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

因此,我还没有找到从docker容器访问主机上(仅限于本地主机)数据库的任何方法。这显然是一种非常常见的模式,但我不知道怎么做。

不幸的是,目前Windows(至少是docker桌面)不支持--net=host

引用自:https://docs.docker.com/network/network-tutorial-host/#prerequisites

主机网络驱动程序仅在Linux主机上运行,在Docker for Mac、Docker for Windows或Docker EE for Windows Server上不受支持。

您可以尝试使用https://docs.docker.com/toolbox/

主机上的服务器正在监听端口5000;它将从主机发回一个字符串响应作为响应

echo“主机响应”|nc-l-p 5000

docker默认在网桥模式下运行(这比在主机网络模式下运行更安全);docker中的进程获取主机上第一个网络接口的ipv4地址,该地址不是127.0.0.1;这个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“来自容器的问候语”|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“来自主机的响应”|nc-l-p 5000'

--暴露5000码头集装箱可以接受端口5000上的连接

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

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

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