Docker 原理探索:cgroups

简介

这是 《容器和容器云》的阅读笔记,本文主要关于 cgroups。cgroups 提供了物理资源控制的相关机制,可以控制不同子系统上的资源分配,比如 cpu,内存等。cgroups 核心有四个概念。任务,指的是进程或者线程。控制组,资源控制以组为单位。子系统,资源调度控制器,比如 CPU 子系统可以控制 CPU 时间分配。层级,cgroups 会有层级,系统默认的 cgroups 里面会包含所有的任务,通过在这个 cgroups 下面创建不同的子 cgroups 来将不同的任务加入到子 cgroups 来实现分组控制。

cgroups 以文件系统的方式进行操作,通过操作文件系统可以进行资源限制,优先级分配,资源统计,任务控制。换言之,cgroups 的使用方式,就是操作目录那么简单。

规则

前面提到了 cgroups 中的四个重要概念:任务,控制组,子系统,层级。下面分析它们相互间的关系。

  1. 同一层级可以附加多个子系统
  2. 一个子系统可以附加到多个层级,当且仅当目标层级只有一个子系统。
  3. 新建一个层级时,所有任务默认加入新建层级的初始化 cgroup。
  4. 任务只能存在于同个层级中的一个 cgroup,能存在于多个层级中的多个 cgroup
  5. 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 层级。

posted @ 2022-04-14 20:10  楷哥  阅读(178)  评论(0编辑  收藏  举报