CLIProxyAPI Docker 部署排错全攻略
CLIProxyAPI Docker 部署排错全攻略
摘要:本文针对 Docker Toolbox (VirtualBox) + Mac Intel 环境下部署 CLIProxyAPI 的常见问题,提供了完整的排错指南。涵盖 CGO 线程创建失败、config.yaml 挂载冲突、服务无法访问等五大核心问题,并给出最终正确的启动命令、配置示例和验证方法。重点解决 seccomp 系统调用拦截、文件/目录挂载冲突、Docker Toolbox 网络访问等典型痛点,帮助用户快速定位并解决问题。
适用环境:Docker Toolbox (VirtualBox) + Mac Intel + eceasy/cli-proxy-api:latest
版本:CLIProxyAPI v7.2.128
一、环境背景
| 项目 | 值 |
|---|---|
| 操作系统 | macOS (Intel) |
| Docker 环境 | Docker Toolbox + VirtualBox(非 Docker Desktop) |
| Docker 版本 | v19.03.12 |
| 镜像 | eceasy/cli-proxy-api:latest |
| Docker Machine 名称 | master(不是 default) |
| 虚拟机 IP | 192.168.99.100 |
| 宿主机 Host-Only 网卡 | vboxnet5 / 192.168.99.1 |
重要前提:Docker Toolbox 运行在 VirtualBox 虚拟机内,Mac 本机 127.0.0.1 不能直接访问容器端口,必须使用虚拟机 IP
192.168.99.100。
二、问题 1:CGO 线程创建失败
现象
runtime/cgo: pthread_create failed: Operation not permitted
SIGABRT: abort
根因
镜像内部新版 glibc 调用 clone3 系统调用,Docker Toolbox 虚拟机的 seccomp 安全策略拦截了该系统调用,CGO 代码创建线程直接崩溃。
解决方案
启动命令增加 --security-opt seccomp=unconfined 参数,临时放开 seccomp 系统调用限制。
docker run --rm \
--security-opt seccomp=unconfined \
...
不推荐使用
--privileged,权限过大。
三、问题 2:config.yaml is a directory
现象
failed to read config file: read /CLIProxyAPI/config.yaml: is a directory
根因
宿主机的 config.yaml 文件不存在。Docker Desktop / Toolbox 在挂载时,如果源文件不存在,会自动把容器内目标路径创建成文件夹,于是程序读取配置文件时报错。
排查命令
ls -la /path/to/config.yaml
# 如果输出是 d 开头(directory),说明是文件夹,不是文件
解决方案
- 删除错误生成的目录
rm -rf /path/to/config.yaml
- 创建真实的配置文件
touch /path/to/config.yaml
# 写入配置内容
四、问题 3:not a directory(挂载冲突)
现象
mounting ...config.yaml ... caused "not a directory"
Are you trying to mount a directory onto a file (or vice-versa)?
根因
镜像构建时,/CLIProxyAPI/config.yaml 已经被创建成了一个目录(镜像层的坑)。当你尝试把宿主机文件挂载到这个已存在的目录上时,Docker 直接拒绝。
验证
docker run --rm --entrypoint ls eceasy/cli-proxy-api:latest -ld /CLIProxyAPI/config.yaml
# 输出开头是 d → 确认是目录
解决方案
不要直接挂载单个文件到 /CLIProxyAPI/config.yaml,改为:
- 将配置文件挂载到容器内全新的无关路径
- 通过
--config启动参数指定配置文件位置
五、问题 4:程序二进制文件丢失
现象
exec: "./CLIProxyAPI": stat ./CLIProxyAPI: no such file or directory
根因
为了绕过上一个问题,把整个 /CLIProxyAPI 目录用宿主机目录覆盖挂载,结果把容器里的程序二进制文件 ./CLIProxyAPI 给覆盖没了,容器启动找不到可执行程序。
解决方案
配置文件挂载到独立路径,不要覆盖 /CLIProxyAPI 整个目录。
六、问题 5:服务启动但访问不了
现象
容器日志显示 API server started successfully on: 0.0.0.0:8317,但浏览器 / curl 访问 http://127.0.0.1:8317 连接失败。
根因
Docker Toolbox 运行在 VirtualBox 虚拟机内,-p 8317:8317 映射的是虚拟机的 8317 端口,不是 Mac 主机的 8317 端口。
排查步骤
第一步:确认 docker-machine 名称
docker-machine ls
# 注意 ACTIVE 带 * 的那台机器名
坑:默认机器名不一定是
default,可能是master或其他名字。docker-machine ip不带参数会去找default,如果你的机器名不同就会报Host is not running。
第二步:获取虚拟机 IP
docker-machine ip master # 替换成你的机器名
# 预期输出:192.168.99.100
第三步:虚拟机内部验证服务
docker-machine ssh master
# 在虚拟机内执行
curl -v http://127.0.0.1:8317
- 虚拟机内部通 → 容器服务正常,问题在 Mac 到虚拟机的网络层
- 虚拟机内部不通 → 容器程序本身有问题,看容器日志
第四步:Mac 主机访问虚拟机 IP
curl -v http://192.168.99.100:8317
如果 Mac 访问虚拟机 IP 超时
检查 VirtualBox 网络配置:
- 打开 VirtualBox → 选中
master虚拟机 → 设置 → 网络 - 确认有一张 Host-Only Adapter 网卡,绑定
vboxnet5 - Mac 端
ifconfig能看到vboxnet5且 IP 为192.168.99.1
想要 Mac 本机 127.0.0.1 直接访问
用 socat 做端口转发:
brew install socat
socat TCP-LISTEN:8317,fork,reuseaddr TCP:192.168.99.100:8317
该命令前台运行,关闭终端转发失效。
七、最终正确启动命令
目录结构
cliproxy-local/
├── conf/
│ └── config.yaml # 配置文件
├── auth-dir/ # 认证数据目录
└── plugins-dir/ # 插件目录
启动命令
cd /path/to/cliproxy-local
docker run --rm \
--security-opt seccomp=unconfined \
-p 8317:8317 \
-v $(pwd)/conf:/opt/clip-conf \
-v $(pwd)/auth-dir:/root/.cli-proxy-api \
-v $(pwd)/plugins-dir:/CLIProxyAPI/plugins \
eceasy/cli-proxy-api:latest \
./CLIProxyAPI --config /opt/clip-conf/config.yaml
关键点说明
| 参数 | 作用 |
|---|---|
--security-opt seccomp=unconfined | 解决 CGO clone3 系统调用被拦截 |
-v $(pwd)/conf:/opt/clip-conf | 配置文件挂载到独立路径,不覆盖程序目录 |
./CLIProxyAPI --config /opt/clip-conf/config.yaml | 通过启动参数指定配置文件路径,绕开镜像内 /CLIProxyAPI/config.yaml 目录冲突 |
八、config.yaml 最简配置示例
host: ""
port: 8317
auth-dir: "/root/.cli-proxy-api"
remote-management:
allow-remote: true
secret-key: "Clip@Admin2026"
disable-control-panel: false
api-keys:
- "sk-clip-local-789abc01"
plugins:
enabled: false
dir: "/CLIProxyAPI/plugins"
debug: true
# 上游 OpenAI 兼容接口示例
openai-compatibility:
- name: glm52-gateway
base-url: "https://your-upstream-gateway/v1"
api-key-entries:
- api-key: "sk-real-upstream-api-key-here"
models:
- name: "glm-5.2"
alias: "glm-5.2"
# 请求参数预处理:自动钳位 thinking.budget_tokens 到 1024 以内
request-modifier: |
function modify(req) {
if (req.body && req.body.thinking && req.body.thinking.budget_tokens) {
req.body.thinking.budget_tokens = Math.min(req.body.thinking.budget_tokens, 1024);
}
return req;
}
YAML 必须使用 2 空格缩进,绝对不能用 Tab。
九、验证方法
1. 检查容器状态
docker ps
# 确认 STATUS 为 Up,PORTS 有 0.0.0.0:8317->8317/tcp
2. 查看容器日志
docker logs -f <容器ID>
# 正常日志末尾应包含:
# API server started successfully on: 0.0.0.0:8317
3. 测试 API 连通性
# 虚拟机 IP 访问(Docker Toolbox 必须用这个)
curl http://192.168.99.100:8317/
# 正常返回:
# {
# "endpoints": [...],
# "message": "CLI Proxy API Server"
# }
4. 测试模型列表
curl http://192.168.99.100:8317/v1/models \
-H "Authorization: Bearer sk-clip-local-789abc01"
5. 管理后台
浏览器访问:http://192.168.99.100:8317/management.html
登录密码:Clip@Admin2026
十、排错速查表
| 报错 | 原因 | 解决方案 |
|---|---|---|
pthread_create failed: Operation not permitted | seccomp 拦截 clone3 | 加 --security-opt seccomp=unconfined |
config.yaml: is a directory | 宿主机文件不存在,Docker 自动建了目录 | 删除目录,创建真实文件 |
not a directory | 容器内目标路径已是目录,文件挂不进去 | 挂载到新路径,用 --config 指定 |
stat ./CLIProxyAPI: no such file or directory | 挂载整个目录覆盖了程序二进制 | 不要覆盖 /CLIProxyAPI 整个目录 |
| 127.0.0.1 访问不通 | Docker Toolbox 端口映射在虚拟机里 | 用虚拟机 IP 192.168.99.100 访问 |
Host is not running | docker-machine 机器名不对 | docker-machine ls 看正确名字 |
| YAML 解析失败 | 用了 Tab 或缩进不对 | 全部换成 2 空格缩进 |
十一、相关报错补充(API 层面)
Thinking.BudgetTokens 超限
field Thinking.BudgetTokens invalid, should be in (-∞, 1024]
上游网关限制 thinking.budget_tokens 最大 1024,在 config.yaml 的模型配置中加 request-modifier 钩子自动钳位(见第八节配置示例)。
TPM 耗尽
inference tpm exhausted
每分钟 token 配额用完,等几十秒滑动窗口释放,或降低并发 / 缩短上下文。
更多推荐
所有评论(0)