
Docker 容器如何优雅地访问宿主机网络
前言
有时,我们需要在容器内访问宿主机上的某个服务,例如 MySQL。
方案一
使用 host 模式启动服务。
在默认情况下,Docker 服务会采用桥接模式启动。这意味着 Docker 容器会使用 Docker 自建的虚拟网络,容器之间可以进行通信,但无法直接访问宿主机的网络服务。如果想要让宿主机或其他网络主机访问,Docker 容器需要暴露自身服务的端口映射。
然而,如果采用 host 模式启动,Docker 容器将与宿主机共享同一网络命名空间,即直接使用宿主机的网络。这样,Docker 容器就能使用宿主机的 IP 地址和端口,直接访问宿主机的网络服务。但是,host 模式也有其局限性,比如 Docker 容器之间无法直接通信,且 Docker 容器的网络性能可能会受到影响。
所以此时启动命令可以改成下边这样:
1 | docker run --name one-api -d \ |
这样容器就能直接访问到宿主机的 3000 了。
然而,由于这种模式的限制,实际生产中很少有人使用,因此不建议采用这种方式。相反,我们更推荐采用第二种方案。
方案二
docker 官方提供了一种支持方案,可通过指向 host.docker.internal
来指向宿主机的 IP。参见文档:从容器连接到主机上的服务
但请注意,该方案存在一个局限性:它仅支持 Mac 和 Windows 桌面环境,并不适用于 Linux 系统,因此无法直接在 Linux 中使用。
于是,有人在官方提交了这个 issue:Support host.docker.internal DNS name to host (opens new window)。
在其中的一个回答里,找到了一种可行方案:
按照如上说明,可以使用如下命令进行启动:
1 | # 运行项目 |
于是我在自己的 Mac 以及 Linux 都使用这种方案做了测试,发现是可以的。
需要注意的是,这个功能在 docker 版本过低的时候,可能支持的有问题,所以你的 docker 版本最好不低于 20。
如果使用的是 docker-compose,则通过添加如下内容进行配置:
1 | extra_hosts: |
比如上边的项目改成 docker-compose 部署,就变成下边这样:
1 | version: '3.9' |
现在,你可以在容器内使用 host.docker.internal
这个主机名来访问宿主机。例如,如果你想从容器中访问宿主机上的一个服务,可以使用
1 | curl http://host.docker.internal:PORT |
其中 PORT
是宿主机上运行的服务的端口。
- Thanks for your appreciation. / 感谢您的赞赏