Docker技术的移植性分析研究
2015-12-25于烨李斌刘思尧
于烨++李斌++刘思尧
摘要:Docker因为其轻量、便捷的特点,受了业界广泛的关注和讨论,目前已有多个相关项目,逐渐形成了围绕Docker的生态体系。Docker的核心思想是利用扩展的LXC(Linux Container)方案实现一种轻量级的虚拟化解决方案。Docker主要利用AUFS机制来实现系统的移植性,节省了存储和内存,也保证了容器的快速部署。本文从AUFS的实现原理入手,详细分析了Docker的移动应用部署的原理和可行性。
关键词:Docker;AUFS;文件系统;移植性
中图分类号:TP311
文献标识码:A
DOI: 10.3969/j.issn.1003-6970.2015.07.012
0 引言
Docker是dotcloud公司于2013初年开始的一个开源项目,最早是该公司已有的云业务的一个自然扩展技术。Docker对容器的使用基本是建立在LXC基础之上的,然而LXC存在的问题是难以移动,即难以通过标准化的模板制作、重建、复制和移动容器。在以VM为基础的虚拟化手段中,有image和snapshot可以用于VM的复制、重建以及移动的功能。想要通过容器来实现快速的大规模部署和更新,这些功能不可或缺。针对这样的问题,Docker利用AUFS来实现对容器的快速更新,Docker0.7中引入了Storage Driver,支持AUFS,VFS,Device Mapper,也为BTRFS以及ZFS的引入提供了可能。
1 Docker简介
Docker是PaaS提供商dotCloud开源的一个基于LXC(Linux Container)的应用容器引擎,让开发者可以将应用程序、依赖的运行库文件打包并移植到一个新的容器中,然后发布到任何系统为Linux的机器上,也可以实现虚拟化解决方案。容器是完全沙箱机制的实现方式,任意容器之间不会有任何接口,具有安全访问资源的特性,可以实现系统的隔离;而且容器的运行资源开销小,可以很容易地在机器和数据中心中运行。最重要的是Docker容器不依赖于任何特定需求实现的编程语言、编程框架或已打包的系统。Docker目前在业界非常受欢迎,包括dotCloud, Google Compute Engine和百度应用引擎(BAE),都使用了Docker。
Docker容器主要解决“依赖地狱”的问题,即应用通常从已存在的组件组合而来,并且依赖其他服务和应用。例如,Python应用可能使用Postgre所为一个数据存储,用Redis缓存以及使用Apache作web服务器。每个这些组件都附带自身的一些依赖,这些依赖可能与其他组件产生冲突。通过打包每个组件及其依赖,Docker容器解决冲突依赖、缺少依赖、平台依赖等问题。
2 Docker的移植性
2.1 AUFS简介
AUFS (AnotherUnionFS)是一种Union FS,简单来说就是支持将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)的文件系统,更进一步地,AUFS支持为每一个成员目录(AKA branch)设定readonly,readwrite和whiteout-able权限,同时AUFS里有一个类似分层的概念,对readonly权限的branch可以逻辑上进行修改(增量地,不影响readonly部分的)。通常Union FS有两个用途,一方面可以实现不借助LVM,RAID将多个disk和挂在到一个目录下,另一个更常用的就是将一个readonly的branch和一个writeable的branch联合在一起,Live CD正是基于此可以允许在OS image不变的基础上允许用户在其上进行一些写操作。
2.2 Docker的移植性分析
Docker使用AuFS作为容器的文件系统。AuFS的层状文件系统能够透明覆盖一个或多个现有文件系统。当一个进程需要修改一个文件时,AuFS创建该文件的一个副本。AuFS可以通过写复制把多层合并成文件系统的单层表示。AuFS允许Docker把某些镜像作为容器的基础。例如,利用AuFS的机制,只需要一个CentOS镜像的副本就可以作为很多不同容器的基础,既节省了存储和内存,也保证了容器的快速部署。
使用AuFS的另一个好处是提升了Docker的版本容器镜像能力。每个新版本都是一个与之前版本的简单差异改动,有效地保持镜像文件最小化。但这也意味着需要一个记录该容器从一个版本到另一个版本改动的审计跟踪。
AUFS是一种Union FS,它是一种支持将不同目录挂载到同一个虚拟文件系统下的文件系统,并且支持为每一个成员目录(AKA branch)设定‘readonly,‘readwrite和 ‘whiteout-able权限,同时AUFS里有一个类似分层的概念,对readonly权限的branch可以逻辑上进行修改。通常Union FS有两个用途,一方面可以实现不借助LVM, RAID将多个disk和挂在到一个目录下,另一个更常用的就是将一个readonly的branch和一个writeable的branch联合在一起,Live CD正是基于此可以允许在OS image不变的基础上允许用户在其上进行一些写操作。Docker在AUFS上构建的container image也正是如此。
典型的Linux启动到运行需要两个FS:bootfs和rootfs(从功能角度而非文件系统角度),如图1所示。
bootfs (boot file system)主要包含bootloader和kernel,bootloader主要用于引导加载kernel,当boot成功后,kernel被加载到内存中,bootfs就被umount了。endprint
rootfs (root file system)包含典型Linux系统中的/dev,/proc,/bin,/etc等标准目录和文件。
由此可见对于不同的linux发行版,bootfs基本是一致的,rootfs会有差别,因此不同的发行版可以公用bootfs如图2所示。
典型的Linux在启动后,首先将rootfs置为readonly,进行一系列检查,然后将其切换为readwrite供用户使用。在docker中,最初也是将rootfs以readonly方式加载并检查,接下来利用unionmount将一个readwrite文件系统挂载在readonly的rootfs之上,允许再次将下层的file system设定为readonly并向上叠加,这样以来一组readonly和一个writeable的结构就构成一个container的运行目录,每一个运行目录被称作一个Layer,如图3所示。
得益于AUFS的特性,每一个对readonly层文件或文件目录的修改都只会存在于上层的writeable层中。这样就可以避免竞争,使多个container可以共享readonly的layer。
因此docker将readonly的层称作“image”,对于容器而言整个rootfs都是read-write的,但事实上所有的修改都写入最上层的writeable层中,image不保存用户状态,可以用于模板、重建和复制。
上层的image依赖下层的image,因此docker中把下层的image称作父image,没有父image的image称作base image,如图4所示。
因此想要从一个image启动一个容器,docker会先加载其父image直到base image,用户的进程运行在writeable的layer中。所有parent image中的数据信息以及ID、网络和lxc管理的资源限制等具体container的配置,构成一个docker概念上的容器,如图5所示。
由此可见,采用AUFS作为docker的容器文件系统,能够提供如下好处:
(1)节省存储空间:多个容器可以共享base image存储;
(2)快速部署:如果要部署多个容器,base image可以避免多次拷贝;
(3)内存更省:因为多个容器共享base image,以及OS的disk缓存机制,多个容器中的进程命中缓存内容的几率大大增加;
(4)升级更方便:相比于copy-on-write类型的FS,base-image也可以挂载为可writeable的,可以通过更新base image而一次性更新其之上的容器;
(5)允许在不更改base-image的同时修改其目录中的文件:所有写操作都发生在最上层的writeable层中,这样可以大大增加base image能共享的文件内容。
以上5条中,1-3条可以通过copy-on-write的FS实现,4可以利用其他的union mount方式实现,5只有AUFS实现的很好。这也是为什么Docker一开始就建立在AUFS之上。
3 结论
Docker使用AuFS作为容器的文件系统。AUFS是一种Union FS,它是一种支持将不同目录挂载到同一个虚拟文件系统下的文件系统,并且为每一个成员目录(AKA branch)设定不同的权限,并基于一种分层的概念,对这些权限从逻辑上进行修改。节省了存储和内存,保证了容器的快速部署和升级的便捷性。endprint