前言
在
docker
中, 我们可以使用同一个镜像创建不同的容器, 这些容器中的数据是完全隔离的, 容器中的数据的更改, 不会在镜像中的生效, 并且在容器间, 数据都是隔离的, 互不影响的, 这是怎么做到的呢? 底层使用的就是linux overlay 文件系统
,下面, 我们便通过一个简单的例子, 来探索
overlay
的使用
什么是 overlay 文件系统
从 overlay
一词便可以猜测出, 这里边有 层
和 覆盖
的概念, 其中的 层
有 上层
和 下层
的概念, 每一个 层
看起来都是一个独立的文件系统
, 有着各自的目录和文件,将这些层进行堆叠覆盖最终合并成一个面向用户
的 文件系统
, 这个文件系统
就叫作 overlay文件系统
, 对于用户来说, 最终看到并且操作的就是这个合并后
的 文件系统
, 所有的增删改查
操作, 就跟操作平常文件系统无异.
由于这个文件系统
是由多层合并的, 合并规则是怎么样的? 并且在合并层
进行 增删改查
操作时, 相应的在下面各个层是怎么反应的? 以及这个系统最终是怎么在docker
中应用的? 这便是本文需要重点探索的问题.
overlay 文件系统的结构
overlay 文件系统
由 3
部分 组成
合并层
: 最终面向用户的层上层
: 堆叠层中的最上面一层若干的下层
: 堆叠层中除了最上一层的所有下层
overlay 文件系统例子
我们尝试创建多个文件夹, 分别表示overlay 文件系统
的各个层, 然后使用 mount
命令, 创建一个 overlay
类型文件系统, 创建完毕, 我们查看每个文件夹的内容以及变化
-
创建例子文件夹
我们创建一个测试目录
test-overlayfs
, 在这个目录下, 我们创建4
个目录, 分别为lower
,upper
,merge
,work
mkdir lower upper merge work
前
3
个文件夹的含义表示overlay
文件系统中的下层
,上层
和合并层
, 至于最后一个文件夹work
, 这是为overlay
文件系统储存元数据
准备的, 用来维持overlay
文件系统, 我们不用管 -
创建例子文件
在
lower
文件夹下创建3
个文件,lower.txt
,delete-me.txt
,duplicate.txt
, 并在duplicate.txt
文件中加入特有内容touch lower.txt delete-me.txt duplicate.txt echo "this is duplicate file in lower" > duplicate.txt
类似的, 我们在
upper
文件夹下创建2
个文件upper.txt
,duplicate.txt
, 同样在duplicate.txt
文件中加入特有内容touch upper.txt duplicate.txt echo "this is duplicate file in upper" > duplicate.txt
我们能观察到,
两个文件夹
分别对映着两层
,两层
中的文件有些许差异
, 那么如果进行堆叠merge
, 最终 在merge
层, 会怎么反映呢? 我们想探索以下几个问题:两层
有一个相同文件duplicate.txt
, 那么如果进行堆叠merge
, 是用哪一个duplicate.txt
呢?- 既然是堆叠, 我
猜测
是上层
的覆盖下层
的 (-> _ ->)
- 既然是堆叠, 我
两层
都存在独有的文件, 如lower
的lower.txt
,delete-me.txt
; 还有upper
的upper.txt
, 最终在merge
层, 应该是进行简单合并吧, 都存在 ?- 在合并后, 如果我删除
lower
中的文件, 如delete-me.txt
, 会同时删除merge
中的文件吗? 同样的, 如果删除upper
中的文件呢?
为了探索上述问题, 我们赶快来尝试一下吧.
-
使用
mount
挂载一个 overlay 类型文件系统在测试目录
test-overlayfs
下执行sudo mount -t overlay -o lowerdir=lower/,upperdir=upper/,workdir=work none merge/
我们来解释一下这个命令, 首先我们指定了要挂载一个
overlay
类型的文件系统, 并且指定了下层
,下层
文件夹分别为lower
,upper
, 不仅如此, 还指定了工作目录
, 以及合并后的目录
, 至于其中的none
, 可以忽略, 据说这是用来指定设备的, 我们这个例子没有额外设备, 我们这里不需要深究, 设置成none
就行 -
观察结果
-
第 2 个问题探索
两层
都存在独有的文件, 如lower
的lower.txt
,delete-me.txt
; 还有upper
的upper.txt
, 最终在merge
层, 应该是进行简单合并吧, 都存在 ?我们使用命名
tree
观察root@walkerjun:/home/walkerjun/test-overlayfs# tree . ├── lower │ ├── delete-me.txt │ ├── duplicate.txt │ └── lower.txt ├── merge │ ├── delete-me.txt │ ├── duplicate.txt │ ├── lower.txt │ └── upper.txt ├── upper │ ├── duplicate.txt │ └── upper.txt └── work └── work
我们可以看到在
merge
文件夹中,两层
中的独有
文件都存在, 这可以很好解释我们上面的第2
个问题: 对于各层的独有文件, 最终都可以合并到merge
层的 -
第 1 个问题探索
两层
有一个相同文件duplicate.txt
, 那么如果进行堆叠merge
, 是用哪一个duplicate.txt
呢?我们再来观察
merge
文件夹中的duplicate.txt
文件root@walkerjun:/home/walkerjun/test-overlayfs# cat merge/duplicate.txt this is duplicate file in upper
我们可以看到,
merge
中的duplicate.txt
用的是upper
中的, 这符合我们对第1
个问题的猜想: 对于各层中的同名文件
, 是使用覆盖
策略, 会优先使用上层
的文件 -
第 3 个问题探索
在合并后, 如果我删除
lower
中的文件, 如delete-me.txt
, 会同时删除merge
中的文件吗? 同样的, 如果删除upper
中的文件呢?我们尝试删除
lower
中的delete-me.txt
root@walkerjun:/home/walkerjun/test-overlayfs# rm lower/delete-me.txt root@walkerjun:/home/walkerjun/test-overlayfs# ls merge/* merge/duplicate.txt merge/lower.txt merge/upper.txt
merge
中的文件也消失掉了诶, 那么如果在lower
中添加新文件呢? 会在merge
中直接出现吗?root@walkerjun:/home/walkerjun/test-overlayfs# touch lower/test-new-file.txt root@walkerjun:/home/walkerjun/test-overlayfs# ls merge/* merge/duplicate.txt merge/lower.txt merge/test-new-file.txt merge/upper.txt
果然的确是这样的, 并且相同的操作在
upper
中操作也是一样的, 但是加入逆向操作呢? 我在merge
中删除刚刚在lower
中新建的文件test-new-file.txt
-
新问题: merge 中的操作会同步到 下层去吗?
root@walkerjun:/home/walkerjun/test-overlayfs# rm merge/test-new-file.txt root@walkerjun:/home/walkerjun/test-overlayfs# ls lower/* lower/duplicate.txt lower/lower.txt lower/test-new-file.txt root@walkerjun:/home/walkerjun/test-overlayfs# ls merge/* merge/duplicate.txt merge/lower.txt root@walkerjun:/home/walkerjun/test-overlayfs# ls upper/* upper/duplicate.txt upper/test-new-file.txt root@walkerjun:/home/walkerjun/test-overlayfs# ls -l upper/* -rw-rw-r-- 1 walkerjun walkerjun 32 7月 6 19:12 upper/duplicate.txt c--------- 2 root root 0, 0 7月 6 20:12 upper/test-new-file.txt
这个操作发生了有意思的事情, 在
merge
中的删除
操作并不会同步
到下层
去,lower
中的对应文件仍然存在, 这就能解释为什么在docker
中,容器
的数据更改, 不会影响镜像
中的数据了, 那就是因为,容器
的文件系统是merge
层, 然而镜像
的文件系统中只是下层
而已. 除此之外, 还有个小现象, 被删除的下层
文件在上层
upper
中有一个标记文件, 这个似乎只是告诉用户这个文件在merge
层删掉了上面尝试了在
merge
层删除
数据, 其实是不完全是更改
数据, 再尝试下在merge
层更改下层
文件内容, 我猜想为了让下层能通用
,merge
层的文件内容更改, 是不会同步到下层
的# 在 lower 增加新文件 root@walkerjun:/home/walkerjun/test-overlayfs# touch lower/test-new-file2.txt root@walkerjun:/home/walkerjun/test-overlayfs# echo "this is test content in test-new-file2.txt" > lower/test-new-file2.txt root@walkerjun:/home/walkerjun/test-overlayfs# cat merge/test-new-file2.txt this is test content in test-new-file2.txt # 在 merge 修改对应文件 root@walkerjun:/home/walkerjun/test-overlayfs# echo "this is extra content that added from merge" >> merge/test-new-file2.txt root@walkerjun:/home/walkerjun/test-overlayfs# cat merge/test-new-file2.txt this is test content in test-new-file2.txt this is extra content that added from merge # 查看是否同步到 lower root@walkerjun:/home/walkerjun/test-overlayfs# root@walkerjun:/home/walkerjun/test-overlayfs# cat lower/test-new-file2.txt this is test content in test-new-file2.txt
如上, 在
merge
层修改的内容并不会同步到下层
-
新问题:
merge
层修改的内容会不会同步到上层 upper
?
这个问题, 我似乎没那么在乎了, 因为我已经知道了多个容器能用同一个镜像的原理了,
这个upper
是哪一层, 我好像不 care -
参考
Linux overlayfs文件系统介绍 | CSDN
Exploring the Power of Overlay File Systems in Linux Containers | Medium