从 Docker 容器内部,如何连接到机器的本地主机? [英] From inside of a Docker container, how do I connect to the localhost of the machine?

查看:41
本文介绍了从 Docker 容器内部,如何连接到机器的本地主机?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我在 docker 容器中运行了一个 Nginx,我在本地主机上运行了一个 mysql,我想从我的 Nginx 中连接到 MySql.MySql运行在localhost上,没有对外暴露端口,所以它绑定在localhost上,而不是绑定在机器的ip地址上.

有没有办法从这个 docker 容器内连接到这个 MySql 或本地主机上的任何其他程序?

此问题与如何从 docker 容器内部获取 docker 主机的 IP 地址"不同,因为 docker 主机的 IP 地址可以是网络中的公共 IP 或私有 IP可能会或可能无法从 docker 容器内访问(我的意思是公共 IP,如果托管在 AWS 或其他地方).即使您拥有 docker 主机的 IP 地址,也并不意味着您可以从容器内连接到 docker 主机,因为您的 Docker 网络可能是覆盖、主机、网桥、macvlan、none 等,这限制了可访问性那个 IP 地址.

解决方案

如果您使用 Docker-for-macDocker-for-Windows 18.03+,只需使用主机host.docker.internal(而不是127.0.0.1)连接到你的mysql服务 在您的连接字符串中).

如果您使用的是 Docker-for-Linux 20.10.0+,您还可以使用主机 host.docker.internal 如果您使用以下命令启动了 Docker 容器--add-host host.docker.internal:host-gateway 选项.

否则,请阅读下文


TLDR

在您的 docker run 命令中使用 --network=host",然后您的 docker 容器中的 127.0.0.1 将指向您的 Docker 主机.

注意:此模式仅适用于 Linux 的 Docker,根据文档.>


docker 容器网络模式注意事项

Docker 在运行容器时提供不同的网络模式.根据您选择的模式,您将以不同的方式连接到在 docker 主机上运行的 MySQL 数据库.

docker run --network="bridge"(默认)

Docker 默认创建一个名为 docker0 的网桥.docker 主机和 docker 容器在该网桥上都有一个 IP 地址.

在 Docker 主机上,输入 sudo ip addr show docker0 你将看到如下输出:

[vagrant@docker:~] $ sudo ip addr show docker04: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP>mtu 1500 qdisc noqueue state UP group default链接/以太 56:84:7a:fe:97:99 brd ff:ff:ff:ff:ff:ffinet 172.17.42.1/16 范围全局 docker0valid_lft 永远首选_lft 永远inet6 fe80::5484:7aff:fefe:9799/64 范围链接valid_lft 永远首选_lft 永远

所以这里我的 docker 主机在 docker0 网络接口上有 IP 地址 172.17.42.1.

现在启动一个新容器并在其上获取一个 shell:docker run --rm -it ubuntu:trusty bash 并在容器内键入 ip addr show eth0 到发现它的主要网络接口是如何设置的:

root@e77f6a1b3740:/# ip addr show eth0863:eth0:<BROADCAST,UP,LOWER_UP>mtu 1500 qdisc pfifo_fast 状态 UP 组默认 qlen 1000链接/以太 66:32:13:f0:f1:e3 brd ff:ff:ff:ff:ff:ffinet 172.17.1.192/16 范围全局 eth0valid_lft 永远首选_lft 永远inet6 fe80::6432:13ff:fef0:f1e3/64 范围链接valid_lft 永远首选_lft 永远

这里我的容器的 IP 地址为 172.17.1.192.现在看路由表:

root@e77f6a1b3740:/# route内核IP路由表目标网关 Genmask Flags Metric Ref Use Iface默认 172.17.42.1 0.0.0.0 UG 0 0 0 eth0172.17.0.0 * 255.255.0.0 U 0 0 0 eth0

因此 docker 主机的 IP 地址 172.17.42.1 被设置为默认路由,并且可以从您的容器访问.

