Linux-容器技术基石2-cgroups

前言

cgroups 是什么?简单来说,cgroups(Control Groups)linux 内核 提供的一种可以 限制程序资源的机制, 被广泛用于容器隔离技术. 使用 cgroups , 我们可以限制一个或一组进程的资源, 如 cpu, 内存, 进而让我们实现两个目的

  • 提前规划好资源, 能确保各个程序都有足够的资源使用
  • 可让资源利用更加高效, 可靠

本文通过几个实际的使用案例, 来探索 cgroups 的使用,
目前 cgroupscgroups-v1 cgroups-v2, 本文只探索 cgroups-v2

cgroup小Demo-限制进程可用cpu数

我们创建一个 cgroup,设置在这个 cgroup 下的进程只能使用两个处理器核, 然后启动一个测试程序, 观察这个程序的可用cpu列表, 然后将进程pid绑定到这个 cgroup, 观察可用cpu列表的变化

  • 创建cpu控制策略
    • 创建 cgroup 文件夹
      mkdir limit-core-01
      

      在目录 /sys/fs/cgroups 下创建一个目录 limit-core-01

      进入目录,会发现里面自动生成了好多文件 (第一次见的我感觉好神奇)

    • 配置处理器核限制

      这里需要使用目录文件下的 cpuset.cpus, 这就是用来限制当前 cgroup 的可用处理器核的, 一般不配置会是空白,表示所有核都能使用,我们希望只使用两个,那么可配置 0-1, 表示只能使用前两个

      echo "0-1" > cpuset.cpus
      
  • 将进程涵盖进 cgroup
    有手动和自动的办法:
    1. 程序启动后手动将 pid 涵盖进 cgroup.procs
    2. 在程序启动时, 使用控制工具 cgroup-tools
    • 先创建一个测试程序
       import os
       import time
      
       for i in range(1000):
           print(f"{os.getpid()}-{i}, limit_cpu: {os.sched_getaffinity(0)}")
           time.sleep(1)
      

      其中 os.sched_getaffinity(0) 为获取当前进程被限制使用的cpu

    • 启动测试程序,将PID加入 cgroup.procs
      echo 15336 > cgroup.procs
      

      cgroup-demo-1686135588625
      启动程序,我们看到 os.sched_getaffinity(0) 的返回一开始是 0-19 (机器20核),在将进程id 15336 放进 cgroup.procs 后,立马变成了我们设置的 0-1,这样就成功对该进程进行了cpu资源限制。

    • [自动] 启动程序时加入该cgroup

      我们需要先安装 cgroup-tools

      sudo apt install  cgroup-tools
      

      启动程序

      sudo cgexec -g cpuset:limit-core-01 python test.py
      

      cgroup-demo-auto

cgroup-v2 的目录结构

cgroup-v2 是一个树形结构,/sys/fs/cgroup 就是一个 cgroup, 其中有文件和目录

  • 文件:基本都是跟当前 cgroup 相关的资源控制策略文件
  • 子目录:也是一个 cgroup,但其只拥有 父cgroup 开放给它的资源控制权限
    • 如在 父cgroup 中配置 cgroup.subtree_control 可用控制器 cpuset memory, 那么 子cgroup 就只能通过这两个控制器 cpuset memory 进行控制的权限。

cgroup-v2 可控制资源

按照 控制器 分类可控制资源, 在 cgroup 根目录 /sys/fs/cgroup

cat cgroup.controllers
walkerjun@walkerjun:/sys/fs/cgroup$ cat cgroup.controllers
cpuset cpu io memory hugetlb pids rdma misc
控制器 用途
cpuset 可用来限制进程可用的cpu 数量
cpu cpu繁忙 时生效,可限制进程cpu的使用额,如在 cpuset 的基础上,只能使用其中 50% 的配额,这个在 cpu 不繁忙 时不会生效
io 用来限制进程对某设备的带宽, 如通过设置上限来实现
memory 限制进程使用的内存
hugetlb 限制 huge pages 使用
pids 限制在这个 cgroup 下绑定的 进程数量
rdma 限制 RDMA/IB-specific 资源使用
misc -

cpu控制器Demo-限制cpu使用率

我们创建一个名为 test-cpu-usage-limit 的新 cgroup, 并使用配置 cpu.max 来控制这个 cgroupcpu 使用率, 然后我们创建一个只有空循环的测试程序, 启动并观察在与不在这个cgroup 下的 cpu 使用率

  • 创建 cgroup test-cpu-usage-limit
    cgroup根目录 /sys/fs/cgroup 下执行
    mkdir test-cpu-usage-limit
    
  • 配置 cpu.max
    进入这个目录 cd test-cpu-usage-limit, 并执行
    echo "50000 100000" > cpu.max
    
    我们配置 50000 100000, 这两个值表示, 在每 100000cpu周期 内, 最多只会有 50000 是分配给这个 cgroup, 这意味着, 该 cgroup 最大的cpu使用率50%
  • 创建程序进行验证
    这里我们仍然使用 python 程序, 由于python 存在 全局解释器锁(GIL), 导致单进程最多只使用一个核, 因此, 我们使用top命令观察 python 程序的 %cpu 会比较方便, 在没有限制下, 最多会是 100%, 如果是空循环程序, 在没有任何限制下, 我们的预期正是 100%, 在我们的 cgroup test-cpu-usage-limit下, 则预期是 50%, 我们来试一下
    • 创建程序
      import os
      print(f"pid: {os.getpid()}")
      while True:
          pass
      
    • 不使用cgroup时cpu使用率
      python test-cpu-usage.py
      

      cgroup-demo-cpu-max-no-limit

      如上, 在没有做任何限制情况下, 该进程的 cpu使用率100% , 这表示完全了1 个核, 这符合我们的预期

    • 使用cgroup时cpu使用率
      sudo cgexec -g cpu:test-cpu-usage-limit python test-cpu-usage.py
      

      cgroup-demo-cpu-max

      如上, 当我们使用 cgroup 时, 我们成功将测试进程的最大cpu使用率 限制在了 50%

memory控制器Demo-限制最大内存

创建一个新 cgroup, 我们限制其最大使用内存是 20 M, 使用 memory.max 配置, 如果超过配置就会触发系统oom, 杀死相关程序, 因此我们通过观察程序是否被杀死来判断配置是否生效

  • 创建 cgroup memory-limit
mkdir memory-limit
  • 配置 memory.max
    cgroup 中所有内存相关的单位都是byte, 对于 memory.max 如果不限制最大内存, 则设置为max(默认配置), 我们这里设置 20 M, 即 20971520 bytes
    echo 20971520 > memory.max
    
    我们使用 python 程序验证这个配置, 由于 python 程序启动就会占用约 10M, 因此我们分别尝试在python 程序中申请 8M15M 内存, 观察 15M 是否会触发 oom
    • 启动程序
      sudo cgexec -g memory:memory-limit python
      
    • 尝试申请内存
      cgroup-demo-memory-max
      如上, 我一开始申请了 8M 内存, 没有问题, 可当再次申请 8M 则触发了 oom, 程序被杀死, 随后重新启动程序, 一开始就申请 15M, 程序则直接就被杀死了, 说明我们的配置已经生效了

cgroup-v2 配置文件

除了上面Demo 中的配置文件, 还有诸如 memory.min 这样的配置, 这些说明可以在 Linux内核文档-core-interface-files中找到, 这里就不搬运了

参考