dushaoshuai / dushaoshuai.github.io

https://www.shuai.host
0 stars 0 forks source link

overlay2 #133

Open dushaoshuai opened 1 year ago

dushaoshuai commented 1 year ago

软件版本:

$ uname -srmo
Linux 6.1.51-1-MANJARO x86_64 GNU/Linux
$ pacman -Qo mount
/usr/bin/mount is owned by util-linux 2.39.2-1

overlay2

OverlayFS 是一种联合文件系统(union filesystem),出现在 Linux 内核 3.18 版本中,它可以将两个文件系统 lowerdir 和 upperdir 叠加、展现为一个单独的文件系统 merged,这个过程叫做联合挂载(union mount)。lowerdir 和 upperdir 被称为层。

OverlayFS 的发展分为两个阶段 - overlay 和 overlay2。overlay2 是 overlay 的改进版,在内核 4.0 中引入,减少了 inode 使用量,提高了性能,增强了稳定性,本文关注 overlay2。overlay2 目前是 docker 默认的存储驱动。

文件系统叠加规则:

文件系统介绍:

挂载一个可读写 OverlayFS

如下,先新建一些文件和文件夹:

$ cd /tmp/
$ mkdir union-mount && cd union-mount/
$ mkdir lower upper work merged
$ echo "bar in lower" > lower/bar && echo "foo in lower" > lower/foo
$ echo "bar in upper" > upper/bar
$ mkdir upper/foo && touch upper/foo/{file1,file2}

此时的目录树如下,其中 lower 目录下 foo 是一个普通文件,upper 目录下 foo 是一个文件夹:

$ tree .
.
├── lower
│   ├── bar
│   └── foo
├── merged
├── upper
│   ├── bar
│   └── foo
│       ├── file1
│       └── file2
└── work

6 directories, 5 files

使用以下命令将 lower 和 upper 目录联合挂载到 merged 目录^1

$ sudo mount -t overlay overlay \
> -o lowerdir=./lower,upperdir=./upper,workdir=./work ./merged

使用 mount 命令查看挂载情况,rw 表明这是一个可读写(read write)的挂载:

$ mount | grep overlay
overlay on /tmp/union-mount/merged type overlay (rw,relatime,lowerdir=./lower,upperdir=./upper,workdir=./work)

查看 merged 目录下内容,和 upper 目录下相同:

$ tree .
.
├── lower
│   ├── bar
│   └── foo
├── merged
│   ├── bar
│   └── foo
│       ├── file1
│       └── file2
├── upper
│   ├── bar
│   └── foo
│       ├── file1
│       └── file2
└── work
    ├── index  [error opening dir]
    └── work  [error opening dir]

9 directories, 8 files

确认 merged 目录下的 bar 文件是 upper 目录下 bar 文件:

$ cat merged/bar 
bar in upper

可见,upper 目录下的内容遮挡了 lower 目录下的内容。

在 merged 目录下创建新文件 zoo,其实是在 upper 目录下创建:

$ touch merged/zoo
$ tree .
.
├── lower
│   ├── bar
│   └── foo
├── merged
│   ├── bar
│   ├── foo
│   │   ├── file1
│   │   └── file2
│   └── zoo
├── upper
│   ├── bar
│   ├── foo
│   │   ├── file1
│   │   └── file2
│   └── zoo
└── work
    ├── index  [error opening dir]
    └── work  [error opening dir]

9 directories, 10 files

取消联合挂载:

$ sudo umount /tmp/union-mount/merged

merged 目录下为空,upper 目录下 zoo 文件依旧在:

$ tree .
.
├── lower
│   ├── bar
│   └── foo
├── merged
├── upper
│   ├── bar
│   ├── foo
│   │   ├── file1
│   │   └── file2
│   └── zoo
└── work
    ├── index  [error opening dir]
    └── work  [error opening dir]

8 directories, 6 files

使用多个 lowerdir

lowerdir 可以是用 : 分隔的目录列表,如 lower1:lower2:lower3,其中,lower3 是 lowerdir 中最低的层,lower1 是 lowerdir 中最高的层。

接着上面的步骤,再新建一些文件和目录:

$ echo "baz in lower" > lower/baz
$ echo "baz in lower1" > lower1/baz
$ echo "baz in lower2" > lower2/baz
$ echo "baz in lower3" > lower3/baz
$ touch lower1/file_in_lower1
$ touch lower2/file_in_lower2
$ touch lower3/file_in_lower3

