Docker 填满 macOS 上的存储空间

Posted

技术标签:

【中文标题】Docker 填满 macOS 上的存储空间【英文标题】:Docker filling up storage on macOS 【发布时间】:2017-02-14 04:36:37 【问题描述】:

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

我注意到每次运行图像并删除它时,我的系统都不会恢复到原来的可用空间量。

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

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

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

容器实际上是从自定义图像创建的,从节点和标准 redis 运行。我的操作系统是 OSX 10.11.6。

在一天结束时,我发现我一直在失去 Mbs。我该如何面对这个问题?

编辑后的帖子

2020 年,问题仍然存在,将此更新留给社区:

今天跑步:

macOS 10.13.6 Docker 引擎 18.9.2 Docker 桌面 Cli 2.0.0.3

解决此问题的最简单方法是使用 Docker 实用程序修剪系统。

docker system prune -a --volumes

【问题讨论】:

【参考方案1】:

警告:

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

Docker 现在有一个命令可以做到这一点:

docker system prune -a --volumes

见Docker system prune docs

【讨论】:

今天的官方最佳解决方案。不理想但工作!感谢您为社区更新此内容@zhongjiajie 看起来duc 报告的是表观尺寸而不是实际尺寸,所以我需要避免对此感到如此震惊。对于使用它的其他人,在显示 gui 时按 a 在外观和实际大小之间切换。【参考方案2】:

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 作业中以定期清理本地磁盘。

【讨论】:

我尝试运行这 3 个命令,但它们都不起作用,而是 Docker 显示此示例消息 "docker volume rm" requires at least 1 argument. See 'docker volume rm --help'. Usage: docker volume rm [OPTIONS] VOLUME [VOLUME...] Remove one or more volumes @rashidkhan 我认为这是因为查询(在$ 之后)没有返回任何结果。你试过accepted answer吗?【参考方案3】:

还值得一提的是,使用以下命令时,docker.qcow2(或 High Sierra 上的 Docker.raw 和 Apple Filesystem)的文件大小可能看起来非常大(~64GiB),比实际更大:

ls -klsh Docker.raw

这可能会产生某种误导,因为它会输出文件的逻辑大小而不是其物理大小。

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

du -h Docker.raw

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

【讨论】:

【参考方案4】:

为什么文件一直在增长?

如果经常使用 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 的使用,它显示了文件实际使用的文件系统块的数量。使用的块数不一定与文件“大小”相同,因为文件可以是sparse。

接下来在单独的终端中启动一个容器,并在其中创建一个 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,其中2097176 512-byte 扇区的增加约为 1GiB,正如预期的那样。如果切换回alpine容器终端并删除文件:

/ # rm -f 1GiB
/ # sync

然后检查主机上的文件:

$ ls -s Docker.raw 
12059672 Docker.raw

文件没有变小!无论 VM 内的文件发生了什么变化,主机似乎都不知道。

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

$ ls -s Docker.raw 
14109456 Docker.raw

它变得更大了!看来如果循环创建和销毁文件,Docker.raw(或Docker.qcow2)的大小会增加到上限(目前设置为64 GiB),即使VM内部的文件系统相对空。

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

由于实际中的块分配器倾向于偏爱未使用的块,结果是Docker.raw(或Docker.qcow2)将不断积累新块,其中许多包含陈旧数据。主机上的文件越来越大,尽管 VM 内的文件系统仍然报告有足够的可用空间。

修剪

TRIM 命令(或DISCARDUNMAP)允许文件系统向磁盘发出信号,告知磁盘范围内的扇区包含陈旧数据并且可以将其遗忘。这允许:

一个 SSD 驱动器,用于擦除和重复使用空间,而不是花时间在四处移动它;和 Docker for Mac 释放主机文件系统中的块,压缩文件。

那么我们如何做到这一点呢?

Docker for Mac 中的自动 TRIM

在 Docker for Mac 17.11 中有一个名为 trim-after-delete 的“任务”containerd 正在侦听 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
***kit-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

文件恢复到(大约)原来的大小——空间终于被释放了!

希望this blog 会有所帮助,还请查看以下针对此问题的 macOS docker 实用程序脚本:

