From inside of a Docker container, how do I connect to the localhost of the machine?
所以我有一个nginx在docker容器中运行,我有一个mysql在localhost上运行,我想从nginx中连接到mysql。MySQL运行在本地主机上,不会向外部世界公开端口,因此它绑定在本地主机上,而不是绑定在计算机的IP地址上。
有没有办法从这个docker容器中连接到这个mysql或者本地主机上的其他程序?
编辑:如果您使用Docker for Mac或Docker for Windows 18.03+,只需使用主机
从Docker 18.09.3开始,这在Linux的Docker上不起作用。已于2019年3月8日提交了修复程序,有望合并到代码库中。在此之前,解决方法是使用Qoomon答案中描述的容器。
TLDR在您的
注意:根据文档,此模式仅适用于Linux的Docker。
Docker容器联网模式说明Docker在运行容器时提供不同的网络模式。根据您选择的模式,您将以不同的方式连接到运行在Docker主机上的MySQL数据库。
docker run--network="bridge"(默认)默认情况下,Docker创建一个名为
在Docker主机上,键入
1 2 3 4 5 6 7 | [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主机在
现在,启动一个新的容器并在其上获得一个shell:
1 2 3 4 5 6 7 | 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地址
1 2 3 4 5 | 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主机
1 2 3 4 5 | 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 |
docker run--network="主机"
或者,可以运行网络设置设置为
请注意,在Docker容器中打开的任何端口都将在Docker主机上打开。这不需要
我的Docker主机上的IP配置:
1 2 3 4 5 6 7 | [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容器:
1 2 3 4 5 6 7 | [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服务正在侦听
为此,请确保在mysql配置文件(my.cnf)中有
如果需要使用网关的IP地址设置环境变量,可以在容器中运行以下代码:
1 | export DOCKER_HOST_IP=$(route -n | awk '/UG[ \t]/{print $2}') |
然后在应用程序中,使用
注意:如果您使用
注2:如果使用
要从主机模式下的容器访问docker主机上运行的mysql,可以在mysql配置中保留
1 2 3 4 5 6 7 8 9 10 11 12 13 | [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> |
注意:不要使用
对于MacOS和Windows
Docker V 18.03及以上(自2018年3月21日起)
使用内部IP地址或连接到特定的DNS名称
Linux支持挂起https://github.com/docker/for-linux/issues/264
带有早期版本Docker的MacOSMac V 17.12至V 18.02的Docker
同上,但使用
Mac V 17.06至V 17.11的Docker
同上,但使用
Mac 17.05及以下的Docker
要从Docker容器访问主机,必须在网络接口上附加一个IP别名。你可以绑定任何你想要的IP,只需确保你没有把它用于任何其他东西。
然后确保您的服务器正在监听上面提到的IP或
然后把你的Docker容器指向这个IP,你就可以访问主机了!
为了测试,您可以在容器中运行类似于
每次重新启动时,别名都会重置,因此如果需要,请创建一个启动脚本。
这里的解决方案和更多文档:https://docs.docker.com/docker for mac/networking/用例和解决方案
我做了一个类似于上面文章的黑客,让本地IP映射到容器中的别名(DNS)。主要的问题是动态获取一个简单的脚本,该脚本在Linux和OSX(主机IP地址)中都可以工作。我编写的这个脚本在两种环境中都可以使用(即使在配置了
1 | 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):
1 2 | 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 |
docker-compose.yml:
1 2 3 4 5 6 | myapp: build: . ports: -"80:80" extra_hosts: -"dockerhost:$DOCKERHOST" |
然后将代码中的
有关如何自定义
这在nginx/php-fpm堆栈上对我很有效,不需要接触任何代码或网络,因为应用程序只希望能够连接到
将
在运行mysql的主机上查找mysql.sock文件的位置:
将该文件安装到Docker中预期的位置:
mysqld.sock的可能位置:
1 2 3 4 | /tmp/mysqld.sock /var/run/mysqld/mysqld.sock /var/lib/mysql/mysql.sock /Applications/MAMP/tmp/mysql/mysql.sock # if running via MAMP |
Windows 10解决方案
Docker社区版17.06.0-ce-win18 2017-06-28(稳定)
您可以使用主机
概览
我需要做一些类似的事情,即从Docker容器连接到本地主机,该主机运行
默认情况下,
这也适用于从Docker容器连接到
Linux解决方案(内核>=3.6)。
好的,本地主机服务器有默认的Docker接口Docker0,IP地址为172.17.0.1。容器从默认网络设置开始--net="bridge"。
从内核文档中:
route_localnet - BOOLEAN: Do not consider loopback addresses as martian source or destination while routing. This enables the use of 127/8 for local routing purposes (default FALSE).
对于Windows上的那些,假设您使用的是网桥网络驱动程序,那么您需要将MySQL具体绑定到Hyper-V网络接口的IP地址。
这是通过通常隐藏的c:programdatamysql文件夹下的配置文件完成的。
绑定到0.0.0.0将不起作用。所需的地址也显示在Docker配置中,在我的例子中是10.0.75.1。
在host.docker.internal为每个平台工作之前,您可以使用我的容器作为NAT网关,而无需任何手动设置https://github.com/qoomon/docker-host
编辑:我最终在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 settings
其次,对于那些使用Linux的用户(我的直接经验是在Ubuntu 14.04 LTS上,我很快就要升级到16.04 LTS的生产环境中),可以让在Docker容器内运行的服务连接到Docker主机上运行的
怎么用?
关键是当您运行Docker容器时,必须以主机模式运行它。命令如下:
当您在容器中执行
重要的是要注意,我是一个Mac用户,但我在Parallels下运行Ubuntu,所以使用Mac并不是一个缺点。;-)
这就是如何将nginx容器连接到运行在
Mac OSX的最简单解决方案
只需使用你的Mac的IP地址。在Mac上运行此命令以获取IP地址并从容器中使用它:
1 | $ ifconfig | grep 'inet 192'| awk '{ print $2}' |
只要在Mac或其他Docker容器中本地运行的服务器正在监听0.0.0.0,Docker容器就可以在该地址进行访问。
如果您只想访问另一个正在监听0.0.0.0的Docker容器,可以使用172.17.0.1
这是我的解决方案:它适用于我的案件
通过注释将本地MySQL服务器设置为公共访问
在/etc/mysql/mysql.conf.d中
#bind-address = 127.0.0.1
重新启动MySQL服务器
sudo /etc/init.d/mysql restart 运行以下命令以打开用户根目录访问任何主机
mysql -uroot -proot
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH
GRANT OPTION;
FLUSH PRIVILEGES;
创建sh脚本:rundocker.sh
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #!bin/bash HOSTIP=`ip -4 addr show scope global dev eth0 | grep inet | awk '{print \$2}' | cut -d / -f 1` docker run -it -d --name web-app \ --add-host=local:${HOSTIP} \ -p 8080:8080 \ -e DATABASE_HOST=${HOSTIP} \ -e DATABASE_PORT=3306 \ -e DATABASE_NAME=demo \ -e DATABASE_USER=root \ -e DATABASE_PASSWORD=root \ sopheamak/springboot_docker_mysql |
与Docker Composer一起运行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25version: '2.1'
</p>
<p>
services:
tomcatwar:
extra_hosts:
-"local:10.1.2.232"
image: sopheamak/springboot_docker_mysql
ports:
- 8080:8080
environment:
- DATABASE_HOST=local
- DATABASE_USER=root
- DATABASE_PASSWORD=root
- DATABASE_NAME=demo
- DATABASE_PORT=3306
</p>
</li>
</ul>
<p>您可以使用Alpine映像获取主机IP
1docker run --rm alpine ip route | awk 'NR==1 {print $3}'这将更加一致,因为您总是使用阿尔卑斯山来运行命令。
与Mariano的答案类似,您可以使用相同的命令来设置环境变量
1DOCKER_HOST=$(docker run --rm alpine ip route | awk 'NR==1 {print $3}') docker-compose up我不同意托马斯列维尔的回答。
将mysql绑定到172.17.42.1将阻止其他程序使用主机上的数据库访问它。只有当您的所有数据库用户都是Dockerized时,这才有效。
将MySQL绑定到0.0.0.0将使数据库向外部世界开放,这不仅是一件非常糟糕的事情,而且与原始问题的作者想要做的相反。他明确表示,"MySQL运行在本地主机上,不向外部世界公开端口,因此它绑定在本地主机上。"
回答伊万特的评论
"Why not bind mysql to docker0 as well?"
这是不可能的。mysql/mariadb文档明确表示不可能绑定到多个接口。只能绑定到0、1或所有接口。
最后,我还没有找到任何方法从Docker容器访问主机上的(仅限本地主机)数据库。这似乎是一个非常常见的模式,但我不知道该怎么做。
CGroups和名称空间在容器生态系统中发挥着重要作用。
命名空间提供了一个隔离层。每个容器在单独的命名空间中运行,其访问权限仅限于该命名空间。cgroups控制每个容器的资源利用率,而namespace控制进程可以看到和访问各自资源的内容。
下面是您可以遵循的解决方案方法的基本理解,
使用网络命名空间
当容器从图像中生成时,定义并创建网络接口。这将为容器提供唯一的IP地址和接口。
1$ docker run -it alpine ifconfig通过将命名空间更改为主机,cotainers网络不会保持与其接口的隔离,进程将可以访问主机网络接口。
1$ docker run -it --net=host alpine ifconfig如果进程在端口上侦听,那么它们将在主机接口上侦听并映射到容器。
使用PID命名空间通过更改pid名称空间,容器可以与超出其正常范围的其他进程进行交互。
此容器将在其自己的命名空间中运行。
1$ docker run -it alpine ps aux通过将命名空间更改为主机,容器还可以看到系统上运行的所有其他进程。
1$ docker run -it --pid=host alpine ps aux共享命名空间
在生产中这样做是一个糟糕的做法,因为您打破了容器安全模型,这可能会打开漏洞,并容易访问窃听器。这只是为了调试工具和了解容器安全中的漏洞。
第一个容器是nginx服务器。这将创建一个新的网络和进程命名空间。此容器将自身绑定到新创建的网络接口的端口80。
1$ docker run -d --name http nginx:alpine另一个容器现在可以重用此命名空间,
1$ docker run --net=container:http mohan08p/curl curl -s localhost此外,此容器还可以看到与共享容器中进程的接口。
1$ docker run --pid=container:http alpine ps aux这将允许您在不更改或重新启动应用程序的情况下授予容器更多权限。以类似的方式,您可以在主机上连接到MySQL,运行和调试您的应用程序。但是,不建议这样做。希望它有帮助。
对于Windows计算机:
运行以下命令在构建期间随机公开Docker端口
1$docker run -d --name MyWebServer -P mediawiki在上面的容器列表中,您可以看到分配为32768的端口。尝试访问
1localhost:32768您可以看到Mediawiki页面
在Windows10 Home上使用Docker工具箱时,没有一个答案对我有效,但10.0.2.2确实有效,因为它使用的是将主机暴露给这个地址上的虚拟机的virtualbox。
非常简单和快速,使用ifconfig(Linux)或ipconfig(Windows)检查主机IP,然后创建一个
docker-compose.yml公司
1
2
3
4
5
6
7
8
9version: '3' # specify docker-compose version
services:
nginx:
build: ./ # specify the directory of the Dockerfile
ports:
-"8080:80" # specify port mapping
extra_hosts:
-"dockerhost:<yourIP>"这样,容器就可以访问主机。访问数据库时,请记住使用前面指定的名称,在本例中是"dockerhost",以及运行数据库的主机的端口。
直到fix未合并到
master 分支中,才能从容器内部运行主机IP:1ip -4 route list match 0/0 | cut -d' ' -f3(如@mahoney建议)。
您可以使用ngrok创建一个到本地主机的安全隧道,然后将该隧道暴露到Docker容器中。
截至2017年5月22日,NGROK可免费使用。
步骤:
1)去NGROK
2)下载ngrok客户端,按照安装说明操作
3)注册一个帐户,他们将提供一个身份验证令牌。注册是必需的,因为ngrok只在注册后提供TCP端口隧道。注册不需要成本或信用卡。
4)在您的终端上执行
ngrok tcp 3306 。3306 是MySQL在本地运行的端口,您也可以使用其他任何端口。5)您将收到来自步骤
4 的地址,如:tcp://0.tcp.ngrok.io:10117 。这是到本地计算机的隧道连接。0.tcp.ngrok.io 映射到您的localhost ,10117 端口映射到您的本地端口3306 。现在,您可以从任何使用此地址的地方访问本地主机端口3306,包括在此计算机上运行的任何Docker容器。在Docker容器(无论它在哪里)中,假设已经安装了MySQL客户机,请执行以下操作:mysql --host 0.tcp.ngrok.io --port 10117 -u root 您可以从Docker容器内部登录您本地机器的
root 帐户!我已经在博客中介绍了这个解决方案,请在这里查看更多详细信息