阅读完 warden启动的源码,又看了创建container的源码:
在lib/warden/server.rb中,run!方法下,使用了EM的start_unix_domain_server的方法启动了一个unixsock,第二个参数ClientConnection定义了接收到东西怎么处理,ClientConnection中的process方法具体处理了create:
when Protocol::CreateRequest
container = Server.container_klass.new
container.register_connection(self)
response = container.dispatch(request)
(container_klass为配置中的Warden::Container::Linux)
通过dispatch,会执行linux.rb中的do_create方法。
(1) 获取,设置 rootfs 的存放目录warden 单独运行时 /tmp/warden/rootfs
(2) 执行脚本 src/warden/root/linux/create.sh ,传入参数:新建的container路径;container需要的其他参数
(2.1) 检查 container 路径是否已经存在,如果已经存在,则停止创建
(2.2) 将\src\warden\warden\root\linux\skeleton 目录下的 全部copy到container
(2.3) 执行container下的脚本,unshare -m setup.sh 创建单独的文件系统命名空间
(2.3.1) 将以下信息 写入 container 下的etc/config 文件,后面在启动网络的时候,会加载该文件
id=17jqe2nv7dh
network_netmask=255.255.255.252
network_host_ip=10.254.0.5
network_host_iface=w-17jqe2nv7dh-0
network_container_ip=10.254.0.6
network_container_iface=w-17jqe2nv7dh-1
user_uid=10001
rootfs_path=/tmp/warden/rootfs
allow_nested_warden=false
(2.3.2)执行setup_fs_ubuntu()
mount -n -t aufs -o br:tmp/rootfs=rw:$rootfs_path=ro+wh none mnt
aufs的参数格式表示tmp/rootfs是以读写方式挂载,$rootfs_path以只读方式挂载,堆叠挂载到mnt上
(2.3.3) 将轻量级的container中需要的文件方法container目录下的mnt路径:包括Container中增加用户,配置dns,配置域名,hosts文件。。。。
(2.4) 函数write_bind_mount_commands:执行lib目录下的hook-child-before-pivot.sh
(2.4.1)将request中需要进行绑定的操作写入到hook-child-before-pivot.sh脚本,如果dea需要增加mount的信息,可以通过设置request参数
(2.4.2) 如果允许嵌套warden,需要在该container中创建 /tmp/warden/cgroup 目录,并将新建的container中的/tmp/warden/cgroup 目录和宿主机上的/tmp/warden/cgroup 进行一次mount,cgroup下的子系统 cpu cpuacct devices memory 进行同样的mount操作 (这里只是将进行的操作写入到脚本ook-child-before-pivot.sh)
(3)启动container,调用启动脚本:warden\root\linux\skeleton\start.sh
(3.1) 载入配置文件source ./etc/config
(3.2) 启动网络 ./net.sh setup
(3.3)执行C 代码
nice -n 10 ./bin/wshd --run ./run --lib ./lib --root ./mnt --title "wshd: $id" \
设置进程优先级, 红色部分为 执行./bin/wshd 的参数
Wshd.c 源码:
1、将参数写入结构体wshd_t
2、parent_run 函数,配置wshd.sock路径
w->fd = un_listen(path); 建立socket绑定
rv = barrier_open(&w->barrier_parent); // 建立管道
rv = barrier_open(&w->barrier_child);
unshare(CLONE_NEWNS); 把挂载的文件系统设置成只在新的挂载命名空间(mountnamespace)中可见
run(w->lib_path, "hook-parent-before-clone.sh"); //执行脚本,将 只读的rootfs和可写的rootfs全部挂载到 container中的 mnt目录
pid = child_start(w); // 进行clone clone参数包含
(各个表示的含义http://www.cnblogs.com/lisperl/archive/2012/05/03/2480316.html)
flags |= CLONE_NEWIPC; //
flags |= CLONE_NEWNET;
flags |= CLONE_NEWNS;
flags |= CLONE_NEWPID;
flags |= CLONE_NEWUTS;
克隆完成后,执行函数int child_run(void *data),这个函数还不是很理解:
大体包含:执行脚本hook-child-before-pivot.sh
设置共享内存,执行container内的 /sbin/wshd 启动container