docker镜像分层背后的秘密-overlayfs介绍

前言

docker镜像比较大的一个优势就是分层管理。每个镜像都由一层或多层layer组成。这种设计使得镜像仓库的管理类似于githup仓库的管理,commit镜像只是提交容器镜像中发生变更的部分,这样大大减轻了仓库的负荷。然而镜像的修改并不像代码修改那么简单,可以用diff一目了然看出,如果实现对镜像修改的内容做差分,就要依赖于内核中的一些技术来支持。例如AUFS、Overlay这些技术的支持。现在我们来看看内核的overlayfs这个内核模块是如何支持docker镜像的分层管理的。

overlayFS简介

overlayFS是一个 FUSE 模块,提供将多个文件夹的内容“合并”到同一个目录下的能力。是在Linux4.2内核引入的(15年8月)。 如下所示,在最上层可以看到所有的文件视图,但是底层是只读的,不能被修改的。如果同名的文件被修改了会在上层新建一个同名的文件,并且覆盖掉底层的展示。

例如假设有如下目录结构: /-a

|- test1 |- test2

| /- def

| /- dir2

| /- test3

/-b

|- test2

| /- abc

|- test4

| /- www

且A目录处于B目录的上层,合并到同一个目录 mp 下则得到

/-mp

|- test1 |- test2

| /- def

/- dir2

/- test3

|- test4

| /- www

如果原文件夹中存在重名文件,则根据覆盖(overlay)次序,后者覆盖前者。

overlayFS简单实战

1.如何判断内核中加载了overlay root@qa-control-pub-ci-build1:~# lsmod |grep over overlay 28140 0 如果没有加载的话,则使用如下命令加载 modprobe overlay 2.挂载overlayfs文件系统 创建几个文件夹如下所示

root@qa-control-pub-ci-build1:~/cxqdir# tree
.
├── low
│   └── 11.txt
├── merged
├── upper
│   └── 22.txt
└── work
    └── work

用下面的命令挂载overlayfs文件系统,该命令将low和upper合并成一个merged 名称的overlayfs文件系统。

mount -t overlay overlay -olowerdir=./low,upperdir=./upper,workdir=./work ./merged

再查看目录结构

root@qa-control-pub-ci-build1:~/cxqdir# tree
.
├── low
│   └── 11.txt
├── merged
│   ├── 11.txt
│   └── 22.txt
├── upper
│   └── 22.txt
└── work
    └── work

5 directories, 4 files

可以看到merged中展示的文件是low和upper里面的文件集合。 3.同名覆盖的测试 原始内容如下

root@qa-control-pub-ci-build1:~/cxqdir/merged# cat 11.txt 
1111111111111111111111
root@qa-control-pub-ci-build1:~/cxqdir/merged# cat 22.txt 
2222222

在merge目录中对11.txt内容进行修改,例如

root@qa-control-pub-ci-build1:~/cxqdir/merged# vim 11.txt 
root@qa-control-pub-ci-build1:~/cxqdir/merged# cat 11.txt 
333333333
分别查看low和upper目录下文件,发现low下面的同名文件内的内容没有变,而upper里面多了一个同名文件。
root@qa-control-pub-ci-build1:~/cxqdir/merged# cat ../low/11.txt
1111111111111111111111
root@qa-control-pub-ci-build1:~/cxqdir/merged# cat ../upper/11.txt
333333333
值得注意的是upper中新增的11.txt文件和merge中的文件node是一样的。
root@qa-control-pub-ci-build1:~/cxqdir/merged# ls -i ../upper/11.txt
350031 ../upper/11.txt
root@qa-control-pub-ci-build1:~/cxqdir/merged# ls -i 11.txt
350031 11.txt
但是跟底层low内的同名文件node不一样
root@qa-control-pub-ci-build1:~/cxqdir/merged# ls -i ../low/11.txt 
350033 ../low/11.txt

4.删除文件的测试

在merge中将11.txt删除。
root@qa-control-pub-ci-build1:~/cxqdir/merged# rm 11.txt 
root@qa-control-pub-ci-build1:~/cxqdir/merged# ls -l 
total 4
-rw-r--r-- 1 root root 8 May  6 13:55 22.txt
查看low文件11.txt仍然是最一开始时的内容。
root@qa-control-pub-ci-build1:~/cxqdir/merged# cat ../low/11.txt 
1111111111111111111111
查看upper目录中仍然有11.txt文件,但是变成一个大小为0,且没有任何人有权限的一个空文件。
root@qa-control-pub-ci-build1:~/cxqdir/merged# ls -l ../upper/11.txt
c--------- 1 root root 0, 0 May  6 14:08 ../upper/11.txt

overlayfs用这种删除标记的方式标识文件被删除,(如果upper中没有该文件的话,则底层low中的同名文件又恢复出来显示了,因此需要有这个空文件来标识删除,并且覆盖底层的文件)

root@qa-control-pub-ci-build1:~/cxqdir/merged# rm ../upper/11.txt    (不建议这么操作)
root@qa-control-pub-ci-build1:~/cxqdir/merged# ls
11.txt    22.txt
root@qa-control-pub-ci-build1:~/cxqdir/merged# cat 11.txt 
1111111111111111111111

docker中overlayFS的应用

如果想在docker中使用overlay模式,则需要在/etc/default/docker配置如下 DOCKER_OPTS=“-s=overlay ” 查看docker目录下的overlay文件夹。 里面放置着多个image分层的uuid文件夹: 例如 ··· root@qa-control-pub-ci-build1:/var/lib/docker/overlay/fe92ccc33d26116c6cf3d6e1fb5ccb18233ad7613e41d43176cb8214061cd598# tree ... .... ├── spool │ ├── mail -> ../mail │ └── plymouth └── tmp

1347 directories, 14849 files ··· 这个标识这一个分层里面的所有内容,如何把多个分层联系起来呢,就要找到/etc/default/docker/graph下的同名文件夹中的json文件,里面有关于本层以及它的parent的描述:


3d6e1fb5ccb18233ad7613e41d43176cb8214061cd598# cat json |python -m json.tool
{
   无关信息省略...
    "created": "2015-12-30T08:22:50.386102166Z", 
    "docker_version": "1.9.1", 
    "id": "fe92ccc33d26116c6cf3d6e1fb5ccb18233ad7613e41d43176cb8214061cd598", 
    "os": "linux", 
    "parent": "7d1b79980f8821729e0dea5f640f508db09fd111ff128bf333b3eb900b5f2610"
}

这样连起来上下多层就可以构成一个完整的镜像,同时每一层又可以独立使用。 一组多层镜像的组织示意图:

小结

docker镜像驱动不止是overlayfs一种,其他还有aufs,device mapper方式,但是原理都基本一致,而且overlayfs是相对比较新的一种方式。如果大家对其他两种存储驱动感兴趣也可以去研究一下。

本文来自网易实践者社区,经作者崔晓晴授权发布。