Docker 在 macOS 上填满存储空间

Docker filling up storage on macOS

(Post 创建于 2016 年 10 月 5 日)

我注意到每次我 运行 图像并删除它时,我的系统都不会 return 到原始可用量 space。

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

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

[运行在默认 mac 终端上 ]

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

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

已编辑 POST

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

今天运行宁:

解决该问题的最简单方法是使用 Docker 实用程序 p运行e 系统。

docker system prune -a --volumes

关于如何限制 docker 磁盘空间有几个选项,我将从 limiting/rotating 日志开始:

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

的 docker 日志

可以挂载 Docker 存储的三个区域,因为 Docker 很谨慎 - 它不会自动删除其中任何一个:退出的容器、未使用的容器卷、未使用的图像层.在具有大量构建和 运行ning 的开发环境中,可能需要大量磁盘 space。

这三个命令清除所有未使用的内容:

  • 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) - 删除未被任何容器使用的卷。

这些对 运行 是安全的,它们不会删除图像引用的图像层或容器使用的数据卷。你可以给它们起别名,and/or把它们放在一个 CRON 作业中,定期清理本地磁盘。

Docker on Mac 有一个伤害很多人的额外问题:docker.qcow2 文件可能会超出比例(最大 64gb)并且不会'永远不会自行缩小。

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

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

The .qcow2 is exposed to the VM as a block device with a maximum size of 64GiB. As new files are created in the filesystem by containers, new sectors are written to the block device. These new sectors are appended to the .qcow2 file causing it to grow in size, until it eventually becomes fully allocated. It stops growing when it hits this maximum size.

...

We're hoping to fix this in several stages: (note this is still at the planning / design stage, but I hope it gives you an idea)

1) we'll switch to a connection protocol which supports TRIM, and implement free-block tracking in a metadata file next to the qcow2. We'll create a compaction tool which can be run offline to shrink the disk (a bit like the qemu-img convert but without the dd if=/dev/zero and it should be fast because it will already know where the empty space is)

2) we'll automate running of the compaction tool over VM reboots, assuming it's quick enough

3) we'll switch to an online compactor (which is a bit like a GC in a programming language)

We're also looking at making the maximum size of the .qcow2 configurable. Perhaps 64GiB is too large for some environments and a smaller cap would help?


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

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

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

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

  • ls -klsh Docker.raw

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

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

  • du -h Docker.raw

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

警告:

By default, volumes are not removed to prevent important data from being deleted if there is currently no container using the volume. Use the --volumes flag when running the command to prune volumes as well:

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

docker system prune -a --volumes

Docker system prune docs

为什么文件一直在增长?

如果经常使用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 字节扇区的增加约为 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),即使里面的文件系统虚拟机比较空。

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

由于实际中的块分配器倾向于使用未使用的块,结果是 Docker.raw(或 Docker.qcow2)将不断积累新块,其中许多包含陈旧数据。主机上的文件变得越来越大,即使 VM 内的文件系统仍然报告大量空闲 space.

TRIM

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

  • 一个 SSD 驱动器,用于擦除和重复使用 space,而不是花时间把它弄乱;和
  • Docker for Mac 释放主机文件系统中的块,缩小文件。

那么我们如何使它起作用呢?

自动 TRIM 在 Docker 中 Mac

在Docker for Mac 17.11 中有一个containerd“任务”叫做trim-after-delete监听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 的一部分),然后 运行s fstrim 在文件系统上。

回到上一节的例子,如果删除alpine容器里面的1GiB文件

/ # 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

文件恢复到(大约)原始大小 – space 终于被释放了!

希望 this blog 对您有所帮助,同时检查以下 macos docker 实用程序脚本来解决这个问题:

https://github.com/wanliqun/macos_docker_toolkit

$ sudo docker system prune

警告!这将删除:

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

因为这里没有任何东西对我有用,所以这就是我所做的。检查文件大小:

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

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