如何从Docker容器内部连接到计算机的本地主机?


1446

所以我有一个Nginx在docker容器中运行,我有一个mysql在本地主机上运行,​​我想从我的Nginx内部连接到MySql。MySql在localhost上运行,并且没有将端口暴露给外界,因此它绑定在localhost上,而不绑定在计算机的IP地址上。

有什么方法可以从此Docker容器中连接到此MySql或localhost上的任何其他程序吗?

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


为什么还不将mysql绑定到docker0?
ivant 2014年

2
对于Windows计算机:-$ docker run -d --name MyWebServer -P httpd
Lokesh S


如果没有network: host,你不能到主机的容器回去。仅托管到容器。这是容器背后的主要思想。由于稳定性和安全性原因,它们是隔离的。
FreeSoftwareServers

Answers:


1965

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

从Docker 18.09.3开始,这不适用于Linux上的Docker。一个修复已三月提交的8日,2019年将有望被合并到代码库。在此之前,解决方法是使用qoomon的answer中所述的容器。

2020-01:取得了一些进展。如果一切顺利,这应该可以在Docker 20.04中找到


TLDR

--network="host"docker run命令中使用,然后127.0.0.1在Docker容器中将指向您的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 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.1docker0网络接口上具有IP地址。

现在启动一个新容器并在其上安装一个外壳: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主机的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

泊坞窗运行--network =“ host”

或者,您可以运行网络设置host为的Docker容器。这样的容器将与docker主机共享网络堆栈,并且从容器的角度来看,localhost(或127.0.0.1)将引用docker主机。

请注意,您在Docker容器中打开的任何端口都将在Docker主机上打开。而且这不需要-por -P docker run选项

我的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.1IP地址上的连接。

要做到这一点,请确保您有两种bind-address = 172.17.42.1或者bind-address = 0.0.0.0在你的MySQL配置文件(my.cnf中)。

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

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

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

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

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

主机模式

要以主机模式从容器访问在docker主机上运行的MySQL ,可以保持bind-address = 127.0.0.1MySQL配置,而您要做的就是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套接字进行连接。


8
谢谢您这么详细的回答!据我了解,使用主机模式是通过localhost获得此功能的唯一方法。我还没有尝试过,但是我认为您可以创建一个单独的网络来通过它们自己的网桥连接容器,从而为它们提供通用的“本地主机”。
2015年

26
OSX用户注意事项:首先使用“ docker-machine ssh default”登录到您的docker虚拟机(boot2docker),然后运行“ sudo ip addr show docker0”。从那里继续执行Thomas的指示。
查理·达萨斯

30
我正在为Mac运行Docker,并且不再有172.17.42.1,也不再有docker0。它曾经是172.17.0.1作为网关,甚至不能telnet 172.17.0.1 3306
zx1986

26
您可以将mysql套接字安装到容器中,而不是像-v /var/run/mysqld/mysqld.sock:/tmp/mysql.sock这样进行联网。
chx

8
当您在Mac上运行Docker而不使用boot2docker时,如果没有docker0接口,有人可以解决这种情况吗?
TheJKFever's

350

对于macOS和Windows

Docker v 18.03及更高版本(自2018年3月21日起)

使用您的内部IP地址或连接到特殊的DNS名称host.docker.internal,它将解析为主机使用的内部IP地址。

Linux支持未决https://github.com/docker/for-linux/issues/264

带有较早版本Docker的MacOS

适用于Mac的Docker v 17.12至v 18.02

与上述相同,但docker.for.mac.host.internal改为使用。

适用于Mac的Docker v 17.06至v 17.11

与上述相同,但docker.for.mac.localhost改为使用。

适用于Mac 17.05及更低版本的Docker

要从docker容器访问主机,必须将IP别名附加到网络接口。您可以绑定所需的任何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


5
太好了,谢谢,这从容器内部对我有用。 mysql -uroot -hdocker.for.mac.localhost
理查德·弗兰克

1
docker.for.mac.localhost正是我想要的。但这同时像地狱一样肮脏。在docker中,人们希望钩子docker.for.mac.localhost是通用的docker内部名称,该名称对任何操作系统都有效,而不仅仅是Mac。但是出于开发目的,这已经足够了。
99索诺,2017年

