正文
在最近的Docker引擎1.12版本中,会发现如下的graphdriver:vfs、aufs、overlay、overlay2、btrfs、zfs、devicemapper和windows。将这个列表归一下类有助于对它们进行更好地定义。
特别的白雪公主:vfs
首先,让我们挑出一个特别的graphdriver – vsf。vfs是接口的“原生”的实现,完全没有使用联合文件系统或者写时复制技术,而是将所有的分层依次拷贝到静态的子文件夹中,然后将最终结果挂载到容器的根文件系统。它并不适合实际或者生产环境使用,但是对于需要进行简单验证的场景,或者需要测试Docker引擎的其他部件的场景,是很有价值的。对于在Docker中运行Docker的场景也很有用,要知道graphdriver嵌套起来,可能会让你丈二和尚摸不着头脑。顺便一提:Docker引擎开发者用来构建Docker自己所使用的
Dockerfile
,也是采用vfs来作为里边Docker的graphdriver。
联合文件系统
有意思的是,现有的graphdriver中只有少部分是真正的有写时复制语义的联合文件系统:Overlay的两个版本,从Docker早期就存在的aufs。记住联合文件系统只是一个基于文件的接口,通过把一组目录交错起来来,形成一个单一视图。所以与它不是一个真正的文件系统,如ext4或者xfs,它仅仅是站在一个已有的文件系统上提供了这些功能。在一些场景,对于底层文件系统是有要求的,并且Docker也会同时检查请求的联合文件系统和底层的文件系统,来保证它们是兼容的。
特定文件系统的实现
剩下的graphdriver都是建立在具体文件系统实现的基础上,需要依赖其内置特性(如快照)能提供必需的能力。这些包含devicemaper、zfs和btrfs驱动。在这每一个情形中,你都需要新建一个磁盘并用该文件系统格式化磁盘(或者为了快速测试,用循环挂载的文件作为磁盘),来使用这些选项作为Docker引擎的存储后端。
首先我们要简要地解释一下graphdriver必须执行什么操作。相关信息在已经被代码化在了守护进程代码库中
ProtoDriver
和
Driver
接口的定义中。同时值得注意的是,有一个ProtoDriver接口的包装器实现叫做NativeDiffDriver。对于那些无法通过原生处理方式来得出分层差异或改动的文件系统,该包装器能通过借用归档软件包,和驱动实现一起来提供这些计算差异的特性。
除了(计算)差别和改动相关的方法,graphdriver最重要的能力是
Get
、
Put
、
Create
和
Remove
方法
。要帮助理解graphdriver的API,我们需要简单地谈一下这个API的消费者。在Docker中的实现被称作
layerStore(分层仓库)
。当终端用户使用Docker客户端或者API下载或导入镜像时,分发(注册表)客户端代码用“分层仓库”来进行添加或者删除层的操作。我们知道镜像可以包含多个分层,并且这些分层有存在父级子级的关系。“分层仓库”的代码利用graphdriver驱动,采用最适合该文件系统实现中类似联合和写时复制(union+CoW-like)的叠层技术,来保存这些分层和它们之间的关系。要处理这些分层镜像的创建和解开(un-tar)操作,以及将镜像解开的内容放到创建的位置,会用到graphdriver的
Create
和
ApplyDiff
接口。显然,当镜像从本地缓存删除的时候需要执行的相反的操作,“分层仓库”会调用graphdriver的
Remove
接口来将分层的内容从系统中删除。
经历了上面这些过程,graphdriver现在已经包含了很多分层的本地缓存,同时包含下载的具名镜像之间的关系。容器需要运行时,在容器启动之前这些必须被组装成可运行的根文件系统。graphdriver的
Get
方法会被调用并带上一个特定的标识符,此时根据graphdriver特定文件系统的实现,需要根据父级连接关系遍历并且使用该文件系统提供的相应技术来将分层堆叠成一个单独的挂载点,并创建可写的上层或者顶部分层来满足容器更改文件系统的需要。
Put
方法来告知graphdriver,某挂载的资源没有用了,并在绝大多数的场景下卸载相关的层。