docker · 2024-11-28 0

linux overlay 文件系统

前言

在尝试在容器中,运行容器时,出现了 failed to extract layer 错误,探究发现和 overlay 文件系统 有关

1.启动容器

zxm@zxm-pc:~$ docker run -itd --name ctr-1 --hostname=ctr-1 --privileged ubuntu:20.04

2.安装 containerd

apt install containerd -y

3.拉取镜像

拉取镜像时,会使用出现 failed to extract layer 错误,镜像的文件在 /var/lib/containerd 下

root@ctr-1:/# ctr image pull docker.io/library/nginx:1.23.3
docker.io/library/nginx:1.23.3:                                                   resolved       |++++++++++++++++++++++++++++++++++++++| 
index-sha256:f4e3b6489888647ce1834b601c6c06b9f8c03dee6e097e13ed3e28c01ea3ac8c:    done           |++++++++++++++++++++++++++++++++++++++| 
...
elapsed: 13.3s                                                                    total:  54.3 M (4.1 MiB/s)                                       
unpacking linux/amd64 sha256:f4e3b6489888647ce1834b601c6c06b9f8c03dee6e097e13ed3e28c01ea3ac8c...
INFO[0014] apply failure, attempting cleanup             error="failed to extract layer sha256:e65242c66bbe3550450dc1ce55da200fdd36a82246b3702cc2f0dbe5ff9ade84: failed to convert whiteout file \"docker-entrypoint.d/.wh..wh..opq\": operation not supported: unknown" key="extract-912331533-jVFX sha256:cc6b5ded0d53019de2911c55226548c7707a29af8cd6a90eb51a437255aa0b42"
ctr: failed to extract layer sha256:e65242c66bbe3550450dc1ce55da200fdd36a82246b3702cc2f0dbe5ff9ade84: failed to convert whiteout file "docker-entrypoint.d/.wh..wh..opq": operation not supported: unknown

4.文件类型

于是,对比到宿主机与容器文件类型的不同,宿主机是 ext4,容器是 overlay

宿主机文件系统:

zxm@zxm-pc:~$ df -TH
文件系统       类型      容量  已用  可用 已用% 挂载点
udev           devtmpfs   17G     0   17G    0% /dev
tmpfs          tmpfs     3.4G  2.7M  3.4G    1% /run
/dev/nvme0n1p2 ext4      491G  363G  104G   78% /
tmpfs          tmpfs      17G  432M   17G    3% /dev/shm
tmpfs          tmpfs     5.3M  4.1k  5.3M    1% /run/lock
tmpfs          tmpfs      17G     0   17G    0% /sys/fs/cgroup
/dev/nvme0n1p1 vfat      536M  6.4M  530M    2% /boot/efi
tmpfs          tmpfs     3.4G   50k  3.4G    1% /run/user/1000
zxm@zxm-pc:~$ df -TH /var/lib/containerd/
文件系统       类型  容量  已用  可用 已用% 挂载点
/dev/nvme0n1p2 ext4  491G  363G  104G   78% /

容器文件系统:

root@ctr-1:/# df -TH
Filesystem     Type     Size  Used Avail Use% Mounted on
overlay        overlay  491G  363G  104G  78% /
tmpfs          tmpfs     68M     0   68M   0% /dev
tmpfs          tmpfs     17G     0   17G   0% /sys/fs/cgroup
shm            tmpfs     68M     0   68M   0% /dev/shm
/dev/nvme0n1p2 ext4     491G  363G  104G  78% /etc/hosts
root@ctr-1:/# df -TH /var/lib/containerd/
Filesystem     Type     Size  Used Avail Use% Mounted on
overlay        overlay  491G  363G  104G  78% /

一、OverlayFS

OverlayFS 就是 UnionFS 的一种实现,是联合文件系统

1.创建 overlay 文件

zxm@zxm-pc:~$ umount ./merged
zxm@zxm-pc:~$ rm -rf lower upper merged work
zxm@zxm-pc:~$ mkdir lower upper merged work
zxm@zxm-pc:~$ echo "I'm from lower!" > lower/in_lower.txt
zxm@zxm-pc:~$ echo "I'm from upper!" > upper/in_upper.txt
zxm@zxm-pc:~$ echo "I'm from lower!" > lower/in_both.txt
zxm@zxm-pc:~$ echo "I'm from upper!" > upper/in_both.txt

