provision
负责管理容器镜像。目前支持docker和APPC格式的镜像。
src/slave/containerizer/mesos/provisioner/docker/message.proto
对象定义
src/slave/containerizer/mesos/provisioner/provisioner.hpp
ProvisionerProcess对象的主要成员有:
- 141:flags
- 148:rootDir,根目录的绝对路径,是在由
--work_dir
指定的目录下的一个目录 - 150:stores,Image类型与Store的hash映射表
- 151:backends,字符串与Backend对象的hash映射表
- 154-157:Info,rootfses。。。。
- 159:infos,容器ID与Info的hash映射表
- 161-167:metrics,统计信息
Store对象定义在store.hpp和store.cpp中
当创建Store对象时,根据不同类型分别调用appc::Store::create或docker::Store::create
初始化
Provisioner::create
- 60-76:创建工作目录
- 78-81:创建镜像本地存储与类型名称的hash映射表
- 83-92:创建provision的后端
- 94-99:创建Provisioner
Provisioner::Provisioner
启动内部对应的ProvisionerProcess进程
ProvisionerProcess::ProvisionerProcess
创建新的对象,根据参数初始化对象的内部变量flags/rootDir/stores/backends
Provisioner的函数
119-149:recover/provision/destroy都是调用ProvisionerProcess类对应的函数,原样传递参数
ProvisionerProcess::provision
参数:
- containerId
- image
流程:
- 263-267:判断image的类型合法
- 270-271:先调用image具体类型的get,得到结果再调用_provision
ProvisionerProcess::_provision
参数:
- containerId
- image
- imageInfo
流程:
- 283:从命令行flags中得到镜像后端存储名称,包括aufs/bind/copy/overlay,缺省是copy(见src/slave/flags.cpp,115-119行)。
- 284:检查该名称合法
- 286:生成一个随机的UUID作为rootfsID
- 288-292:得到rootfs目录
- 299-303:。。。。。。。。。。。。。。。。
- 305-308:得到后端目录
- 310-314:调用指定后端的get函数,再调用__provision
copy 后端
CopyBackendProcess::provision
参数:
- layers
- rootfs
流程:
- 98-104:layers是镜像各层对应的路径名;rootfs是容器根文件系统在系统中的路径名,这里判断他们的合法性
- 106-110:创建根文件系统的目录
- 111-117:对镜像的每一层,创建一个函数调用插入到一个列表futures,函数调用是_provision
- 119-120:对futures中的每个元素等待它完成,元素是刚刚创建的函数调用。这里的collect是否会并行??????
CopyBackendProcess::_provision
参数:
- layers
- rootfs
流程:
- 131-141:构建命令"cp....",将layers目录内容拷贝到rootfs目录,cp的说明:
- -a :相当于 -pdr 的意思
- -d :若来源文件为连结文件的属性(link file),则复制连结文件属性而非档案本身
- -p :保持指定的属性(默认:模式,所有权,时间戳)
- -r :递归持续复制,用于目录的复制行为;
- -T :将目标目录视作普通文件
- 143-168:创建子进程,运行刚刚创建的命令
这样逐层拷贝,得到完整的根文件系统内容。
CopyBackendProcess::destroy
- 174-185:创建子进程,调用删除命令,删除容器的根文件系统
- 187-197:判断子进程是否正确执行
AUFS后端
AUFS概述
UnionFS就是把不同物理位置的目录合并mount到同一个目录中。UnionFS的一个最主要的应用是,把一张CD/DVD和一个硬盘目录给联合 mount在一起,然后,你就可以对这个只读的CD/DVD上的文件进行修改(当然,修改的文件存于硬盘上的目录里)。
Aufs是一种Union FS, 简单来说就是支持将不同的目录挂载到同一个虚拟文件系统下,并实现一种layer的概念。Aufs将挂载到同一虚拟文件系统下的多个目录分别设置成read-only,read-write以及whiteout-able权限,对read-only目录只能读,而写操作只能实施在read-write目录中。重点在于,写操作是在read-only上的一种增量操作,不影响read-only目录。当挂载目录的时候要严格按照各目录之间的这种增量关系,将被增量操作的目录优先于在它基础上增量操作的目录挂载,待所有目录挂载结束了,继续挂载一个read-write目录,如此便形成了一种层次结构。
传统的Linux加载bootfs时会先将rootfs设为read-only,然后在系统自检之后将rootfs从read-only改为read-write,然后我们就可以在rootfs上进行写和读的操作了。但Docker的镜像却不是这样,它在bootfs自检完毕之后并不会把rootfs的read-only改为read-write。而是利用union mount(UnionFS的一种挂载机制)将一个或多个read-only的rootfs加载到之前的read-only的rootfs层之上。在加载了这么多层的rootfs之后,仍然让它看起来只像是一个文件系统,在Docker的体系里把union mount的这些read-only的rootfs叫做Docker的镜像。但是,此时的每一层rootfs都是read-only的,我们此时还不能对其进行操作。当我们创建一个容器,也就是将Docker镜像进行实例化,系统会在一层或是多层read-only的rootfs之上分配一层空的read-write的rootfs。
例如,我们docker pull一个ubuntu:14.04的镜像,使用docker images -tree查看结果如下:
[root@qingze qingze]# docker images -tree
Warning: '-tree' is deprecated, it will be removed soon. See usage.
└─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,
可以看到Ubuntu的镜像中有多个长ID的layer,且以一种树状结构继承下来,如下图。其中,第n+1层继承了第n层,并在此基础上有了自己的内容,直观上的表现就是第n+1层占用磁盘空间增大。并且,不同的镜像可能会有相同的父镜像。例如,图中Tomcat和Nginx 继承于同一个Vim 镜像,这种组织方式起到共享的作用,节约了镜像在物理机上占用的空间。
AufsBackendProcess::provision
参数:
- layers
- rootfs
- backendDir
流程:
- 115-124:创建根文件系统目录,判断参数合法性
- 126-137:创建工作目录:。。。。。。。。。。。。。
- 146:将各层反过来,得到的options是这样的:"dirs=工作目录:layer0目录:layer1目录:....."
- 150-161:调用mount系统调用,安装根文件系统
- 164-188:安装根文件系统,shared+slave
AufsBackendProcess::destroy
- 196-199:得到系统安装的文件系统列表
- 201-220:对于每个安装的文件系统,若其是容器安装的根文件系统,先做umount,再将对应的目录删除
docker镜像的处理
store.cpp定义了对象StoreProcess,其中包含了MetadataManager
store.hpp定义了对象Store,其中包含了一个StoreProcess
provisioner.hpp中定义了对象ProvisionerProcess,其中包含了一个hash映射表stores
MesosContainerizerProcess中包含了provisioner对象
MetadataManagerProcess::recover
- 202-208:得到存储docker镜像的目录(通常是/tmp/mesos/store/docker,在命令行可设置)
- 210-220:得到镜像描述(通过protobuf反序列化),镜像描述的格式定义在src/slave/containerizer/mesos/provisioner/docker/message.proto中
- 222:对每一个镜像,执行以下动作:
- 225:对镜像的每一个layer执行以下动作:
- 226-231:检查该层rootfs路径是否有效,如果有无效的,则跳过整个镜像(236-239行)
- 234:得到镜像名字
- 241-243:若当前已经缓冲了该镜像,报警告
- 244-246:否则将镜像记录在storedImages中
- 225:对镜像的每一个layer执行以下动作: