所以我在 docker 容器中运行了一个 Nginx,我在主机系统上运行了一个 mysql,我想从我的容器中连接到 MySql。 MySql 仅绑定到 localhost 设备。
有没有办法从这个 docker 容器中连接到这个 MySql 或本地主机上的任何其他程序?
这个问题与“如何从 docker 容器内部获取 docker 主机的 IP 地址”不同,因为 docker 主机的 IP 地址可能是网络中的公共 IP 或私有 IP,这可能是也可能是无法从 docker 容器中访问(如果托管在 AWS 或其他地方,我的意思是公共 IP)。即使您拥有 docker 主机的 IP 地址,这并不意味着您可以从容器内连接到 docker 主机,因为您的 Docker 网络的 IP 地址可能是覆盖、主机、网桥、macvlan、none 等,这限制了那个IP地址。
network: host
,您将无法从容器返回到主机。仅托管到容器。这是容器背后的主要思想。出于稳定性和安全原因,它们被隔离。
编辑:
如果您使用的是 Docker-for-mac 或 Docker-for-Windows 18.03+,只需使用主机 host.docker.internal
(而不是连接字符串中的 127.0.0.1
)连接到您的 mysql 服务。
如果您使用的是 Docker-for-Linux 20.10.0+,您还可以使用主机 host.docker.internal
if 使用 --add-host host.docker.internal:host-gateway
选项启动 Docker 容器。
否则,请阅读下文
TLDR
在您的 docker run
命令中使用 --network="host"
,然后您的 docker 容器中的 127.0.0.1
将指向您的 docker 主机。
注意:此模式仅适用于 Docker for Linux,per the documentation。
docker 容器网络模式注意事项
Docker 在运行容器时提供 different networking modes。根据您选择的模式,您将连接到在 docker 主机上运行的 MySQL 数据库。
docker run --network="bridge" (默认)
Docker 默认创建一个名为 docker0
的网桥。 docker 主机和 docker 容器在该网桥上都有一个 IP 地址。
在 Docker 主机上,输入 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 主机在 docker0
网络接口上有 IP 地址 172.17.42.1
。
现在启动一个新容器并在其上获取一个 shell: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
。现在查看路由表:
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 主机 172.17.42.1
的 IP 地址被设置为默认路由,并且可以从您的容器中访问。
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
搬运工运行--network =“主机”
或者,您可以使用 network settings set to host
运行 docker 容器。这样的容器将与 docker 主机共享网络堆栈,从容器的角度来看,localhost
(或 127.0.0.1
)将引用 docker 主机。
请注意,在您的 docker 容器中打开的任何端口都将在 docker 主机上打开。这不需要 -p
or -P
docker run
option。
我的 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 地址。
从容器连接到 MySQL
桥接模式
要从 桥接模式 的容器访问在 docker 主机上运行的 MySQL,您需要确保 MySQL 服务正在侦听 172.17.42.1
IP 地址上的连接。
为此,请确保您的 MySQL 配置文件 (my.cnf) 中有 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 的连接。
注意:如果您使用 bind-address = 0.0.0.0
,您的 MySQL 服务器将侦听所有网络接口上的连接。这意味着可以从 Internet 访问您的 MySQL 服务器;确保相应地设置防火墙规则。
注意 2:如果您使用 bind-address = 172.17.42.1
,您的 MySQL 服务器将不会监听到 127.0.0.1
的连接。想要连接到 MySQL 的 docker 主机上运行的进程必须使用 172.17.42.1
IP 地址。
主机模式
要从 主机模式 中的容器访问在 docker 主机上运行的 MySQL,您可以将 bind-address = 127.0.0.1
保留在 MySQL 配置中,您需要做的就是从容器连接到 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 套接字进行连接。
适用于所有平台
Docker v 20.10 及更高版本(自 2020 年 12 月 14 日起)
使用您的内部 IP 地址或连接到将解析为主机使用的内部 IP 地址的特殊 DNS 名称 host.docker.internal
。
在 Linux 上,将 --add-host=host.docker.internal:host-gateway
添加到您的 Docker 命令以启用此功能。要在 Linux 上的 Docker Compose 中启用此功能,请将以下几行添加到容器定义中:
extra_hosts:
- "host.docker.internal:host-gateway"
对于 Docker 的旧 macOS 和 Windows 版本
Docker v 18.03 及更高版本(自 2018 年 3 月 21 日起)
使用您的内部 IP 地址或连接到将解析为主机使用的内部 IP 地址的特殊 DNS 名称 host.docker.internal
。
Linux 支持待定 https://github.com/docker/for-linux/issues/264
对于旧 macOS 版本的 Docker
Docker for Mac v 17.12 到 v 18.02
与上面相同,但使用 docker.for.mac.host.internal
代替。
Docker for Mac v 17.06 到 v 17.11
与上面相同,但使用 docker.for.mac.localhost
代替。
适用于 Mac 17.05 及更低版本的 Docker
要从 docker 容器访问主机,您必须将 IP 别名附加到网络接口。你可以绑定任何你想要的IP,只要确保你没有将它用于其他任何东西。
sudo ifconfig lo0 alias 123.123.123.123/24
然后确保您的服务器正在侦听上述 IP 或 0.0.0.0
。如果它在 localhost 127.0.0.1
上侦听,它将不接受连接。
然后只需将你的 docker 容器指向这个 IP,你就可以访问主机了!
要进行测试,您可以在容器内运行 curl -X GET 123.123.123.123:3000
之类的东西。
别名将在每次重新启动时重置,因此如有必要,请创建一个启动脚本。
此处的解决方案和更多文档:https://docs.docker.com/docker-for-mac/networking/#use-cases-and-workarounds
mysql -uroot -hdocker.for.mac.localhost
docker run -e HOSTNAME= docker.for.mac.host.internal
时,容器已创建,但没有发生任何事情。我必须然后crtl + C。至少使用 --net=host -e HOSTNAME=localhost
容器运行并抱怨它找不到我需要的服务(MySQL db)。
使用
host.docker.internal
代替
localhost
对我来说完美无缺。 👍
我做了一个类似于上述帖子的破解,获取本地 IP 以映射到容器中的别名 (DNS)。主要问题是使用一个在 Linux 和 OSX 中都可以工作的简单脚本动态获取主机 IP 地址。我做了这个在两种环境中都有效的脚本(即使在配置了 "$LANG" != "en_*"
的 Linux 发行版中):
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):
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
码头工人-compose.yml:
myapp:
build: .
ports:
- "80:80"
extra_hosts:
- "dockerhost:$DOCKERHOST"
然后在您的代码中将 http://localhost
更改为 http://dockerhost
。
有关如何自定义 DOCKERHOST
脚本的更高级指南,请查看 this post 并解释其工作原理。
DOCKERHOST
值而不是“localhost”或 0.0.0.0。
export DOCKERHOST=$(docker network inspect --format='{{range .IPAM.Config}}{{.Gateway}}{{end}}' <NETWORK-NAME> | awk -F "/" 'NR==1{print $1}')
其中 <NETWORK-NAME> 可以是 bridge 或 docker 定义的网络名称-compose(通常是 path-name-network_name)。
dockerhost
作为 db 连接的主机(通常替换配置文件中的 localhost
)。
这在 NGINX/PHP-FPM 堆栈上对我有用,无需触及应用程序希望能够连接到 localhost
的任何代码或网络
将 mysqld.sock
从主机装载到容器内部。
在运行 mysql 的主机上查找 mysql.sock 文件的位置:
netstat -ln | awk '/mysql(.*)?\.sock/ { print $9 }'
将该文件挂载到 docker 中的预期位置:
docker run -v /hostpath/to/mysqld.sock:/containerpath/to/mysqld.sock
mysqld.sock 的可能位置:
/tmp/mysqld.sock
/var/run/mysqld/mysqld.sock
/var/lib/mysql/mysql.sock
/Applications/MAMP/tmp/mysql/mysql.sock # if running via MAMP
Linux 解决方案(内核 >=3.6)。
好的,您的 localhost
服务器有一个 IP 地址为 172.17.0.1
的默认 docker 接口 docker0
。您的容器以默认网络设置 --net="bridge"
启动。
为 docker0 接口启用 route_localnet: $ sysctl -w net.ipv4.conf.docker0.route_localnet=1 将这些规则添加到 iptables: $ iptables -t nat -I PREROUTING -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 Create MySQL user with access from '%' 这意味着 - 从任何人,不包括 localhost:CREATE USER 'user'@'%' IDENTIFIED BY 'password';在脚本中将 mysql-server 地址更改为 172.17.0.1。
route_localnet - BOOLEAN:路由时不要将环回地址视为火星源或目标。这允许将 127/8 用于本地路由目的(默认为 FALSE)。
在 host.docker.internal
适用于所有平台之前,您可以将我的容器用作 NAT 网关,而无需任何手动设置:
https://github.com/qoomon/docker-host
docker run --rm alpine ping host.docker.internal
docker run --rm alpine ping docker.for.win.localhost
docker run --rm alpine ping gateway.docker.internal
非常简单快捷,使用 ifconfig (linux) 或 ipconfig (windows) 检查您的主机 IP,然后创建一个
码头工人-compose.yml
version: '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”以及运行数据库的主机端口
适用于 Mac OSX 的最简单解决方案
只需使用 Mac 的 IP 地址即可。在 Mac 上运行此命令以获取 IP 地址并在容器内使用它:
ifconfig | grep 'inet 192'| awk '{ print $2}'
只要在您的 Mac 或另一个 docker 容器中本地运行的服务器正在侦听 0.0.0.0
,docker 容器就能够访问该地址。
如果您只想访问另一个正在监听 0.0.0.0
的 docker 容器,您可以使用 172.17.0.1
docker.for.mac.host.internal
主机名。
host.docker.internal
在 Mac 上可用。更多信息:docs.docker.com/desktop/networking/…
适用于 Windows 10 的解决方案
Docker Community Edition 17.06.0-ce-win18 2017-06-28 (stable)
您可以使用主机 docker.for.win.localhost
的 DNS 名称来解析到内部 IP。 (警告一些来源提到 windows
但它应该是 win
)
概述
我需要做类似的事情,即从我的 Docker 容器连接到运行 Azure Storage Emulator
和 CosmosDB Emulator
的本地主机。
默认情况下,Azure Storage Emulator
在 127.0.0.1 上侦听,虽然您也可以更改其绑定的 IP,但我一直在寻找可以使用默认设置的解决方案。
这也适用于从我的 Docker 容器连接到 SQL Server
和 IIS
,它们都使用默认端口设置在我的主机上本地运行。
想到了几个解决方案:
首先将您的依赖项移动到容器中 使您的其他服务可从外部访问并使用该外部 IP 连接到它们 在没有网络隔离的情况下运行您的容器 避免通过网络连接,而是使用作为卷安装的套接字
这不能开箱即用的原因是容器默认使用自己的网络命名空间运行。这意味着 localhost(或指向环回接口的 127.0.0.1)对于每个容器都是唯一的。连接到此将连接到容器本身,而不是在 docker 外部或不同 docker 容器内部运行的服务。
选项 1:如果您的依赖项可以移动到容器中,我会先这样做。它使您的应用程序堆栈可移植,因为其他人尝试在他们自己的环境中运行您的容器。而且您仍然可以在您的主机上发布端口,其他尚未迁移的服务仍然可以访问它。您甚至可以将端口发布到 docker 主机上的 localhost 接口,以避免使用如下语法从外部访问它:-p 127.0.0.1:3306:3306
表示已发布的端口。
选项 2:有多种方法可以从容器内部检测主机 IP 地址,但每种方法的工作场景数量有限(例如,Mac 需要 Docker)。最便携的选项是使用环境变量或配置文件之类的东西将主机 IP 注入容器,例如:
docker run --rm -e "HOST_IP=$(ip route get 1 | sed -n 's/^.*src \([0-9.]*\) .*$/\1/p')" ...
这确实要求您的服务正在侦听该外部接口,这可能是一个安全问题。对于从容器内部获取主机 IP 地址的其他方法,see this post。
使用 host.docker.internal
的便携性稍差。这适用于当前版本的 Docker for Windows 和 Docker for Mac。在 20.10 中,当您通过以下特殊主机条目传递时,该功能已添加到 Docker for Linux:
docker run --add-host host.docker.internal:host-gateway ...
host-gateway
是 Docker 20.10 中添加的一个特殊值,它会自动扩展为主机 IP。有关详细信息,请参阅 this PR。
选项 3:在没有网络隔离的情况下运行,即使用 --net host
运行,意味着您的应用程序正在主机网络命名空间上运行。这对容器的隔离较少,这意味着您无法通过具有 DNS 的共享 docker 网络访问其他容器(相反,您需要使用已发布的端口来访问其他容器化应用程序)。但是对于需要访问主机上仅在主机上的 127.0.0.1
上侦听的其他服务的应用程序,这可能是最简单的选择。
选项 4:各种服务也允许通过基于文件系统的套接字进行访问。此套接字可以作为绑定安装卷安装到容器中,允许您访问主机服务而无需通过网络。对于 docker 引擎的访问,您经常会看到将 /var/run/docker.sock
挂载到容器中的示例(授予该容器对主机的根访问权限)。使用 mysql,您可以尝试 -v /var/run/mysqld/mysqld.sock:/var/run/mysqld/mysql.sock
之类的操作,然后连接到 mysql 使用套接字转换为的 localhost
。
ifconfig | grep 'inet ' | grep -v 127.0.0.1 | awk '{ print $2 }' | head -1 | sed -n 's/[^0-9]*\([0-9\.]*\)/\1/p'
--add-host host.docker.internal:host-gateway
是金色的
对于窗户,
我在 spring 配置中更改了数据库 url:spring.datasource.url=jdbc:postgresql://host.docker.internal:5432/apidb
然后构建镜像并运行。它对我有用。
在 Windows 10 Home 上使用 Docker Toolbox 时,没有一个答案对我有用,但 10.0.2.2
确实有效,因为它使用 VirtualBox 将主机暴露给该地址上的 VM。
Ethernet adapter vEthernet (DockerNAT)
下的 IP 地址
这不是对实际问题的回答。这就是我解决类似问题的方法。解决方案完全来自:Define Docker Container Networking so Containers can Communicate。感谢尼克·拉博伊
将这里留给可能想要在一个容器和另一个容器之间进行 REST 调用的其他人。回答问题:在 docker 环境中用什么代替 localhost?
了解您的网络的外观docker network ls
创建一个新网络 docker network create -d my-net
启动第一个容器 docker run -d -p 5000:5000 --network="my-net" --name "first_container" <MyImage1:v0.1>
检查第一个容器 docker inspect first_container
的网络设置。 “网络”:应该有“我的网络”
启动第二个容器 docker run -d -p 6000:6000 --network="my-net" --name "second_container" <MyImage2:v0.1>
检查第二个容器 docker inspect second_container
的网络设置。 “网络”:应该有“我的网络”
SSH 到您的第二个容器 docker exec -it second_container sh
或 docker exec -it second_container bash
。
在第二个容器内,您可以通过 ping first_container
ping 第一个容器。此外,您的代码调用(例如 http://localhost:5000
)可以替换为 http://first_container:5000
对于 Windows 上的用户,假设您使用的是桥接网络驱动程序,您需要专门将 MySQL 绑定到 hyper-v 网络接口的 IP 地址。
这是通过通常隐藏的 C:\ProgramData\MySQL
文件夹下的配置文件完成的。
绑定到 0.0.0.0
将不起作用。所需的地址也显示在 docker 配置中,在我的例子中是 10.0.75.1
。
编辑:我最终在 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 主机(例如您的笔记本电脑)上运行的 localhost
服务。
如何?
关键是当你运行 Docker 容器时,你必须以主机模式运行它。该命令如下所示:
docker run --network="host" -id <Docker image ID>
当您在容器内执行 ifconfig
(您需要 apt-get install net-tools
容器以使 ifconfig
可调用)时,您将看到网络接口与 Docker 主机上的网络接口相同(例如,您的笔记本电脑)。
需要注意的是,我是 Mac 用户,但是我在 Parallels 下运行 Ubuntu,所以使用 Mac 并不是劣势。 ;-)
这就是您将 NGINX 容器连接到在 localhost
上运行的 MySQL 的方式。
--network="host"
的容器,如何连接到主机 mysql?
localhost
。查看我的 GitHub 源代码:github.com/sivabudh/system-in-a-box/blob/master/dj_host_docker/…。搜索 'HOST'
,你会看到 127.0.0.1 连接到 Postgresql。
对于 Linux,您无法更改 localhost 服务绑定到的接口
我们需要解决两个问题
获取主机的 IP 使我们的 localhost 服务对 Docker 可用
第一个问题可以使用 qoomon 的 docker-host image 解决,如其他答案所示。
您需要将此容器添加到与其他容器相同的桥接网络中,以便您可以访问它。在您的容器内打开一个终端并确保您可以 ping dockerhost
。
bash-5.0# ping dockerhost
PING dockerhost (172.20.0.2): 56 data bytes
64 bytes from 172.20.0.2: seq=0 ttl=64 time=0.523 ms
现在,更难的问题是让 docker 可以访问该服务。
我们可以使用 telnet 来检查我们是否可以访问主机上的端口(您可能需要安装它)。
问题是我们的容器将只能访问绑定到所有接口的服务,例如 SSH:
bash-5.0# telnet dockerhost 22
SSH-2.0-OpenSSH_7.6p1 Ubuntu-4ubuntu0.3
但是仅绑定到 localhost 的服务将无法访问:
bash-5.0# telnet dockerhost 1025
telnet: can't connect to remote host (172.20.0.2): Connection refused
此处正确的解决方案是将服务绑定到 dockers 桥接网络。但是,此答案假定您无法更改此设置。所以我们将改为使用 iptables
。
首先,我们需要通过 ifconfig
找到 docker 使用的桥接网络的名称。如果您使用的是未命名的网桥,则它只是 docker0
。但是,如果您使用的是命名网络,您将拥有一个以 br-
开头的网桥,而 docker 将使用该网桥。我的是br-5cd80298d6f4
。
一旦我们有了这个网桥的名字,我们就需要允许从这个网桥路由到 localhost。出于安全原因,默认情况下禁用此功能:
sysctl -w net.ipv4.conf.<bridge_name>.route_localnet=1
现在设置我们的 iptables
规则。由于我们的容器只能访问 docker bridge 网络上的端口,我们将假设我们的服务实际上绑定到该网络上的一个端口。
为此,我们会将所有对 <docker_bridge>:port
的请求转发给 localhost:port
iptables -t nat -A PREROUTING -p tcp -i <docker_bridge_name> --dport <service_port> -j DNAT --to-destination 127.0.0.1:<service_port>
例如,对于我在端口 1025 上的服务
iptables -t nat -A PREROUTING -p tcp -i br-5cd80298d6f4 --dport 1025 -j DNAT --to-destination 127.0.0.1:1025
您现在应该能够从容器访问您的服务:
bash-5.0# telnet dockerhost 1025
220 127.0.0.1 ESMTP Service Ready
sysctl -w net.ipv4.conf.docker0.route_localnet=1
和 iptables -t nat -A PREROUTING -p tcp -i docker0 --dport 1025 -j DNAT --to-destination 127.0.0.1:1025
首先查看 this 答案,了解您必须解决此问题的选项。但是如果您使用 docker-compose
,您可以将 network_mode: host
添加到您的服务中,然后使用 127.0.0.1
连接到本地主机。这只是上述答案中描述的选项之一。您可以在下面找到我如何从 https://github.com/geerlingguy/php-apache-container.git
修改 docker-compose.yml
:
---
version: "3"
services:
php-apache:
+ network_mode: host
image: geerlingguy/php-apache:latest
container_name: php-apache
...
+
表示我添加的行。
[附加信息] 这在版本 2.2
中也有效。和“主机”或只是“主机”都在 docker-compose
中工作。
---
version: "2.2"
services:
php-apache:
+ network_mode: "host"
or
+ network_mode: host
...
如果您使用 --net=host 运行,则 localhost 应该可以正常工作。如果您使用默认网络,请使用静态 IP 172.17.0.1。
看到这个 - https://stackoverflow.com/a/48547074/14120621
我不同意 Thomasleveil 的回答。
使 mysql 绑定到 172.17.42.1 将阻止其他程序使用主机上的数据库访问它。这仅在您的所有数据库用户都已 dockerized 时才有效。
让mysql绑定到0.0.0.0会向外界打开db,这不仅是一件非常糟糕的事情,而且与原始问题作者想要做的相反。他明确表示“MySql 在 localhost 上运行并且没有向外界公开端口,因此它绑定在 localhost 上”
回答 ivant 的评论
“为什么不将 mysql 也绑定到 docker0 呢?”
这是不可能的。 mysql/mariadb 文档明确表示无法绑定到多个接口。您只能绑定到 0、1 或所有接口。
作为结论,我还没有找到任何方法可以从 docker 容器访问主机上的(仅限本地主机)数据库。这绝对是一种非常常见的模式,但我不知道该怎么做。
172.17.42.1
地址连接到 MySQL 服务器。但你的笔记是对的。 Aso,我使用 host
网络模式编辑了我的答案,该模式允许将 MySQL 服务器绑定到 127.0.0.1
,同时允许容器连接到它
0.0.0.0
,然后设置防火墙,以便无法从 Internet 访问数据库。
在 7 年的时间里,有人问这个问题,要么是 docker 改变了,要么没有人尝试过这种方式。所以我将包括我自己的答案。
我发现所有答案都使用复杂的方法。今天,我需要这个,并找到了2个非常简单的方法:
在您的主机上使用 ipconfig 或 ifconfig 并记下所有 IP 地址。容器至少可以使用其中的两个。我在 WiFi LAN 适配器上有一个固定的本地网络地址:192.168.1.101。这可能是 10.0.1.101。结果会根据你的路由器而改变我在 Windows 上使用 WSL,它有自己的 vEthernet 地址:172.19.192.1
我在 WiFi LAN 适配器上有一个固定的本地网络地址:192.168.1.101。这可能是 10.0.1.101。结果将根据您的路由器而改变
我在 Windows 上使用 WSL,它有自己的 vEthernet 地址:172.19.192.1
使用 host.docker.internal。大多数答案都有这种或另一种形式,具体取决于操作系统。顾名思义,它现在被 docker 全局使用。
第三种选择是使用机器的 WAN 地址,或者换句话说,由服务提供商提供的 IP。但是,如果 IP 不是静态的,并且需要路由和防火墙设置,这可能不起作用。
host.docker.internal
通常是答案....但是如果您使用的是 wsl,那么 docker 将不得不消除多个 IP 地址的歧义。这可能会导致超级烦人的问题,即您在不同端口上本地运行多个服务器,但您只能使用 host.docker.internal
打几个。
尝试这个:
version: '3.5'
services:
yourservice-here:
container_name: container_name
ports:
- "4000:4000"
extra_hosts: # <---- here
- localhost:192.168.1.202
- or-vitualhost.local:192.168.1.202
要获得 192.168.1.202
,请使用 ifconfig
这对我有用。希望这有帮助!
您需要知道 gateway!我使用本地服务器的解决方案是在 0.0.0.0:8000
下公开它,然后使用 subnet 和 run container 运行 docker,例如:
docker network create --subnet=172.35.0.0/16 --gateway 172.35.0.1 SUBNET35
docker run -d -p 4444:4444 --net SUBNET35 <container-you-want-run-place-here>
所以,现在您可以通过 http://172.35.0.1:8000
访问您的环回
连接到网关地址。
❯ docker network inspect bridge | grep Gateway
"Gateway": "172.17.0.1"
确保主机上的进程正在侦听此接口或所有接口,并在 docker 之后启动。如果使用 systemd,您可以添加以下内容以确保它在 docker 之后启动。
[Unit]
After=docker.service
例子
❯ python -m http.server &> /dev/null &
[1] 149976
❯ docker run --rm python python -c "from urllib.request import urlopen;print(b'Directory listing for' in urlopen('http://172.17.0.1:8000').read())"
True
这是我的解决方案:它适用于我的情况
通过 /etc/mysql/mysql.conf.d 中的注释 #bind-address = 127.0.0.1 将本地 mysql 服务器设置为公共访问
重启mysql服务器 sudo /etc/init.d/mysql restart
运行以下命令以打开用户 root 访问任何主机 mysql -uroot -proot GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION;同花顺特权;
创建 sh 脚本:run_docker.sh
#!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 版本运行:'2.1' 服务:tomcatwar:extra_hosts:-“local:10.1.2.232”图像:sopheamak/springboot_docker_mysql 端口:-8080:8080 环境:-DATABASE_HOST=local -DATABASE_USER=root -DATABASE_PASSWORD=root - DATABASE_NAME=demo - DATABASE_PORT=3306
您可以使用 alpine 映像获取主机 ip
docker run --rm alpine ip route | awk 'NR==1 {print $3}'
这会更加一致,因为您总是使用 alpine 来运行命令。
与 Mariano 的回答类似,您可以使用相同的命令设置环境变量
DOCKER_HOST=$(docker run --rm alpine ip route | awk 'NR==1 {print $3}') docker-compose up
CGroups 和命名空间在容器生态系统中扮演着重要角色。
命名空间提供了一层隔离。每个容器都在单独的命名空间中运行,并且它的访问权限仅限于该命名空间。 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
为了使一切正常,您需要为您的服务器(caddy、nginx)创建一个配置,其中主域将是“docker.for.mac.localhost”。为此替换“http://docker.for.mac.localhost/api”上的 baseURL“http://localhost/api”
码头工人-compose.yml
backend:
restart: always
image: backend
build:
dockerfile: backend.Dockerfile
context: .
environment:
# add django setting.py os.getenv("var") to bd config and ALLOWED_HOSTS CORS_ORIGIN_WHITELIST
DJANGO_ALLOWED_PROTOCOL: http
DJANGO_ALLOWED_HOSTS: docker.for.mac.localhost
POSTGRES_PASSWORD: 123456
POSTGRES_USER: user
POSTGRES_DB: bd_name
WAITDB: "1"
volumes:
- backend_static:/app/static
- backend_media:/app/media
depends_on:
- db
frontend:
restart: always
build:
dockerfile: frontend.Dockerfile
context: .
image: frontend
environment:
# replace baseURL for axios
API_URL: http://docker.for.mac.localhost/b/api
API_URL_BROWSER: http://docker.for.mac.localhost/b/api
NUXT_HOST: 0.0.0.0
depends_on:
- backend
caddy:
image: abiosoft/caddy
restart: always
volumes:
- $HOME/.caddy:/root/.caddy
- ./Caddyfile.local:/etc/Caddyfile
- backend_static:/static
- backend_media:/media
ports:
- 80:80
depends_on:
- frontend
- backend
- db
球童文件.local
http://docker.for.mac.localhost {
proxy /b backend:5000 {
header_upstream Host {host}
header_upstream X-Real-IP {remote}
header_upstream X-Forwarded-For {remote}
header_upstream X-Forwarded-Port {server_port}
header_upstream X-Forwarded-Proto {scheme}
}
proxy / frontend:3000 {
header_upstream Host {host}
header_upstream X-Real-IP {remote}
header_upstream X-Forwarded-For {remote}
header_upstream X-Forwarded-Port {server_port}
header_upstream X-Forwarded-Proto {scheme}
}
root /
log stdout
errors stdout
gzip
}
http://docker.for.mac.localhost/static {
root /static
}
http://docker.for.mac.localhost/media {
root /media
}
django settings.py
ALLOWED_HOSTS = [os.getenv("DJANGO_ALLOWED_HOSTS")]
CORS_ORIGIN_WHITELIST = [f'{os.getenv("DJANGO_ALLOWED_PROTOCOL")}://{os.getenv("DJANGO_ALLOWED_HOSTS")}']
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql_psycopg2",
"NAME": os.getenv("POSTGRES_DB"),
"USER": os.getenv("POSTGRES_USER"),
"PASSWORD": os.getenv("POSTGRES_PASSWORD"),
"HOST": "db",
"PORT": "5432",
}
}
nuxt.config.js(baseURL 变量将覆盖环境的 API_URL)
axios: {
baseURL: 'http://127.0.0.1:8000/b/api'
},
您可以简单地在主机上执行 ifconfig
以检查您的主机 IP,然后从您的容器内连接到该 ip,这对我来说非常适合。
ifconfig
命令并获取了第一个 inet
ip,它似乎是正确的
telnet 172.17.0.1 3306
-v /var/run/mysqld/mysqld.sock:/tmp/mysql.sock
这样的网络。