root@e77f6a1b3740:/# ping 172.17.42.1PING 172.17.42.1 (172.17.42.1) 56(84) 字节数据.来自 172.17.42.1 的 64 个字节:icmp_seq=1 ttl=64 time=0.070 ms来自 172.17.42.1 的 64 个字节:icmp_seq=2 ttl=64 time=0.201 ms来自 172.17.42.1 的 64 字节:icmp_seq=3 ttl=64 time=0.116 ms

docker run --network="host"

或者,您可以使用 网络设置设置为 来运行 docker 容器主机.这样的容器将与 docker 主机共享网络堆栈,从容器的角度来看,localhost(或 127.0.0.1)将指代 docker 主机.>

请注意,在 docker 容器中打开的任何端口都将在 docker 主机上打开.这不需要 -p-P docker run option.

我的 docker 主机上的 IP 配置:

[vagrant@docker:~] $ ip addr show eth02: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP>mtu 1500 qdisc pfifo_fast 状态 UP 组默认 qlen 1000链接/以太 08:00:27:98:dc:aa brd ff:ff:ff:ff:ff:ffinet 10.0.2.15/24 brd 10.0.2.255 范围全局 eth0valid_lft 永远首选_lft 永远inet6 fe80::a00:27ff:fe98:dcaa/64 范围链接valid_lft 永远首选_lft 永远

并且来自 host 模式下的 docker 容器:

[vagrant@docker:~] $ docker run --rm -it --network=host ubuntu:trusty ip addr show eth02: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP>mtu 1500 qdisc pfifo_fast 状态 UP 组默认 qlen 1000链接/以太 08:00:27:98:dc:aa brd ff:ff:ff:ff:ff:ffinet 10.0.2.15/24 brd 10.0.2.255 范围全局 eth0valid_lft 永远首选_lft 永远inet6 fe80::a00:27ff:fe98:dcaa/64 范围链接valid_lft 永远首选_lft 永远

如您所见,docker 主机和 docker 容器共享完全相同的网络接口,因此具有相同的 IP 地址.


从容器连接到 MySQL

桥接模式

要以桥接模式从容器访问在 docker 主机上运行的 MySQL,您需要确保 MySQL 服务正在侦听 172.17.42.1 IP 地址上的连接.

为此,请确保您的 MySQL 配置文件 (my.cnf).

如果需要设置网关IP地址的环境变量,可以在容器中运行如下代码:

export DOCKER_HOST_IP=$(route -n | awk '/UG[ 	]/{print $2}')

然后在您的应用程序中,使用 DOCKER_HOST_IP 环境变量打开与 MySQL 的连接.

注意:如果您使用 bind-address = 0.0.0.0 您的 MySQL 服务器将侦听所有网络接口上的连接.这意味着可以从 Internet 访问您的 MySQL 服务器;确保相应地设置防火墙规则.

注意 2:如果你使用 bind-address = 172.17.42.1 你的 MySQL 服务器将不会监听到 127.0.0.1.在 docker 主机上运行的想要连接到 MySQL 的进程必须使用 172.17.42.1 IP 地址.

主机模式

要以主机模式从容器访问在 docker 主机上运行的 MySQL,您可以在 MySQL 配置中保留 bind-address = 127.0.0.1 以及所有您需要的做的是从你的容器连接到 127.0.0.1:

[vagrant@docker:~] $ docker run --rm -it --network=host mysql mysql -h 127.0.0.1 -uroot -p输入密码:欢迎使用 MySQL 监视器.命令以 ; 结尾或g.你的 MySQL 连接 ID 是 36服务器版本:5.5.41-0ubuntu0.14.04.1 (Ubuntu)版权所有 (c) 2000, 2014,Oracle 和/或其附属公司.版权所有.Oracle 是 Oracle Corporation 和/或其附属公司的注册商标.其他名称可能是其各自所有者的商标.输入帮助;"或 'h' 寻求帮助.键入 'c' 清除当前输入语句.mysql>