如何访问在9093处公开的端口。我正在尝试telnet docker.for.mac.localhost 9093。它无法访问,但是如果我ping docker.for.mac.localhost,它可以访问。我在这里错过了什么吗?
Achilleus

1
从容器中解析主机时,应使用DNS名称docker.for.mac.host.internal而不是docker.for.mac.localhost(仍然有效),因为存在RFC禁止使用localhost的子域。参见tools.ietf.org/html/draft-west-let-localhost-be-localhost-06
杰亚

这对我不起作用。当我docker run -e HOSTNAME= docker.for.mac.host.internal 创建容器时,但是没有发生。然后,我必须crtl + C。随着--net=host -e HOSTNAME=localhost至少容器运行,并抱怨说,它无法找到该服务,我需要(MySQL数据库)。
Jorge Orpinel '18年

83

我在做类似于以上文章的技巧,将本地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

docker-compose.yml

myapp:
  build: .
  ports:
    - "80:80"
  extra_hosts:
    - "dockerhost:$DOCKERHOST"

然后更改http://localhosthttp://dockerhost您的代码。

有关如何自定义DOCKERHOST脚本的更高级指南,请看一下这篇文章,并解释其工作原理。


1
根据您的用例,您甚至可能不使用DOCKERHOSTdocker容器需要在本地连接的任何服务中使用此处的值而不是“ localhost”或0.0.0.0。
enderland '17

2
我对您的解决方案进行了稍微修改,使其与自定义网络兼容:export DOCKERHOST=$(docker network inspect --format='{{range .IPAM.Config}}{{.Gateway}}{{end}}' <NETWORK-NAME> | awk -F "/" 'NR==1{print $1}') 其中<NETWORK-NAME>可以是网桥,也可以是docker-compose定义的网络名称(通常是path-name - network_name)。
dieresys

1
您需要添加注释:dockerhost用作数据库连接的主机(通常localhost在配置文件中替换为)。
贾斯汀

奇怪的解决方案,但它是唯一使xdebug在php cli下在docker下工作的方法
Eddie

此溶液在haproxy中后,Acl停止工作。知道为什么吗?
HyukHyukBoi

41

这在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

2
这是一种更加干净的解决方案,不会将Mysql暴露在外部(如果不使用防火墙的话)。
user1226868 2015年

5
套接字的伸缩性不如TCP,因为它们阻塞的频率更高,并且可能导致奇怪的行为。尽可能使用TCP。
乔尔·萨拉斯

3
@JoelESalas您是否有该申诉的消息来源?
私人

我发现这是最简单的解决方案。赞好user833482!您应该为StackOverflow做出更多的贡献。
私人

2
@JoelESalas我想你错了。默认情况下,mysql客户端库甚至在连接到本地主机时甚至使用unix套接字,而不是实际连接到本地主机。Unix套接字避免了TCP堆栈和路由的开销,并且应运行得更快。
M康拉德,

25

host.docker.internal适用于所有平台之前,您无需任何手动设置即可将我的容器用作NAT网关:

https://github.com/qoomon/docker-host


5
我可以确认这在具有Windows容器的Windows 19.03.2的Docker中不起作用。
KMC

任何想法如何解决?(我不是Windows用户)
qoomon

如果环境不阻止mysql使用的端口,则可以通过托管的计算机名称引用服务器。因此,在您的连接字符串中,将您的计算机名称用作服务器名称。
KMC

24

Linux解决方案(内核> = 3.6)。

好的,您的本地主机服务器具有默认docker接口docker0,其IP地址为172.17.0.1。您的容器以默认的网络设置--net =“ bridge”开头

  1. 为docker0接口启用route_localnet:
    $ sysctl -w net.ipv4.conf.docker0.route_localnet=1
  2. 将此规则添加到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
  3. 创建具有'%'访问权限的mysql用户-表示从任何人(不包括本地主机)访问:
    CREATE USER 'user'@'%' IDENTIFIED BY 'password';
  4. 在脚本中将mysql服务器地址更改为172.17.0.1


