今天研究warden的源码,分析了启动流程,整理了一下。
Warden 启动入口:src\warden\warden\lib\warden\server.rb def self.run!
(1)Process.setrlimit(Process::RLIMIT_NOFILE, 32768):linux 内核资源限制,一个进程能够打开的最大文件数
(2)container_klass.setup(self.config) 调用src\warden\warden\lib\warden\container\linux.rb setup
(3)执行脚本\src\warden\warden\root\linux\setup.sh
(4) cgroup 控制
(4.1)创建 /tmp/warden/cgroup
(4.2)mount -t tmpfs none /tmp/warden/cgroup 创建虚拟文件系统(存储的内容在RM或者Swap空间)
(4.3) 挂载cgroup子系统
none /tmp/warden/cgroup/cpu cgroup rw,relatime,cpu 0 0
none /tmp/warden/cgroup/cpuacct cgroup rw,relatime,cpuacct 0 0
none /tmp/warden/cgroup/devices cgroup rw,relatime,devices 0 0
none /tmp/warden/cgroup/memory cgroup rw,relatime,memory 0 0
Cgroup子系统作用介绍
blkio : 这个子系统设置限制每个块设备的输入输出控制。例如:磁盘,光盘以及usb等等。
cpu : 这个子系统使用调度程序为cgroup任务提供cpu的访问。
cpuacct : 产生cgroup任务的cpu资源报告。
cpuset : 如果是多核心的cpu,这个子系统会为cgroup任务分配单独的cpu和内存。
devices : 允许或拒绝cgroup任务对设备的访问。
freezer : 暂停和恢复cgroup任务。
memory : 设置每个cgroup的内存限制以及产生内存资源报告。
net_cls : 标记每个网络包以供cgroup方便使用。
ns : 名称空间子系统。
perf_event: 增加了对每group的监测跟踪的能力,即可以监测属于某个特定的group的所有线程以及运行在特定CPU上的线程,此功能对于监测整个group非常有用
(5) 网络配置,执行脚本src\warden\warden\root\linux\net.sh
(5.1)setup_filter:
iptables -N warden-forward 2> /dev/null || iptables -F warden-forward
iptables -A warden-forward -j DROP
创建过滤链,增加过滤规则(丢弃封包不予处理,进行完此处理动作后,将不再比对其它规则,直接中断过滤程序)
iptables -N warden-default 2> /dev/null || iptables -F warden-default
创建默认过滤链
iptables -A warden-default -m conntrack –ctstate ESTABLISHED,RELATED -j ACCEPT
默认过滤链增加规则,允许已经建立的连接到containers
iptables -A warden-default –destination “$n” –jump RETURN
iptables -A warden-default –destination “$n” –jump DROP
设置配置文件中配置的 被允许的网络,以及被禁止的网络
iptables -A FORWARD -i w-+ –jump warden-forward
配置outbound traffic
default_interface=$(ip route show | grep default | cut -d’ ‘ -f5 | head -1)
iptables -I warden-forward -i $default_interface –jump ACCEPT
设置使用的网卡接口 设置inround traffic
(5.2)setup_nat
iptables -t nat -N warden-prerouting 2> /dev/null || true
新建一个 nat规则表
(iptables -t nat -S PREROUTING | grep -q “\-j warden-prerouting\b”) ||
iptables -t nat -A PREROUTING \
–jump warden-prerouting
检查是否存在nat的prerouting 规则链 与warden-prerouting 绑定,如果没有将warden-prerouting 绑定到nat的prerouting规则链。
(iptables -t nat -S OUTPUT | grep -q “\-j warden-prerouting\b”) ||
iptables -t nat -A OUTPUT \
–out-interface “lo” \
–jump warden-prerouting
Bind chain to OUTPUT (for traffic originating from same host)
# Create postrouting chain
iptables -t nat -N ${nat_postrouting_chain} 2> /dev/null || true
# Bind chain to POSTROUTING
(iptables -t nat -S POSTROUTING | grep -q “\-j ${nat_postrouting_chain}\b”) ||
iptables -t nat -A POSTROUTING \
–jump ${nat_postrouting_chain}
# Enable NAT for traffic coming from containers
(iptables -t nat -S ${nat_postrouting_chain} | grep -q “\-j SNAT\b”) ||
iptables -t nat -A ${nat_postrouting_chain} \
–source ${POOL_NETWORK} \
–jump SNAT \
–to $(external_ip)
(6) 关闭AppArmor
(7) 设置warden的配额
配置文件设置了quota:
disk_quota_enabled: true
并且存放container的目录(/tmp/warden/containers)开启了配额管理
mount -o remount,usrjquota=aquota.user,grpjquota=aquota.group,jqfmt=vfsv0 $CONTAINER_DEPOT_MOUNT_POINT_PATH
(8)回到 src\\warden\\warden\\lib\\warden\\server.rb 执行:recover\_containers检查 /tmp/warden/containers 的container 状态
(1)将死去的container删除(destroy.sh)
(2)将仍然存活的container 启动(根据snapshot.json 中的信息恢复)
(9) 启动warden 进程FileUtils.rm_f(unix_domain_path)
server = ::EM.start_unix_domain_server(unix_domain_path, ClientConnection)
::EM.start_server(“127.0.0.1”, config.health_check_server[“port”],HealthCheck)
(10)
@drainer = Drainer.new(server, “USR2”)
@drainer.on_complete do
Fiber.new do
logger.info(“Drain complete”)
# Serialize container state
container_klass.registry.each { |_, c| c.write_snapshot }
EM.stop
end.resume
End
目前还不清楚是做什么。
(11)
FileUtils.chmod(unix_domain_permissions, unix_domain_path)
修改/tmp/warden.sock 文件属性为0777
# Let the world know Warden is ready for action.
logger.info(“Listening on #{unix_domain_path}”)
if pidfile = config.server[“pidfile”]
logger.info(“Writing pid #{Process.pid} to #{pidfile}”)
PidFile.new(piddir: File.dirname(pidfile), pidfile: File.basename(pidfile))
end