Mac 上的 Docker 很少一下子看起来就很大。它是逐层增长的。
起初只是一个镜像、一个项目、一个数据库卷、一个已停止的容器、一个你打算稍后清理的构建缓存。然后机器空间越来越紧,Docker Desktop 开始变得可疑,而常见的结论模糊但情感上令人满意:“Docker 在吞噬我的磁盘。”
这个结论方向是对的,但太模糊了以至于没有实际用处。真正的问题通常不是”Docker 整体”,而是镜像、层、构建缓存、已停止的容器、卷和运行时数据中无人作为整体审查过的累积。
快速回答
- Mac 上 Docker 磁盘增长通常由累积造成,而非某一个有问题的文件夹。
- 常见的存储来源包括镜像、共享层、构建缓存、已停止的容器、卷和悬空对象。
- 在 Mac 上,Docker Desktop 将 Linux 容器和镜像存储在一个大型磁盘映像文件中,因此仅从 Finder 看占用是不透明的。
- 第一步是检查而非删除:在清理之前先审查实际可回收的空间。
- 在 Docker 管理的路径中直接使用
rm比通过 Docker 自身的清理命令风险更大,因为 Docker 跟踪运行时状态和元数据。 prune可能有帮助,但前提是你了解自己删除的是可重建的缓存还是持久数据。
为什么 Docker 在 Mac 上会悄悄变得这么大
Docker 的设计初衷是保留有用的状态,直到你明确告诉它清理。Docker 自己的文档将清理描述为保守的:未使用的镜像、容器、卷和网络通常不会被移除,除非你要求 Docker 这样做。
这对开发者工作流程很方便,也正是磁盘占用悄然增长的原因。
在 Mac 上,情况更加不明显,因为 Docker Desktop 将 Linux 容器和镜像存储在一个大型磁盘映像文件中。这意味着宿主机可能显示一个巨大的 Docker 占用,而真正的原因埋藏在多层运行时数据中。
增长模式通常是以下因素的组合:
- 跨多个项目拉取和重建的镜像;
- 跨标签和版本复用的共享层;
- 仍保留可写层的已停止容器;
- 存储数据库、上传文件或本地服务状态的卷;
- 保持构建快速但最终变得昂贵的构建缓存;
- 重建和重新标记后留下的悬空对象。
结果是占用空间悄悄扩大,因为每次单独的增加看起来都很正常。
Docker 在 Mac 上把数据存在哪里
在 Mac 上,Docker 不像原生应用那样把文件散落在磁盘各处。Docker Desktop 在虚拟机里运行 Linux,并把几乎所有东西(镜像、容器和卷)放进一个很大的磁盘映像文件里。
默认情况下,这个文件大致在:
~/Library/Containers/com.docker.docker/Data/vms/0/data/Docker.raw
确切路径会随 Docker Desktop 版本变化,但思路始终一样:一个受管文件承载整个 Linux 侧的占用。所以单个 Docker.raw 在访达里会显示为几十 GB,即便其中很大一部分是可回收的,或者那只是磁盘映像被允许增长到的最大尺寸。
这种设计带来两个后果:
- 访达显示的大小会误导人。 宿主机上的工具常常报告磁盘映像的最大尺寸,而不是 Docker 在里面实际用掉的空间。
- 不要直接动
Docker.raw。 Docker 自己的 Mac 文档明确提醒:不要在访达里移动或删除这个磁盘映像,否则 Docker Desktop 可能找不到它。空间要通过 Docker 回收,而不是通过文件系统。
Docker 在 Mac 上到底占用了什么空间
如果你想要一个有用的清理计划,请将 Docker 占用按类别分解,而不是把它当作一个巨大的黑箱。
| 组件 | 增长原因 | 首先检查什么 | 盲目清理的风险 |
|---|---|---|---|
| 镜像和共享层 | 拉取基础镜像、重新标记、重建服务、保留多个版本 | 哪些镜像仍被活跃容器或活跃项目使用 | 中等 |
| 构建缓存 | BuildKit 和重复的镜像构建保留缓存以加速未来构建 | 空间是否主要是缓存,以及重建速度今天是否重要 | 中等 |
| 已停止的容器 | 已退出的容器仍保留可写层和引用 | 这些容器是故意停止的还是被遗忘的 | 低到中等 |
| 卷 | 数据库、上传文件、索引、包仓库和本地服务状态存放在这里 | 卷是否包含你仍需要的持久项目数据 | 高 |
| 悬空对象 | 未标记的镜像和孤立产物在重建后累积 | 它们是否真正未被引用且可回收 | 低 |
| Docker Desktop 运行时数据 | Mac 端磁盘映像和运行时管理的存储使一切看起来像一个大型块 | 可见的宿主机占用是实际使用量、可回收空间还是仅是分配的运行时存储 | 中等到高 |
这就是为什么通用的”最大文件夹”工作流程对 Docker 效果不佳。相同的总大小可能意味着非常不同的清理决策,取决于空间主要是构建缓存还是真实的卷数据。
| 目标 | 真实含义 | 典型风险 | 清理后可能的后果 |
|---|---|---|---|
| 构建缓存 | 构建器保留的以速度为导向的重建缓存 | 低到中等 | 下次构建变慢,直到缓存重新预热 |
| 已停止的容器 | 保留的可写层和便于恢复的容器状态 | 低到中等 | 你失去非活跃环境的便捷恢复状态 |
| 未使用的镜像 | 当前没有活跃容器需要的已拉取或已构建的镜像 | 中等 | 下次运行可能需要重新拉取或重建 |
| 卷 | 持久本地服务数据,如数据库、上传文件或索引 | 高 | 真实的本地项目数据可能消失 |
Docker 镜像和共享层
镜像通常是开发者首先想到的,但更深层的故事是层。一台拥有多种语言运行时、类似 CI 的本地构建和多个微服务的机器,可以快速积累大量共享和独立的层。
这就是为什么磁盘占用并不总是与你记忆中拉取的镜像列表整齐对应。
Docker 构建缓存
构建缓存是活跃开发机器上最常见的隐藏原因之一。它的存在是为了让未来的构建更快,这意味着它会一直保留直到你清理它。这也意味着删除它通常是一种性能权衡,而不是免费的空间回收。
已停止的 Docker 容器
开发者总是低估这一点。一个没有运行的容器仍然是一个存储对象。如果它仍然存在,它可能仍然占用磁盘空间。
Docker 卷
卷是风险上升的地方。它们可能包含你真正关心的数据:数据库、包镜像、上传文件、搜索索引、本地仓库内容或服务状态。
这就是 Docker 清理与普通缓存清理的区别。一些 Docker 存储是可重建的。一些是你的环境。
悬空的 Docker 镜像和对象
悬空对象通常是最安全的清理候选项。Docker 的 prune 文档将悬空镜像定义为未被标记且未被任何容器引用的镜像。它们正是通过正常迭代产生的那种累积。
如何检查 Mac 上 Docker 的磁盘占用
最好的第一步不是 Finder。而是 Docker 级别的视图,看看守护进程认为什么在占用空间。
Docker 在 Mac 上的推荐从 docker system df -v 开始,它显示镜像、容器、本地卷和可回收空间的使用情况。这是停止猜测最快的方式。
按以下审查顺序使用:
1. 从 docker system df -v 开始
这是最佳的首次摘要,因为它显示:
- 镜像的总使用量和可回收量;
- 容器使用量;
- 本地卷使用量;
- 使用详细标志时更详细的分解。
如果可回收空间很小,广泛清理可能帮助不大。
2. 在 prune 之前审查已停止的容器
检查是否有许多已退出且无人需要的容器。与卷或活跃运行时状态相比,这些通常是较安全的清理候选项。
3. 将镜像与构建缓存分开审查
镜像和构建缓存解决不同的问题。如果缓存是主要问题,专注于缓存的清理通常比对 Docker 拥有的一切进行广泛重置更好。
4. 在使用任何涉及 --volumes 的操作之前审查卷
这是人们经常跳过并后悔的部分。一个卷可能看起来与当前运行的容器分离,但仍然代表你计划明天再次启动的项目的真实本地数据。
5. 审查 Docker Desktop 在 Mac 端的磁盘映像
Docker 的 Mac 常见问题指出,Docker Desktop 将 Linux 容器和镜像存储在单个磁盘映像文件中,某些工具显示的是最大文件大小而非实际消耗的大小。这很重要,因为一个看起来吓人的宿主机端数字并不总是与立即可回收的浪费相同。
Docker 清理原则:在审查总空间之前先审查可回收空间。仅凭一个大的占用数字并不能告诉你哪个清理操作是安全的。
在清理之前
- 确认真正的压力来自构建缓存、镜像、已停止的容器还是卷。
- 检查是否有正在运行或最近停止的容器仍属于活跃工作。
- 将卷视为数据审查,而非缓存审查。
- 优先使用能解决问题的最窄范围的 Docker 感知清理。
- 预期清理后的重建、重新拉取或较慢的启动成本。
- 不要因为看到一个大的不透明宿主机端磁盘映像数字就情绪化地使用 Docker 清理。
快速 Docker 审查命令
在删除任何内容之前,这些检查命令很有用:
docker system df -v
docker ps -a --size
docker images --format 'table {{.Repository}}\t{{.Tag}}\t{{.Size}}'
docker volume ls
使用它们在选择任何 prune 范围之前确认实际可回收的空间。
如何在 Mac 上释放 Docker 的磁盘空间
当 docker system df -v 已经显示出真正可回收的部分,就用能解决问题的最小范围去释放,而不是一次大扫除:
# 删除已停止的容器
docker container prune
# 删除构建缓存(BuildKit)
docker builder prune
# 删除悬空(无标签)镜像
docker image prune
# 删除未使用的卷 - 先确认里面没有你需要的数据
docker volume prune
如果希望 Docker 一次清理多种对象,docker system prune 会在一步里处理已停止的容器、未使用的网络、悬空镜像和未使用的构建缓存。加上 -a 还会删除没有被任何容器使用的镜像,而 --volumes 只在你确定没有任何卷保存真实数据时才加。
你也可以从 Docker Desktop 本身回收空间:打开 Settings → Resources 调整或缩小虚拟磁盘大小,或者用 Troubleshoot → Clean / Purge data 做更重的重置。两条路都留在 Docker 自己的流程里,比手工去动 Docker.raw 安全。
代价始终一样:清理缓存和镜像换来的是下一次构建更慢、需要重新拉取,而不是丢失源码;清理卷则可能带走真实的本地数据,所以这一范围要最谨慎对待。
为什么直接删除 Docker 文件夹有风险
直接删除看起来很有吸引力,因为它看起来很果断。但它也是将 Docker 清理变成运行时清理赌博的方式。
有两个原因。
第一,Docker 跟踪运行时状态和元数据。当你在 Docker 自身工作流程之外删除 Docker 管理的文件时,你可能会破坏运行时所相信存在的与磁盘上实际存在的之间的关系。
第二,在 Mac 上,Docker 占用与 Docker Desktop 管理的磁盘映像和运行时存储相关联。Docker 自己的 Mac 文档明确警告不要在 Finder 中直接移动磁盘映像,因为 Docker Desktop 可能会失去对它的跟踪。同样的经验教训适用于 Docker 管理存储内的暴力删除:Docker 感知的操作比文件系统猜测更安全。
这也是为什么删除运行中容器内的文件与回收宿主机磁盘空间不是一回事。Docker 的 Mac 文档指出,当镜像被删除时才回收宿主机空间,而不是当文件在运行中容器内消失时自动回收。
prune 什么时候有帮助
当你已经了解了占用情况并希望 Docker 移除它认为未使用的对象时,prune 很有用。
它有帮助的主要场景很直接:
- 当已停止的容器、未使用的网络、悬空镜像和未使用的构建缓存堆积时,使用
docker system prune; - 当构建缓存是真正的问题时,使用
docker builder prune; - 当你已确认未使用的卷确实是一次性的时候,使用
docker volume prune; - 当你希望缩小范围而非清扫一切时,使用按时间或标签过滤的清理。
这就是 Docker 感知清理明显优于原始文件删除的地方。运行时理解对象类型。Finder 不理解。
docker system prune 什么时候危险
危险不在于 prune 本身不好。危险在于 Docker 中”未使用”仍然可能意味着”对我的工作流程很重要”。
在以下情况需要小心:
- 一个已停止的容器是你期望恢复的本地环境的一部分;
- 下次构建需要你即将清除的缓存;
- 本地卷包含你仍关心的数据库或服务数据;
docker system prune -a会移除当前没有运行但仍是活跃工作一部分的镜像;- 你打算添加卷清理但尚未确认这些卷代表什么。
Docker 文档明确指出卷不会自动移除,因为那可能破坏数据。这是卷清理的正确思维模型:卷比镜像或悬空缓存需要更多怀疑。
在清理之前如何理解后果
在清理任何内容之前,用简单的语言回答后果问题:
清理之后我需要重建、重新拉取、恢复或重新创建什么?
这个问题比”我能删除多少”更有用。
对于 Docker,实际的审查通常如下:
- 主要占用是镜像、构建缓存、已停止的容器还是卷?
- 是否有正在运行的容器是计划的一部分,还是清理需要先停止它们?
- 如果我清理缓存,我能接受之后较慢的构建或重新拉取吗?
- 如果我清理卷,什么服务状态或数据会随之消失?
- 我使用 Docker 清理是在解决一个真正的可回收空间问题,还是仅仅对一个大的不透明磁盘映像做出反应?
这就是受控的开发者清理与随机存储恐慌之间的区别。
为什么开发者清理不同于普通文件清理
普通文件清理问的是”哪个文件夹最大?”
Docker 清理需要不同的问题:
- 这是可重建的缓存还是持久的服务数据;
- 运行时是否将其报告为可回收的;
- 清理是否应该通过 Docker 命令而非文件系统删除进行;
- 运行中的容器、已停止的容器或卷是否是后果模型的一部分;
- 在执行有风险的清理路径之前是否需要引导式审查?
这就是为什么 Docker 应该属于容器感知的工作流程,而不是与删除下载文件或清空普通缓存文件夹归入同一个思维类别。
StorageRadar 的定位
这很重要,因为 Docker 不仅仅是”一个大文件夹”。它是一个由不同对象类型组成的生态系统,每种类型有不同的清理后果。
如果构建缓存是问题,你的行动与卷密集型机器不同。如果运行中的容器必须先停止,这应该在清理之前可见。如果配置有风险,工作流程应该有意让你放慢速度。
在清理之前先检查 Docker 占用。
查看开发者清理不要做的事
避免这些常见错误:
- 不要把每个大型 Docker 占用当作一个可以用一个命令解决的问题;
- 不要因为 Docker 管理的目录路径看起来大就直接在其中运行
rm -rf; - 不要假设大的 Docker Desktop 磁盘映像意味着所有空间现在都可以安全回收;
- 如果你没有检查那些卷里有什么,不要随意添加卷清理;
- 不要在你承担不起的演示、发布或本地环境重建之前使用广泛的 prune。
如果 Docker 只是更大的开发者机器问题的一部分,关于 Xcode DerivedData 在 Mac 上占用过多空间的配套指南是不错的后续阅读。
总结
一旦你将 Mac 上的 Docker 磁盘占用按正确的类别分解,它通常并不神秘。最大的贡献者通常是镜像、层、构建缓存、已停止的容器、卷、悬空对象和 Docker Desktop 运行时存储。
安全的做法是先检查占用情况,将可重建的产物与持久数据分离,只有在理解后果之后才使用 Docker 感知的清理。
常见问题
为什么 Docker 在 Mac 上占用这么多磁盘空间?
Docker 随着时间积累镜像、共享层、已停止的容器、构建缓存、卷和运行时数据。在 Mac 上,Docker Desktop 还将 Linux 容器和镜像存储在一个大型磁盘映像文件中,因此增长可能看起来不透明。
如何检查 Mac 上 Docker 的磁盘占用?
从 docker system df -v 开始,然后检查镜像、已停止的容器、卷,以及你看到的那个大数字是实际可回收的空间还是仅仅是配置的磁盘映像上限。
在 Finder 中直接删除 Docker 文件夹或使用 rm -rf 安全吗?
通常不安全。Docker 跟踪自己的运行时状态和元数据,而在 Mac 上 Docker Desktop 管理着一个磁盘映像文件。直接删除文件夹可能导致 Docker 不同步、丢失重要状态或造成清理混乱。
docker system prune 在 Mac 上什么时候有用?
当多余的已停止容器、悬空镜像、未使用的网络和构建缓存累积时它很有用。它是一个审查优先的清理步骤,而不是解决每个大型 Docker 占用问题的万能方案。
prune 什么时候可能有风险?
当卷可能包含真实数据、当你仍依赖已停止的容器或缓存层、或者当广泛清理会减慢下次构建、拉取或本地环境恢复时,prune 的风险会增加。
Docker 卷与镜像或构建缓存相同吗?
不同。镜像和构建缓存通常可以重建。卷是持久容器数据可能存放的地方,因此在清理前需要更多谨慎。
Docker 在 Mac 上把镜像和数据存在哪里?
在 Mac 上,Docker Desktop 把 Linux 镜像、容器和卷保存在一个磁盘映像文件里,默认大致位于 ~/Library/Containers/com.docker.docker/Data/vms/0/data/Docker.raw,确切路径随 Docker Desktop 版本而变。因为它是一个受管文件,宿主机工具常常报告它的最大尺寸,而不是实际占用的空间。
如何在 Mac 上释放 Docker 的磁盘空间?
先用 docker system df -v 看清哪些真正可回收,然后有针对性地清理:用 docker container prune 清已停止的容器,用 docker builder prune 清构建缓存,用 docker image prune 清悬空镜像。docker volume prune 要在确认卷里没有你需要的数据之后再用。在 Docker Desktop 里,也可以通过 Settings 再到 Resources,或者 Troubleshoot 再到 Clean 或 Purge data 来回收空间。