Docker的存储机制采用了非常灵活的模块化设计,目前支持5种存储引擎,分别为aufs、btrfs、device mapper、vfs和overlay。它们的共同特点都是实现了graphdriver.Driver接口:
-
type ProtoDriver interface {
-
String() string
-
//创建layer
-
Create(id, parent string) error
-
//删除layer
-
Remove(id string) error
-
//mount, 获取容器挂载点
-
Get(id, mountLabel string) (dir string, err error)
-
//umount文件系统
-
Put(id string)
-
Exists(id string) bool
-
Status() [][2]string
-
Cleanup() error
-
}
-
-
type Driver interface {
-
ProtoDriver
-
Diff(id, parent string) (archive.Archive, error)
-
Changes(id, parent string) ([]archive.Change, error)
-
ApplyDiff(id, parent string, diff archive.ArchiveReader)(size int64,err error)
-
DiffSize(id, parent string) (size int64, err error)
-
}
所以,只要实现了存储驱动接口定义的方法,就可以扩展出一种存储引擎。想要更换存储引擎有两种方法:
1. docker daemon进程启动时指定-s参数:docker –s aufs。
2. 修改配置文件:DOCKER_OPTS=”–storage-driver=aufs”。
在Docker存储模型中,bootfs同宿主机,rootfs则是由多个镜像层和一个容器层构成,其中镜像层只读,容器层可读写,多个镜像层之间有父子关系,下层作为上层镜像的父镜像,最下面的镜像称为base images(基础镜像),相关定义可以参考。
aufs是Docker最早支持的一种存储引擎,它的工作机制和优缺点在前文『』中已有介绍,aufs能将不同的目录挂载到某一目录下,将各个源目录下的内容联合到目标目录下,并可对不同目录进行权限控制。这个特性非常契合Docker的存储模型:
1. 镜像分层模型对应aufs中的分支(源目录)。
2. 镜像层对应aufs的ro分支,只读;容器层对应aufs的rw分支,可读写。
默认配置下,Docker镜像和容器存储路径($DOCKROOT)位于/var/lib/docker,如果选择的是aufs文件系统作为存储引擎,那么它的子目录树结构(基于docker 1.4.1)应该如下:
-
# tree .
-
├── aufs
-
│ ├── diff 镜像和容器每层的差异内容
-
│ ├── layers 镜像和容器每层的继承关系
-
│ └── mnt 容器挂载点
-
├── containers 容器配置文件,环境变量和日志文件
-
├── graph 镜像详情、大小等
-
└── repositories-aufs 镜像摘要
举例说明,当前本地镜像库有一个ubuntu:14.04的镜像,它的层级关系如下:
-
# docker images -t
-
└─511136ea3c5a Virtual Size: 0 B
-
└─3b363fd9d7da Virtual Size: 192.5 MB
-
└─607c5d1cca71 Virtual Size: 192.7 MB
-
└─f62feddc05dc Virtual Size: 192.7 MB
-
└─8eaa4ff06b53 Virtual Size: 192.7 MB Tags: ubuntu:14.04
那么在aufs/diff目录(相对于$DOCKROOT,下同)下会有以各个层级id命名的目录,每个目录存储着与它父镜像之间的差异:
-
# ls -l aufs/diff/
-
total 20
-
drwxr-xr-x 21 3b363fd9d7dab4db9591058a3f43e806f6fa6f7e2744b63b2df4b84eadb0685a
-
drwxr-xr-x 2 511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158
-
drwxr-xr-x 6 607c5d1cca71dd3b6c04327c3903363079b72ab3e5e4289d74fb00a9ac7ec2aa
-
drwxr-xr-x 2 8eaa4ff06b53ff7730c4d7a7e21b4426a4b46dee064ca2d5d90d757dc7ea040a
-
drwxr-xr-x 3 f62feddc05dc67da9b725361f97d7ae72a32e355ce1585f9a60d090289120f73
aufs/layers目录下有以各个层级id命名的文件,文件内容为该层所有的祖先镜像id。例如
-
# cat aufs/layers/8eaa4ff06b53ff7730c4d7a7e21b4426a4b...
-
f62feddc05dc67da9b725361f97d7ae72a32e355ce1585f9a60d090289120f73
-
c5d1cca71dd3b6c04327c3903363079b72ab3e5e4289d74fb00a9ac7ec2aa
-
b363fd9d7dab4db9591058a3f43e806f6fa6f7e2744b63b2df4b84eadb0685a
-
ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158
graph目录中存储的是每一层镜像的详细信息和大小:
-
# tree graph/
-
graph/
-
├── 3b363fd9d7dab4db9591058a3f43e806f6fa6f7e2744b63b2df4b84eadb0685a
-
│ ├── json
-
│ └── layersize
-
├── 511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158
-
│ ├── json
-
│ └── layersize
-
├── 607c5d1cca71dd3b6c04327c3903363079b72ab3e5e4289d74fb00a9ac7ec2aa
-
│ ├── json
-
│ └── layersize
-
├── 8eaa4ff06b53ff7730c4d7a7e21b4426a4b46dee064ca2d5d90d757dc7ea040a
-
│ ├── json
-
│ └── layersize
-
└── f62feddc05dc67da9b725361f97d7ae72a32e355ce1585f9a60d090289120f73
-
├── json
-
└── layersize
其中,json为该层元信息,layersize为该层大小。
此时用ubuntu:14.04镜像起一个容器:
-
# docker run -it -d ubuntu:14.04 /bin/bash
-
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查询):
-
# cat /sys/fs/aufs/si_13ac476258e8c5e8/br*
-
/var/lib/docker/aufs/diff/4262b031135...=rw
-
/var/lib/docker/aufs/diff/4262b031135...-init=ro
-
/var/lib/docker/aufs/diff/8eaa4ff06b5...=ro
-
/var/lib/docker/aufs/diff/f62feddc05d...=ro
-
/var/lib/docker/aufs/diff/607c5d1cca7...=ro
-
/var/lib/docker/aufs/diff/3b363fd9d7d...=ro
-
/var/lib/docker/aufs/diff/511136ea3c5...=ro
aufs为Docker镜像存储带来了可重用性、权限分明、层次清晰等优点后,也带来了它的固有缺陷:
1. 写时复制(Copy On Write),性能不够好。
2. 最大层数限制(127层)。
关于绕开最大层数限制,在『』中已有讨论,这里针对Docker的使用场景再进行一次归纳:
1. 更换docker存储驱动类型:device mapper, btrfs …
2. 重新编译aufs: CONFIG_AUFS_BRANCH_MAX_32767=y
3. 精简Dockerfile指令:RUN指令合并,脚本化
4. docker export & docker import
–EOF–
阅读(2528) | 评论(0) | 转发(0) |