Docker 原理探索:cgroups
简介
这是 《容器和容器云》的阅读笔记,本文主要关于 cgroups。cgroups 提供了物理资源控制的相关机制,可以控制不同子系统上的资源分配,比如 cpu,内存等。cgroups 核心有四个概念。任务,指的是进程或者线程。控制组,资源控制以组为单位。子系统,资源调度控制器,比如 CPU 子系统可以控制 CPU 时间分配。层级,cgroups 会有层级,系统默认的 cgroups 里面会包含所有的任务,通过在这个 cgroups 下面创建不同的子 cgroups 来将不同的任务加入到子 cgroups 来实现分组控制。
cgroups 以文件系统的方式进行操作,通过操作文件系统可以进行资源限制,优先级分配,资源统计,任务控制。换言之,cgroups 的使用方式,就是操作目录那么简单。
规则
前面提到了 cgroups 中的四个重要概念:任务,控制组,子系统,层级。下面分析它们相互间的关系。
- 同一层级可以附加多个子系统
- 一个子系统可以附加到多个层级,当且仅当目标层级只有一个子系统。
- 新建一个层级时,所有任务默认加入新建层级的初始化 cgroup。
- 任务只能存在于同个层级中的一个 cgroup,能存在于多个层级中的多个 cgroup
- fork/clone 子任务的创建,默认加入父任务的 cgroup。
子系统
子系统可以通过下面的命令列举,在 /sys/fs/cgroup/
目录下面,每个目录对应一个子系统,每个目录下面的文件,代表着子系统的控制配置。通过操作这些文件,就可以控制对应的资源。比如 cpu.shares
这个文件,可以控制任务在 CPU 上的执行时间权重,默认是 1024,权重越大,被调度到的机会越大。cgroups 的实现原理,本质上是给任务加上钩子,当涉及某种资源时,就触发钩子上附带的子系统。cgroup 和任务之间是多对多的关系。
(base) percent1@ubuntu:~$ mount -t cgroup
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,name=systemd)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,net_cls,net_prio)
cgroup on /sys/fs/cgroup/rdma type cgroup (rw,nosuid,nodev,noexec,relatime,rdma)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb)
cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
Docker 和 cgroups
通过下面的命令,可以创建一个在 cpu 子系统下面的控制组,控制组里面的文件,都是 cgroups 自动生成的。只要往 cgroup.procs 里面写 pid,就可以将进程加入到对应的控制组里面。
(base) percent1@ubuntu:~/code$ ls /sys/fs/cgroup/
blkio cpu cpuacct cpu,cpuacct cpuset devices freezer hugetlb memory net_cls net_cls,net_prio net_prio perf_event pids rdma systemd unified
(base) percent1@ubuntu:/sys/fs/cgroup/cpu$ sudo mkdir cg1
[sudo] password for percent1:
(base) percent1@ubuntu:/sys/fs/cgroup/cpu$ ls cg1 # 下面这些都是系统生成的
cgroup.clone_children cpuacct.stat cpuacct.usage_all cpuacct.usage_percpu_sys cpuacct.usage_sys cpu.cfs_period_us cpu.shares notify_on_release
cgroup.procs cpuacct.usage cpuacct.usage_percpu cpuacct.usage_percpu_user cpuacct.usage_user cpu.cfs_quota_us cpu.stat tasks
Docker 和 cgroups:docker 会在 /sys/fs/cgroup/docker
这个控制组下面,为每个容器创建一个子控制组。比如我们可以使用下面的命令,启动一个容器。根据容器 id,可以找到对应的目录,并且在 cpu 子目录里面,可以看到 cpu.shares 的权重。
# 终端1 绑定一个容器
(base) root@ubuntu:~/code/cmake_cpp_cuda/build# docker run -it --rm --cpu-shares 10000 busybox
/ #
# 终端2 可以查看
(base) percent1@ubuntu:/sys/fs/cgroup/cpu$ docker container ls
... # 根据 container id 找到对应的目录
(base) percent1@ubuntu:/sys/fs/cgroup/cpu$ cat docker/71f8e3aef5d17b60ecf7c1fedd0a82227bb1ade4b7da88013e4f2a00132e56a2/cpu.shares
10000
总结
通过上面的简单探索,对 cgroups 有一个感性的认识。Docker 使用它来资源限制,优先级分配,资源统计,任务控制等,核心概念有四个:任务,子系统,控制组,cgroups 层级。