CI 镜像里预装 dsh plugins:DeepSeek Harness 缓存分层、lockfile 与版本固定

安装与快速上手发布于 2026-10-19作者: DeepSeek Plugin 插件市场
DeepSeek HarnessDSH pluginCI镜像lockfile版本固定
CI 镜像里预装 dsh plugins 怎么做:DeepSeek Harness 本体、插件与缓存分层,lockfile 固定版本,以及构建后验证插件真的进镜像。

把 dsh plugins 预装进 CI 镜像,真正要解决的是版本可复现与断网可用,而不是把安装命令塞进 Dockerfile。 DeepSeek Harness 本体、插件依赖和包管理器缓存的变化频率完全不同,混在一层里会让每次构建都重新下载。下面按构造顺序拆开讲,每一层都给出可以直接抄用的片段与验证方式。

CI 镜像预装 dsh plugins 的分层理由

分层不是为了好看,而是为了让变化慢的东西留在缓存里。

镜像构建的时间主要花在依赖下载上,而三类内容的变化频率并不一致:Harness 本体几个月才动一次,插件跟随 lockfile 变化,包管理器缓存几乎每次都可能不同。把三者压进同一条 RUN,任何一次插件升级都会让本体层失效,缓存命中率随之归零。分层之后,稳定层可以长期复用,易变层才需要重跑。

这也是为什么构建日志里最值得看的不是总耗时,而是每一层是 CACHED 还是重新执行。如果每次改一个插件版本都导致本体重新安装,说明层顺序写反了。层顺序应该从最稳定写到最易变,把 COPY lockfile 放在安装依赖之前,把源码与配置放到最后。

需要强调的是,分层只解决构建效率,不解决运行时行为。插件被装进镜像,并不等于它在运行时不会访问网络,模型调用与外部服务仍然需要出网策略。把构建期依赖和运行期依赖分开看,后面的验证才不会误判。

固定 DeepSeek Harness 本体:基础层只做一件事

基础层只做一件事:把 DeepSeek Harness 本体固定到精确版本,并准备好运行它的最小环境。

基础层里最容易犯的错是写 latest 或者只写主版本号,短时间内看不出问题,过一段时间重建就会拿到不同的运行时。正确做法是写完整的语义化版本,并在注释里记录升级原因,让下一次改动有据可查。Node 主版本也要一起写死,因为原生模块会随 ABI 变化。

dockerfile
FROM node:20-bookworm-slim

ARG DSH_VERSION=0.8.3
RUN npm install -g @deepseek-ai/dsh@${DSH_VERSION} \
    && dsh --version \
    && npm cache clean --force

WORKDIR /workspace

片段里的 dsh --version 不是装饰,它让构建在版本解析失败时立刻失败,而不是把问题留到运行时。npm cache clean --force 放在同一条 RUN 里,避免缓存被写进镜像层,否则清理动作本身也会变成一层垃圾。ARG 默认值可以在 CI 里覆盖,但生产镜像应当显式传入同一个值。

基础层不需要装任何社区插件。把插件留到下一层,既能让本体镜像被多个项目复用,也能让插件升级不牵动运行时。若团队确实需要一组所有任务共用的插件,也应单独做一层,而不是混进本体安装命令。

按 lockfile 装 DSH插件:插件层怎么写

插件层要回答的问题只有一个:这一次构建装进去的 DSH插件,是否与 lockfile 记录的完全一致。

项目目录安装比全局安装更容易复现,因为依赖解析结果被 lockfile 固定,安装时可以要求冻结模式。全局安装适合所有任务共用的小集合,但它没有天然的版本边界,时间一长就会出现某个任务依赖旧版本的情况。两种方式不要在同一个镜像里混用,否则排查冲突会非常痛苦。

dockerfile
COPY package.json package-lock.json ./
RUN npm ci --omit=dev \
    && npx dsh plugin install --from-lockfile \
    && npx dsh plugin list

npm ci 与 npm install 的差别在于前者严格按 lockfile 安装,发现不一致会直接报错,这正是 CI 需要的行为。把 package.json 与 lockfile 一起 COPY,再执行安装,可以让人只改业务代码时仍然命中依赖层缓存。安装完立即执行 plugin list,把实际版本写进构建日志,事后对账才有依据。

如果插件来自多个来源,优先让 lockfile 收敛版本,而不是用强制覆盖把冲突压下去,社区 DeepSeek插件 尤其容易在这里出问题。覆盖只会把冲突推迟到运行时,届时表现可能是某个工具静默失效。遇到无法收敛的依赖,宁可拆成两个镜像,也不要在同一层里赌。

缓存层:DeepSeek Harness plugin 构建里 layer cache 为什么不能省

缓存不能省,但也不能当成安装结果;它只负责加速,正确性必须由 lockfile 与验证来保证。

