在macOS上,Docker占用了大量存储空间

111

(帖子创建于2016年10月05日)

我注意到每次运行并删除图像后,我的系统都没有返回到原来的可用空间。

我正在应用于我的容器的生命周期是:

> docker build ...
> docker run CONTAINER_TAG
> docker stop CONTAINER_TAG
> rm docker CONTAINER_ID
> rmi docker image_id

[ 在默认的 Mac 终端上运行 ]

实际上,这些容器是从自定义镜像创建的,使用 node 和标准的 redis 运行。我的操作系统是 OSX 10.11.6。

到了最后,我发现我一直在失去 Mbs。我该如何解决这个问题?

编辑后的帖子

2020 年,问题仍然存在,留下这篇更新供社区参考:

今天运行:

  • macOS 10.13.6
  • Docker Engine 18.9.2
  • Docker Desktop Cli 2.0.0.3

解决此问题的最简单方法是使用 Docker 工具清理系统。

docker system prune -a --volumes
11个回答

158

警告:

默认情况下,卷不会被删除,以防止重要数据被误删。如果当前没有容器使用该卷,请在运行命令时使用--volumes标志来清理卷:

Docker现在有一个单独的命令可执行此操作:

docker system prune -a --volumes

查看Docker system prune文档


4
今天官方最佳解决方案。不是理想但可行!感谢 @zhongjiajie 为社群更新此内容。 - Franco Rabaglia
看起来 duc 报告的是表面大小而不是实际大小,所以我需要避免对此过于担忧。对于任何其他使用它的人,在 GUI 显示时按下 a 键可以在表面大小和实际大小之间切换。 - Sridhar Sarnobat
如果我想排除某些容器或镜像不被删除怎么办?否则就像删除所有东西以释放空间一样! - User

48

有三个 Docker 存储区域可能会积累,因为 Docker 很谨慎 - 它不会自动删除它们:已退出的容器、未使用的容器卷和未使用的镜像层。在大量构建和运行的开发环境中,这可能占用了很多磁盘空间。

以下三个命令清除未使用的部分:

  • docker rm $(docker ps -f status=exited -aq) - 删除已停止的容器
  • docker rmi $(docker images -f "dangling=true" -q) - 删除任何映像中未使用的图像层
  • docker volume rm $(docker volume ls -qf dangling=true) - 删除未被任何容器使用的数据卷

这些命令是安全的,它们不会删除被映像引用的图像层或被容器使用的数据卷。您可以别名它们,并/或将它们放入 CRON 作业以定期清理本地磁盘。


2
我尝试运行这三个命令,但它们都无法工作,Docker 显示了以下示例消息:"docker volume rm" 至少需要一个参数。 请参阅 'docker volume rm --help'。 用法: docker volume rm [选项] VOLUME [VOLUME ...] 删除一个或多个卷。 - rashidkhan
@rashidkhan 我认为这是因为查询(在 $ 后面)没有返回任何结果。你尝试过被接受的答案了吗? - willk

29

值得一提的是,当使用以下命令时,docker.qcow2文件(或High Sierra上的Docker.raw文件)的大小看起来可能非常大(约为64GiB),实际上比它实际大小要大:

  • ls -klsh Docker.raw

这可能会有些误导,因为它将输出文件的逻辑大小而不是物理大小。

要查看文件的物理大小,您可以使用此命令:

  • du -h Docker.raw

来源:https://docs.docker.com/docker-for-mac/faqs/#disk-usage


27

为什么文件会不断增大?

如果经常使用 Docker,即使删除文件,Docker.raw(或Docker.qcow2)的大小也可能会不断增大。

为了展示这种影响,请先在主机上检查文件的当前大小:

$ cd ~/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/
$ ls -s Docker.raw
9964528 Docker.raw

请注意使用了 -s 参数,它显示了文件实际使用的文件系统块数。实际使用的块数不一定与文件的“大小”相同,因为文件可以是稀疏的。
接下来在单独的终端中启动一个容器并创建一个1GiB的文件:
$ docker run -it alpine sh
# and then inside the container:
/ # dd if=/dev/zero of=1GiB bs=1048576 count=1024
1024+0 records in
1024+0 records out
/ # sync

