DeepAI Paper Hermes Agent 教程 Docker 重新 build 突然 invalid file request:Hermes 的 runtime data 为什么混进了构建上下文

Docker 重新 build 突然 invalid file request:Hermes 的 runtime data 为什么混进了构建上下文

Docker 构建失败时,很多人第一反应是 Dockerfile 写错了。

但 NousResearch/hermes-agent issue #13925 的坑更隐蔽:第一次 docker compose build 成功,容器跑过一次后,下一次 build 反而失败。

错误类似:

ERROR: failed to build: failed to solve: invalid file request data/.config/pulse/<host>-runtime

看起来像 Docker 本身抽风。

实际是:运行时数据被 bind mount 到项目目录里的 ./data,但 .dockerignore 没排除 data/。容器在 /opt/data 里写出的 dangling symlink 又被下一次 build 当成 build context 打包,最后 Docker tar packer 走到坏链接时直接报错。

一句话:

运行时垃圾进了构建上下文。

复现场景:第一次 build 没事,跑过容器后再 build 就炸

issue 给出的复现很清楚。

先用 compose bind mount:

services:
  hermes:
    build: .
    image: hermes-agent:local
    stdin_open: true
    tty: true
    volumes:
      - ./data:/opt/data

第一次构建:

docker compose build

通常成功,因为此时 data/ 还是空的。

然后运行一次容器:

docker compose run --rm hermes doctor

容器可能在 /opt/data 里写入 XDG / PulseAudio 相关状态。

宿主机上就会看到类似:

ls -la data/.config/pulse/

出现:

<host>-runtime -> /tmp/pulse-<random>

这个 symlink 的目标在容器里存在,但在宿主机上不存在。

于是它变成了 dangling symlink。

下一次:

docker compose build

Docker 打包 build context 时走到这个坏链接,就报:

invalid file request

根因:data/ 是运行时目录,却没进 .dockerignore

Hermes Dockerfile 声明了:

VOLUME /opt/data

compose 又把宿主机的:

./data

挂到容器的:

/opt/data

这本身没问题。

问题是 .dockerignore 没有排除:

data/

所以 Docker build 时会把项目目录下的 data/ 也纳入构建上下文。

data/ 不是源代码。

它是运行时状态目录,里面可能包含:

  • dangling symlinks;
  • Unix sockets;
  • character devices;
  • log files;
  • session history;
  • memory cache;
  • browser / audio / XDG runtime 文件。

这些东西不应该被送进 Docker daemon 作为 build context。


为什么 .gitignore 有还不够?

issue 里还有一个很重要的点:

仓库的 .gitignore 已经包含:

data/

说明项目知道 data/ 是运行时数据,不应该进 Git。

但 Docker build 不看 .gitignore

Docker 看的是:

.dockerignore

这两个文件不是一回事。

所以会出现这种割裂:

Git 不提交 data/,但 Docker build 仍然打包 data/。

这也是很多 Docker 项目会踩的坑。


最小修复:把 data/ 加进 .dockerignore

issue 提出的修复非常小:

 # Environment files
 .env
 
 *.md
+
+# Runtime data (bind-mounted at /opt/data; must not leak into build context)
+data/

这行的意义不只是避免 broken symlink。

它还会让 build context 更干净:

  • 不再上传日志;
  • 不再上传 session;
  • 不再上传 memory state;
  • 不再上传 browser/audio 临时文件;
  • 不再随着运行时间越来越膨胀。

从构建速度、隐私和稳定性上都更合理。


为什么 PulseAudio 会触发?

issue 里提到常见触发点是 PulseAudio。

它会在运行时生成类似:

data/.config/pulse/<host>-runtime -> /tmp/pulse-<random>

这个 target 在容器命名空间里有意义,在宿主机上却可能不存在。

对宿主机 Docker build context packer 来说,它就是一个坏链接。

但这个问题不只限于 PulseAudio。

任何容器写到 /opt/data 的非普通文件都可能触发:

  • socket;
  • device;
  • dangling symlink;
  • 特殊 runtime 文件。