此时的目录树如下:

$ tree .
.
├── lower
│   ├── bar
│   ├── baz
│   └── foo
├── lower1
│   ├── baz
│   └── file_in_lower1
├── lower2
│   ├── baz
│   └── file_in_lower2
├── lower3
│   ├── baz
│   └── file_in_lower3
├── merged
├── upper
│   ├── bar
│   ├── foo
│   │   ├── file1
│   │   └── file2
│   └── zoo
└── work
    ├── index  [error opening dir]
    └── work  [error opening dir]

11 directories, 13 files

联合挂载:

$ sudo mount -t overlay overlay \
> -o lowerdir=./lower:./lower1:./lower2:./lower3,upperdir=upper,workdir=work ./merged

可以猜想到,lower 目录是 lowerdir 中的最高层,因此 lower/baz 会遮盖 lower1/baz,出现在 merged 目录中的 baz 会是 lower/baz;而 lower1/file_in_lower1、lower2/file_in_lower2、lower3/file_in_lower3 都未被上层文件遮盖,因此都会出现在 merged 目录中。

事实也确实是这样:

$ tree .
.
├── lower
│   ├── bar
│   ├── baz
│   └── foo
├── lower1
│   ├── baz
│   └── file_in_lower1
├── lower2
│   ├── baz
│   └── file_in_lower2
├── lower3
│   ├── baz
│   └── file_in_lower3
├── merged
│   ├── bar
│   ├── baz
│   ├── file_in_lower1
│   ├── file_in_lower2
│   ├── file_in_lower3
│   ├── foo
│   │   ├── file1
│   │   └── file2
│   └── zoo
├── upper
│   ├── bar
│   ├── foo
│   │   ├── file1
│   │   └── file2
│   └── zoo
└── work
    ├── index  [error opening dir]
    └── work  [error opening dir]

12 directories, 21 files
$
$ cat merged/baz
baz in lower

取消挂载:

$ sudo umount /tmp/union-mount/merged 
$ tree .
.
├── lower
│   ├── bar
│   ├── baz
│   └── foo
├── lower1
│   ├── baz
│   └── file_in_lower1
├── lower2
│   ├── baz
│   └── file_in_lower2
├── lower3
│   ├── baz
│   └── file_in_lower3
├── merged
├── upper
│   ├── bar
│   ├── foo
│   │   ├── file1
│   │   └── file2
│   └── zoo
└── work
    ├── index  [error opening dir]
    └── work  [error opening dir]

11 directories, 13 files

挂载一个只读 OverlayFS

挂载只读 overlay 时,不需要指定 upperdir 和 workdir。先新建一些文件和文件夹:

cd /tmp/
mkdir union-mount && cd union-mount/
mkdir lower1 lower2 merged
echo "a in lower1" > lower1/a
echo "b in lower1" > lower1/b
echo "a in lower2" > lower2/a
echo "c in lower2" > lower2/c

此时目录树为:

$ tree .
.
├── lower1
│   ├── a
│   └── b
├── lower2
│   ├── a
│   └── c
└── merged

4 directories, 4 files

挂载一个只读的 overlay 到 merged 目录,其中 lower1 层位于 lower2 层的上方:

$ sudo mount -t overlay overlay \
> -o lowerdir=./lower1:./lower2 ./merged

查看挂载情况,ro 表明这是一个只读(read only)的挂载:

$ mount | grep overlay
overlay on /tmp/union-mount/merged type overlay (ro,relatime,lowerdir=./lower1:./lower2,index=off)

此时目录树和文件情况如下,可见 lower1 是较高的层,其中的文件遮挡了 lower2 中的文件:

$ tree .
.
├── lower1
│   ├── a
│   └── b
├── lower2
│   ├── a
│   └── c
└── merged
    ├── a
    ├── b
    └── c

4 directories, 7 files
$
$ cat merged/*
a in lower1
b in lower1
c in lower2

尝试在 merged 目录下新建文件,失败:

$ touch merged/d
touch: cannot touch 'merged/d': Read-only file system

取消挂载:

$ sudo umount /tmp/union-mount/merged

merged 目录下为空:

$ tree .
.
├── lower1
│   ├── a
│   └── b
├── lower2
│   ├── a
│   ├── c
│   └── d
└── merged

4 directories, 5 files

OverlayFS 使用场景

(以下内容由 Bard 生成)

参见