使用 mount 挂载,类型是 overlay

zxm@zxm-pc:~$ mount -t overlay overlay -o lowerdir=./lower,upperdir=./upper,workdir=./work ./merged

目录下的文件有:

zxm@zxm-pc:~$ ls ./merged/
in_both.txt  in_lower.txt  in_upper.txt
zxm@zxm-pc:~$ ls ./upper/
in_both.txt  in_upper.txt
zxm@zxm-pc:~$ ls ./lower/
in_both.txt  in_lower.txt

文件系统是:

zxm@zxm-pc:~$ df -TH
文件系统       类型      容量  已用  可用 已用% 挂载点
udev           devtmpfs   17G     0   17G    0% /dev
tmpfs          tmpfs     3.4G  2.7M  3.4G    1% /run
/dev/nvme0n1p2 ext4      491G  363G  104G   78% /
tmpfs          tmpfs      17G  432M   17G    3% /dev/shm
tmpfs          tmpfs     5.3M  4.1k  5.3M    1% /run/lock
tmpfs          tmpfs      17G     0   17G    0% /sys/fs/cgroup
/dev/nvme0n1p1 vfat      536M  6.4M  530M    2% /boot/efi
tmpfs          tmpfs     3.4G   50k  3.4G    1% /run/user/1000
overlay        overlay   491G  363G  104G   78% /home/zxm/merged
zxm@zxm-pc:~$ df -TH merged/
文件系统       类型     容量  已用  可用 已用% 挂载点
overlay        overlay  491G  362G  104G   78% /home/zxm/merged
zxm@zxm-pc:~$ df -TH upper/
文件系统       类型  容量  已用  可用 已用% 挂载点
/dev/nvme0n1p2 ext4  491G  362G  104G   78% /
zxm@zxm-pc:~$ df -TH lower/
文件系统       类型  容量  已用  可用 已用% 挂载点
/dev/nvme0n1p2 ext4  491G  362G  104G   78% /
zxm@zxm-pc:~$ df -TH work/
文件系统       类型  容量  已用  可用 已用% 挂载点
/dev/nvme0n1p2 ext4  491G  362G  104G   78% /

挂载点:

zxm@zxm-pc:~$ cat /proc/mounts | grep overlay
overlay /home/zxm/merged overlay rw,relatime,lowerdir=./lower,upperdir=./upper,workdir=./work 0 0

2.分析 overlay

OverlayFS 的一个 mount 命令牵涉到四类目录,分别是 lower,upper,merged 和 work

  • “merge层”相当于提供给用户进行交互的视图层;
  • “upper层”相当于存储实际发生变动的地方;
  • “lower层”是不变的,用户通过 merge 层视图对 lower 层文件的所有操作,都被重定向到“upper层”了,特殊的是删除操作,会在upper层生成一个特殊的c类型的文件来代表该文件被删。
  • 用户交互时只能对 merge 层的视图来操作。
  • 在 merge 层的视图中,上层覆盖下层同名文件,上下关系不只是 upper 和 lower 之间,即便在多个 lower 层中,也是上层覆盖下层。

1) 首先,最下面的"lower/",也就是被 mount 两层目录中底下的这层(lowerdir)。

在 OverlayFS 中,最底下这一层里的文件是不会被修改的,可以认为它是只读的。在这个例子里我们只有一个 lower/ 目录,不过 OverlayFS 是支持多个 lowerdir 的。

2) 然后看"uppder/",它是被 mount 两层目录中上面的这层 (upperdir)。

在 OverlayFS 中,如果有文件的创建,修改,删除操作,那么都会在这一层反映出来,它是可读写的。

3) 接着是最上面的"merged" ,它是挂载点(mount point)目录,也是用户看到的目录,用户的实际文件操作在这里进行。

4) 还有一个"work/",它只是一个存放临时文件的目录,OverlayFS 中如果有文件修改,就会在中间过程中临时存放文件到这里。

