从容器内连接宿主机服务:几种方式详解与排错
容器访问宿主机服务的三种方式:host.docker.internal 域名、docker0 网桥 IP(Linux)、host 网络模式;连接不通时按监听地址、防火墙、DNS 解析三步排查。
速查:Mac/Windows 容器内用 host.docker.internal:端口;Linux 可加 --add-host host.docker.internal:host-gateway 复用同写法,或直接访问 docker0 网桥 IP(通常 172.17.0.1);Linux 上还可用 --network host 让容器共享宿主机网络栈,localhost 即宿主机。连不通时按"服务监听地址 → 防火墙 → DNS/路由"顺序排查。
方式一:host.docker.internal(跨平台统一写法)
# 容器内
curl http://host.docker.internal:8080
Docker Desktop(Mac/Windows)内置解析。Linux(Docker 20.10+)需显式加映射:
docker run --add-host host.docker.internal:host-gateway myapp
方式二:docker0 网桥 IP(Linux 原生)
ip addr show docker0 | grep 'inet ' # 查得,如 172.17.0.1
容器内直接访问 http://172.17.0.1:8080。仅适用于相应原生Linux网桥拓扑;自定义网络、rootless或Desktop不保证存在相同docker0地址。
方式三:host 网络模式(Linux)
docker run --network host myapp
容器与宿主机共用网络栈,localhost:8080 直通宿主机服务。代价:无网络隔离、端口直接冲突、Docker Desktop4.34+可选择启用host networking,主要限TCP/UDP且与原生Linux实现边界不同。
连不通?三步排查
- 服务监听地址:宿主机上
ss -ltnp | grep 8080,Linux网桥路径需监听容器可达的主机地址(例如网桥地址或经允许的内网地址),不必开放所有接口;127.0.0.1:8080对网桥来的流量不响应。 - 防火墙:
iptables -L -n/firewall-cmd --list-all,确认 docker0 网段入站放行。 - 域名解析:容器内
getent hosts host.docker.internal,解析不到说明没加--add-host。
常见问题(FAQ)
Q:docker-compose 里怎么写?
A:extra_hosts: ["host.docker.internal:host-gateway"],然后服务内统一用该域名。
Q:能访问宿主机的 unix socket 吗?
A:可以挂载进来(如 -v /var/run/mysqld.sock:/sock/mysqld.sock),比走 TCP 更直接,需daemon所在主机实际存在该socket、UID/GID与权限兼容;Desktop或远端daemon不等同于CLI本机。
Q:Swarm/K8s 环境下呢?
A:访问节点既有服务可用可达节点IP并检查监听/网络策略;hostPort是把Pod服务暴露到节点,并不是访问节点服务的必要条件,hostNetwork也有隔离代价;长期方案是把依赖服务也纳入编排统一管理。