CI 平台的构建缓存通常按指令与输入文件计算键,lockfile 一改键就变,这是最省心的失效策略。若把缓存目录挂到持久卷,也要让缓存键跟随 lockfile 哈希,否则会命中旧依赖。缓存损坏时的正确反应是回退到全新安装,而不是继续复用。

dockerfile
RUN --mount=type=cache,target=/root/.npm \
    npm ci --omit=dev

这条指令只加速下载,不改变安装结果,因此可以在不同构建之间共享。真正决定镜像内容的是 lockfile 与 npm ci 的严格模式,缓存命中与否都不应影响最终插件版本。若发现清空缓存后构建失败,说明安装步骤本身有隐含依赖,应该先修构建脚本。

缓存层还有一个常被忽略的作用:它让失败重试变便宜。CI 里网络抖动很常见,如果没有缓存,一次超时就要从头下载全部依赖。把缓存与安装结果区分开,重试时可以放心复用下载,而验证仍然每次照做。

断网验证:确认 DeepSeek插件 真的在镜像里

只有在一个没有 registry 访问的容器里仍能列出插件并跑通最小任务,预装才算完成。

构建成功不代表插件在镜像里,它可能只是在构建阶段被临时下载,运行时又依赖外网。验证要在禁用出网或移除 registry 配置的容器里进行,先列插件,再跑一个最小会话。任何一步需要联网,都说明镜像的自包含性没有做到。

  1. 用 --network none 启动镜像,确认容器本身能正常运行。
  2. 执行 dsh plugin list,把输出与构建日志里的清单逐项对照。
  3. 跑一个只依赖单个插件的最小任务,确认加载路径正确。
  4. 检查插件目录权限,确保 CI 用户不是靠 root 才能读取。
  5. 把上述命令与输出写进构建产物,便于回溯。

验证时最好使用与生产一致的启动参数,包括 profile、工作目录与用户。用 root 在默认目录里能跑通,不代表普通 CI 用户也能跑通。权限问题往往在切换用户后才暴露,而那时已经很难和插件安装联系起来。

bash
docker run --rm --network none <image> \
  dsh plugin list

把验证做成镜像构建的一部分,而不是文档里的建议,是这套流程能长期成立的关键。每次构建都留下插件清单与最小任务的输出,版本漂移就会在合并前暴露。至于 DSH插件 与 DeepSeek插件 的具体条目,可以到 DSH Plugin Hub 对照名称与来源。

来源:DeepSeek Harness 快速开始、npm @deepseek-ai/dsh、deepseek-harness 仓库。

常见问题

CI 镜像里预装 dsh plugins,应该装到系统目录还是项目目录?

CI 镜像里预装 dsh plugins,系统目录适合所有任务共用,项目目录适合按 lockfile 复现。两者不要混用,否则会出现版本漂移与权限问题。

DeepSeek Harness 的插件预装进镜像后,为什么运行时还要联网?

DeepSeek Harness 插件预装进镜像后仍可能联网,是因为插件运行时要访问模型或外部服务。预装解决的是安装阶段,不解决运行时依赖。

用 lockfile 固定 dsh plugins 版本,镜像构建还需要缓存吗?

用 lockfile 固定 dsh plugins 版本能保证可复现,但构建缓存仍能显著加速。缓存要按 lockfile 哈希分层,lockfile 变了就失效。

怎么验证 dsh plugins 真的进了 CI 镜像,而不是构建时临时下载?

验证 dsh plugins 是否进镜像,要在断网或禁用 registry 的容器里启动并列出插件。能列出且版本正确,才说明镜像里真的有包。

CI 镜像预装多个 dsh plugins,版本冲突怎么处理?

CI 镜像预装多个 dsh plugins 出现版本冲突时,先按 lockfile 收敛,再考虑分层镜像。不要用强制覆盖解决,冲突会在运行时以更难查的方式出现。

相关术语

base image(基础镜像)
base image 是 CI 任务复用的底层镜像,预装 DeepSeek Harness 与常用插件能减少每次构建时间。它应保持最小化与可复现。— https://deepseek-harness.github.io/deepseek-harness/guide/quickstart
lockfile(依赖锁文件)
lockfile 记录依赖的精确版本与解析结果,是 CI 可复现的关键。镜像缓存应按 lockfile 哈希分层,避免命中过期缓存。— https://www.npmjs.com/package/@deepseek-ai/dsh
layer cache(镜像层缓存)
layer cache 是容器构建复用的镜像层,依赖安装步骤越靠前越容易复用。把易变步骤放后面,能减少重复下载。— https://github.com/deepseek-ai/deepseek-harness
offline verification(断网验证)
offline verification 是在无网络环境启动镜像并检查插件,用来证明包真的在镜像里而不是构建时临时下载。它是预装成功的硬证据。— https://deepseek-harness.github.io/deepseek-harness/guide/quickstart

来源