可以看到,OverlayFS 会 mount 两层目录,分别是 lower 层和 upper 层,这两层目录中的文件都会映射到挂载点上。

从挂载点的视角看,upper 层的文件会覆盖 lower 层的文件,比如"in_both.txt"这个文件,在 lower 层和 upper 层都有,但是挂载点 merged/ 里看到的只是 upper 层里的 in_both.txt.

3.操作 overlay

如果我们在 merged/ 目录里做文件操作,具体包括这三种:

1) 新建文件,这个文件会出现在 upper/ 目录中。

2) 删除文件,如果我们删除"in_upper.txt",那么这个文件会在 upper/ 目录中消失。
如果删除"in_lower.txt", 在 lower/ 目录里的"in_lower.txt"文件不会有变化,只是在 upper/ 目录中增加了一个特殊文件来告诉 OverlayFS,"in_lower.txt'这个文件不能出现在 merged/ 里了,这就表示它已经被删除了。

3) 修改文件,类似如果修改"in_lower.txt",那么就会在 upper/ 目录中新建一个"in_lower.txt"文件,包含更新的内容,而在 lower/ 中的原来的实际文件"in_lower.txt"不会改变。

1) 新建文件

在 merged/ 下新建 t1.txt 文件,可以看到 mergerd/ 和 upper/ 都有这个文件

zxm@zxm-pc:~$ touch merged/t1.txt
zxm@zxm-pc:~$ ls merged/
in_both.txt  in_lower.txt  in_upper.txt  t1.txt
zxm@zxm-pc:~$ ls upper/
in_both.txt  in_upper.txt  t1.txt
zxm@zxm-pc:~$ ls lower/
in_both.txt  in_lower.txt

2) 删除文件

删除 merged/ 下的 in_upper.txt 文件,可以看到 mergerd/ 和 upper/ 都有没有了这个文件

如果删除 merged/ 下的 in_lower.txt,可以看到 mergerd/ 没有了这个文件,lower/ 还有这个文件,但在 upper/ 层中创建了同名 whiteout 文件,它们的文件类型为c

zxm@zxm-pc:~$ rm -rf merged/in_upper.txt 
zxm@zxm-pc:~$ ls merged/
in_both.txt  in_lower.txt  t1.txt
zxm@zxm-pc:~$ ls upper/
in_both.txt  t1.txt
zxm@zxm-pc:~$ ls lower/
in_both.txt  in_lower.txt

3) 修改文件

修改 merged/ 下的 in_lower.txt 文件,可以看到 upper/ 下会新增 in_lower.txt 文件,内容是最新的,lower/ 下的 in_lower.txt 还是原来的内容

zxm@zxm-pc:~$ vim merged/in_lower.txt
zxm@zxm-pc:~$ ls merged/
in_both.txt  in_lower.txt  t1.txt
zxm@zxm-pc:~$ ls upper/
in_both.txt  in_lower.txt  t1.txt
zxm@zxm-pc:~$ ls lower/
in_both.txt  in_lower.txt
zxm@zxm-pc:~$ cat upper/in_lower.txt 
I'm from lower!
Update!
zxm@zxm-pc:~$ cat lower/in_lower.txt 
I'm from lower!

二、docker 与 overlayfs

容器的镜像文件中各层正好作为 OverlayFS 的 lowerdir 的目录,然后加上一个空的 upperdir 一起挂载好后,就组成了容器的文件系统。

