容器与 CI 里卸载 DeepSeek Harness:DSH plugin 缓存、镜像层与卷清理
容器里「卸载 DeepSeek Harness」这件事天生比宿主复杂,因为默认行为是「程序随容器走、数据留在卷里」。 删掉容器只清掉可写层,数据卷里的 profile、已装 DSH plugin 记录、会话与凭据照样在;而即使把容器和卷都删了,镜像层与构建缓存仍会占着磁盘——这三件事互不相干,很多人只做了第一件就以为卸干净了。所以正确做法是先明确目标:要彻底不留痕迹就删容器 + 删卷 + 清镜像与构建缓存;只想清程序保留数据就只删容器。
容器里卸载 DeepSeek Harness 和宿主差在哪
一句话结论:宿主卸载是「删程序 + 决定数据留不留」,容器卸载是「删容器 + 决定卷留不留 + 清镜像层」——多了一层。
| 维度 | 宿主卸载 | 容器卸载 |
|---|---|---|
| 程序本体 | 卸载命令或删安装目录 | 删容器(可写层消失) |
| 数据 | 手动决定是否删数据目录 | 默认保留在卷里,要显式删卷 |
| 额外残留 | 缓存目录 | 镜像层 + 构建缓存 |
| 是否影响别的环境 | 否 | 共享镜像的其它容器不受影响,但镜像仍占空间 |
方案 A:丢容器重建(最干净)
一句话结论:不「清理」而是「重建」——删容器与不再需要的卷,下次从镜像重新起一个,比在容器里逐项清更彻底。
- 确认数据是否要留(这一步决定后面的动作):
docker volume ls | grep dsh # 列出与 DeepSeek Harness 相关的卷
# 预期:看到你之前挂的数据卷名;不想留则下一步一并删
- 停并删容器:
docker rm -f dsh
- 按需删卷(这一步才决定数据是否真的消失):
docker volume rm dsh-data # 数据卷:删了 = 会话与插件记录都没了
- 重建:按原来的方式重新起一个容器(写法见 DeepSeek Harness 容器化安装)。
- 验证:新容器里
dsh plugin清单是否符合预期(空 = 数据确实清了;有 = 卷还在)。
方案 B:容器内定向清理(想保留容器)
一句话结论:保留容器、只清插件与缓存时,按「插件清单 → 缓存 → 索引」的顺序清,别动配置与凭据。
- 先记录清单(万一要重装):
dsh plugin # 记下装了什么,便于后续按清单恢复
- 移除插件:用卸载/移除类子命令逐个处理(参数名以
dsh plugin --help为准)。 - 清缓存与索引:只删缓存类目录(可重建),不要删整个数据目录。
- 看体积确认效果:
du -sh "$DSH_HOME"/* 2>/dev/null | sort -h | tail -5
# 预期:确认清理后主要占用是否下降
- 验证:重装一个插件跑一次,确认环境仍然可用。
方案 C:镜像瘦身(构建阶段清理)
一句话结论:镜像变小只能在构建阶段做——运行时删掉的文件已经写进层里,不会减小镜像。
- 多阶段构建:构建阶段装依赖与编译,运行阶段只拷贝产物。
- 同一层内「装 → 用 → 清」:把安装、使用与清理缓存放进同一条
RUN,避免缓存留在中间层。 - 基础镜像选小的(但注意:
slim/alpine装带原生模块的插件容易失败,取舍见容器化安装一文)。 - 清构建缓存(这一步常被忘):
docker builder prune
# 预期:释放构建缓存占用;执行前确认没有正在进行的构建
- 验证:
docker images看镜像体积变化;功能跑一轮确认没删错东西。
DSH plugin 容器的三个卷分别怎么处理
一句话结论:数据卷决定「会不会丢会话」、工作区卷决定「会不会丢文件」、缓存卷可以放心删。
| 卷 | 内容 | 卸载时怎么处理 |
|---|---|---|
数据卷(DSH_HOME) | profile、已装 DSH plugin 记录、会话、凭据 | 谨慎:删了不可恢复;要留就保卷重建容器 |
| 工作区卷 | 你处理的项目文件 | 绝不能随手删:这是你的业务数据 |
| 缓存卷(包/索引缓存) | 可重建的中间产物 | 放心删,代价只是下次变慢 |
- 命名要能区分:卷名带语义前缀(
dsh-data/proj-data/dsh-cache),避免清理时误删。 - 清理前先列清单,确认每个卷归属。
- 备份优先于清理:数据卷要删之前先备份(备份口径见 DeepSeek Harness 磁盘布局全景)。
DeepSeek Harness 在 CI 里的收尾三步
一句话结论:CI 的干净靠「不挂持久卷 + 临时容器 + 显式清缓存」三步——第一步最关键。
- 数据目录指向容器内临时路径(不挂卷):容器结束数据随之消失,无需额外清理。
- 用临时容器跑(
--rm),避免残留容器堆积。 - 流水线末尾清本地缓存与临时目录,防止构建机上长期积累。
docker run --rm -e DSH_HOME=/tmp/dsh -v "$PWD:/workspace" dsh-local:0.2.0-rc.2 dsh --version
# 预期:容器退出即销毁,/tmp/dsh 中的数据不留痕
- 验证方法:跑完看构建机上的卷列表与磁盘占用,确认没有累积。
DSH plugin 排查注意事项
一句话结论:卸载类问题先分清「删了什么」——容器、卷、镜像层是三样东西,别用一个动作期待三种效果。
- 数据没清→ 卷还在(删容器不会删卷)。
- 磁盘没释放→ 镜像与构建缓存还在(删容器与卷都不会回收镜像层)。
- 误删了数据→ 检查是否删到了数据卷或工作区卷;有备份就恢复,无备份只能重来。
- CI 越跑越占空间→ 数据目录挂了持久卷,或未清构建缓存。
- 重装后插件还在→ 说明数据卷被保留了(有时是期望行为,有时不是,先确认目标)。
- 修复状态如实:本文基于 Docker 的容器/卷/镜像层语义与官方 CLI 的数据目录说明;容器化 DeepSeek Harness 无官方专文,具体卷名、缓存目录名以你自己环境的实际布局为准。
清理前先把已装清单记下来——DSH Plugin Hub 的已安装列表可以直接当这份清单用,重建容器后照着重装。

宿主侧(非容器)的卸载与残留清理,见dsh 卸载命令与数据清理。
来源:apps/cli/README.md、Docker Docs · volumes、Docker Docs · build cache。
常见问题
删容器只清掉容器可写层里的东西,挂在数据卷里的 DeepSeek Harness 数据(profile、已装 DSH plugin 记录、会话、凭据)不会消失——它按设计就是持久化的。所以「卸干净」要分两步:删容器 + 决定数据卷要不要一起删;只删容器等于卸掉程序、留下数据。
在 DeepSeek Harness 里,因为镜像层不会被删容器回收:镜像本身占着空间,构建过程中产生的中间层也会留在本地缓存里。要真正释放空间,需要额外处理镜像(删掉不再使用的镜像标签)与构建缓存(清理构建缓存),这一步和容器/卷的删除是三件独立的事。
在 DeepSeek Harness 里,用临时容器跑(退出即删)、把数据目录指向容器内临时路径而不是挂载卷、并在流水线末尾显式清理本地缓存与临时目录。三步里最关键的是「数据目录不挂持久卷」——只要不挂,容器结束数据就随之消失,不需要额外清理动作。
在 DeepSeek Harness 里,在构建阶段清理,而不是运行时:把安装依赖、构建产物与运行所需内容分成不同阶段,运行阶段只拷贝产物;同一阶段内先装后用再删缓存,避免把缓存留在层里。运行时清理已经写进镜像层的文件不会减小镜像体积——这一点是最常见的误解。
在 DeepSeek Harness 里,可行,前提是数据在挂载卷里:删容器不动卷,重建容器后重新挂上同一个卷,会话与插件清单就还在。这也是容器化 DeepSeek Harness 的推荐做法——程序随容器走、数据留在卷里,升级与清理都不影响数据。
相关术语
- 容器可写层(container writable layer)
- 容器可写层是容器运行时新增的文件层,随容器删除而消失。它只包含运行期改动,挂载进来的卷内容不在此列,因此删除容器不等于删除数据。— https://docs.docker.com/storage/volumes/
- 数据卷(volume)
- 数据卷是独立于容器生命周期的持久化存储。DeepSeek Harness 的数据目录通常挂在卷上,所以「卸载」是否彻底,取决于你是否显式删除了这个卷。— https://docs.docker.com/storage/volumes/
- 镜像层(image layer)
- 镜像层是容器镜像的组成部分,每一层记录一组文件变更。容器删除不会回收镜像层占用的空间,需要单独删除镜像标签与构建缓存才能释放。— https://docs.docker.com/build/cache/
- 构建缓存(build cache)
- 构建缓存是镜像构建过程中复用的中间结果,用于加速后续构建。它长期占用磁盘,且在「清理磁盘空间」的场景下常被忽略。— https://docs.docker.com/build/cache/
来源
- deepseek-ai/deepseek-harness — apps/cli/README.md(卸载与数据目录说明)· deepseek-ai(GitHub)
- Docker Docs — 容器的生命周期与数据卷(rm / volume 语义)· Docker
- Docker Docs — 镜像分层与构建缓存(层不可回收的含义)· Docker