内核文档中

route_localnet -BOOLEAN:路由时,请勿将环回地址视为火星源或目的地。这样就可以将127/8用于本地路由(默认为FALSE)。


1
第二个iptable命令的目的是什么?我可以理解,第一个是将与172.17.0.1:3306匹配的所有tcp目标重写为127.0.0.1:3306,但是为什么第二个iptable命令是必需的?
帕特里克

17

Windows 10解决方案

Docker Community Edition 17.06.0-ce-win18 2017-06-28(稳定)

您可以使用主机的DNS名称docker.for.win.localhost解析为内部IP。(警告提到了一些资料,windows但应该如此win

概述
我需要做类似的事情,即从Docker容器连接到运行Azure Storage Emulatorand的本地主机CosmosDB Emulator

Azure Storage Emulator通过默认监听127.0.0.1,而你可以改变它的束缚太多,我一直在寻找,将使用默认设置工作的解决方案的IP。

这也适用于从我的Docker容器连接到SQL ServerIIS,两者都使用默认端口设置在我的主机上本地运行。


13

非常简单快速,请使用ifconfig(linux)或ipconfig(windows)检查主机IP,然后创建一个

docker-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”和运行数据库的主机的端口


在HaProxy中,由于某种原因,此解决方案已停止了ACL的工作,只有默认设置有效。
HyukHyukBoi

1
在linux系统上有效的唯一解决方案。+1
拉菲克·法哈德

11

在Windows 10 Home上使用Docker Toolbox时,没有任何答案对我有用,但是10.0.2.2可以使用,因为它使用VirtualBox将该主机暴露给该地址上的VM。


2
有用。甚至无需指定--network = host。看起来10.0.2.2已设置为主机的默认IP。谢谢。
TheManish

但是,我可以在所有版本的Windows和Mac上使用此静态IP吗,如何通过脚本在多个平台上使用它呢?
151291

这对我有用。只需在主机(Windows)上运行ipconfig并在Ethernet adapter vEthernet (DockerNAT)
Kihats

10

对于Windows上的用户,假设您正在使用网桥网络驱动程序,则需要将MySQL专门绑定到hyper-v网络接口的ip地址。

这是通过通常隐藏的C:\ ProgramData \ MySQL文件夹下的配置文件完成的。

绑定到0.0.0.0将不起作用。所需的地址也显示在docker配置中,在我的情况下为10.0.75.1。


3
您应该获得一枚奖章!我已经整整工作了两天。感谢您的帮助!
迈克尔”

1
我也为此工作了整整两天。这是我在网上提到的唯一位置。当谈到谈论从Docker容器连接到MSSQL时,Microsoft对此完全保持沉默。它使您想知道他们是否能够自己工作!
Contango

8

编辑:我最终在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容器中运行的服务连接到localhost在Linux上运行的服务。 Docker主机(例如您的笔记本电脑)。

怎么样?

关键是当您运行Docker容器时,必须以主机模式运行它。该命令如下所示:

docker run --network="host" -id <Docker image ID>

在容器内部进行操作ifconfig(您需要将apt-get install net-tools容器ifconfig可调用)时,您会看到网络接口与Docker主机(例如,笔记本电脑)上的网络接口相同。

需要特别注意的是,我是Mac用户,但是我在Parallels下运行Ubuntu,因此使用Mac并非不利。;-)

这就是将NGINX容器连接到在上运行的MySQL的方式localhost


1
重要的是要注意,主机模式由于使用OS网络堆栈而提供了更好的性能。
sivabudh's

2
那里很好。尽管可以使用未使用的IP从容器连接到主机服务,但请附加docs.docker.com/docker-for-mac/networking。这不是一个令人愉快的解决方案,但是可以。
XavierHuppé17年

好东西 一旦进入容器,例如--network="host",如何连接到主机mysql?
迈克尔(Michael)

1
@Buccleuch只需使用localhost。查看我的GitHub源代码:github.com/sivabudh/system-in-a-box/blob/master/dj_host_docker/…。搜索'HOST',您将看到127.0.0.1连接到Postgresql。
sivabudh

