写点什么

Docker 里面不能使用 127.0.0.1 来访问宿主机

作者:玄兴梦影
  • 2025-12-11
    云南
  • 本文字数:2545 字

    阅读完需:约 8 分钟

在 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 端口

所以,一旦你进入容器:

docker exec -it my-app /bin/bashcurl 127.0.0.1:3306
复制代码

此时你访问的不是宿主机的 MySQL,而是“my-app 容器自己”的 3306。大部分情况下,这个端口根本没开,于是就连接失败——这就是“Docker 里不能用 127.0.0.1 访问宿主机”的根源。


二、Docker 默认网络:容器和宿主机是“邻居”,不是“合体”

绝大部分情况下,你起容器的时候并没有显式配置网络模式,Docker 就会用默认的 bridge 网络,例如:

docker run -d --name my-app -p 8080:8080 my-image
复制代码

此时网络关系大致是这样:

  • 宿主机:有自己的网卡(如 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 / 其他服务

  • 在容器配置里写成:

MYSQL_SERVICE_HOST: 127.0.0.1MYSQL_SERVICE_PORT: 3306
复制代码

结果一连就报错:连接超时 / Connection refused / communications link failure

原因就是:容器里的 127.0.0.1 根本不是宿主机,而是容器自己,而且容器自己根本没开 3306 端口。


四、那怎么正确访问宿主机?

1. 使用宿主机的真实 IP(通用做法)

Linux 环境中最通用的办法就是:查出宿主机在局域网中的 IP,然后在容器中用这个 IP。

例如:

  • 宿主机 IP:192.168.1.100

  • MySQL:192.168.1.100:3306

容器配置里这样写:

environment:  MYSQL_SERVICE_HOST: 192.168.1.100  MYSQL_SERVICE_PORT: 3306
复制代码

前提是:

  • 宿主机防火墙允许外部访问 3306(至少允许来自 Docker 网桥网段的访问)

  • MySQL 监听的是 0.0.0.0:3306 或该网卡 IP,而不是只绑定 127.0.0.1

MySQL 配置示例(my.cnf):

[mysqld]bind-address = 0.0.0.0
复制代码



2. 使用 host.docker.internal(Docker Desktop 推荐)

在 Windows / macOS 上,用 Docker Desktop 时,Docker 帮你准备了一个特殊域名:

host.docker.internal
复制代码

它在容器里会自动解析到宿主机的 IP。

所以你可以在容器里这样配置数据库:

environment:  MYSQL_SERVICE_HOST: host.docker.internal  MYSQL_SERVICE_PORT: 3306  MYSQL_SERVICE_USER: root  MYSQL_SERVICE_PASSWORD: 123456
复制代码

然后在容器里测试:

ping host.docker.internal# 或者telnet host.docker.internal 3306
复制代码

如果通了,那就 OK 了。

在一些 Linux 环境下默认没有 host.docker.internal,可以在运行容器时手动加一条 hosts 映射:

docker run --add-host=host.docker.internal:宿主机IP ...


3. 使用 --network=host 直连宿主机网络(仅限 Linux)

在 Linux 上,你可以让容器直接共享宿主机网络栈:

docker run --network=host ...
复制代码

或者 docker-compose

services:  my-app:    image: my-image    network_mode: host
复制代码

此时:

  • 容器与宿主机处于同一个网络命名空间

  • 在容器里访问 127.0.0.1:3306真的是宿主机的 3306

优点:

  • 配置简单,很多“访问宿主机”的问题瞬间消失

缺点:

  • 端口直接暴露到宿主机,端口可能冲突

  • 隔离性下降,安全性也稍差一些

  • Windows / macOS 不支持这个模式,只适用于 Linux


4. 干脆把数据库也放进 Docker(最推荐的生产方案)

从实践来看,更推荐的方式是:

不要依赖宿主机安装的 MySQL,而是用 Docker 起一个 MySQL 容器。

这样:

  • MySQL 作为一个 service 出现在 docker-compose.yml

  • Nacos / 应用容器只需要用 服务名 访问它,例如 mysql:3306

示例:

version: '3.8'
services: mysql: image: mysql:5.7 container_name: my-mysql environment: MYSQL_ROOT_PASSWORD: 123456 MYSQL_DATABASE: nacos ports: - "3306:3306"
nacos: image: nacos/nacos-server:v2.0.3 container_name: nacos depends_on: - mysql environment: SPRING_DATASOURCE_PLATFORM: mysql MYSQL_SERVICE_HOST: mysql # 注意这里是服务名,不是 IP MYSQL_SERVICE_PORT: 3306 MYSQL_SERVICE_DB_NAME: nacos MYSQL_SERVICE_USER: root MYSQL_SERVICE_PASSWORD: 123456
复制代码

在 Docker 的自定义网络里,mysql 这个服务名就像一个域名,会被解析到对应容器的 IP,各个容器之间访问就非常自然。


五、常见错误排查小结

如果你在 Docker 里访问宿主机服务遇到问题,可以按这个 checklist 查:

  1. 是否误用了 127.0.0.1

    在容器里,127.0.0.1 只指向容器自己。

  2. 宿主机 IP 写的对不对?

    在 Linux:用 ip addr 查实际 IP,比如 192.168.1.x

    在 Docker Desktop:优先尝试 host.docker.internal

  3. 服务监听地址是否只绑定 127.0.0.1

    MySQL / Redis / 其他服务需要绑定 0.0.0.0 或宿主机局域网 IP。

  4. 防火墙和端口是否开放?

    firewalld / iptables 有可能挡住容器过来的请求。

  5. 日志里报的是什么错?

    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

发布于: 刚刚阅读数: 2
用户头像

玄兴梦影

关注

做一个诗意的工程师。 2018-12-30 加入

一个不是诗人的诗人,不是程序员的程序员。

评论

发布
暂无评论
Docker 里面不能使用 127.0.0.1 来访问宿主机_Docker_玄兴梦影_InfoQ写作社区