[toc]
我们知道,容器启动的速度是非常快的,不同于服务器虚拟化的镜像,容器镜像的体积可以做的很小,启动时不需要做完整copy,一次下载,多次使用。
在讲解namespace时用chroot
做了一个简单的演示,过程中临时生成的文件都留在了chroot
目录里,下一次演示时还需要生成全新的chroot
目录,
如果文件系统目录很大,且要为启动多个容器复制多份,那效率必然很低。
那么docker是如何处理文件系统的呢?
如果每次生成容器时都去挂载同一个chroot目录,但写操作都不在原地执行,容器退出时清理掉这些数据,就能达到互不干扰、快速启动的效果了
docker提供了好几种方案,aufs
、btrfs
、devicemapper
、overlayfs
、zfs
、vfs
下面首先从overlayfs
入手来了解容器的文件系统处理过程
OverlayFS
OverlayFS是一种联合文件系统,它将一个Linux主机中的两个目录组合起来,一个在上,一个在下,对外提供统一的视图
在下的称为lowerdir,在上的称为upperdir,合并起来称为merged,应用程序能看到的是merged目录里的内容
他们之间的关系如下图
lowerdir是只读的,应用程序在merged进行的读写操作都发生在upperdir,当要读的文件的不在upperdir中时,会去lowerdir查找
当要修改的文件在lowdir层时,会通过中间目录将文件拷贝至upperdir再操作, 这个中间目录称为workdir
下面通过实践来看看具体效果
环境准备
% cd /tmp
% mkdir mkdir lower upper work merged
在只读层lower目录里生成测试数据
% mkdir lower/{a,b,c,d}
% date > lower/date
% tree lower
lower/
├── a
├── b
├── c
├── d
└── date
4 directories, 1 file
联合挂载
% mount -t overlay overlay -o lowerdir=/tmp/lower,upperdir=/tmp/upper,workdir=/tmp/work /tmp/merged
% tree /tmp/merged
/tmp/merged
├── a
├── b
├── c
├── d
└── date
4 directories, 1 file
可以看到,merged目录的内容和lower目录的一致,这是因为upper目录是空的
读操作
在读操作发生时
- 文件在upper层存在,直接读取,忽略lower层
- 文件不在upper层,从lower层查找
- 也就是说,文件查找层级只有2层,对比aufs的多层要简单明了的说,将节省大量时间
写操作
在写操作发生时
- 如果upper层有此文件,直接在upper层写
- 如果lower层和upper层都没有此文件,则直接在upper层写
- 如果文件只在lower层有,通过copy-up,将文件经过work层拷贝至upper层进行写操作
此操作只发生一次,因为下一次写操作会发现在upper层有此文件
% date > merged/date
% ls -l -i */date
20722267 -rw-r--r-- 1 root root 43 1月 4 22:43 lower/date
5534205 -rw-r--r-- 1 root root 43 1月 4 23:10 merged/date
5534205 -rw-r--r-- 1 root root 43 1月 4 23:10 upper/date
% touch merged/a/newfile
% ll -i */a/newfile
5534181 -rw-r--r-- 1 root root 0 1月 4 23:11 merged/a/newfile
5534181 -rw-r--r-- 1 root root 0 1月 4 23:11 upper/a/newfile
可以看到,写操作在upper层,并在merged层做了硬链接
删除操作
在删除操作发生时
- 文件只在upper层存在,直接删除
- 文件在upper层和lower层都存在,将在upper层创建同名的字符设备文件
- 文件只在lower层存在,将在upper层创建同名的字符设备文件
% rm -f merged/a/newfile
% ls -l */a/newfile
ls: 无法访问*/a/newfile: 没有那个文件或目录
% rm -f merged/date
% ls -l */date
-rw-r--r-- 1 root root 43 1月 4 22:43 lower/date
c--------- 1 root root 0, 0 1月 4 23:19 upper/date
% rm -f merged/d
% ls -ld */d
drwxr-xr-x 2 root root 6 1月 4 22:43 lower/d
c--------- 1 root root 0, 0 1月 4 23:24 upper/d
因为本机测试环境是3.10内核,删除时文件变为了字符设备
效果是一样的,merged层看不到删除的文件,lower层的文件从未发生改变
% tree merged/
merged/
├── a
├── b
└── c
3 directories, 0 files