Cloud Foundry 源码解析一览(warden)

来源:互联网 发布:百无一用是书生知乎 编辑:程序博客网 时间:2024/06/05 02:13

warden是其核心部分的资源管理容器,完成了各种资源分配的事情。

代码位置在:https://github.com/cloudfoundry/warden

这一部分也是我最想了解细节的地方,因为在一个paas平台中,资源的隔离才是最有价值的部分。

基础知识

rv= unshare(CLONE_NEWNS);

unshare这个调用,可以把挂载的文件系统设置成只在新的挂载命名空间(mountnamespace)中可见。

execvp(argv[0],argv);

execvp()会从PATH环境变量所指的目录中查找符合参数file的文件名,找到后便执行该文件,然后将第二个参数argv传给该欲执行的文件。

shopt-s nullglob

设置shell环境变量nullglob的值为onnullglobon时对于通配符匹配时,若匹配不到时为空(相对应的为通配符本身)。

intstat(const char *restrict pathname, struct stat *restrict buf);

提供文件名字,获取文件对应属性。

build-essential软件包

作用是提供编译程序必须软件包的列表信息,也就是说编译程序有了这个软件包,它才知道头文件在哪,才知道库函数在哪,还会下载依赖的软件包,最后才组成一个开发环境。

工具debootstrap

可以用于在系统的某个目录中安装一套基本系统,这个基本系统除了一些配置项外,与ubuntu安装程序在安装的第一阶段安装的内容基本相同。这项功能有许多有趣的功能,例如,你可以从某个定制版本的ubuntuLive光盘上通过这个命令快速的在硬盘上安装ubuntu而不需要ubuntu的安装程序,也可以把创建在硬盘上的基本系统目录作为某些涉及系统安全性服务的chroot运行环境,通过chroot进入该目录并调试和运行一些可能修改系统配置的应用程序,作为定制小型系统模板等等。

aufs

一种文件格式,可以mount到目录,同时控制只读和读写。

overlayfs

另一种文件格式,在ubuntu11.04后开始替代aufs作为官方livecd的文件格式。

cloudfoundrywarden代码解读-part2

代码结构

|--em-warden-client基于eventmachineclient依赖warden-clientwarden-protocol通过unixsocket来通讯

|--warden巨复杂的warden实现,大部分是shell脚本+ruby,还有两个c实现。

|--warden-client客户端驱动,提供与warden的阻塞式通讯client。依赖warden-protocol。其中的V1.rb对各自command进行解析之后的处理。这里有一个v1mode的概念,v1mode使用字符串,转为pb后与其他的一起使用protobuf

`--warden-protocol依赖beefcake(protobuflibrary for Ruby)protocol下有所有支持的pb生成格式。

小坑:ruby中的send方法

send其实就是动态地根据名字调用函数,传递后面的内容作为调用参数,api函数原型为:

obj.send(symbol[, args...]) => obj

V1.rb中,所能的convert_xxxx_request方法都是这样被调用到的。

专注warden实现

src下四个C程序:

|--clone用来快速复制一个环境 夹杂一堆的shell在其中运行

|--iomux分成两个部分:iomux-spawn把子进程的pid写到stdout来标示它已经做好准备接收连接。在尝试连接之后一直等待。iomux-link是用来根据pid重新link到其上去。

|--oom通过eventfd得到内存不够的通知

`--repquota报告quota使用情况

四个c程序将在编译后复制到root/linux/skeleton/bin

其他目录:

|--bin下面有两个脚本文件,用来启动和进入命令行的

|--config下面有一个配置文件,定义了linux下的配置

|--lib所有的ruby代码

|--root各种shell脚本,操作cgroup之类的

启动warden

环境:

chenzhen@ubuntu-chenzhen:~/warden/warden$lsb_release -a

NoLSB modules are available.

DistributorID: Ubuntu

Description:Ubuntu 12.04 LTS

Release:12.04

Codename:precise

$cdwarden/warden

$sudobundle exec rake setup[config/linux.yml]

$sudobundle exec rake warden:start[config/linux.yml]

$ctrl+z

$bg

$sudobundle exec bin/warden-repl

$ping

...pong

调用过程:

bin/warden-repl>> lib/warden/repl.rb >> Warden::Client >>warden.sock >> lib/warden/server.rb <<Warden::Server.run! << Rakefile

处理调用:

server.rb> ClientConnection > receive_request > process(request) >process_container_request(request, container) > base.rb >dispatch(request, &blk) > send(do_method, request, response,&blk) -> linux.rb > do_xxx > shell script

clone.c分析:

src/clone/clone.c:main ->

console.c:openpty ->

clone.c:daemonize ->

barrier.c:barrier_open ->

clone.c:run("./hook-parent-before-clone.sh"); ->

clone.c:parent_clone_child ->

clone.c:pid = clone(start, stack, flags, h); ->

clone.c:start() ->

console_mount(&h->console,"dev/console"); ->

pivot_root->

clone.c:run("./hook-parent-after-clone.sh"); ->

