容器核心技术之Union FS

UnionFS概述

  • 联合文件系统(UnionFS )是一种轻量级的高性能分层文件系统,它支持将文件系统中的
    修改信息作为一次提交,并层层叠加,同时可以将不同目录挂载到同一个虚拟文件系统下,
    应用看到的是挂载的最终结果 。
  • 支持为每一个成员目录 (类似 Git 的分支) 设定 只读(readonly)、读写(readwrite) 和 写出(whiteout-able) 权限
  • 文件系统分层, 对 readonly 权限的 分支 可以逻辑上进行修改(增量地, 不影响 readonly 部分的)
  • 通常 Union FS 有两个用途, 一方面可以将多个 disk 挂到同一个目录下, 另一个更常用的就是将一个readonly 的 分支 和一个 writeable 的 分支 联合在一起。
  • 联合文件系统是实现 Docker 镜像的技术基础

docker启动过程

典型的 Linux 文件系统组成:

  • Bootfs(boot file system)
    • Bootloader - 引导加载 kernel,
    • Kernel - 当 kernel 被加载到内存中后 umount bootfs。
  • rootfs (root file system)
    • /dev,/proc,/bin,/etc 等标准目录和文件。
    • 对于不同的 linux 发行版, bootfs 基本是一致的,但 rootfs 会有差别。

Linux启动

  • 在启动后,首先将 rootfs 设置为 readonly, 进行一系列检查, 然后将其切换为 “readwrite”供用户使用。

docker启动:

  • 初始化时将 rootfs 以 readonly 方式加载并检查,然而接下来利用 union mount 的方式将一个
    readwrite 文件系统挂载在 readonly 的 rootfs 之上;
  • 并且允许再次将下层的 FS(file system) 设定为 readonly 并且向上叠加。
  • 这样一组 readonly 和一个 writeable 的结构构成一个 container 的运行时态, 每一个 FS 被称作一个 FS层。

docker写操作原理

由于镜像具有共享特性,所以对容器可写层的操作需要依赖存储驱动提供的写时复制和用时分配机制,以此来支持对容器可写层的修改,进而提高对存储和内存资源的利用率。

  • 写时复制
    • 写时复制,即 Copy-on-Write。
    • 一个镜像可以被多个容器使用,但是不需要在内存和磁盘上做多个拷贝。
    • 在需要对镜像提供的文件进行修改时,该文件会从镜像的文件系统被复制到容器的可写层的文件系统进行修改,而镜像里面的文件不会改变。
    • 不同容器对文件的修改都相互独立、互不影响。
  • 用时分配
    • 用时分配按需分配空间,而非提前分配,即当一个文件被创建出来后,才会分配空间。

overlay2 存储驱动

存储驱动概述

  • docker历史上又多种存储驱动,如aufs、overlayfs、devicemapper、btrfs等。
  • 目前常用的存储驱动为overlayfs2
  • overlay2 把目录的下一层叫作lowerdir(镜像层),上一层叫作upperdir(容器层),联合挂载后的结果叫作merged
  • overlay2 文件系统最多支持 128 个层数叠加,也就是说你的 Dockerfile 最多只能写 128 行

overlay2练习

1、创建overlay文件系统

# 创建四个目录
mkdir upper lower merged work

# 分别往这四个目录添加内容
echo "I'm from lower" > lower/in_lower.txt
echo "I'm from upper" > upper/in_upper.txt
echo "I'm from lower" > lower/in_both.txt
echo "I'm from upper" > upper/in_both.txt

# 将upper lower work目录挂载到merged目录
sudo mount -t overlay overlay \
 -o lowerdir=./lower,upperdir=./upper,workdir=./work \
 ./merged

2、目录说明

我们可以看到,OverlayFS的一个mount命令牵涉到四类目录,分别是lower,upper,merged和work,那它们是什么关系呢?

首先,最下面的"lower/",也就是被mount两层目录中底下的这层(lowerdir)。

在OverlayFS中,最底下这一层里的文件是不会被修改的,你可以认为它是只读的。OverlayFS是支持多个lowerdir的。

