一、Docker使用的存储引擎
Docker镜像是分层的结构,一个镜像一般是由多层镜像所构成的,然后通过联合文件系统,把各个镜像层进行组合,形成rootfs供容器使用。
现在docker默认使用的存储引擎是overlay2
# docker info
Storage Driver: overlay2
Backing Filesystem: xfs
Supports d_type: true
Native Overlay Diff: true
二、什么是overlayfs?
Overlayfs是一种堆叠文件系统,它依赖并建立在其它的文件系统之上(例如ext4fs和xfs等等),并不直接参与磁盘空间结构的划分,仅仅将原来底层文件系统中不同的目录进行“合并”,然后向用户呈现。因此对于用户来说,它所见到的overlay文件系统根目录下的内容就来自挂载时所指定的不同目录的“合集”。
三、使用overlayfs
挂载一个overlay文件系统,可以使用如下命令
mount -t overlay -o <options> overlay <mount point>
mount -t overlay -o lowerdir=/dir1:/dir2:/dir3:...:/dir25,upperdir=... overlay <mount point>
<mount point>是最终overlay的挂载点,其中overlay的options有如下:
- lowerdir=<dir>:指定用户需要挂载的lower层目录,lower层支持多个目录,用“:”间隔,优先级依次降低。最多支持500层。
- upperdir=<dir>:指定用户需要挂载的upper层目录,upper层优先级高于所有的lower层目录。
- workdir=<dir>:指定文件系统挂载后用于存放临时和间接文件的工作基础目录。
- default_permissions:
- redirect_dir=on/off:开启或关闭redirect directory特性,开启后可支持merged目录和纯lower层目录的rename/renameat系统调用。
- index=on/off:开启或关闭index特性,开启后可避免hardlink copyup broken问题。
让我们实例操作下
# mkdir -p lower/common-dir
# mkdir -p lower/lower-dir
# mkdir -p upper/common-dir
# mkdir -p upper/upper-dir
# mkdir merge work
# echo From lower >>lower/common-dir/lower-file
# echo From lower >>lower/lower-dir/lower-file
# echo From lower >>lower/lower-file
# echo From lower >>lower/common-file
# echo From upper >>upper/common-dir/upper-file
# echo From upper >>upper/upper-dir/upper-file
# echo From upper >>upper/upper-file
# echo From upper >>upper/common-file
# mount -t overlay \
-o lowerdir=/data/lower,upperdir=/data/upper,workdir=/data/work \
overlay /data/merge
# tree merge/
merge/
|-- common-dir
| |-- lower-file
| `-- upper-file
|-- common-file
|-- lower-dir
| `-- lower-file
|-- lower-file
|-- upper-dir
| `-- upper-file
`-- upper-file
# more merge/common-file
From upper
1、在merge目录创建文件或目录,新建的文件或目录会出现在upper目录的对应位置
# mkdir merge/new-dir
# touch merge/new-file merge/common-dir/new-file merge/lower-dir/new-file
# ll */new-file
-rw-r--r-- 1 root root 0 Oct 5 16:29 merge/new-file
-rw-r--r-- 1 root root 0 Oct 5 16:29 upper/new-file
# ll -d */new-dir
drwxr-xr-x 2 root root 6 Oct 5 16:28 merge/new-dir
drwxr-xr-x 2 root root 6 Oct 5 16:28 upper/new-dir
# ll */common-dir/new-file
-rw-r--r-- 1 root root 0 Oct 5 16:29 merge/common-dir/new-file
-rw-r--r-- 1 root root 0 Oct 5 16:29 upper/common-dir/new-file
# ll */lower-dir/new-file
-rw-r--r-- 1 root root 0 Oct 5 16:29 merge/lower-dir/new-file
-rw-r--r-- 1 root root 0 Oct 5 16:29 upper/lower-dir/new-file
2、修改merge目录中的upper的文件,upper目录中相应的文件被修改
# echo new > merge/common-dir/upper-file
# ll */common-dir/upper-file
-rw-r--r-- 1 root root 4 Oct 6 10:42 merge/common-dir/upper-file
-rw-r--r-- 1 root root 4 Oct 6 10:42 upper/common-dir/upper-file
# echo new > merge/upper-dir/upper-file
# ll */upper-dir/upper-file
-rw-r--r-- 1 root root 4 Oct 6 10:45 merge/upper-dir/upper-file
-rw-r--r-- 1 root root 4 Oct 6 10:45 upper/upper-dir/upper-file
# echo new > merge/common-file
# ll */common-file
-rw-r--r-- 1 root root 11 Oct 5 16:22 lower/common-file
-rw-r--r-- 1 root root 4 Oct 6 10:46 merge/common-file
-rw-r--r-- 1 root root 4 Oct 6 10:46 upper/common-file
3、修改merge目录中lower的文件,lower目录的中文件没有修改,upper目录拷贝了lower的文件,并进行修改
# echo new > merge/common-dir/lower-file # ll */common-dir/lower-file
-rw-r--r-- 1 root root 11 Oct 5 16:22 lower/common-dir/lower-file
-rw-r--r-- 1 root root 4 Oct 6 10:43 merge/common-dir/lower-file
-rw-r--r-- 1 root root 4 Oct 6 10:43 upper/common-dir/lower-file
# echo new > merge/lower-dir/lower-file
# ll */lower-dir/lower-file
-rw-r--r-- 1 root root 11 Oct 5 16:22 lower/lower-dir/lower-file
-rw-r--r-- 1 root root 4 Oct 6 10:44 merge/lower-dir/lower-file
-rw-r--r-- 1 root root 4 Oct 6 10:44 upper/lower-dir/lower-file
4、重命名merge中的lower目录,lower目录没有变化,upper目录新增whitout文件和重命名后的目录
# mv merge/lower-dir merge/new-dir
# ll -d */lower-dir
drwxr-xr-x 2 root root 24 Oct 5 16:22 lower/lower-dir
c--------- 1 root root 0, 0 Oct 6 10:48 upper/lower-dir
# ll -d */new-dir
drwxr-xr-x 3 root root 23 Oct 6 10:48 merge/new-dir
drwxr-xr-x 3 root root 23 Oct 6 10:48 upper/new-dir
5、删除文件或目录
Whiteout文件在用户删除文件时创建,用于屏蔽底层的同名文件,同时该文件在merge中是不可见的,所以用户就看不到被删除的文件或目录了。
whiteout文件并非普通文件,而是主次设备号都为0的字符设备(可以通过"mknod <name> c 0 0"命令手动创建),当用户在merge中通过ls命令(将通过readddir系统调用)检查父目录的目录项时,overlayfs会自动过过滤掉和whiteout文件自身以及和它同名的lower层文件和目录,达到了隐藏文件的目的,让用户以为文件已经被删除了。
在merge目录无法看到任何文件,lower目录文件没有任何变化,upper目录删除了属于其的文件,并创建了whieout文件遮盖lower的文件
# rm -rf merge/*
# ll merge/*
ls: cannot access merge/*: No such file or directory
# ll upper/*
c--------- 1 root root 0, 0 Oct 6 10:55 upper/common-dir
c--------- 1 root root 0, 0 Oct 6 10:55 upper/common-file
c--------- 1 root root 0, 0 Oct 6 10:48 upper/lower-dir
c--------- 1 root root 0, 0 Oct 6 10:55 upper/lower-file
# ll lower/*
-rw-r--r-- 1 root root 11 Oct 5 16:22 lower/common-file
-rw-r--r-- 1 root root 11 Oct 5 16:22 lower/lower-file
lower/common-dir:
total 4
-rw-r--r-- 1 root root 11 Oct 5 16:22 lower-file
lower/lower-dir:
total 4
-rw-r--r-- 1 root root 11 Oct 5 16:22 lower-file
五、在容器中的应用
Docker容器将镜像层(image layer)作为lower dir,将容器层(container layer)作为upper dir,最后挂载到容器merge挂载点,即容器的根目录下
# docker run -d ubuntu:latest sleep 3600
# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
605074f51a09 ubuntu:latest "sleep 3600" 17 minutes ago Up 17 minutes nostalgic_murdock
# docker inspect 605074f51a09
"GraphDriver": {
"Data": {
"LowerDir":
"/var/lib/docker/overlay2/e79c703ecfde4f4d62ac45a8006708b9557eea24743adb7b03881f699aafc56c-init/diff:
/var/lib/docker/overlay2/261602d78f852f9ebff7ffa4bc3b39469738e4a280f50886d797fb687b7e8703/diff:
/var/lib/docker/overlay2/3a613e532ba2bc17f964c5379070bb1c3a1408b9df958346cfa693463fd41290/diff:
/var/lib/docker/overlay2/b066cee05900179651f310ff3e8acbe2728236c7813cdb551a069765c9427204/diff",
"MergedDir": "/var/lib/docker/overlay2/e79c703ecfde4f4d62ac45a8006708b9557eea24743adb7b03881f699aafc56c/merged",
"UpperDir": "/var/lib/docker/overlay2/e79c703ecfde4f4d62ac45a8006708b9557eea24743adb7b03881f699aafc56c/diff",
"WorkDir": "/var/lib/docker/overlay2/e79c703ecfde4f4d62ac45a8006708b9557eea24743adb7b03881f699aafc56c/work"
},
"Name": "overlay2"
},
Lower层,容器镜像
"LowerDir":
"/var/lib/docker/overlay2/e79c703ecfde4f4d62ac45a8006708b9557eea24743adb7b03881f699aafc56c-init/diff:
/var/lib/docker/overlay2/261602d78f852f9ebff7ffa4bc3b39469738e4a280f50886d797fb687b7e8703/diff:
/var/lib/docker/overlay2/3a613e532ba2bc17f964c5379070bb1c3a1408b9df958346cfa693463fd41290/diff:
/var/lib/docker/overlay2/b066cee05900179651f310ff3e8acbe2728236c7813cdb551a069765c9427204/diff",
# docker image inspect ubuntu:latest
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:d42a4fdf4b2ae8662ff2ca1b695eae571c652a62973c1beb81a296a4f4263d92",
"sha256:90ac32a0d9ab11e7745283f3051e990054616d631812ac63e324c1a36d2677f5",
"sha256:782f5f011ddaf2a0bfd38cc2ccabd634095d6e35c8034302d788423f486bb177"
]
},
镜像由三层组成
# tree /var/lib/docker/overlay2/e79c703ecfde4f4d62ac45a8006708b9557eea24743adb7b03881f699aafc56c-init/diff
/var/lib/docker/overlay2/e79c703ecfde4f4d62ac45a8006708b9557eea24743adb7b03881f699aafc56c-init/diff
|-- dev
| |-- console
| |-- pts
| `-- shm
`-- etc
|-- hostname
|-- hosts
|-- mtab -> /proc/mounts
`-- resolv.conf
Upper层
"UpperDir": "/var/lib/docker/overlay2/e79c703ecfde4f4d62ac45a8006708b9557eea24743adb7b03881f699aafc56c/diff",
# ll /var/lib/docker/overlay2/e79c703ecfde4f4d62ac45a8006708b9557eea24743adb7b03881f699aafc56c/diff
total 0
空目录
Merge目录
"MergedDir": "/var/lib/docker/overlay2/e79c703ecfde4f4d62ac45a8006708b9557eea24743adb7b03881f699aafc56c/merged",
Work目录
"WorkDir": "/var/lib/docker/overlay2/e79c703ecfde4f4d62ac45a8006708b9557eea24743adb7b03881f699aafc56c/work"