如何从 Docker 容器内部访问宿主机上的端口?
容器内访问宿主机服务,用特殊域名 host.docker.internal:端口(Linux 需 --add-host host.docker.internal:host-gateway),或宿主机内网 IP;原生 Linux 桥接访问需服务监听可达宿主地址;Docker Desktop 转发行为不同,不必一律绑定 0.0.0.0。
做法:容器内把 localhost 换成宿主机的地址——Mac/Windows 直接用 host.docker.internal:端口;Linux 启动时加 --add-host host.docker.internal:host-gateway 后用同样域名,或直接用宿主机的内网 IP。原生Linux桥接容器需服务绑定可达的宿主地址,仅回环通常不可达;Docker Desktop转发行为不同,不必一律改成0.0.0.0。地址指Docker daemon所在主机,远程context不一定是当前电脑。
典型场景
宿主机上跑着 MySQL(3306),容器里的应用要连它:
# 容器内测试连通性
mysql -h host.docker.internal -P 3306 -u app -p # 使用MySQL客户端
# Linux 启动容器时先加映射
docker run -d --add-host host.docker.internal:host-gateway myapp
docker-compose:
services:
app:
extra_hosts:
- "host.docker.internal:host-gateway"
用宿主机 IP 的备选方案
查宿主机在 docker 网桥上的地址:
ip addr show docker0 | grep inet # 通常是 172.17.0.1
容器内以MySQL协议连接该地址的3306端口,不使用HTTP。缺点:网桥 IP 可能随 Docker 配置变化,不如 host-gateway 稳定。
三个常见失败原因
- 服务只听 127.0.0.1:容器流量从网桥进来,不算本地回环,应绑定允许容器访问的具体宿主地址,避免不必要地开放所有接口(注意评估暴露面,配合防火墙只放行内网)。
- 防火墙拦截:宿主机 iptables/firewalld 拦了 docker0 网段的入站。
- 容器内还在用 localhost:容器内 localhost 是容器自己,不是宿主机。
反向问题:宿主机访问容器
方向反过来时用端口映射 docker run -p 8080:80,宿主机访问 localhost:8080——两个方向机制不同,别混淆。
常见问题(FAQ)
Q:K8s 里 Pod 怎么访问节点上的服务?
A:用节点 IP(status.hostIP 可注入环境变量)或 hostNetwork;推荐把服务也容器化或用 Service 抽象。
Q:host.docker.internal 能 ping 通但连不上端口?
A:ping只检查ICMP,不能证明TCP端口与数据库认证可用;还需检查服务、地址、端口和策略,按上面三点逐个查。
Q:生产环境推荐这种做法吗?
A:权宜之计可以,长期建议服务全部容器化编排,或数据库用云服务的内网地址,减少宿主机耦合。