然后我们看"uppder/",它是被mount两层目录中上面的这层 (upperdir)。在OverlayFS中,如果有文件的创建,修改,删除操作,那么都会在这一层反映出来,它是可读写的。

接着是最上面的"merged" ,它是挂载点(mount point)目录,也是用户看到的目录,用户的实际文件操作在这里进行。

还有一个"work/",这个目录没有在这个图里,它只是一个存放临时文件的目录,OverlayFS中如果有文件修改,就会在中间过程中临时存放文件到这里。

3、文件操作

如果我们在merged/目录里做文件操作,具体包括这三种。

第一种,新建文件,这个文件会出现在upper/ 目录中。

第二种是删除文件,如果我们删除"in_upper.txt",那么这个文件会在upper/目录中消失。如果删除"in_lower.txt", 在 lower/目录里的"in_lower.txt"文件不会有变化,只是在 upper/目录中增加了一个特殊文件来告诉OverlayFS,"in_lower.txt’这个文件不能出现在merged/里了,这就表示它已经被删除了

还有一种操作是修改文件,类似如果修改"in_lower.txt",那么就会在upper/目录中新建一个"in_lower.txt"文件,包含更新的内容,而在lower/中的原来的实际文件"in_lower.txt"不会改变。

overlay在docker中的应用

通过ubuntu:16.04看 overlay2 是如何存放镜像文件
1、pull镜像

# docker pull ubuntu:16.04
16.04: Pulling from library/ubuntu
58690f9b18fc: Pull complete 
b51569e7c507: Pull complete 
da8ef40b9eca: Pull complete 
fb15d46c38dc: Pull complete 
Digest: sha256:454054f5bbd571b088db25b662099c6c7b3f0cb78536a2077d54adc48f00cd68
Status: Downloaded newer image for ubuntu:16.04
docker.io/library/ubuntu:16.04

可以看到镜像被分为四层

2、查看overlay2目录

# ls -l /var/lib/docker/overlay2/
total 0
drwx-----x. 3 root root     47 Oct 13 16:34 1133896ce991157dd016815c510609ce9b8dedd379a9ca9567015489bb0cbd28
drwx-----x. 4 root root     72 Oct 13 16:34 610a3087aee462a80b92b7e49e696d0cd534888c3946892bf772e107994af341
drwx-----x. 4 root root     72 Oct 13 16:34 76fc1a6fad04775ee034ea2ae03b8ad246e468ebac2fa12f842f7108918629d1
drwx-----x. 4 root root     55 Oct 13 16:34 7f59c5e2adc963612e1bf8202b91459507ce69190f6a7118eb46d39292e38937
brw-------. 1 root root 253, 0 Oct 12 02:32 backingFsBlockDev
drwx-----x. 2 root root    142 Oct 13 16:34 l

可以看到 overlay2 目录下出现了四个镜像层目录和一个l目录,我们首先来查看一下l目录的内容:

# ls -l l
total 0
lrwxrwxrwx. 1 root root 72 Oct 13 16:34 AVIMWR2WDK2V56X4FH73CQBSEU -> ../610a3087aee462a80b92b7e49e696d0cd534888c3946892bf772e107994af341/diff
lrwxrwxrwx. 1 root root 72 Oct 13 16:34 Q245O4UVMNEC2JSCDOSHOMMRLE -> ../7f59c5e2adc963612e1bf8202b91459507ce69190f6a7118eb46d39292e38937/diff
lrwxrwxrwx. 1 root root 72 Oct 13 16:34 RP7HB5ZQRKZG6SM33H3AZKA4LK -> ../1133896ce991157dd016815c510609ce9b8dedd379a9ca9567015489bb0cbd28/diff
lrwxrwxrwx. 1 root root 72 Oct 13 16:34 WWJF2YUSDMDXPY7M4II4KCH3R2 -> ../76fc1a6fad04775ee034ea2ae03b8ad246e468ebac2fa12f842f7108918629d1/diff

