WiWarden启动源码分析

今天研究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