Docker容器和镜像存储机制—images—目录树结构

http://ju.outofmemory.cn/entry/114344


Docker的存储机制采用了非常灵活的模块化设计,目前支持5种存储引擎,分别为aufs、btrfs、device mapper、vfs和overlay。它们的共同特点都是实现了graphdriver.Driver接口:

点击(此处)折叠或打开

  1. type ProtoDriver interface {
  2.   String() string
  3.   //创建layer
  4.   Create(id, parent string) error
  5.   //删除layer
  6.   Remove(id string) error
  7.   //mount, 获取容器挂载点
  8.   Get(id, mountLabel string) (dir string, err error)
  9.   //umount文件系统
  10.   Put(id string)
  11.   Exists(id string) bool
  12.   Status() [][2]string
  13.   Cleanup() error
  14. }
  15.  
  16. type Driver interface {
  17.   ProtoDriver
  18.   Diff(id, parent string) (archive.Archive, error)
  19.   Changes(id, parent string) ([]archive.Change, error)
  20.   ApplyDiff(id, parent string, diff archive.ArchiveReader)(size int64,err error)
  21.   DiffSize(id, parent string) (size int64, err error)
  22. }

所以,只要实现了存储驱动接口定义的方法,就可以扩展出一种存储引擎。想要更换存储引擎有两种方法:
1. docker daemon进程启动时指定-s参数:docker –s aufs。
2. 修改配置文件:DOCKER_OPTS=”–storage-driver=aufs”。

在Docker存储模型中,bootfs同宿主机,rootfs则是由多个镜像层和一个容器层构成,其中镜像层只读,容器层可读写,多个镜像层之间有父子关系,下层作为上层镜像的父镜像,最下面的镜像称为base images(基础镜像),相关定义可以参考官网解释
docker image layer

aufs是Docker最早支持的一种存储引擎,它的工作机制和优缺点在前文『aufs文件系统』中已有介绍,aufs能将不同的目录挂载到某一目录下,将各个源目录下的内容联合到目标目录下,并可对不同目录进行权限控制。这个特性非常契合Docker的存储模型:
1. 镜像分层模型对应aufs中的分支(源目录)。
2. 镜像层对应aufs的ro分支,只读;容器层对应aufs的rw分支,可读写。

默认配置下,Docker镜像和容器存储路径($DOCKROOT)位于/var/lib/docker,如果选择的是aufs文件系统作为存储引擎,那么它的子目录树结构(基于docker 1.4.1)应该如下:


点击(此处)折叠或打开

  1. # tree .
  2. ├── aufs
  3. │ ├── diff 镜像和容器每层的差异内容
  4. │ ├── layers 镜像和容器每层的继承关系
  5. │ └── mnt 容器挂载点
  6. ├── containers 容器配置文件,环境变量和日志文件
  7. ├── graph 镜像详情、大小等
  8. └── repositories-aufs 镜像摘要

举例说明,当前本地镜像库有一个ubuntu:14.04的镜像,它的层级关系如下:


点击(此处)折叠或打开

  1. # docker images -t
  2. └─511136ea3c5a Virtual Size: 0 B
  3.   └─3b363fd9d7da Virtual Size: 192.5 MB
  4.     └─607c5d1cca71 Virtual Size: 192.7 MB
  5.       └─f62feddc05dc Virtual Size: 192.7 MB
  6.         └─8eaa4ff06b53 Virtual Size: 192.7 MB Tags: ubuntu:14.04

那么在aufs/diff目录(相对于$DOCKROOT,下同)下会有以各个层级id命名的目录,每个目录存储着与它父镜像之间的差异:


点击(此处)折叠或打开

  1. # ls -l aufs/diff/
  2. total 20
  3. drwxr-xr-x 21 3b363fd9d7dab4db9591058a3f43e806f6fa6f7e2744b63b2df4b84eadb0685a
  4. drwxr-xr-x 2 511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158
  5. drwxr-xr-x 6 607c5d1cca71dd3b6c04327c3903363079b72ab3e5e4289d74fb00a9ac7ec2aa
  6. drwxr-xr-x 2 8eaa4ff06b53ff7730c4d7a7e21b4426a4b46dee064ca2d5d90d757dc7ea040a
  7. drwxr-xr-x 3 f62feddc05dc67da9b725361f97d7ae72a32e355ce1585f9a60d090289120f73