zxm@zxm-pc:~$ mount
overlay on /var/lib/docker/overlay2/17194c2493dd94625f22cab761c232d5460ca893b4ced1899cef6185fcc6e124/merged type overlay (rw,relatime,lowerdir=/var/lib/docker/overlay2/l/FDHYZNDRHZDNMZZACFIA4FXLNK:/var/lib/docker/overlay2/l/XGL366BVX5QSVR6D5K7LBN5CI5,upperdir=/var/lib/docker/overlay2/17194c2493dd94625f22cab761c232d5460ca893b4ced1899cef6185fcc6e124/diff,workdir=/var/lib/docker/overlay2/17194c2493dd94625f22cab761c232d5460ca893b4ced1899cef6185fcc6e124/work)
zxm@zxm-pc:~$ cat /proc/mounts | grep overlay
overlay /var/lib/docker/overlay2/17194c2493dd94625f22cab761c232d5460ca893b4ced1899cef6185fcc6e124/merged overlay rw,relatime,lowerdir=/var/lib/docker/overlay2/l/FDHYZNDRHZDNMZZACFIA4FXLNK:/var/lib/docker/overlay2/l/XGL366BVX5QSVR6D5K7LBN5CI5,upperdir=/var/lib/docker/overlay2/17194c2493dd94625f22cab761c232d5460ca893b4ced1899cef6185fcc6e124/diff,workdir=/var/lib/docker/overlay2/17194c2493dd94625f22cab761c232d5460ca893b4ced1899cef6185fcc6e124/work 0 0

查看 merged/ 文件系统类型是 overlay

zxm@zxm-pc:~$ df -TH /var/lib/docker/overlay2/17194c2493dd94625f22cab761c232d5460ca893b4ced1899cef6185fcc6e124/merged/
文件系统       类型     容量  已用  可用 已用% 挂载点
overlay        overlay  491G  361G  105G   78% /var/lib/docker/overlay2/17194c2493dd94625f22cab761c232d5460ca893b4ced1899cef6185fcc6e124/merged
zxm@zxm-pc:~$ ls -lh /var/lib/docker/overlay2/17194c2493dd94625f22cab761c232d5460ca893b4ced1899cef6185fcc6e124/merged
lrwxrwxrwx  1 root root    7 4月  12  2023 bin -> usr/bin
drwxr-xr-x  2 root root 4.0K 4月  15  2020 boot
drwxr-xr-x  1 root root 4.0K 11月 29 09:18 dev
drwxr-xr-x  1 root root 4.0K 11月 29 09:18 etc
drwxr-xr-x  2 root root 4.0K 4月  15  2020 home
lrwxrwxrwx  1 root root    7 4月  12  2023 lib -> usr/lib
lrwxrwxrwx  1 root root    9 4月  12  2023 lib32 -> usr/lib32
lrwxrwxrwx  1 root root    9 4月  12  2023 lib64 -> usr/lib64
lrwxrwxrwx  1 root root   10 4月  12  2023 libx32 -> usr/libx32
drwxr-xr-x  2 root root 4.0K 4月  12  2023 media
drwxr-xr-x  2 root root 4.0K 4月  12  2023 mnt
drwxr-xr-x  2 root root 4.0K 4月  12  2023 opt
drwxr-xr-x  2 root root 4.0K 4月  15  2020 proc
drwx------  2 root root 4.0K 4月  12  2023 root
drwxr-xr-x  5 root root 4.0K 4月  12  2023 run
lrwxrwxrwx  1 root root    8 4月  12  2023 sbin -> usr/sbin
drwxr-xr-x  2 root root 4.0K 4月  12  2023 srv
drwxr-xr-x  2 root root 4.0K 4月  15  2020 sys
drwxrwxrwt  2 root root 4.0K 4月  12  2023 tmp
drwxr-xr-x 13 root root 4.0K 4月  12  2023 usr
drwxr-xr-x 11 root root 4.0K 4月  12  2023 var

lowerdir 允许有多个目录,在被挂载后,这些目录里的文件都是不会被修改或者删除的,也就是只读的;upperdir 只有一个,不过这个目录是可读写的,挂载点目录中的所有文件修改都会在 upperdir 中反映出来。

容器的镜像文件中各层正好作为 OverlayFS 的 lowerdir 的目录,然后加上一个空的 upperdir 一起挂载好后,就组成了容器的文件系统。

三、解决

docker run -itd --name ctr-1 --hostname=ctr-1 -v /data/node1/var/lib/containerd:/var/lib/containerd --privileged ubuntu:20.04

要想在容器内运行容器:

把容器内 containerd 需要操作变为 overlay 类型的目录,挂载到宿主机器,这样就保证了容器内的 /var/lib/containerd 目录是 ext4 类型