不能只靠 docker system prune,因为它会无差别删除悬空镜像和未被容器引用的镜像,可能误删 CI/CD 中正在构建的中间层,导致 buildkit 缓存失效、构建失败。

直接用 docker system prune -f 最简单,但容易误删正在构建中的镜像;真正安全的清理必须结合 docker images 输出 + 状态过滤 + 时间判断。
为什么不能只靠 docker system prune
这个命令会无差别删除所有悬空镜像(<none>)和未被容器引用的镜像,但如果你在 CI/CD 流水线中正并行构建多个镜像,某些中间层可能暂时没被任何容器引用,却还在构建链路上——这时 prune 会提前干掉它们,导致后续构建失败。
常见错误现象:failed to solve: failed to compute cache key: failed to walk /var/lib/docker/tmp/buildkit-mount*: no such file or directory,本质就是 buildkit 缓存层被误删。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 优先用
docker images --format "{{.ID}}\t{{.Repository}}\t{{.Tag}}\t{{.CreatedSince}}"获取结构化输出,比解析docker images默认表格更可靠 - 过滤掉
Repository为<none>且Tag为<none>的镜像(即纯悬空层) - 对非悬空镜像,检查是否超过 7 天未被使用(需配合
docker ps -a查容器历史创建时间)
如何识别“真正无用”的镜像(非悬空但长期闲置)
Docker 本身不记录镜像最后使用时间,所以得靠间接方式:查所有已退出容器的 Image 字段,再排除这些镜像;剩下的、又不是当前运行中容器所用的,才可视为“闲置”。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 用
docker ps -a --format "{{.Image}}"提取所有曾存在过的容器镜像名(含 tag) - 用
docker ps --format "{{.Image}}"提取当前运行中容器的镜像名 - 把这两组结果合并去重,得到“至少被某个容器用过”的镜像集合
- 再用
docker images --format "{{.Repository}}:{{.Tag}}"对比,不在该集合里的,才是可清理目标 - 注意:有些镜像只用于一次性任务(如 cron 容器),它们退出后不会再次启动,但镜像仍需保留——这类需白名单配置,比如写死
myapp/cleaner:2024不进清理列表
Python 脚本里调用 Docker 命令的安全要点
别用 os.system() 或 subprocess.call() 直接拼字符串,容易被镜像名里的空格或特殊字符(比如带冒号、斜杠)注入破坏。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 统一用
subprocess.run()并传入参数列表,例如:subprocess.run(["docker", "images", "-q", "--filter", "dangling=true"]) - 获取镜像 ID 列表时,加
--quiet(即-q)避免格式干扰,返回纯 ID 行序列 - 批量删除前,先用
docker image inspect <id>检查RepoTags字段是否为空——空则确认是悬空层,非空则跳过(除非白名单策略允许) - 删除命令必须加
--force(-f),否则遇到正在被 build cache 引用的镜像会卡住等待确认
定时执行与日志留存怎么做才不踩坑
Linux 上用 crontab 最常见,但默认环境变量缺失(比如 PATH 不含 /usr/bin/docker),脚本常静默失败。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- crontab 条目里显式指定完整路径:
0 3 * * * /usr/bin/python3 /opt/scripts/clean-docker.py >> /var/log/docker-clean.log 2>&1 - 脚本开头加
import logging,把每一步操作(查到几个悬空镜像、跳过了哪些白名单、实际删了哪几个 ID)都记到文件,别只依赖 print - 避免在凌晨 3 点这种高并发时段运行;如果宿主机上有 Jenkins 或其他 CI 工具,最好错开它们的构建高峰
- 首次上线前,把删除逻辑注释掉,只打印将要删的 ID,并人工核对 2–3 天
最麻烦的其实是镜像依赖关系——Docker 的分层存储让“某个镜像是否真的无用”变得动态且上下文相关。你永远没法 100% 自动判断一个中间层镜像是否还在 build cache 链上,所以白名单机制和人工抽检不能省。


