https://github.com/wanliqun/macos_docker_toolkit

【讨论】:

【参考方案5】:

Mac 上的 Docker 还存在一个让很多人感到痛苦的问题:docker.qcow2 文件可能会不成比例地增长(高达 64gb)并且不会自行缩小。

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

正如 djs55 的其中一个回复所述,这是在计划中修复,但不是快速修复。引用:

.qcow2 作为块设备暴露给 VM,具有最大大小 64GiB。当容器在文件系统中创建新文件时, 新扇区被写入块设备。这些新领域是 附加到 .qcow2 文件导致它的大小增长,直到它 最终变为完全分配。当它碰到这个时它停止生长 最大尺寸。

...

我们希望分几个阶段解决此问题:(请注意,这仍处于 规划/设计阶段,但我希望它能给你一个想法)

1) 我们将切换到支持 TRIM 的连接协议,并且 在 qcow2 旁边的元数据文件中实现空闲块跟踪。 我们将创建一个可以离线运行的压缩工具来缩小 磁盘(有点像 qemu-img 转换但没有 dd if=/dev/zero 它应该很快,因为它已经知道空的位置 空间是)

2) 我们将在 VM 重新启动时自动运行压缩工具, 假设它足够快

3) 我们将切换到在线压缩器(有点像 GC 中的 编程语言)

我们也在考虑使 .qcow2 的最大大小 可配置。也许 64GiB 对于某些环境来说太大了,而且 较小的上限会有所帮助吗?


2019 年更新:自发布此答案以来,Docker for Mac 已经进行了许多更新以帮助缓解问题(特别是:支持不同的文件系统)。

尽管清理仍然不是全自动的,您可能需要不时进行修剪。有关有助于清理磁盘空间的单个命令,请参阅zhongjiajie's answer。

【讨论】:

这是答案。我的 .qcow2 高达 35Gb++! 非常感谢。我认为解决这个问题的唯一方法是经常清理这个文件。 @FrancoRabaglia 是的,我现在没有看到合适的解决方法,这将是计划修复的第一阶段:/ 如果我发现任何更新,我会将其编辑为答案。 我参考github.com/docker/for-mac/issues/371#issuecomment-315385246,然后输入docker run --rm --net=host --pid=host --privileged -it justincormack/nsenter1 /sbin/fstrim /var,qcow2文件被收缩了。 Docker 桌面现在支持调整磁盘映像的大小。它实际上以不同的大小重新创建它,从而丢失了其中的所有内容,但它仍然有帮助。【参考方案6】:
docker container prune
docker system prune
docker image prune
docker volume prune

【讨论】:

这会做什么?请详细说明。 还有其他可能有帮助的修剪命令,可能应该添加到此答案中,包括 docker image prunedocker volume prune【参考方案7】:

关于如何限制 docker 磁盘空间有几个选项,我将从限制/旋转日志开始:Docker container logs taking all my disk space

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

的 docker 日志

【讨论】:

这是一个 Mac 问题,不是 Linux 问题。【参考方案8】:

由于这里没有什么对我有用,所以我就是这样做的。检查文件大小:

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

然后在 docker 桌面简单地减小磁盘映像大小(我使用的是原始格式)。它会说它将删除所有内容,但是当您阅读这篇文章时,您可能已经拥有了。这样就创建了一个全新的空文件。

【讨论】:

【参考方案9】:
$ sudo docker system prune

警告!这将删除:

所有停止的容器 至少一个容器未使用的所有网络 所有悬空图像 所有悬空构建缓存

【讨论】:

以上是关于Docker 填满 macOS 上的存储空间的主要内容,如果未能解决你的问题,请参考以下文章

NODE.JS 如何在不填满存储空间的情况下保存 JSON 数据 [关闭]

全网最细Docker安装Minio,填满最新版大坑(强烈推荐收藏)

全网最细Docker安装Minio,填满最新版大坑(强烈推荐收藏)

Docker镜像分层存储与镜像精简

SQL Server 2008 在具有空间索引的可空地理列上的性能

系统存储在 macOS Mojave 中占用了太多空间