Docker 镜像在提取过程中大幅膨胀,无法提取 docker 镜像

Docker 镜像在提取过程中大幅膨胀,无法提取 docker 镜像

系统信息

我们公司在本地嵌入式 Linux 设备(Debian 9 OS)上运行基于 arm32v7/python:3.11-bullseye 镜像打包在 Docker 镜像中的应用程序,大小约为 800MB。

这些设备(下称“边缘设备”)具有有限的板载内存;设备是标准化的,每个设备具有约 6GB eMMC 内存,并且几乎所有空间都分配给了 overlayfs,这也是 Docker 配置来存储其数据的地方。

dockerd的daemon.json:

{
    "graph": "/overlayfs/docker",
    "dns": [
        "8.8.8.8"
    ],
    "log-driver": "json-file",
    "log-opts": {
      "max-size": "10m",
      "max-file": "3"
    }
}

该公司使用的应用程序的总图像大小为839MB拉出后 - 我通过docker image ls另一台同样在生产中运行的边缘设备检查了这一点。

问题

将图像从注册表拉到边缘设备时,我在提取阶段用完了空间 - 而可用空间明显大于图像大小。

错误信息(不同运行的实际路径不同):

write /var/lib/docker/vfs/dir/< long hash here >/usr/lib/arm-linux-gnueabihf/libicudata.a: no space left on device

这种情况是最近才开始发生的,镜像没有任何变化——之前在同样的设备上部署了同样的镜像,可用空间差别不大(大致4GB正常情况下可在所有设备上使用)。

在提取过程中,我反复检查剩余的可用空间df -h,发现它在死机前已占用了所有约 4GB 的可用空间。

df -h开始拉动之前的输出:

Filesystem      Size  Used Avail Use% Mounted on
devtmpfs        494M     0  494M   0% /dev
tpmfs           504M   48M  457M  10% /run
/dev/mmcblk0p2  446M  344M   75M  83% /
/dev/mmcblk0p3  6.6G  2.5G  3.9G  39% /overlayfs
overlay         6.6G  2.5G  3.9G  39% /var
overlay         6.6G  2.5G  3.9G  39% /etc
overlay         6.6G  2.5G  3.9G  39% /home
overlay         6.6G  2.5G  3.9G  39% /root
overlay         6.6G  2.5G  3.9G  39% /sbin
overlay         6.6G  2.5G  3.9G  39% /bin
overlay         6.6G  2.5G  3.9G  39% /usr
overlay         6.6G  2.5G  3.9G  39% /lib
overlay         6.6G  2.5G  3.9G  39% /tmp
overlay         6.6G  2.5G  3.9G  39% /mnt
overlay         6.6G  2.5G  3.9G  39% /opt
overlay         6.6G  2.5G  3.9G  39% /media
tmpfs           504M  4.0K  504M   1% /dev/shm
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           504M     0  504M   0% /sys/fs/cgroup
tmpfs           101M     0  101M   0% /run/user/1001

df -h拉动失败前的输出:

Filesystem      Size  Used Avail Use% Mounted on
devtmpfs        494M     0  494M   0% /dev
tpmfs           504M   48M  457M  10% /run
/dev/mmcblk0p2  446M  344M   75M  83% /
/dev/mmcblk0p3  6.6G  6.2G  193M  98% /overlayfs
overlay         6.6G  6.2G  193M  98% /var
overlay         6.6G  6.2G  193M  98% /etc
overlay         6.6G  6.2G  193M  98% /home
overlay         6.6G  6.2G  193M  98% /root
overlay         6.6G  6.2G  193M  98% /sbin
overlay         6.6G  6.2G  193M  98% /bin
overlay         6.6G  6.2G  193M  98% /usr
overlay         6.6G  6.2G  193M  98% /lib
overlay         6.6G  6.2G  193M  98% /tmp
overlay         6.6G  6.2G  193M  98% /mnt
overlay         6.6G  6.2G  193M  98% /opt
overlay         6.6G  6.2G  193M  98% /media
tmpfs           504M  4.0K  504M   1% /dev/shm
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           504M     0  504M   0% /sys/fs/cgroup
tmpfs           101M     0  101M   0% /run/user/1001

这就引出了以下问题:

为什么会发生这种情况我该如何防止这种情况发生或解决这个问题

到目前为止我已经尝试了以下方法:

  1. 修剪 docker 系统和图像。结果:回收了 0B。
  2. 完全删除 Docker 的 VFS (/var/lib/docker/vfs/dir/) 下的所有内容。结果:回收了拉取操作占用的所有空间,但问题并未解决 - 再次拉取操作时仍发生完全相同的事情。
  3. docker save 到 tar.gz 存档中,docker load 到目标设备。结果:与 pull 时完全相同。
  4. 直接在边缘设备上重建映像。拉取基础映像时也会发生同样的事情。

我没有找到任何方法来限制 Docker 用于提取的(临时?)空间。

答案1

在我的案例中,问题的根本原因是受影响系统上的 Docker 守护进程停止使用 overlay2 存储驱动程序,并开始使用 VFS 存储驱动程序。可以通过docker info以下方式识别此问题,如果 dockerd 已关闭,则通过检查 /var/lib/docker/vfs/dir/ 中是否存在文件(或者是否存在)。

对于相同的图像,VFS 会消耗更多存储空间,如下所示VFS 存储驱动程序的 Docker 文档页面

由于 VFS 模式从未打算在生产场景中启用(或者,在我们的案例中,从来没有启用过),因此从未使用与该存储驱动程序配对的 dockerd 测试应用程序映像,并且 VFS 下的生成映像确实超出了可用空间。

解决方案

在这种特殊情况下,解决方案是手动将以下内容添加到 /etc/docker/daemon.json 中:"storage-driver": "overlay2"

仅声明了存储驱动程序的示例 daemon.json:

{
  "storage-driver": "overlay2"
}

不幸的是,这个问题还意味着 overlay2 很可能由于某种原因在目标设备上停止工作,因为它是 dockerd 尝试加载的第一个存储驱动程序之一,但如果我们假设内核支持 overlayfs 并且 dockerd 不在容器本身下运行,那么纠正这个问题超出了这个问题的范围。

在我的特定情况下,dockerd 可能尝试将其存储挂载在 /var/lib/docker 或已使用 OverlayFS 挂载的其他目录下。docker 不支持此功能,因此我手动指定它将所有数据放在 overlayfs/ 下的特定文件夹中,使用图形选项。

这是允许 dockerd 使用 overlay2 驱动程序的 daemon.json:

{
    "graph": "/overlayfs/docker",
    "dns": [
        "8.8.8.8"
    ]
}

相关内容