aufs/layers目录下有以各个层级id命名的文件,文件内容为该层所有的祖先镜像id。例如


点击(此处)折叠或打开

  1. # cat aufs/layers/8eaa4ff06b53ff7730c4d7a7e21b4426a4b...
  2. f62feddc05dc67da9b725361f97d7ae72a32e355ce1585f9a60d090289120f73
  3. c5d1cca71dd3b6c04327c3903363079b72ab3e5e4289d74fb00a9ac7ec2aa
  4. b363fd9d7dab4db9591058a3f43e806f6fa6f7e2744b63b2df4b84eadb0685a
  5. ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158

graph目录中存储的是每一层镜像的详细信息和大小:


点击(此处)折叠或打开

  1. # tree graph/
  2. graph/
  3. ├── 3b363fd9d7dab4db9591058a3f43e806f6fa6f7e2744b63b2df4b84eadb0685a
  4. │ ├── json
  5. │ └── layersize
  6. ├── 511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158
  7. │ ├── json
  8. │ └── layersize
  9. ├── 607c5d1cca71dd3b6c04327c3903363079b72ab3e5e4289d74fb00a9ac7ec2aa
  10. │ ├── json
  11. │ └── layersize
  12. ├── 8eaa4ff06b53ff7730c4d7a7e21b4426a4b46dee064ca2d5d90d757dc7ea040a
  13. │ ├── json
  14. │ └── layersize
  15. └── f62feddc05dc67da9b725361f97d7ae72a32e355ce1585f9a60d090289120f73
  16.     ├── json
  17.     └── layersize

其中,json为该层元信息,layersize为该层大小。

此时用ubuntu:14.04镜像起一个容器:


点击(此处)折叠或打开

  1. # docker run -it -d ubuntu:14.04 /bin/bash
  2. b0311350933de15936136b4c9142635782f8fd1a015d2fd2d6c54ed05efb

新建容器的操作会在aufs下三个子目录中分别新建两个以容器id为名的文件/目录,例如4262b031135…和4262b031135…- init,其中4262b031135…-init表示容器的初始层,它记录的信息和ubuntu:14.04镜像的最上层一致。所有在新建容器中的文件 操作最终都会记录到aufs/diff/4262b031135…目录中,比如:
1. 新建文件,修改文件。
2. 删除文件和目录,以.wh.{obj}标记。在联合文件系统中被称为除白(Whiteout)对象。
3. 删除目录后新建,以.wh..wh..opq标记。在联合文件系统中被称为不透明(Opaque directory)对象。

aufs/mnt目录是容器的挂载点,通过df命令和mount -v命令进行确认,另外容器的操作日志、环境变量、元信息等也会在containers目录以容器id命名的目录中。容器运行后,可以在sysfs目录中 找到对应的从上到下的镜像层次结构,读写权限一目了然(si可以通过mount -v查询):


点击(此处)折叠或打开

  1. # cat /sys/fs/aufs/si_13ac476258e8c5e8/br*
  2. /var/lib/docker/aufs/diff/4262b031135...=rw
  3. /var/lib/docker/aufs/diff/4262b031135...-init=ro
  4. /var/lib/docker/aufs/diff/8eaa4ff06b5...=ro
  5. /var/lib/docker/aufs/diff/f62feddc05d...=ro
  6. /var/lib/docker/aufs/diff/607c5d1cca7...=ro
  7. /var/lib/docker/aufs/diff/3b363fd9d7d...=ro
  8. /var/lib/docker/aufs/diff/511136ea3c5...=ro

aufs为Docker镜像存储带来了可重用性、权限分明、层次清晰等优点后,也带来了它的固有缺陷:
1. 写时复制(Copy On Write),性能不够好。
2. 最大层数限制(127层)。

关于绕开最大层数限制,在『aufs文件系统』中已有讨论,这里针对Docker的使用场景再进行一次归纳:
1. 更换docker存储驱动类型:device mapper, btrfs …
2. 重新编译aufs: CONFIG_AUFS_BRANCH_MAX_32767=y
3. 精简Dockerfile指令:RUN指令合并,脚本化
4. docker export & docker import

EOF

















<script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script>
阅读(70) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~
评论热议
posted @ 2016-02-01 00:00  张同光  阅读(480)  评论(0编辑  收藏  举报