系统信息
我们公司在本地嵌入式 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
这就引出了以下问题:
为什么会发生这种情况和我该如何防止这种情况发生或解决这个问题?
到目前为止我已经尝试了以下方法:
- 修剪 docker 系统和图像。结果:回收了 0B。
- 完全删除 Docker 的 VFS (/var/lib/docker/vfs/dir/) 下的所有内容。结果:回收了拉取操作占用的所有空间,但问题并未解决 - 再次拉取操作时仍发生完全相同的事情。
- docker save 到 tar.gz 存档中,docker load 到目标设备。结果:与 pull 时完全相同。
- 直接在边缘设备上重建映像。拉取基础映像时也会发生同样的事情。
我没有找到任何方法来限制 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"
]
}