cloud foundry之warden源码解读(二)

overlayfs

说到warden就不能不说起overlayfs,试想想一个warden内部要创建多个容器,每个容器里面有自己独立的操作系统,而linux的每个 系统包即rootfs都有100多MB,如果没创建一个新的container,就去拷贝一个rootfs显然不是明智的选择。那么你就会想到如果所有的 容器共用一套rootfs,而且对所有的容器都可见,那么容器之间独立与隔离的效果完全达不到。这么时候使用overlayfs就是一个绝佳 的解决方案。

ubuntu系统支持overlayfs,所以warden能在ubuntu上顺利的运行起来,但是其他的不支持overlayfs的linux都是aufs的文件系统,这 是迄今为止cloud foundry移植的最大障碍。下面我们就先来说说overlayfs:

  • overlayfs分为两层,分别为上层(upperdir)和下层(lowwerdir),两层文件系统组成了一种很好的隐藏机制,比如:

    - dir1/目录里有
      ./fire
      ./water
    - dir2/目录里有
      ./apple
      ./banana
    

    mount -t overlayfs overlayfs -o lowerdir=/dir1,upperdir=/dir2 /test1/ 上面这条命令将两个文件夹mount到一起,得到test1这个目录就是:

     - test1/目录里有
        ./fire
        ./water
        ./apple
        ./banana
    

    在test1目录中的test1/fire与dir1/fire是同一个文件,他们有相同的inode。如果dir1与dir2里面出现同名的文件,那么上层的文件夹将盖住下层的文件夹,即test1中显示的是dir2的而不是dir1的。

    overlayfs有一个相当重要的特性就是下层的文件系统是只读(readonly)的,也就是说下层的文件系统是不可更改的,那么就意味 着对overlayfs所有的更改都是针对上层文件系统的。如果你想修改overlayfs对应的下层来达到定制的目的,实际上是将下层的文件夹 拷贝到上层,然后你再做相应的修改,而下层的文件系统就像被隐藏了一样,始终不会被改变。所以操作overlayfs时:

      新建:直接在上层创建文件
      删除:是上层目录,则直接删除;如果是下层目录,则将其隐藏起来(实际下层目录依然存在,只是暂时你看不见而已)
      写文件:是上层文件,则直接写即可;如果是下层文件,则先拷贝到上层,然后允许你在上层写入
    
    • warden中正式利用了这个机制,只需在宿主机上拷贝一份必要的rootfs,作为下层文件系统,因为它是只读的,所以不必担心其 被修改,各个container中只需生成自己需要的目录,然后就可以运行整个系统了:

      mount -n -t overlayfs -o rw,upperdir=tmp/rootfs,lowerdir=$rootfs_path none mnt
      

warden准备

  • rootfs,在warden运行之前必须得有rootfs,container才会有操作系统支撑。你可以在启动warden之前将完整的rootfs准备好,然后给warden 运行指定好相应的路径即可。当然你也可以通过warden/root/linux/rootfs/setup.sh来构建rootfs,ubuntu是通过bootstrap来构建的 centos则直接是下载的rpm包。

  • 接下来是一系列的环境准备,组要包括三个方面:

    1. 构建cgroup,因为warden的资源隔离底层是通过cgroup来实现的,在/tmp/warden/cgroup下我们可以看到,cgroup实现多个container之间的cpu,dev(设备)和memory的隔离控制。
    
    2. 修改宿主机的iptables,主要是添加filter和nat两个表中的规则,以便宿主机不会把外界与container里面的app通信的数据包丢弃。
    
    3. 关闭apparmor,apparmor会限制进程读写某些文件和网络端口。设置quota,限制进程的磁盘使用。
    

这样warden的启动准备工作就大致完成了,接下来就可以接受dea的命令开始创建容器了。

container

在warden/lib/warden/container/linux.rb中有针对container的各个动作,具体如下:

    do_create       创建container
    do_stop         停掉container,可以理解为shutdown操作系统
    do_destroy      清除container
    do_copy_in/out  拷贝文件进出container
    create_job      创建任务,比如脚本要在容器中运行等

我们来看一下do_create:

1. 它先把skeleton这个文件夹拷贝入container_path中,它就是一个容器的外层文件夹。
2. 挂载overlayfs,将宿主机上的rootfs文件夹作为底层,tmp/rootfs作为上层,mnt是container内操作系统的核心文件系统。
3. 在container中创建设备文件,导入环境参数,修改配置等 
4. 启动container中的linux系统。

启动container中的系统可以看作是跟正常linux启动过程一样,它会为每个container虚拟出一个虚拟网卡,container的ip地址是 warden在ip-pool中取出来的,另外它也会自己配置自己的iptables来建立网络连接。

container系统启动最重要的就是wsh,它是由c语言写的一个linux虚拟机,通过它能够控制container内操作系统的启动,也能通过它 进入一个shell的控制终端。wsh给我们提供了一个进入container内部操作系统的入口,完成的功能和一般系统的initd进程差不多。

正常启动的container里面会有已经创建好的用户vcap,这样/home/vcap/用户主目录就成了app的目录空间。

后记

以上就是warden的主要工作过程了,需要挖掘的还很多,cgroup、wsh要展开说更是不止这些。到这里cloud foundry的核心组件都说的 差不多了,至于cloud controller和health manager都是基于EM或sinatra的编程处理一些业务逻辑,不太具有可读性。



Previous     Next
zhing /
Published under (CC) BY-NC-SA in categories cloudfoundry  tagged with cloudfoundry