docker无法连接到ollama服务的问题排查和解决方案
一、环境背景
服务端(Ollama):运行于 Windows 宿主机上。属于非系统级服务,可通过桌面快捷方式(羊驼图标)或命令行(ollama serve)手动启动。
客户端(Docker):运行于 WSL2 Ubuntu 子系统内的原生 Docker 引擎,通过命令行执行docker compose up进行容器编排。(注意:未使用 Docker Desktop)
故障现象:在 WSL2 环境下运行的 Docker 容器内,应用始终无法连接到 Windows 宿主机的 Ollama API 服务。
二、前期排查过程(排除常规网络与服务问题)
在定位到根本原因前,已确认以下配置均正确无误:
1. 代码与配置:代码及docker-compose.yml中的环境变量均指向http://host.docker.internal:11434。
2. 监听地址:已在 Windows 系统环境变量中设置OLLAMA_HOST=0.0.0.0,确保 Ollama 允许外部访问。
3. 防火墙策略:已在 Windows 高级安全防火墙中添加名为 “ollama docker access” 的入站规则,放行 TCP 协议的 11434 端口,且授权对象设为“任何”。
4. 网络配置文件:Windows 当前网络连接属性已设置为“专用网络”(Private),排除了公用网络的严格拦截限制。
5. 进程监听验证:在 Windows CMD 中执行netstat -ano | findstr 11434,确认输出包含tcp 0.0.0.0:11434 ... LISTENING,证明 Ollama 服务已正常启动并正确绑定了所有网卡接口。
尽管上述网络层和服务层的配置全部正确,但无论是命令行启动还是托盘启动 Ollama,WSL2 中的 Docker 容器依然无法建立连接。
三、根本原因分析:DNS 解析缺失
经过深入排查,发现导致该问题的核心并非 Ollama 未正确监听或 Windows 防火墙拦截,而是 WSL2 原生 Docker 环境的 DNS 机制差异。
host.docker.internal的本质:这个特殊的内部域名是 Docker Desktop 为了便利 Windows/macOS 容器与宿主机通信而专门注入到容器 DNS 解析器中的功能。
原生 Docker 的盲区:在纯 WSL2 Ubuntu + 原生 Docker 引擎的环境下,并没有集成 Docker Desktop 的这一特性。因此,容器内部的 Linux 系统根本无法解析host.docker.internal这个域名。
结果:由于 DNS 解析失败,容器甚至找不到目标 IP,网络请求直接被丢弃,从而表现为“无法连接”。
四、最终解决方案:显式指定宿主机网关 IP
既然自动的 DNS 解析失效,我们需要手动将容器的请求指向 WSL2 虚拟网卡的真实网关 IP。
- 获取真实 IP:在 Windows 终端执行
ipconfig,找到名为vEthernet (WSL)的网络适配器,记录其 IPv4 地址(例如:172.28.0.1)。 - 修改配置:将项目代码以及
docker-compose.yml文件中所有的http://host.docker.internal:11434替换为真实的网关 IP,即http://172.28.0.1:11434。 - 重启生效:重新执行
docker compose up,容器即可成功穿透网络边界,正常连接到 Windows 端的 Ollama 服务。
五. 修改内容相关截图:
代码修改如下:
总结经验:http://127.0.0.1:11434:
适用场景:Web 应用与 Ollama 均直接运行在 Windows 宿主机上(未使用 Docker)。
核心原理:此时客户端与服务端处于同一个操作系统环境中,直接使用本地回环地址(Localhost)进行内部通信即可。
http://host.docker.internal:11434
适用场景:项目部署在 Docker Desktop (Windows/macOS) 中时。
核心原理:这是 Docker Desktop 专门为容器访问宿主机提供的一个特殊 DNS 域名。它充当了容器与宿主机之间的“翻译官”,自动解析到宿主机的真实 IP。
http://172.31.64.1:11434(注:IP因机器而异)
适用场景:项目部署在 WSL2 原生 Docker(纯命令行环境,无 Docker Desktop)中时。
核心原理:原生 Docker 引擎不包含上述的特殊 DNS 功能,导致容器无法解析 host.docker.internal。因此,必须手动通过 ipconfig 找到 WSL2 虚拟网卡(vEthernet (WSL))的真实 IPv4 网关地址来进行硬编码连接。
docker-compose.yml文件关于web端的内容如下:
在引入 Celery Worker 等后台任务队列的场景下,切勿遗漏对 Worker 容器的网络配置。必须在 docker-compose.yml 中为 Worker 显式声明 Ollama 的访问地址(如 WSL2 网关 IP)。否则,Worker 在执行 RAGAS 评估等依赖大模型的推理任务时,将因无法建立网络连接而导致任务失败。
额外的小建议:
由于 WSL2 的虚拟网卡 IP 偶尔可能会因为系统重启或网络重置而发生变化,如果希望以后不用每次都去查 IP,也可以在启动 Docker 容器时加上 extra_hosts 参数来手动注入这个域名:
extra_hosts: - "host.docker.internal:host-gateway"(注:虽然 host-gateway 在某些极老版本的 WSL2 环境下可能不生效,但在较新的 Docker Engine 中通常能完美解决原生 Docker 的 DNS 问题。如果不行,“直连真实 IP” 依然是最稳妥的终极方案. )
希望我这个倒霉蛋的经验能帮到你们,解决了的话帮忙赞一下谢谢~我会开心很久的!
