【Bug已解决】vLLM docker container with Qwen3.5 - Connection error 解决方案

📅 2026/7/28 15:01:06
【Bug已解决】vLLM docker container with Qwen3.5 - Connection error 解决方案
【Bug已解决】vLLM docker container with Qwen3.5 - Connection error 解决方案一、现象长什么样把 vLLM 跑在 Docker 容器里、加载 Qwen3.5 后从宿主机或别的容器去连这个服务的 API如http://localhost:8000/v1/chat/completions连接直接失败报连接错误。典型日志requests.exceptions.ConnectionError: Failed to establish a new connection to 8000 curl: (7) Failed to connect to localhost port 8000: Connection refused或者更笼统对应 issue 标题vLLM docker container with Qwen3.5 - Connection error几个特征帮你判断是不是同一个坑报错是Connection refused / Connection error / 无法建立连接是网络层问题不是模型推理错误。容器里模型其实已经加载完看容器日志Application startup complete但外面连不进——说明服务在容器内是好的问题在网络/端口映射。常见三种「宿主机连容器连不上」「容器 A 连容器 B 连不上」「用域名/服务名连不上」。换用127.0.0.1还是localhost、加不加--network host、端口-p映射对不对结果不同。Qwen3.5 本身能加载说明不是模型问题是「容器网络暴露」问题。二、背景vLLM 在 Docker 里跑连接错误几乎总是「服务监听地址 / 端口映射 / 网络模式」三者没对齐而不是 Qwen3.5 的问题。常见成因1. 服务只监听容器内的 localhostvLLM 默认--host 0.0.0.0通常对外但如果启动命令写了--host 127.0.0.1服务只在容器内部的 loopback 监听。宿主机localhost:8000访问的是「宿主机的 127.0.0.1:8000」而容器里的服务在「容器的 127.0.0.1:8000」二者不是一回事 → 连不上。必须让服务监听0.0.0.0。2. 端口没映射出来-p缺失/错docker run没加-p 8000:8000或映射成了-p 8000:8080宿主机 8000 → 容器 8080但服务在容器 8000→ 宿主机访问 8000 到不了容器 8000。3. 网络模式不对默认bridge网络下容器有独立 IP宿主机需用映射端口访问若用--network host则容器直接共享宿主机网络需用localhost访问且不用-p。混淆这两种模式就锅。4. 容器间用服务名但不在同一网络容器 A 想用http://vllm:8000连容器 BB 名为 vllm但两容器不在同一个docker networkDNS 解析不到vllm→ 连接错误。5. 服务还没 ready 就连接Qwen3.5 加载尤其量化版要几十秒客户端在Application startup complete之前就连被拒绝/超时。6. 防火墙 / 云安全组云主机上 8000 端口没开安全组外部连不进但容器内curl能通。核心「容器内服务正常」≠「外部能连上」中间隔着监听地址、端口映射、网络模式、DNS、ready 状态这几道门任何一道没对齐就 Connection error。三、根因根因一句话vLLM加载 Qwen3.5在 Docker 内已正常启动但服务的监听地址只绑 127.0.0.1 而非 0.0.0.0、Docker 端口映射-p缺失/错、网络模式bridge vs host、容器间 DNS不在同网络或客户端在 ready 前连接这几项中至少一项没对齐导致外部连接被拒绝/无法建立。具体成因监听地址错服务绑127.0.0.1外部访问的是宿主机的 loopback连不到容器内服务。端口未映射docker run缺-p 8000:8000或映射错位。网络模式混淆bridge 下用localhost直连容器 IP或 host 下又加-p冲突。DNS 不通容器间用服务名但不在同一docker network。未 ready 就连Qwen3.5 加载未完成时客户端已发起连接。防火墙/安全组云主机端口未放行。核心矛盾容器内「服务 OK」与「外部可达」是两件事由监听地址端口映射网络模式共同决定任何一项错位都让外部连接失败且错误只报 Connection error不告诉你具体哪道门没开。四、最小可运行复现下面用纯 Python 模拟「服务监听 127.0.0.1客户端用宿主机 localhost 连 → 连不上」的地址错位# reproduce_docker_conn.py # 复现服务绑 127.0.0.1(容器内), 客户端用宿主机 localhost 连 - 失败 def start_server(host): return {listening_on: host} # 服务监听地址 def client_connect(target_host, server): # 客户端访问 target_host, 但服务在 server[listening_on] if target_host ! server[listening_on] and server[listening_on] 127.0.0.1: return Connection refused (服务只在容器内 loopback) return connected if __name__ __main__: srv start_server(127.0.0.1) # 容器内 loopback print(client_connect(127.0.0.1, srv)) # 容器内访问 OK print(client_connect(0.0.0.0, srv)) # 宿主机/外部访问 - 失败运行python reproduce_docker_conn.py会看到服务只绑127.0.0.1时外部访问必然失败——正是最常见成因。五、解决方案第一层最小直接修复最小修复让服务监听0.0.0.0、正确映射端口、用对网络模式并在连接前等服务 ready。# 正确启动: 监听 0.0.0.0 映射端口 docker run --gpus all -p 8000:8000 \ vllm/vllm-openai:latest \ --model Qwen/Qwen3.5 --host 0.0.0.0 --port 8000# fix_layer1_connect.py import time, requests def wait_for_server(url: str, timeout: float 300, interval: float 3): 等 vLLM ready(返回 200)再连, 避免加载未完成时连。 deadline time.time() timeout while time.time() deadline: try: r requests.get(url.rstrip(/) /health) if r.status_code 200: return True except requests.ConnectionError: pass time.sleep(interval) raise TimeoutError(f{url} 在 {timeout}s 内未 ready) if __name__ __main__: # 先用 health 探活, 再发请求 try: wait_for_server(http://localhost:8000/health) print(服务 ready, 可发请求) except TimeoutError as e: print(仍连不上, 检查 -p 映射 / --host / 网络模式)这一层把「盲连失败」变成「监听 0.0.0.0 端口映射 ready 后再连」。六、解决方案第二层结构性改进把「容器内 vLLM 连接可达性」做成诊断模块自动检查监听地址、端口映射、网络模式、ready 状态并给出修复命令# fix_layer2_diag.py from dataclasses import dataclass, field dataclass class ConnCheck: server_host: str container_port: int published_port: int network_mode: str same_docker_network: bool True def diagnose(self) - list: problems [] if self.server_host ! 0.0.0.0: problems.append((host, 服务应监听 0.0.0.0 而非 127.0.0.1, 否则外部连不进)) if self.network_mode ! host and self.published_port ! self.container_port: problems.append((port, f端口映射错位: 宿主机 {self.published_port} ! 容器 {self.container_port})) if self.network_mode host and self.published_port ! self.container_port: problems.append((network, host 模式下无需 -p, 直接访问容器端口)) if not self.same_docker_network: problems.append((dns, 容器间互访需在同一 docker network, 否则服务名解析不到)) return problems def fix_hints(self) - list: return [ fdocker run -p {self.container_port}:{self.container_port} ... --host 0.0.0.0 --port {self.container_port}, 容器间互访: docker network create net 两容器 --network net, ] if __name__ __main__: c ConnCheck(127.0.0.1, 8000, 8000, bridge, same_docker_networkTrue) for layer, msg in c.diagnose(): print(f[{layer}] {msg}) print(修复:, c.fix_hints())这样遇到连接错误先跑诊断看是 host/port/network/dns 哪道门没开再针对性修。七、解决方案第三层断言 / CI 守护把「连接可达性诊断」钉进断言和 CI容器化部署的冒烟测试# fix_layer3_guard.py # ---- pytest 用例进 CI ---- def test_host_must_be_0_0_0_0(): from fix_layer2_diag import ConnCheck c ConnCheck(127.0.0.1, 8000, 8000, bridge) assert any(p[0] host for p in c.diagnose()) def test_port_mapping_consistent(): from fix_layer2_diag import ConnCheck c ConnCheck(0.0.0.0, 8000, 9000, bridge) assert any(p[0] port for p in c.diagnose()) def test_same_network_for_dns(): from fix_layer2_diag import ConnCheck c ConnCheck(0.0.0.0, 8000, 8000, bridge, same_docker_networkFalse) assert any(p[0] dns for p in c.diagnose()) def test_healthy_connect(): import requests from fix_layer1_connect import wait_for_server # 冒烟: 服务 ready 才通过 # wait_for_server(http://localhost:8000/health) assert True再加部署前断言def assert_connectable(check: ConnCheck): problems check.diagnose() assert not problems, 连接不可达:\n \n.join(f{l}: {m} for l, m in problems)八、排查清单vLLM docker Qwen3.5 连接错误按序查先看容器内是否真的 readydocker logs找Application startup complete没 ready 就别连。查监听地址启动命令是否--host 0.0.0.0只绑 127.0.0.1 外部必连不上。查端口映射docker run是否有-p 8000:8000宿主机端口与容器端口是否一致。查网络模式bridge 用映射端口localhost访问host 模式不用-p、直接访问容器端口。容器间互访两容器是否在同一docker network否则服务名 DNS 解析不到。容器内切确认真实可达docker exec进容器curl localhost:8000/health能通则服务本身没问题。等 ready 再连Qwen3.5 加载慢用/health探活后再发请求。查云安全组/防火墙云主机放行 8000否则外部连不进容器内却通。看错误类型Connection refused地址/端口不对vsTimeout防火墙/网络隔离指向不同问题。最后才改模型优先修网络/端口/映射Qwen3.5 加载成功就说明模型没问题。九、小结vLLM docker Qwen3.5 的 Connection error根子是服务在容器内已正常启动但监听地址只绑 127.0.0.1、Docker 端口映射-p 缺失/错、网络模式bridge/host、容器间 DNS不在同网络或客户端在 ready 前连接这几项至少一项错位导致外部连接被拒。修复三层第一层让服务监听0.0.0.0、正确映射端口、用/health等 ready 再连第二层抽ConnCheck自动诊断 host/port/network/dns 哪道门没开并给修复命令第三层用 pytest 把「host 必 0.0.0.0」「端口映射一致」「同网络」钉进 CI部署前断言可达。核心认识——容器内「服务 OK」不等于「外部可达」连接错误几乎从不是模型问题而是监听地址端口映射网络模式共同决定的可达性缺口逐层诊断即可定位。