docker镜像(一)overlayfs
一、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"