所以根因不是 PulseAudio,而是 runtime data 泄漏进 build context。


排查时怎么确认是这个问题?

如果你遇到:

invalid file request data/...

可以先检查:

find data -xtype l -ls

这会找出 dangling symlink。

也可以看 PulseAudio 目录:

ls -la data/.config/pulse/

如果看到类似:

*-runtime -> /tmp/pulse-...

基本就对上了。

再看 .dockerignore

grep -n '^data/' .dockerignore

如果没有,建议加上。


临时解决方案

方案一:清理 data/ 里的坏链接

find data -xtype l -delete

然后再:

docker compose build

但这只是临时修复。

方案二:把 data/ 加进 .dockerignore

printf '\n# Runtime data\ndata/\n' >> .dockerignore

这是根治方向。

方案三:把运行时数据放到项目目录外

例如:

volumes:
  - /var/lib/hermes/data:/opt/data

这样 build context 根本不会扫描到运行时数据。

方案四:用 named volume

volumes:
  hermes-data:/opt/data

volumes:
  hermes-data:

如果不需要直接在宿主项目目录里看数据,named volume 更干净。


对 DeepAI API 中转站用户的边界说明

这篇问题发生在 Docker build context 和运行时目录隔离层,不在模型 API 层。

DeepAI API 中转站可以作为 Hermes 或其他 Agent 的 OpenAI-compatible 模型入口,解决:

  • Base URL;
  • API Key;
  • 模型调用;
  • 上游模型切换。

但它不能修复:

  • .dockerignore 漏掉 data/
  • bind mount 把 runtime state 写回项目目录;
  • broken symlink 进入 Docker build context;
  • Docker tar packer 报 invalid file request

所以看到 Docker build 报错时,要先看构建上下文,不要把问题归到模型 API。


FAQ

为什么第一次 build 成功,第二次失败?

第一次 data/ 可能是空的。容器运行后写入 runtime files,下一次 build 时这些文件进入 build context,触发错误。

为什么 .gitignore 里有 data/ 还会影响 Docker?

Docker build 不看 .gitignore,它看 .dockerignore

invalid file request data/.config/pulse/... 是什么?

通常是 Docker 打包 build context 时遇到了宿主机上的 dangling symlink 或非普通文件。

删除 data/ 可以吗?

可以临时解决,但可能会删掉运行时状态。更推荐把 data/ 加入 .dockerignore,或把数据目录放到项目目录外。

DeepAI 能解决这个问题吗?

不能。这是 Docker 构建上下文问题,不是模型 API 问题。


总结

#13925 的核心教训是:

运行时目录不要进构建上下文。

./data:/opt/data 适合保存 Hermes 运行状态,但 data/ 必须被 .dockerignore 排除。

否则容器写出来的 symlink、socket、日志和缓存,下一次 build 都可能变成 Docker 的负担,甚至直接让构建失败。

Related Post

hermes doctor 说 DashScope key 无效,但接口明明 200:一次区域端点误判复盘hermes doctor 说 DashScope key 无效,但接口明明 200:一次区域端点误判复盘

hermes doctor 报 Alibaba/DashScope invalid API key,但同一个 DASHSCOPE_API_KEY 访问中国区 DashScope endpoint 返回 HTTP 200?本文复盘 #18904:健康检查默认 endpoint 与实际区域不一致时,为什么会把 region mismatch 误判成密钥无效。

没装 Claude,Agent 却偏要调用 Claude:Hermes delegate_task 的“示例诱导”问题没装 Claude,Agent 却偏要调用 Claude:Hermes delegate_task 的“示例诱导”问题

Hermes delegate_task 在工具 schema 中把 claude 和 Claude Code 写成显眼示例,可能诱导 Agent 在未安装 Claude 的环境里尝试 Claude ACP。本文复盘 #22013:为什么工具说明本身也是 prompt surface,以及如何用环境检测和 schema gating 降低误调用。