clone.c:barrier_signal(&h->barrier_parent); ->

clone.c:barrier_wait(&h->barrier_child);

cloudfoundrywarden代码解读-part3

根据part2里提到的过程,本节以create命令为例进行追踪。

调用过程:

bin/warden-repl>> lib/warden/repl.rb >> Warden::Client >>warden.sock >> lib/warden/server.rb <<Warden::Server.run! << Rakefile

处理调用:

server.rb> ClientConnection > receive_request > process(request) >process_container_request(request, container) > base.rb >dispatch(request, &blk) > send(do_method, request, response,&blk) -> linux.rb > do_xxx > shell script

过程放大

一、进入repl命令行

1.1名词bundle:主要用于管理Ruby应用程序的依赖关系,并按照此依赖关系安装所需的Gems。当运行bundleinstall命令来安装Gems时,bundler会使用当前目录下的名为Gemfile的文件来处理依赖关系。

gem:就是ruby的软件包,一个gem就是一个ruby软件。

Gemfile:定义了各种依赖情况,bundler命令必须在存在此文件的目录下执行。

Gemfile.lock:记录本机目前所有依赖的gem命令和版本。

rake:编译工具,类似javaant

Rakefilerake命令所定义的配置任务文件,类似ant.xml

1.2进入#sudobundle exec bin/warden-repl

使用bundleexec来保证项目依赖的gem版本。在bin目录下有warden-repl脚本(ruby),这将会执行lib/warden/repl.rb文件,先会使用Warden:Client发起对warden.sock的连接,然后在start方法中对命令行模式的交互进行反馈。

二、输入create

当输入create时,repl.rb执行到process_line中的respond_to的判断:

2.1respond_to?if respond_to? words[0].to_sym。。。

这种写法的意思是,当前对象中是否有方法名为words[0].to_sym变量值的方法。

2.2createrepl.rb果断有这个create方法,然后talk_to_warden。就进入了client写的过程了。

三、warden收到create的响应

3.1warden server的启动早在part2中,使用了命令:

sudobundle exec rake warden:start[config/linux.yml]

就已经启动了warden

这将使在bundle定义的环境下,执行warden/warden/Rakefile里写好的任务:Warden::Server.run!

3.2wardenserver的响应在lib/warden/server.rb中,run!方法下,使用了EMstart_unix_domain_server的方法启动了一个unixsock,第二个参数ClientConnection定义了接收到东西怎么处理。

ClientConnection中的process方法具体处理了create

whenProtocol::CreateRequest

container= Server.container_klass.new

container.register_connection(self)

response= container.dispatch(request)

container_klass为配置中的Warden::Container::Linux

最终,将会执行linux.rb中的do_create方法。

四、shell脚本中的猫腻

warden/root/linux中,有大量的sh脚本,里面通过一系列的命令,完成了基础环境的搭建,非常值得一读。

4.1linux/base/setup.sh这个脚本在运行安装warden时会被执行,按照执行过程:

1)分析本机最近的apt源地址。

2debootstrap/tmp/warden

3debootstrap的作用见前面的文章,主要是可以用于在系统的某个目录中安装一套基本系统.http://www.54chen.com/architecture/cloud-foundry-warden-part1.html

4)使用chroot将子系统中的缺失软件安装好

4.2base.rbdispatchcreate过程1)拼接before_create

2)执行linux.rb中的features/quota.rbbefore_create方法

2.5)执行base中的before_create方法,产生一个十六进制的handle值(也就是每个contaner的标识)

3setquota

4linux.rbdo_create

4.3linux.rbdo_create过程1create.sh脚本的执行:传入目录,检查是否存在;unshare-m setup.sh

2unshare的作用是在指定的环境下执行程序setup.sh,不影响上一级环境。

3)此处的setup.shbase/setup.sh相比,没有了debootstrap的过程。

4setup.sh中设置了cgroup、磁盘挂载、限额、网络。

5)紧接着如果需要会执行hook-parent-before-clone.sh

6)修改limits.conf的参数

7)执行start.sh:建立子网,打通两条ssh通道。

8)完成create

五、交互演示

$sudo bundle exec bin/warden-repl

warden>list

["16bp35aue5i"]

warden>stop 16bp35aue5i

"ok"

warden>list

["16bp35aue5i"]

warden>destroy 16bp35aue5i

"ok"

warden>list

nil

warden>create

16bp35aue5j

warden>info 16bp35aue5j

{"state"=>"active",

"host_ip"=>"10.254.0.5",

"container_ip"=>"10.254.0.6",

"container_path"=>"/tmp/warden/containers/16bp35aue5j",

"memory_stat"=>

,

"cpu_stat"=>

,

"disk_stat"=>

}

warden>spawn 16bp35aue5j w

2

warden>link 16bp35aue5j 2

exitstatus: 0

stdout:

03:18:51up 29 days, 14:51, 0 users, load average: 0.00, 0.04, 0.05

USERTTY FROM LOGIN@ IDLE JCPU PCPU WHAT

stderr: