如何清理 Docker ZFS 旧共享

Red*_*dro 7 zfs volumes docker

概括

鉴于:

  • 存储驱动docker用户为ZFS;
  • docker创建legacy数据集;

重击:

$ docker ps -a | wc -l
16

$ docker volume ls | wc -l
12

$ zfs list | grep legacy | wc -l
157
Run Code Online (Sandbox Code Playgroud)

16 个容器(运行和停止)。12卷。157 个数据集。这似乎是大量的遗留数据集。我想知道他们中的很多人是否是如此孤儿,甚至docker不再了解他们,所以他们没有得到清理。

基本原理

我的 Debian zfs 池中有大量遗留卷。当我开始在这台机器上使用 Docker 时,它们开始出现:

$ sudo zfs list | grep legacy | wc -l
486
Run Code Online (Sandbox Code Playgroud)

它们都是以下形式:

pool/var/<64-char-hash>                  202K  6,18T   818M  legacy
Run Code Online (Sandbox Code Playgroud)

此位置仅供 docker 使用。

$ docker info | grep -e Storage -e Dataset
Storage Driver: zfs
 Parent Dataset: pool/var
Run Code Online (Sandbox Code Playgroud)

我开始清理。

$ docker system prune -a
  (...)
$ sudo zfs list | grep legacy | wc -l
154
Run Code Online (Sandbox Code Playgroud)

这样更好。但是,我只运行了大约 15 个容器,并且在运行之后docker system prune -a,历史记录或每个容器都显示只有最后一个图像层仍然可用。其余的是<missing>(因为它们被清理了)。

$ docker images | wc -l
15
Run Code Online (Sandbox Code Playgroud)

如果所有容器在修剪其余部分后只使用最后一个镜像层,那么 docker 不应该只使用 15 个镜像层和 15 个正在运行的容器,总共 30 个卷吗?

$ sudo zfs list | grep legacy | wc -l
154
Run Code Online (Sandbox Code Playgroud)

我可以知道它们是否正在被容器/图像使用吗?是否有一个命令可以遍历pool/var/<hash>ZFS 中的所有数据集并找出它们属于哪个 docker 容器/映像?要么可以删除其中的很多,要么我不明白如何弄清楚(不仅仅是信任docker system prune)他们不能。

docker 过度使用 zfs 卷zfs list在视觉和性能方面都弄乱了我的命令。列出 zfs 卷现在需要大约 10 秒而不是 <1 秒。

证明 docker 看不到更多悬空计数

$ docker ps -qa --no-trunc --filter "status=exited"
  (no output)
$ docker images --filter "dangling=true" -q --no-trunc
  (no output)
$ docker volume ls -qf dangling=true
  (no output)
Run Code Online (Sandbox Code Playgroud)

zfs list 例子:

NAME                                                                                       USED  AVAIL  REFER  MOUNTPOINT
pool                                                                                      11,8T  5,81T   128K  /pool
pool/var                                                                                   154G  5,81T   147G  /mnt/var
pool/var/0028ab70abecb2e052d1b7ffc4fdccb74546350d33857894e22dcde2ed592c1c                 1,43M  5,81T  1,42M  legacy
pool/var/0028ab70abecb2e052d1b7ffc4fdccb74546350d33857894e22dcde2ed592c1c@211422332       10,7K      -  1,42M  -
# and 150 more of the last two with different hashes
Run Code Online (Sandbox Code Playgroud)

小智 6

我有同样的问题,但找不到满意的答案。添加我最终发现的内容, since this question is one of the top search results.

\n\n

背景

\n\n

Docker 的 ZFS 存储驱动程序将每个映像的每一层存储为单独的旧数据集。

\n\n

即使只有少量图像也可能产生大量层,每个层对应一个legacyZFS 数据集。

\n\n
    \n
  • 引自Docker ZFS 驱动程序文档:\n\n
    \n

    映像的基础层是 ZFS 文件系统。每个子层都是基于其下层的 ZFS 快照的 ZFS 克隆。容器是基于其创建的映像顶层的 ZFS 快照的 ZFS 克隆\xe2\x80\x99。

    \n
  • \n
\n\n

调查

\n\n

您可以通过运行以下命令来检查一张图像使用的数据集:

\n\n
 $ docker image inspect [IMAGE_NAME]\n
Run Code Online (Sandbox Code Playgroud)\n\n

输出示例:

\n\n
...\n"RootFS": {\n    "Type": "layers",\n    "Layers": [\n        "sha256:f2cb0ecef392f2a630fa1205b874ab2e2aedf96de04d0b8838e4e728e28142da",\n        ...\n        ...\n        ...\n        "sha256:2e8cc9f5313f9555a4decca744655ed461e21fbe48a0f078ed5f7c4e5292ad2e",\n    ]\n},\n...\n
Run Code Online (Sandbox Code Playgroud)\n\n

这解释了为什么您可以在仅运行十几个容器时看到创建的 150 多个数据集。

\n\n

解决方案

\n\n
    \n
  1. 修剪并删除未使用的图像。

    \n\n
    $ docker image prune -a\n
    Run Code Online (Sandbox Code Playgroud)
  2. \n
  3. 为了避免速度缓慢zfs list,请指定感兴趣的数据集。
    \n假设您将 docker 存储在 中tank/docker,其他文件存储在tank/data. data通过递归选项仅列出数据集:

    \n\n
    # recursively list tank/data/*\n$ zfs list tank/data -r\n
    Run Code Online (Sandbox Code Playgroud)
  4. \n
\n