基于overlayfs的硬盘资源隔离工具troot

[原写于2012年6月]

某些开发测试团队会有这样的需求:多个开发或测试人员在一台物理机上搭环境、装rpm包、测试等,目录很可能互相干扰。避免干扰的最直接办法当然是装虚拟机,但是如果仅仅只是想把根目录隔离一下,而不需要隔离CPU和内存,那么虚拟机方案偏重了些。
所以,我们做了一个叫troot的小工具,每个人都可以自己创建一个虚根目录,然后进入这个虚根目录工作,工作起来感觉就像一个全新的跟别人互不干扰的新根目录一样。
不过这个troot的主要实现是靠overlayfs,也就是说,必须用淘宝linux-kernel,淘宝linux-kernel源代码的git库在 http://kernel.taobao.org/git/?p=taobao-kernel.git;a=summary
而troot本身只是个小shell脚本而已,代码在这里:
http://code.taobao.org/p/troot/src/

制作troot的rpm方法是:

svn co http://code.taobao.org/svn/troot/trunk troot
cd troot
sh rpm/troot-build.sh `pwd`

装上淘宝linux-kernel和troot以后就可以用了,用法:

troot list#显示本机已经创建的根目录,第二栏显示当前处于哪个根目录
troot create world1#创建名为"world1“的根目录
troot enter world1#进入名为"world1"的根目录,进入以后,就可以随意写文件了
#直接敲入exit就可以从根目录中退出

欢迎感兴趣的同学试用反馈

overlay filesystem

[原写于2012年2月]

需求大概是这样:在一个linux系统上,想跑多个不同应用,这些应用由不同的运维来操作,为了避免互相干扰,希望运维只能看见自己的文件,而看不见别的应用的文件信息。一个常用解决办法就是干脆装多个虚拟机,但是,虚拟机对我们来说偏“重”,比如,多个应用公用的一些动态链接库(比如 libc.so)和配置文件(比如 hosts.conf)就复制了多份,如果原先一个系统在运行时系统文件占了500M的cache,那么现在装了4台虚拟机,就有2G的cache被重复占用了。

怎样才能让系统文件只占一份cache呢?我们首先想到这么个主意:把linux系统装到ext4上,然后做4个snapshot("快照“),这4个snapshot分别mount到4个目录,4个运维chroot到这4个目录里,然后就自己干自己的,干扰不到别人的文件。由于ext4 snapshot的实现机制是让同一个物理block被映射到不同的文件系统里,所以我们觉得,这一个4k的物理block应该就只占4k的cache。

(也许有人要说,这么费劲干嘛,直接把系统常用的动态链接库做4个软链接出来,给4个运维用不就行了?这样做有两个问题,第一,动态链接库以及各种系统文件很多,不可能一一做软链接;第二,也是关键的一点,如果其中一位运维错误操作,例如覆盖写了某个系统文件,那么其他的运维就歇菜了,因为软链接实际指向的是同一个实际文件。)

于是开始考察ext4的snapshot。ext4目前是没有snapshot功能的,但是Amir Goldstein已经开发好了对应的patch,但是目前还没有被收入mainline。粗略看了一下,Amir的patch目前只支持readonly的snapshot,于是我发邮件问“如果改成writable snapshot,代码量大不大?“,Amir回帖表示代码量不大;另外还有别人回帖,推荐不用ext4而是用device mapper提供的thin provision的internal snapshot(1,2),这样就不用依赖于某一个文件系统(就是如果咱们以后不用ext4了,也可以继续做snapshot)。

鉴于ext4 snapshot不支持writable snapshot,且有7000行的改动之多,且目前都没有进mainline的计划,而device mapper的thin provision已经进了3.2 kernel,且只有5000行改动,且支持writable snapshot,所以。。。转而又考察thin provision。考察基本顺利,做snapshot没有问题,snapshot写入没问题,最后chroot然后编译kernel测试速度也没问题,但是,最后发现一个郁闷的事情:这些snapshot被mount以后,公用的文件在不同的文件系统里各自都要占一份cache,也就是说,明明是一个4k物理block,mount到4个不同的文件系统,就占4 x 4k的内存cache了!

难道是device mapper的问题?于是再试了一下ext4的snapshot,甚至btrfs的snapshot,都一样!这就是vfs的特性:只要是inode不同,即使这些inode指向的是同一个物理block,那么它们的cache都是各自独有的,不共享。

我把这个事儿告诉了coly

coly: (石化片刻)唉,我们之前想漏了,snapshot根本不能解决这个问题。。。太郁闷了,测了快两周才发现

我: 想开一点吧,还好是测出来的,而不是上线了才发现——到时候运维找过来“你们的这个方案好像不省内存啊”,然后还得解释,还得回滚,就更被动更狼狈了

coly: 噢,你这样一说,我舒坦多了

最后还是马涛同学给出了一个方案——overlay fs,能把两个目录(甭管是什么文件系统的两个目录,是目录就行)“叠合”成一个文件系统,而这个新文件系统的inode其实还是原来目录里的那个,但是视图已经是“叠合”后的了。

比如,有两个目录,其中一个目录dir1有两个文件,是:

./ab (ino:14)
./cd (ino:16)

另一个目录dir2有三个文件,是:

./apple (ino:23)
./banana (ino:27)
./lemon (ino:31)

最后用

mount -t overlayfs overlayfs -olowerdir=/dir1,upperdir=/dir2 /test/

建立的新文件系统/test/里看上去是这样:

./ab (ino:14)
./cd (ino:16)
./apple (ino:23)
./banana (ino:27)
./lemon (ino:31)

注意,inode还是那些inode,但是他们“凑一块儿了”,而且,这个新文件系统是可写的,即使覆盖写了某个文件,也只影响upperdir(例子里的dir2)的内容,而lowerdir(例子里的dir1)没有任何影响。这样,我们就可以把linux系统根目录当成lowerdir,而每个运维自己的系统当成 upperdir ,某个运维的错误操作就不会影响其他人了。

感谢马涛同学的推荐,目前这个还没有进mainline的overlay fs非常契合我们的应用。