Docker底层文件系统UnionFS实践

虚拟化技术、容器技术都已经十分成熟,在日常工作中我们经常会使用到docker。容器技术的出现方便了广大开发者,并且,让企业在开发团队间协作上节省了一大笔钱,还提高了开发效率。

前置知识

本篇文章讲解docker的底层相关知识。针对docker的学习,我认为应该分阶段来讲。

docker镜像操作
docker容器操作
Dockerfile定制
docker底层原理
docker项目源码

因为这个正好对应了 “知道这个是什么东西” ,到 “会用这个东西,并且还很溜” ,再到 “完全了解这个东西” 的步骤。 书面一点的表达就是从 “应用” 到 “技术体系” 再到 “方法论” 的过程。

关于docker的入门教程可以看看docker中文文档:
docker中文文档 http://www.dockerinfo.net/document

言归正传,开始之前先提一句容器技术的心法: Namespace做了彼此隔离,Cgroup做了资源限制,rootfs做了文件管控(针对的是Liunx容器) 。这是容器技术的核心,网上已经有很多相关的学习资料,可以查阅学习。本篇主要讲的是上述心法的第三部分,文件系统相关的知识。

rootfs文件管控的内容,一个知识点是mount文件挂载,这个决定容器与宿主机看到的文件系统情况,能够打包应用与对应的文件目录供容器使用;另外一个知识点就是容器文件系统的组织方式,这个决定了容器镜像文件的组织形式,允许通过”增量“的方式修改镜像里打包的文件(可以用git的提交方式来理解这个“增量”是什么情况)。

容器底层文件系统实现

这一篇文章主要介绍容器的文件系统(第二个知识点)。容器采用了UnionFS,即联合文件系统。

简单来说,就是将文件分层,有一层为只读(readonly),一层可写层(writeable)。通过这两层的性质,只读层在下,可写层在上,构成了容器运行时状态,多个容器可以用同一个镜像。如果文件发生改变,会从文件系统重复制一份出来,而不会影响之前的文件信息,复制出来的这个文件修改完成后,会向上叠加;没有发生改变的文件则可以容器共用,节省空间。

这个操作可以归纳为:写时复制、用时分配。具体怎么体现呢?后面实践可以看看。

在实践之前,先看看容器存储驱动,存储驱动是用来干什么的?就是完成UnionFS性质的方式,“通过什么方式做到写时复制、用时分配呢?”,不同的驱动实现的方式不一样。

容器的存储驱动有AUFS、OverlayFS、Device Mapper等等。
以OverlayFS为例,这个是一种联合系统。只有两层,只读层和可写层。
在这里插入图片描述
镜像层不可改变,容器层可写。

我们可以使用例子模拟一下,看看这样的结构怎么做到“写时复制、用时分配”。

OverlayFS实践

结构:

首先Overlay分为两层,lower层与upper层,其中lower为镜像层(只读),upper为容器层(可写)。
然后两层往上合并为文件Mount视图。

# 创建文件夹,lower、upper、merged、work
mkdir lower  upper  merged  work

# 先写入内容
echo from lower > lower/in_lower.txt
echo from upper > upper/in_upper.txt
# 上面是lower upper各不同的,下面写入相同的
echo from lower > lower/in_same.txt
echo from upper > upper/in_same.txt

# 将文件夹联合
mount -t overlay overlay -o lowerdir=`pwd`/lower,upperdir=`pwd`/upper,workdir=`pwd`/work `pwd`/merged
tree .
.
├── lower
│   ├── in_lower.txt
│   └── in_same.txt
├── merged
│   ├── in_lower.txt
│   ├── in_same.txt
│   └── in_upper.txt
├── upper
│   ├── in_same.txt
│   └── in_upper.txt
└── work
    └── work

# 从merged文件查看
cat merged/in_same.txt
cat merged/in_lower.txt
# 可以看到lower中的内容被upper中的内容遮盖了

接下来可以做一些尝试

# 在merged中增加
echo new from merge >> merged/in_same.txt       # merged追加
echo from merge > merged/in_merge.txt           # merged新建
echo "add in upper"  > upper/in_upper.txt       # upper追加
echo new file upper > upper/new_file_upper.txt  # upper新建

# merge中的追加,会作用在upper上        -       Dockerfile中增加一层(一行命令)的情况
# upper中新建,会体现在merged上         -
# merged中新建,会作用在upper上

# 在merged中删除
rm -i merged/in_same.txt            # merged中删除
rm -i upper/new_file_upper.txt      # upper中删除

# merged中删除文件,upper中文件还是存在
# upper中删除文件,merged中文件也消失

# 在merge中修改
vi upper/in_upper.txt
vi lower/in_lower.txt

cat upper/in_upper.txt
cat lower/in_lower.txt
# merged中修改,会直接修改到upper ;
# merged中修改in_lower , lower文件夹中不变,只会修改到upper文件夹中的in_lower

# 如果从upper直接修改,并不会带到merged中,并且merged中的也会和upper中的文件割裂开来(merge的改动不会带到upper); 而从merged中修改则可以作用到upper中

可以看到,联合文件系统的运行过程就是这种上下层控制的,形成上下覆盖映射,实现写时复制,用时分配的功能。

docker体现的方法论、技术体系、应用,都是十分值得学习的,推荐大家去深入学习并总结自己的东西出来。😃

以上实践的例子我放在了这里:
https://gitee.com/zeng-jinghao/kubernetes_stu/blob/master/1.docker_stu/


参考

https://github.com/cncamp/101

Logo

华为云1024程序员节送福利,参与活动赢单人4000元礼包,更有热门技术干货免费学习

更多推荐