回到主机后,再次检查文件大小:

$ ls -s Docker.raw 
12061704 Docker.raw

请注意,从 9964528 增加到 12061704,增加的 2097176512 字节扇区约为 1GiB,正如预期的那样。如果您切换回 alpine 容器终端并删除该文件:
/ # rm -f 1GiB
/ # sync

然后在主机上检查文件:

$ ls -s Docker.raw 
12059672 Docker.raw

文件大小并没有变小!无论虚拟机中的文件发生了什么,主机似乎并不知道。

接下来,如果您再次在容器中创建“相同”的1GiB文件,然后再次检查文件大小,您会看到:

$ ls -s Docker.raw 
14109456 Docker.raw

它甚至变得更大了!如果你在一个循环中创建和销毁文件,即使虚拟机内部的文件系统相对空闲,Docker.raw(或Docker.qcow2)的大小也会增加到上限(目前设置为64 GiB)。

这种奇怪行为的解释在于文件系统通常如何管理块。当需要创建或扩展文件时,文件系统会找到一个空闲块并将其添加到文件中。当删除文件时,从文件系统的角度来看,这些块变为“空闲”,但没有人告诉磁盘设备。更糟糕的是,新释放的块可能不会立即被重新使用,完全取决于文件系统的块分配算法。例如,该算法可能设计为优先为文件分配连续的块:最近释放的块可能不是用于扩展文件的理想位置。

由于实际上块分配器倾向于未使用的块,因此结果是Docker.raw(或Docker.qcow2)将不断积累新的块,其中许多包含过期数据。尽管虚拟机内部的文件系统仍报告有足够的可用空间,但主机上的文件会变得越来越大。

TRIM

TRIM命令(或DISCARDUNMAP)允许文件系统向磁盘发出信号,表明一些扇区包含过期数据,可以被遗忘。这允许:

  • 使用SSD固态硬盘擦除并重复利用空间,而不是花费时间来移动它;
  • 使用Docker for Mac释放主机文件系统中的块,缩小文件。

那么我们该如何实现呢?

Docker for Mac中的自动TRIM

在Docker for Mac 17.11中,有一个名为trim-after-deletecontainerd“任务”监听Docker镜像删除事件。可以通过ctr命令查看:

$ docker run --rm -it --privileged --pid=host walkerlee/nsenter -t 1 -m -u -i -n ctr t ls
TASK                    PID     STATUS    
vsudd                   1741    RUNNING
acpid                   871     RUNNING
diagnose                913     RUNNING
docker-ce               958     RUNNING
host-timesync-daemon    1046    RUNNING
ntpd                    1109    RUNNING
trim-after-delete       1339    RUNNING
vpnkit-forwarder        1550    RUNNING

当接收到图像删除事件时,该过程会等待几秒钟(以防其他图像正在被删除,例如作为 docker system prune 的一部分),然后在文件系统上运行 fstrim
回到前面一节的示例,如果您删除了 alpine 容器内的 1 GiB 文件。
/ # rm -f 1GiB

然后在主机的终端中手动运行fstrim

$ docker run --rm -it --privileged --pid=host walkerlee/nsenter -t 1 -m -u -i -n fstrim /var/lib/docker

然后检查文件大小:

$ ls -s Docker.raw 
9965016 Docker.raw

文件已经回到(大约)原始大小——空间终于被释放了!
希望这篇博客有所帮助,此外,请查看以下macOS Docker实用脚本以解决此问题:

https://github.com/wanliqun/macos_docker_toolkit


13

在Mac上使用Docker会遇到一个额外的问题,这会影响很多人:docker.qcow2文件可能会变得非常大(高达64GB),而且不会自动缩小。

https://github.com/docker/for-mac/issues/371

正如djs55其中一条回复所述,这个问题计划进行修复,但这不是一个快速解决的问题。引用:

