美文网首页
[mydocker]---通过例子理解存储驱动AUFS

[mydocker]---通过例子理解存储驱动AUFS

作者: nicktming | 来源:发表于2019-05-11 09:55 被阅读0次

    前言

    Docker内置多种存储驱动. 最开始采用AUFS作为文件系统, 其分层概念实现了多个Container可以共享同一个image. 由于AUFS未并入Linux内核, 且只支持Ubuntu, 因此Docker 0.7版本中引入了存储驱动, 目前Docker支持5中存储驱动.

    文件系统/存储 存储驱动名称
    OverlayFs overlay/overlay2
    AUFS aufs
    Btrfs btrfs
    Device Mapper devicemapper
    VFS vfs
    ZFS zfs

    本文主要介绍AUFS, 会先通过一个例子来理解AUFS是如何工作的, 最后会解释其原理.

    AUFS

    AUFS能透明覆盖一或多个现有文件系统的层状文件系统,把多层合并成文件系统的单层表示.

    例子

    root@nicktming:~/aufs# pwd
    /root/aufs
    root@nicktming:~/aufs# ls 
    run.sh
    root@nicktming:~/aufs# cat run.sh
    mkdir container-layer 
    echo "I am container-layer" > container-layer/container-layer.txt
    
    mkdir mnt
    
    for i in {1..3}
    do 
    mkdir -p image-layer$i/subdir$i
    echo "I am image layer $i" > image-layer$i/image-layer$i.txt
    echo "subdir $i" > image-layer$i/subdir$i/subdir$i.txt
    done
    root@nicktming:~/aufs# ./run.sh 
    root@nicktming:~/aufs# tree
    .
    |-- container-layer
    |   `-- container-layer.txt
    |-- image-layer1
    |   |-- image-layer1.txt
    |   `-- subdir1
    |       `-- subdir1.txt
    |-- image-layer2
    |   |-- image-layer2.txt
    |   `-- subdir2
    |       `-- subdir2.txt
    |-- image-layer3
    |   |-- image-layer3.txt
    |   `-- subdir3
    |       `-- subdir3.txt
    |-- mnt
    `-- run.sh
    
    8 directories, 8 files
    

    可以看到当前aufs文件夹的目录结构. 并且每个文件的内容如下:

    root@nicktming:~/aufs# cat container-layer/container-layer.txt 
    I am container-layer
    root@nicktming:~/aufs# cat image-layer1/image-layer1.txt 
    I am image layer 1
    root@nicktming:~/aufs# cat image-layer1/subdir1/subdir1.txt 
    subdir 1
    root@nicktming:~/aufs# cat image-layer2/image-layer2.txt 
    I am image layer 2
    root@nicktming:~/aufs# cat image-layer2/subdir2/subdir2.txt 
    subdir 2
    root@nicktming:~/aufs# cat image-layer3/image-layer3.txt 
    I am image layer 3
    root@nicktming:~/aufs# cat image-layer3/subdir3/subdir3.txt 
    subdir 3
    root@nicktming:~/aufs# ls mnt/
    root@nicktming:~/aufs# 
    

    可以将这些文件目录联合起来挂载到mnt目录下.

    root@nicktming:~/aufs# mount -t aufs -o dirs=./container-layer:./image-layer1:./image-layer2:./image-layer3 none ./mnt
    root@nicktming:~/aufs# cat /sys/fs/aufs/
    config               si_e9a1e7a68699fcc6/ 
    root@nicktming:~/aufs# cat /sys/fs/aufs/si_e9a1e7a68699fcc6/*
    /root/aufs/container-layer=rw
    /root/aufs/image-layer1=ro
    /root/aufs/image-layer2=ro
    /root/aufs/image-layer3=ro
    64
    65
    66
    67
    /root/aufs/container-layer/.aufs.xino
    

    可以看到aufs文件系统会默认把dirs后的第一个文件设置为可读写, 其余文件设置为只读. 接下来看一下整个目录结构.

    root@nicktming:~/aufs# tree
    .
    |-- container-layer
    |   `-- container-layer.txt
    |-- image-layer1
    |   |-- image-layer1.txt
    |   `-- subdir1
    |       `-- subdir1.txt
    |-- image-layer2
    |   |-- image-layer2.txt
    |   `-- subdir2
    |       `-- subdir2.txt
    |-- image-layer3
    |   |-- image-layer3.txt
    |   `-- subdir3
    |       `-- subdir3.txt
    |-- mnt
    |   |-- container-layer.txt
    |   |-- image-layer1.txt
    |   |-- image-layer2.txt
    |   |-- image-layer3.txt
    |   |-- subdir1
    |   |   `-- subdir1.txt
    |   |-- subdir2
    |   |   `-- subdir2.txt
    |   `-- subdir3
    |       `-- subdir3.txt
    `-- run.sh
    
    11 directories, 15 files
    

    可以看到挂载点mnt中已经有每个被挂载的文件, 也就是说将不同目录挂载到同一个虚拟文件系统. 无论底下有多少层都是只读的,只有最上层的文件系统是课写的, 也就是这里的container-layer.

    layer.png

    将多个目录合并成一个虚拟文件系统,成员目录称为虚拟文件系统的一个分支(branch). 也就是说container-layer, image-layer1, image-layer2, image-layer3都被称为branch. 每个branch3个权限, 只读(ro),读写(rw),写隐藏(wo). 一般情况下,aufs只有最上层的branch(在这里是container-layer)有读写权限, 其余branch为只读权限.

    6791554437422_.pic.jpg

    如果增加一层的话,也只有最顶层的文件有可读写权限.


    6771554437359_.pic.jpg

    mnt称为挂载点, 用户做操作是在mnt挂载点上做操作. 接下来可以做些简单的操作来看看做些文件是如何变化的.

    修改

    修改image-layer1.txt中的内容.

    root@nicktming:~/aufs# cat mnt/image-layer1.txt 
    I am image layer 1
    root@nicktming:~/aufs# echo "\n write something to image/layer1/image-layer1.txt\n" >> mnt/image-layer1.txt
    root@nicktming:~/aufs# cat mnt/image-layer1.txt 
    I am image layer 1
    \n write something to image/layer1/image-layer1.txt\n
    

    可以看到mnt/image-layer1.txt中的内容确实发生了变化, 接下来看看image-layer1/image-layer1.txt中的内容是否发生了改变.

    root@nicktming:~/aufs# cat image-layer1/image-layer1.txt 
    I am image layer 1
    

    可以看到image-layer1/image-layer1.txt中的内容没有丝毫改变. 因为mnt只是个挂载点, 当取消挂载的时候mnt里面的内容都会没有了的,那真正写上去的内容在哪里呢?此时查看一下整个目录的结构.

    root@nicktming:~/aufs# tree
    .
    |-- container-layer
    |   |-- container-layer.txt
    |   `-- image-layer1.txt
    |-- image-layer1
    |   |-- image-layer1.txt
    |   `-- subdir1
    |       `-- subdir1.txt
    |-- image-layer2
    |   |-- image-layer2.txt
    |   `-- subdir2
    |       `-- subdir2.txt
    |-- image-layer3
    |   |-- image-layer3.txt
    |   `-- subdir3
    |       `-- subdir3.txt
    |-- mnt
    |   |-- container-layer.txt
    |   |-- image-layer1.txt
    |   |-- image-layer2.txt
    |   |-- image-layer3.txt
    |   |-- subdir1
    |   |   `-- subdir1.txt
    |   |-- subdir2
    |   |   `-- subdir2.txt
    |   `-- subdir3
    |       `-- subdir3.txt
    `-- run.sh
    
    11 directories, 16 files
    

    可以看到container-layer文件夹下面多了一个image-layer1.txt, 查看里面的内容.

    root@nicktming:~/aufs# cat container-layer/image-layer1.txt 
    I am image layer 1
    \n write something to image/layer1/image-layer1.txt\n
    

    发现container-layer/image-layer1.txt正是所要的修改. 从这里可以看到container-layer确实可读写的, image-layer1是只读.

    mnt.png

    user的角度可以看到所有被挂载的文件, 当修改mntimage-layer1.txt时, 可读写层也就是container-layer会从只读层也就是image-layer1中把对应的image-layer1.txt复制到可写层container-layer并且修改, 当user看到文件的时候读到的container-layerimage-layer1.txt, 因为此时container/image-layer1.txt会覆盖image-layer1/image-layer1.txt, 但是image-layer1/image-layer1.txt并没有做任何改变, 整个image-layer1层没有做任何改变. 如下图所示:

    update.png
    删除

    删除mnt/image-layer2.txt看看会有什么改变.

    root@nicktming:~/aufs# rm mnt/image-layer2.txt 
    root@nicktming:~/aufs# cat mnt/image-layer2.txt
    cat: mnt/image-layer2.txt: No such file or directory
    root@nicktming:~/aufs# cat image-layer2/image-layer2.txt 
    I am image layer 2
    root@nicktming:~/aufs# tree
    .
    |-- container-layer
    |   |-- container-layer.txt
    |   `-- image-layer1.txt
    |-- image-layer1
    |   |-- image-layer1.txt
    |   `-- subdir1
    |       `-- subdir1.txt
    |-- image-layer2
    |   |-- image-layer2.txt
    |   `-- subdir2
    |       `-- subdir2.txt
    |-- image-layer3
    |   |-- image-layer3.txt
    |   `-- subdir3
    |       `-- subdir3.txt
    |-- mnt
    |   |-- container-layer.txt
    |   |-- image-layer1.txt
    |   |-- image-layer3.txt
    |   |-- subdir1
    |   |   `-- subdir1.txt
    |   |-- subdir2
    |   |   `-- subdir2.txt
    |   `-- subdir3
    |       `-- subdir3.txt
    `-- run.sh
    
    11 directories, 15 files
    

    发现mnt目录下看不到image-layer2.txt, 但是image-layer2层的image-layer2.txt仍然存在, 所以可以说只是逻辑删除了该image-layer2.txt文件, 或者是此aufs做了什么操作让用户看不到该image-layer2.txt文件.

    原因: 因为删除的image-layer2.txt是属于镜像层文件, 容器层container-layer会创建一个.wh前缀的隐藏文件, 从而实现对image-layer2.txt的隐藏.

    root@nicktming:~/aufs# ls -la container-layer/
    total 24
    drwxr-xr-x 4 root root 4096 Apr  5 14:44 .
    drwxr-xr-x 7 root root 4096 Apr  5 11:12 ..
    -rw-r--r-- 1 root root   21 Apr  5 11:12 container-layer.txt
    -rw-r--r-- 1 root root   73 Apr  5 13:44 image-layer1.txt
    -r--r--r-- 2 root root    0 Apr  5 11:15 .wh.image-layer2.txt
    -r--r--r-- 2 root root    0 Apr  5 11:15 .wh..wh.aufs
    drwx------ 2 root root 4096 Apr  5 11:15 .wh..wh.orph
    drwx------ 2 root root 4096 Apr  5 11:15 .wh..wh.plnk
    
    delete.png
    增加

    mnt中增加文件. 基于上面的知识, 可以知道创建的文件肯定会存在于container-layer中, 并且也是在容器层container-layer中创建的.

    root@nicktming:~/aufs# echo "container-01" > mnt/container-test.txt
    root@nicktming:~/aufs# cat mnt/container-test.txt 
    container-01
    root@nicktming:~/aufs# cat container-layer/container-test.txt 
    container-01
    root@nicktming:~/aufs# tree 
    .
    |-- container-layer
    |   |-- container-layer.txt
    |   |-- container-test.txt
    |   `-- image-layer1.txt
    |-- image-layer1
    |   |-- image-layer1.txt
    |   `-- subdir1
    |       `-- subdir1.txt
    |-- image-layer2
    |   |-- image-layer2.txt
    |   `-- subdir2
    |       `-- subdir2.txt
    |-- image-layer3
    |   |-- image-layer3.txt
    |   `-- subdir3
    |       `-- subdir3.txt
    |-- mnt
    |   |-- container-layer.txt
    |   |-- container-test.txt
    |   |-- image-layer1.txt
    |   |-- image-layer3.txt
    |   |-- subdir1
    |   |   `-- subdir1.txt
    |   |-- subdir2
    |   |   `-- subdir2.txt
    |   `-- subdir3
    |       `-- subdir3.txt
    `-- run.sh
    
    11 directories, 17 files
    
    图片.png

    可以看到在容器层container-layer中增加删除修改容器层的文件是不会影响到镜像层中的任何内容的. 由此可以达到根据一个image启动多个容器的目的.

    containers.png
    umount
    root@nicktming:~/aufs# df -h
    df: ‘/tmp/tmp5RAi0E’: No such file or directory
    Filesystem      Size  Used Avail Use% Mounted on
    /dev/vda1        50G  2.7G   45G   6% /
    none            4.0K     0  4.0K   0% /sys/fs/cgroup
    udev            487M   12K  487M   1% /dev
    tmpfs           100M  356K  100M   1% /run
    none            5.0M     0  5.0M   0% /run/lock
    none            497M   24K  497M   1% /run/shm
    none            100M     0  100M   0% /run/user
    none             50G  2.7G   45G   6% /root/aufs/mnt
    root@nicktming:~/aufs# umount /root/aufs/mnt 
    root@nicktming:~/aufs# tree
    .
    |-- container-layer
    |   |-- container-layer.txt
    |   |-- container-test.txt
    |   `-- image-layer1.txt
    |-- image-layer1
    |   |-- image-layer1.txt
    |   `-- subdir1
    |       `-- subdir1.txt
    |-- image-layer2
    |   |-- image-layer2.txt
    |   `-- subdir2
    |       `-- subdir2.txt
    |-- image-layer3
    |   |-- image-layer3.txt
    |   `-- subdir3
    |       `-- subdir3.txt
    |-- mnt
    `-- run.sh
    
    8 directories, 10 files
    

    可以看到umount之后mnt里面没有任何内容了, 所有内容保存在了container-layer之中了.

    原理

    通过上面的例子基本上可以理解AUFS是如何工作的, 其实其涉及到的技术为写时复制(copy-on-write).

    写时复制

    是一种对可修改资源实现高效复制的资源管理技术. 思想为如果一个资源是重复的并且没有任何修改,这时并不需要立即创建一个新的资源, 因为这个资源可以被新旧实例共享. 创建新资源发生在第一次写操作, 也就是对资源进行修改的时候.

    比如对一个image可以启动多个容器, 多个容器可以共享镜像层的文件, 这样可以减少大量的磁盘空间, 但是当某个容器的容器层需要对镜像层的文件进行修改的时候, 此时该容器的容器层会复制一份镜像层中此文件到容器层, 但是别的容器还是可以共享此镜像层的这个文件并不需要创建. 使用CoW可以有效的提高磁盘的利用率.

    参考

    1. https://blog.csdn.net/yourun_cloud/article/details/62883721
    2. http://dockone.io/article/1513
    3. 自己动手写docker.(基本参考此书,加入一些自己的理解,加深对docker的理解)

    全部内容

    mydocker.png

    1. [mydocker]---环境说明
    2. [mydocker]---urfave cli 理解
    3. [mydocker]---Linux Namespace
    4. [mydocker]---Linux Cgroup
    5. [mydocker]---构造容器01-实现run命令
    6. [mydocker]---构造容器02-实现资源限制01
    7. [mydocker]---构造容器02-实现资源限制02
    8. [mydocker]---构造容器03-实现增加管道
    9. [mydocker]---通过例子理解存储驱动AUFS
    10. [mydocker]---通过例子理解chroot 和 pivot_root
    11. [mydocker]---一步步实现使用busybox创建容器
    12. [mydocker]---一步步实现使用AUFS包装busybox
    13. [mydocker]---一步步实现volume操作
    14. [mydocker]---实现保存镜像
    15. [mydocker]---实现容器的后台运行
    16. [mydocker]---实现查看运行中容器
    17. [mydocker]---实现查看容器日志
    18. [mydocker]---实现进入容器Namespace
    19. [mydocker]---实现停止容器
    20. [mydocker]---实现删除容器
    21. [mydocker]---实现容器层隔离
    22. [mydocker]---实现通过容器制作镜像
    23. [mydocker]---实现cp操作
    24. [mydocker]---实现容器指定环境变量
    25. [mydocker]---网际协议IP
    26. [mydocker]---网络虚拟设备veth bridge iptables
    27. [mydocker]---docker的四种网络模型与原理实现(1)
    28. [mydocker]---docker的四种网络模型与原理实现(2)
    29. [mydocker]---容器地址分配
    30. [mydocker]---网络net/netlink api 使用解析
    31. [mydocker]---网络实现
    32. [mydocker]---网络实现测试

    相关文章

      网友评论

          本文标题:[mydocker]---通过例子理解存储驱动AUFS

          本文链接:https://www.haomeiwen.com/subject/xrshiqtx.html