Docker 里面不能使用 127.0.0.1 来访问宿主机
在 Docker 里,容器不能用 127.0.0.1 访问宿主机,本质上不是“Docker 有问题”,而是网络模型和 127.0.0.1 本身的含义决定的。
下面就从概念到示例,写一篇说明清楚的小文章,顺便给出几种正确的访问方式。
一、先搞清楚:127.0.0.1 到底是谁?
127.0.0.1 是一个特殊 IP,叫做 回环地址(loopback)。它的含义是:“我自己这台机器”,但这个“我自己”永远是当前网络命名空间里的自己。
在你的宿主机上:
127.0.0.1= 宿主机自己curl 127.0.0.1:8080:访问的是宿主机上的 8080 端口在 Docker 容器里:
127.0.0.1= 容器自己curl 127.0.0.1:8080:访问的是容器内部的 8080 端口
所以,一旦你进入容器:
此时你访问的不是宿主机的 MySQL,而是“my-app 容器自己”的 3306。大部分情况下,这个端口根本没开,于是就连接失败——这就是“Docker 里不能用 127.0.0.1 访问宿主机”的根源。
二、Docker 默认网络:容器和宿主机是“邻居”,不是“合体”
绝大部分情况下,你起容器的时候并没有显式配置网络模式,Docker 就会用默认的 bridge 网络,例如:
此时网络关系大致是这样:
宿主机:有自己的网卡(如
eth0),还有一个 Docker 的虚拟网桥(如docker0)容器:在
docker0上分配到一个独立 IP(例如172.17.0.2)容器自己的
127.0.0.1只指向容器内部,不会跑到宿主机去
可以理解为:
宿主机 = 一栋楼容器 = 楼里的很多房间,每个房间有自己的“内线电话”(127.0.0.1)。你在房间 A 拿起内线打 127.0.0.1,只能打到房间 A 自己,不可能打到楼管理处(宿主机)。
所以要从容器访问宿主机服务,就不能说 “我自己(127.0.0.1)”,而要说 “那台机器的 IP”。
三、实际案例:容器里连宿主机 MySQL 为啥总失败?
最常见的就是下面这种场景:
宿主机装了 MySQL:
地址:
127.0.0.1:3306用户:
root容器里跑着 Nacos / Spring Boot / 其他服务
在容器配置里写成:
结果一连就报错:连接超时 / Connection refused / communications link failure。
原因就是:容器里的 127.0.0.1 根本不是宿主机,而是容器自己,而且容器自己根本没开 3306 端口。
四、那怎么正确访问宿主机?
1. 使用宿主机的真实 IP(通用做法)
在 Linux 环境中最通用的办法就是:查出宿主机在局域网中的 IP,然后在容器中用这个 IP。
例如:
宿主机 IP:
192.168.1.100MySQL:
192.168.1.100:3306
容器配置里这样写:
前提是:
宿主机防火墙允许外部访问 3306(至少允许来自 Docker 网桥网段的访问)
MySQL 监听的是
0.0.0.0:3306或该网卡 IP,而不是只绑定127.0.0.1
MySQL 配置示例(my.cnf):
2. 使用 host.docker.internal(Docker Desktop 推荐)
在 Windows / macOS 上,用 Docker Desktop 时,Docker 帮你准备了一个特殊域名:
它在容器里会自动解析到宿主机的 IP。
所以你可以在容器里这样配置数据库:
然后在容器里测试:
如果通了,那就 OK 了。
在一些 Linux 环境下默认没有
host.docker.internal,可以在运行容器时手动加一条 hosts 映射:docker run --add-host=host.docker.internal:宿主机IP ...
3. 使用 --network=host 直连宿主机网络(仅限 Linux)
在 Linux 上,你可以让容器直接共享宿主机网络栈:
或者 docker-compose:
此时:
容器与宿主机处于同一个网络命名空间
在容器里访问
127.0.0.1:3306就 真的是宿主机的 3306
优点:
配置简单,很多“访问宿主机”的问题瞬间消失
缺点:
端口直接暴露到宿主机,端口可能冲突
隔离性下降,安全性也稍差一些
Windows / macOS 不支持这个模式,只适用于 Linux
4. 干脆把数据库也放进 Docker(最推荐的生产方案)
从实践来看,更推荐的方式是:
不要依赖宿主机安装的 MySQL,而是用 Docker 起一个 MySQL 容器。
这样:
MySQL 作为一个
service出现在docker-compose.yml里Nacos / 应用容器只需要用
服务名访问它,例如mysql:3306
示例:
在 Docker 的自定义网络里,mysql 这个服务名就像一个域名,会被解析到对应容器的 IP,各个容器之间访问就非常自然。
五、常见错误排查小结
如果你在 Docker 里访问宿主机服务遇到问题,可以按这个 checklist 查:
是否误用了
127.0.0.1?在容器里,
127.0.0.1只指向容器自己。宿主机 IP 写的对不对?
在 Linux:用
ip addr查实际 IP,比如192.168.1.x;在 Docker Desktop:优先尝试
host.docker.internal。服务监听地址是否只绑定
127.0.0.1?MySQL / Redis / 其他服务需要绑定
0.0.0.0或宿主机局域网 IP。防火墙和端口是否开放?
firewalld/iptables有可能挡住容器过来的请求。日志里报的是什么错?
Access denied for user:账号/密码/权限问题;Connection refused:端口没开或 IP 不对;Timeout:网络不通、防火墙或 IP 写错。
六、总结:一句话的本质原因
在 Docker 容器中,
127.0.0.1指的是容器自身,而不是宿主机。想访问宿主机,必须用宿主机的 IP、host.docker.internal,或使用--network=host(Linux),而不是直接写127.0.0.1。
版权声明: 本文为 InfoQ 作者【玄兴梦影】的原创文章。
原文链接:【http://xie.infoq.cn/article/b6c9e857317d1e8f9b6e3bd61】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。







评论