可以看到l目录是一堆软连接,把一些较短的随机串软连到镜像层的 diff 文件夹下,这样做是为了避免达到mount命令参数的长度限制。

下面我们查看任意一个镜像层下的文件内容

# ls -l 7f59c5e2adc963612e1bf8202b91459507ce69190f6a7118eb46d39292e38937/
total 8
drwxr-xr-x. 3 root root 17 Oct 13 16:34 diff
-rw-r--r--. 1 root root 26 Oct 13 16:34 link
-rw-r--r--. 1 root root 86 Oct 13 16:34 lower
drwx------. 2 root root  6 Oct 13 16:34 work

注意:镜像层的 link 文件内容为该镜像层的短 ID,diff 文件夹为该镜像层的改动内容,lower 文件为该层的所有父层镜像的短 ID。

3、通过docker image inspect命令来查看某个镜像的层级关系

# docker inspect ubuntu:16.04
......
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/76fc1a6fad04775ee034ea2ae03b8ad246e468ebac2fa12f842f7108918629d1/diff:/var/lib/docker/overlay2/610a3087aee462a80b92b7e49e696d0cd534888c3946892bf772e107994af341/diff:/var/lib/docker/overlay2/1133896ce991157dd016815c510609ce9b8dedd379a9ca9567015489bb0cbd28/diff",
                "MergedDir": "/var/lib/docker/overlay2/7f59c5e2adc963612e1bf8202b91459507ce69190f6a7118eb46d39292e38937/merged",
                "UpperDir": "/var/lib/docker/overlay2/7f59c5e2adc963612e1bf8202b91459507ce69190f6a7118eb46d39292e38937/diff",
                "WorkDir": "/var/lib/docker/overlay2/7f59c5e2adc963612e1bf8202b91459507ce69190f6a7118eb46d39292e38937/work"
            },
            "Name": "overlay2"
        },
......

其中 MergedDir 代表当前镜像层在 overlay2 存储下的目录,LowerDir 代表当前镜像的父层关系,使用冒号分隔,冒号最后代表该镜像的最底层。

4、将镜像运行起来成为容器:

# docker run --name=ubuntu -d ubuntu:16.04 sleep 3600

5、docker inspect命令来查看一下容器的工作目录

# docker inspect ubuntu
......
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/9155d11f6bcdb7865eb9aa57f92c730ed16107912b675697396e142e7b80d155-init/diff:/var/lib/docker/overlay2/7f59c5e2adc963612e1bf8202b91459507ce69190f6a7118eb46d39292e38937/diff:/var/lib/docker/overlay2/76fc1a6fad04775ee034ea2ae03b8ad246e468ebac2fa12f842f7108918629d1/diff:/var/lib/docker/overlay2/610a3087aee462a80b92b7e49e696d0cd534888c3946892bf772e107994af341/diff:/var/lib/docker/overlay2/1133896ce991157dd016815c510609ce9b8dedd379a9ca9567015489bb0cbd28/diff",
                "MergedDir": "/var/lib/docker/overlay2/9155d11f6bcdb7865eb9aa57f92c730ed16107912b675697396e142e7b80d155/merged",
                "UpperDir": "/var/lib/docker/overlay2/9155d11f6bcdb7865eb9aa57f92c730ed16107912b675697396e142e7b80d155/diff",
                "WorkDir": "/var/lib/docker/overlay2/9155d11f6bcdb7865eb9aa57f92c730ed16107912b675697396e142e7b80d155/work"
            },
            "Name": "overlay2"
        },
......

link 和 lower 文件与镜像层的功能一致,link 文件内容为该容器层的短 ID,lower 文件为该层的所有父层镜像的短 ID 。diff 目录为容器的读写层,容器内修改的文件都会在 diff 中出现,merged 目录为分层文件联合挂载后的结果,也是容器内的工作目录。

总体来说,overlay2 是这样储存文件的:overlay2将镜像层和容器层都放在单独的目录,并且有唯一 ID,每一层仅存储发生变化的文件,最终使用联合挂载技术将容器层和镜像层的所有文件统一挂载到容器中,使得容器中看到完整的系统文件。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值