我在 docker 容器中运行了一个 Nginx,我在 localhost 上运行了一个 mysql,我想从我的 Nginx 中连接到 MySql。MySql 在 localhost 上运行并且没有向外界公开端口,因此它绑定在 localhost 上,而不是绑定在机器的 ip 地址上。
有没有办法从这个 docker 容器中连接到这个 MySql 或本地主机上的任何其他程序?
这个问题与“如何从 docker 容器内部获取 docker 主机的 IP 地址”不同,因为 docker 主机的 IP 地址可能是网络中的公共 IP 或私有 IP,这可能是也可能是无法从 docker 容器中访问(如果托管在 AWS 或其他地方,我的意思是公共 IP)。即使您拥有 docker 主机的 IP 地址,但这并不意味着您可以从容器内连接到 docker 主机,因为您的 Docker 网络的 IP 地址可能是覆盖、主机、网桥、macvlan、none 等,这限制了那个IP地址。
如果您使用的是Docker-for-mac或Docker-for-Windows 18.03+,只需使用主机host.docker.internal(而不是127.0.0.1连接字符串中的)连接到您的 mysql 服务。
host.docker.internal
127.0.0.1
如果您使用的是 Docker-for-Linux 20.10.0+,host.docker.internal 如果--add-host host.docker.internal:host-gateway您使用该选项启动 Docker 容器,您也可以使用主机。
--add-host host.docker.internal:host-gateway
否则,请阅读下文
--network="host"在您的命令中使用docker run,然后127.0.0.1在您的 docker 容器中将指向您的 docker 主机。
--network="host"
docker run
注意:根据文档,此模式仅适用于 Docker for Linux 。
Docker在运行容器时提供了不同的网络模式。根据您选择的模式,您将连接到在 docker 主机上运行的 MySQL 数据库。
Docker 创建一个docker0默认命名的网桥。docker 主机和 docker 容器在该网桥上都有一个 IP 地址。
docker0
在 Docker 主机上,键入sudo ip addr show docker0您将看到如下输出:
sudo ip addr show docker0
[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 主机172.17.42.1在docker0网络接口上有 IP 地址。
172.17.42.1
现在启动一个新容器并在其上获取一个 shell:docker run --rm -it ubuntu:trusty bash并在容器类型ip addr show eth0中发现它的主网络接口是如何设置的:
docker run --rm -it ubuntu:trusty bash
ip addr show eth0
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 地址172.17.1.192。现在查看路由表:
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 主机的 IP 地址172.17.42.1被设置为默认路由,并且可以从您的容器中访问。
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
或者,您可以运行一个将网络设置设置为host. 这样的容器将与 docker 主机共享网络堆栈,从容器的角度来看,localhost(或127.0.0.1)将引用 docker 主机。
host
localhost
请注意,在您的 docker 容器中打开的任何端口都将在 docker 主机上打开。这不需要-por-P docker run选项。
-p
-P
我的 docker 主机上的 IP 配置:
[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 容器中:
[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 地址。
要以桥接模式从容器访问 docker 主机上运行的 MySQL ,您需要确保 MySQL 服务正在侦听172.17.42.1IP 地址上的连接。
为此,请确保您的 MySQL 配置文件 (my.cnf) 中有一个bind-address = 172.17.42.1或其中一个。bind-address = 0.0.0.0
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 的连接。
DOCKER_HOST_IP
注意:如果您使用bind-address = 0.0.0.0MySQL 服务器将侦听所有网络接口上的连接。这意味着可以从 Internet 访问您的 MySQL 服务器;确保相应地设置防火墙规则。
注意 2:如果您使用bind-address = 172.17.42.1MySQL 服务器,则不会侦听与127.0.0.1. 在 docker 主机上运行的想要连接到 MySQL 的进程必须使用172.17.42.1IP 地址。
要从主机模式下的容器访问在 docker 主机上运行的 MySQL ,您可以保留bind-address = 127.0.0.1MySQL 配置,您需要做的就是127.0.0.1从容器连接到:
bind-address = 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 套接字进行连接。
mysql -h 127.0.0.1
mysql -h localhost