bigywater.tech
Docker · 26

OverlayFS 里的删除:whiteout 与 opaque 目录

容器里 rm 一个来自镜像的文件,下层的文件明明还在,怎么就“消失”了?这篇直接读 upperdir:whiteout 是什么类型的文件,删除后重建目录为什么带一个 opaque 属性,以及 docker commit 后它们在镜像层里变成什么。

0:0
被删除的镜像文件在 upperdir 里是主次设备号都为 0 的字符设备
opaque=y
删除后重建的目录,upperdir 里带 trusted.overlay.opaque=y,盖住下层同名目录的全部内容
.wh.gone.txt
docker commit 之后,被删文件在镜像层的 tar 里的名字

删除一个文件

实测 · 本机执行输出
  初始 upperdir:(空)
  rm /gone.txt 之后 upperdir:gone.txt
  upperdir/gone.txt 是:character special file, 主设备号:次设备号 = 0:0
  容器里 ls /gone.txt:ls: /gone.txt: No such file or directory
  upperdir/gone.txt 的大小:0 字节

下层(镜像层)是只读的,删除只能在可写层里“标记”。upperdir 里出现一个同名的字符设备,主设备号 0、次设备号 0,大小 0 字节;合并视图因此不再显示这个文件。

不是所有删除都要标记

实测 · 本机执行输出
  upperdir/tmp 里:(空)(创建又删除一个只在可写层的文件)

删除只存在于可写层的文件,upperdir 里不留痕迹:下层没有这个名字,就没什么需要遮住。

目录与 opaque

实测 · 本机执行输出
  rm -rf /dir 之后 upperdir/dir 是:character special file, 主设备号:次设备号 = 0:0;容器里 ls /dir:ls: /dir: No such file or directory
  重新 mkdir /dir 并写入 c.txt 之后 upperdir/dir 是:directory, 主设备号:次设备号 = 0:0;里面有:c.txt
  upperdir/dir 的扩展属性:{'trusted.overlay.opaque': 'y'}
  容器里 ls /dir:c.txt(原来的 a.txt、b.txt 被这个 opaque 目录整个盖住了)

rm -rf 一个目录,在 upperdir 里是同名的 0:0 字符设备。之后再 mkdir 同名目录,它是普通目录,但带 trusted.overlay.opaque=y 扩展属性,下层同名目录里的文件(a.txt、b.txt)不再透出。我是用特权容器挂载 upperdir 后用 Python 读到的这个属性。

同名重建

实测 · 本机执行输出
  upperdir/keep.txt 是:regular file, 主设备号:次设备号 = 0:0;内容:again

文件删除后又用同名创建,upperdir 里只是一个普通文件,不需要 whiteout。

commit 以后

实测 · 本机执行输出
  commit 退出码 0;镜像共 3 层,最后一层(只含这个容器的改动)的条目:['dir', 'dir/.wh.a.txt', 'dir/.wh.b.txt', 'dir/c.txt', '.wh.gone.txt', 'keep.txt']

运行时的 whiteout 和镜像层里的 whiteout 是两种形式:docker commit 后,新层 tar 里是 .wh.gone.txt、dir/.wh.a.txt 这样的条目。这次 commit 里目录没有出现 .wh..wh..opq,而是逐个文件写了 .wh.——别的构建方式(Dockerfile 里的 RUN rm)产生什么,见 c3。

分步演示

删除与 opaque
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Docker Desktop(Engine 29.8.2,容器跑在 Docker Desktop 自带的 Linux 虚拟机里,内核与宿主机的 macOS 不同);镜像为 linux/arm64;需要看虚拟机内部时用特权容器 + nsenter;计时用 time / date +%s%N,数字每次运行会有小幅抖动。进入虚拟机的方法见 c19(特权容器加 nsenter);读扩展属性是用特权的 python:3.12-alpine 容器只读挂载 upperdir 后 os.getxattr;docker commit 后用 docker save 读出最后一层的 tar;实验后已删除容器和镜像
    • 没有验证:经典 overlay2 驱动、metacopy 与 redirect_dir 的影响、用 Dockerfile 的 RUN rm -rf 构建出的层里是否有 .wh..wh..opq、rename 目录在 overlay 里的表现、内核版本差异
    京ICP备2026067502号-1京公网安备11010502063487号