我可以通过按@ user833482安装卷来访问主机mysql数据库,当然也可以在docker容器上安装mysql-client和server之后。
迈克尔

7

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


1
Docker for Mac docker.for.mac.host.internal现在公开主机名。
马特

5

这不是对实际问题的答案。这就是我解决类似问题的方式。该解决方案完全来自:定义Docker容器网络,以便容器可以通信。感谢Nic Raboy

将其留给其他可能想要在一个容器与另一个容器之间进行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。“网络”:应具有“ my-net”

启动第二个容器 docker run -d -p 6000:6000 --network="my-net" --name "second_container" <MyImage2:v0.1>

检查第二个容器的网络设置docker inspect second_container。“网络”:应具有“ my-net”

ssh放入第二个容器docker exec -it second_container shdocker exec -it second_container bash

在第二个容器内,您可以通过ping通第一个容器ping first_container。另外,您的代码调用(例如)http://localhost:5000可以替换为http://first_container:5000


正是我想要的。谢谢:D
Simar Singh

5

对于Windows,

我在春季配置中更改了数据库URL: spring.datasource.url=jdbc:postgresql://host.docker.internal:5432/apidb

然后生成映像并运行。它为我工作。


有趣....
菲尔

对我来说不起作用。我有Mac,并尝试从php容器连接到localhost mysql。任何的想法 ?
A. Zalonis

4

我不同意Thomasleveil的回答。

使mysql绑定到172.17.42.1将阻止其他程序使用主机上的数据库访问它。仅当您所有的数据库用户都被docker化后,这才起作用。

使mysql绑定到0.0.0.0将使数据库向外界开放,这不仅是一件非常糟糕的事情,而且与作者最初想做的事情背道而驰。他明确表示“ MySql在本地主机上运行,​​并且没有将端口暴露给外界,因此它绑定在本地主机上”

回答ivant的评论

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

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

结论是,我还没有找到从Docker容器访问主机上(仅本地主机)数据库的任何方法。这绝对是一个非常非常常见的模式,但是我不知道该怎么做。


4
从docker主机上,您仍然可以使用该172.17.42.1地址连接到MySQL服务器。但是您的注释是正确的。麻生太郎,我用host网络模式编辑了我的答案,该模式允许与MySQL服务器绑定,127.0.0.1同时允许容器连接到它
Thomasleveil 2015年

不,正如我所说,如果mysql绑定到本地主机,则无法连接到172.17.42.1。
Orzel 2015年

4
“使mysql绑定到172.17.42.1将阻止其他使用主机上的数据库的程序访问它。” -那是不对的。其他程序可以使用mysql,它们只需要连接到172.17.42.1,而不是localhost / 127.0.0.1。
0x89

解决此问题的方法通常是让MySQL服务器绑定到该服务器0.0.0.0,然后设置防火墙,以便无法从Internet访问该数据库。
Halfer

4