注意:请使用 mysql -h 127.0.0.1 而不是 mysql -h localhost;否则 MySQL 客户端会尝试使用 unix 套接字进行连接.

So I have a Nginx running inside a docker container, I have a mysql running on localhost, I want to connect to the MySql from within my Nginx. The MySql is running on localhost and not exposing a port to the outside world, so its bound on localhost, not bound on the ip address of the machine.

Is there any way to connect to this MySql or any other program on localhost from within this docker container?

This question is different from "How to get the IP address of the docker host from inside a docker container" due to the fact that the IP address of the docker host could be the public IP or the private IP in the network which may or may not be reachable from within the docker container (I mean public IP if hosted at AWS or something). Even if you have the IP address of the docker host it does not mean you can connect to docker host from within the container given that IP address as your Docker network may be overlay, host, bridge, macvlan, none etc which restricts the reachability of that IP address.

解决方案

Edit:

If you are using Docker-for-mac or Docker-for-Windows 18.03+, just connect to your mysql service using the host host.docker.internal (instead of the 127.0.0.1 in your connection string).

If you are using Docker-for-Linux 20.10.0+, you can also use the host host.docker.internal if you started your Docker container with the --add-host host.docker.internal:host-gateway option.

Otherwise, read below


TLDR

Use --network="host" in your docker run command, then 127.0.0.1 in your docker container will point to your docker host.

Note: This mode only works on Docker for Linux, per the documentation.


Note on docker container networking modes

Docker offers different networking modes when running containers. Depending on the mode you choose you would connect to your MySQL database running on the docker host differently.

docker run --network="bridge" (default)

Docker creates a bridge named docker0 by default. Both the docker host and the docker containers have an IP address on that bridge.

on the Docker host, type sudo ip addr show docker0 you will have an output looking like:

[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

So here my docker host has the IP address 172.17.42.1 on the docker0 network interface.

Now start a new container and get a shell on it: docker run --rm -it ubuntu:trusty bash and within the container type ip addr show eth0 to discover how its main network interface is set up:

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

Here my container has the IP address 172.17.1.192. Now look at the routing table:

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

So the IP Address of the docker host 172.17.42.1 is set as the default route and is accessible from your container.

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="host"

Alternatively you can run a docker container with network settings set to host. Such a container will share the network stack with the docker host and from the container point of view, localhost (or 127.0.0.1) will refer to the docker host.

Be aware that any port opened in your docker container would be opened on the docker host. And this without requiring the -p or -P docker run option.

IP config on my docker host:

[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

and from a docker container in host mode:

[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

As you can see both the docker host and docker container share the exact same network interface and as such have the same IP address.


Connecting to MySQL from containers

bridge mode

To access MySQL running on the docker host from containers in bridge mode, you need to make sure the MySQL service is listening for connections on the 172.17.42.1 IP address.

To do so, make sure you have either bind-address = 172.17.42.1 or bind-address = 0.0.0.0 in your MySQL config file (my.cnf).

If you need to set an environment variable with the IP address of the gateway, you can run the following code in a container :

export DOCKER_HOST_IP=$(route -n | awk '/UG[ 	]/{print $2}')

then in your application, use the DOCKER_HOST_IP environment variable to open the connection to MySQL.

Note: if you use bind-address = 0.0.0.0 your MySQL server will listen for connections on all network interfaces. That means your MySQL server could be reached from the Internet ; make sure to setup firewall rules accordingly.

Note 2: if you use bind-address = 172.17.42.1 your MySQL server won't listen for connections made to 127.0.0.1. Processes running on the docker host that would want to connect to MySQL would have to use the 172.17.42.1 IP address.

host mode

To access MySQL running on the docker host from containers in host mode, you can keep bind-address = 127.0.0.1 in your MySQL configuration and all you need to do is to connect to 127.0.0.1 from your containers:

[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>

note: Do use mysql -h 127.0.0.1 and not mysql -h localhost; otherwise the MySQL client would try to connect using a unix socket.

这篇关于从 Docker 容器内部,如何连接到机器的本地主机?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