.qcow2以最大64GiB的块设备形式暴露给虚拟机。随着容器在文件系统中创建新文件,新的扇区被写入块设备。这些新扇区被追加到.qcow2文件中,导致其大小增长,直到最终完全分配。当它达到此最大大小时,它将停止增长。
...
我们希望分几个阶段解决这个问题:(请注意,这仍处于规划/设计阶段,但我希望它能给您一个想法)
1)我们将切换到支持TRIM的连接协议,并在qcow2旁边的元数据文件中实现空闲块跟踪。我们将创建一个压缩工具,可以离线运行以缩小磁盘(有点像qemu-img convert,但不需要dd if=/dev/zero,而且应该很快,因为它已经知道空闲空间在哪里)。
2)我们将自动运行压缩工具来重新启动虚拟机,假设它足够快。
3)我们将切换到在线压缩器(类似于编程语言中的GC)。
我们还在考虑使.qcow2的最大大小可配置。也许64GiB对某些环境来说太大了,更小的限制会有所帮助?
2019年更新: 自此答案发布以来,Docker for Mac 已经进行了许多更新以帮助缓解问题(特别是:支持不同的文件系统)。

虽然清理仍然不是完全自动化的,但您可能需要定期修剪。有一个单一的命令可以帮助清理磁盘空间,请参见zhongjiajie的答案


1
这是答案。我的.qcow2文件已经达到了35Gb++! - Franco Rabaglia
非常感谢。我认为唯一的方法是经常清理这个文件。 - Franco Rabaglia
@FrancoRabaglia 是的,我现在看不到一个合适的解决方法,这将是计划修复的第一阶段 :/ 如果我发现任何更新,我会编辑到答案中。 - Gimby
我参考了https://github.com/docker/for-mac/issues/371#issuecomment-315385246,然后输入`docker run --rm --net=host --pid=host --privileged -it justincormack/nsenter1 /sbin/fstrim /var`,qcow2文件就被压缩了。 - runitao
2
Docker桌面版现在支持调整磁盘映像的大小。它实际上会使用不同大小重新创建映像,因此会丢失其中的所有内容,但仍然有所帮助。 - Carlos Ferreyra

12
docker container prune
docker system prune
docker image prune
docker volume prune

3
这会做什么?请详细说明。 - Hizqeel
1
还有其他可能对此答案有帮助的修剪命令,包括 docker image prunedocker volume prune,建议将它们添加进去。 - jpgard
docker system prune --volumes 与其他命令重复。 - Shannon
还有一个 builder prune 命令,请参见 https://docs.docker.com/engine/reference/commandline/builder_prune/。 - Shannon

9

我不确定它是否与当前主题相关,但对我个人来说这是一个解决方案。

打开 Docker 设置 -> 资源 -> 磁盘映像大小 - 16GB


2
这是最好的答案。 - A J
通过调整大小,可能会清除Docker的所有文件。这比仅使用docker system prune -a --volumes更有助于释放更多空间。 - Kamal Hossain

7

由于这里的方法对我不起作用,下面是我所做的。检查文件大小:

ls -lhks ~/Library/Containers/com.docker.docker//Data/vms/0/data/Docker.raw

然后在Docker桌面应用程序中简单地缩小磁盘映像的大小(我使用的是原始格式)。它会说它将删除所有内容,但是当您阅读本帖子时,您可能已经这样做了。因此,这将创建一个全新的空文件。


这是你的解决方案吗?! - User

5
它一直占用着我的120GB空间。由于我只使用256GB的MacBook Air,这给我带来了很多困扰。
我认为这是最简单且持久的解决方案: enter image description here

enter image description here


2

有几种方法可以限制Docker的磁盘空间,我建议从限制/轮换日志开始:Docker容器日志占用所有磁盘空间

例如,如果您使用最新的Docker版本,可以为每个容器启动一个--log-opt max-size=50m选项。此外,如果您有旧的、未使用的容器,可以考虑查看位于/var/lib/docker/containers/*/*-json.log的Docker日志。


这是一个关于 Mac 的问题,不是一个关于 Linux 的问题。 - Berend de Boer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接