这是我的解决方案:适用于我的情况

  • 通过 #bind-address = 127.0.0.1 /etc/mysql/mysql.conf.d中的注释将本地mysql服务器设置为公共访问权限

  • 重启mysql服务器 sudo /etc/init.d/mysql restart

  • 运行以下命令以打开用户root访问任何主机 mysql -uroot -proot GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'root' WITH GRANT OPTION; FLUSH PRIVILEGES;

  • 创建sh脚本:run_docker.sh

    #!bin / bash

    HOSTIP =`ip -4 addr show scope全局开发eth0 | grep inet | awk'{print \ $ 2}'| 切-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 =演示\
                  -e DATABASE_USER = root \
                  -e DATABASE_PASSWORD = root \
                  sopheamak / springboot_docker_mysql

  
  • 使用docker-composer运行

    版本:“ 2.1”

    服务:
    tomcatwar: extra_hosts: -“本地:10.1.2.232” 图片:sopheamak / springboot_docker_mysql
    端口: -8080:8080 环境: -DATABASE_HOST =本地 -DATABASE_USER =根 -DATABASE_PASSWORD =根 -DATABASE_NAME =演示 -DATABASE_PORT = 3306


4

我想到了几种解决方案:

  1. 首先将依赖项移至容器中
  2. 使您的其他服务可从外部访问,并使用该外部IP连接到它们
  3. 在没有网络隔离的情况下运行容器
  4. 避免通过网络连接,而应使用作为卷安装的套接字

开箱即用的原因是默认情况下,容器使用其自己的网络名称空间运行。这意味着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 r s 0/0 | awk '{print $3}')" ...

这确实要求您的服务正在该外部接口上侦听,这可能是安全问题。有关从容器内部获取主机IP地址的其他方法,请参见这篇文章

选项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,然后localhost使用套接字连接mysql转换为的内容。


3

您可以使用高山图像获取主机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

3

对于Linux,您无法更改localhost服务绑定到的接口

我们需要解决两个问题

  1. 获取主机的IP
  2. 使localhost服务可用于Docker

如其他答案所示,可以使用qoomon的docker -host映像解决第一个问题。

您将需要将此容器与其他容器添加到同一网桥网络,以便可以访问它。打开容器内的终端,并确保可以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

但是仅绑定到本地主机的服务将无法访问:

bash-5.0# telnet dockerhost 1025
telnet: can't connect to remote host (172.20.0.2): Connection refused

正确的解决方案是将服务绑定到dockers网桥。但是,此答案假定您无法更改此设置。因此,我们将改为使用iptables

首先,我们需要找到docker使用的桥接网络的名称ifconfig。如果您使用的是未命名的网桥,则为docker0。但是,如果您使用的是命名网络,则将以br-docker 开头的网桥代替。我的是br-5cd80298d6f4

一旦有了该网桥的名称,就需要允许从该网桥路由到本地主机。出于安全原因,默认情况下禁用此功能:

sysctl -w net.ipv4.conf.<bridge_name>.route_localnet=1

现在建立我们的iptables规则。由于我们的容器只能访问docker网桥网络上的端口,因此我们要假装我们的服务实际上已绑定到该网络上的端口。

为此,我们会将所有请求转发<docker_bridge>:portlocalhost: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

1
这与@ ray-d上面提到的相同,但很好地解释了。谢谢!此外,在使用docker-compose时,我还必须在PREROUTING链中为到达docker0接口的所有数据包添加DNAT规则:因为,docker-compose似乎在构建期间正在使用docker0(令人惊讶的是,不在运行期间):sysctl -w net.ipv4.conf.docker0.route_localnet=1iptables -t nat -A PREROUTING -p tcp -i docker0 --dport 1025 -j DNAT --to-destination 127.0.0.1:1025
arvindd

2

CGroups和命名空间在容器生态系统中发挥着重要作用。

命名空间提供了一层隔离。每个容器都在单独的名称空间中运行,并且其访问仅限于该名称空间。Cgroup控制每个容器的资源利用,而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,运行和调试应用程序。但是,不建议这样走。希望能帮助到你。


2

您需要知道网关!我对本地服务器的解决方案是将其公开在0.0.0.0:8000,然后使用子网运行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


2

尝试这个:

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

这对我有用。希望有帮助!


1

对于Windows机器:-

在构建期间运行以下命令随机暴露docker端口

$docker run -d --name MyWebServer -P mediawiki

在此处输入图片说明

在此处输入图片说明

在上面的容器列表中,您可以看到分配为32768的端口。尝试访问

localhost:32768 

您可以看到mediawiki页面


5
尽管此答案可能会为某些用户提供有用的信息,但这是错误的方法!它是关于从主机访问容器中运行的服务。但是,问题是关于从容器访问主机上运行的服务。
einjohn,


1

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


这是最简单的解决方案。它为我工作,我推荐了许多人
Sopia Alfred,

-1

我这样做的方法是将主机IP作为环境变量传递给容器。然后容器通过该变量访问主机。


您能举例说明如何做到吗?我曾经尝试过这种方法,但没有获得太大的成功
kmjb

`docker run -i -t -e HOST = 10.145.2.123 ubuntu root @ ce2a843da3ee:/ tmp#./telnet $ HOST 22正在尝试10.145.2.123 ...已连接到10.145.2.123。转义字符为'^]'。SSH-2.0-OpenSSH_7.4`
F. Kam
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.