Linux-Cgroup V2 初体验

linux,cgroup,v2 · 浏览次数 : 4

小编点评

本文主要介绍了 Linux Cgroup V2 版本的基本使用操作,包括 CPU 和 Memory 子系统的演示。 1. **开启 Cgroup V2 版本检查**:通过运行 `stat -fc %T /sys/fs/cgroup` 命令来查看当前系统使用的 Cgroups V1 还是 V2。如果输出是 `cgroup2fs`,则表示 V2 版本。 2. **启用 cgroup v2**: - 如果当前系统未启用 Cgroup V2,可以通过修改内核 cmdline 引导参数手动启用。 - 对于使用 GRUB 的发行版,在 `/etc/default/grub` 下的 `GRUB_CMDLINE_LINUX` 中添加 `systemd.unified_cgroup_hierarchy=1`,然后执行 `sudo update-grub`。 - 最后查看启动参数,确认配置已修改,并重启系统。 3. **基本使用 cgroup v2**:介绍了如何创建子 cgroup、移动进程到指定 cgroup、删除 cgroup,以及修改 CPU 和 Memory 限制。 4. **v1 v2 对比**:对比了 V1 和 V2 版本的 Cgroups,指出 V2 版本简化了层次结构,将所有子系统合并到一个统一的树形结构中。 5. **小结**:总结了本文内容,并推荐了相关资料,鼓励读者进一步学习。 总的来说,本文详细介绍了 Linux Cgroup V2 版本的使用方法和与 V1 版本的差异,为 Linux 用户提供了一个关于 Cgroups 的实用指南。

正文

本文主要记录 Linux Cgroup V2 版本基本使用操作,包括 cpu、memory 子系统演示。

1. 开启 Cgroup V2

版本检查

通过下面这条命令来查看当前系统使用的 Cgroups V1 还是 V2

stat -fc %T /sys/fs/cgroup/

如果输出是cgroup2fs 那就是 V2,就像这样

root@tezn:~# stat -fc %T /sys/fs/cgroup/
cgroup2fs

如果输出是tmpfs 那就是 V1,就像这样

[root@docker cgroup]# stat -fc %T /sys/fs/cgroup/
tmpfs

启用 cgroup v2

如果当前系统未启用 Cgroup V2,也可以通过修改内核 cmdline 引导参数在你的 Linux 发行版上手动启用 cgroup v2。

如果你的发行版使用 GRUB,则应在 /etc/default/grub 下的 GRUB_CMDLINE_LINUX 中添加 systemd.unified_cgroup_hierarchy=1, 然后执行 sudo update-grub

具体如下:

1)编辑 grub 配置

vi /etc/default/grub

内容大概是这样的:

GRUB_DEFAULT=0
GRUB_TIMEOUT_STYLE=hidden
GRUB_TIMEOUT=0
GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
GRUB_CMDLINE_LINUX=""

对最后一行GRUB_CMDLINE_LINUX进行修改

GRUB_CMDLINE_LINUX="quiet splash systemd.unified_cgroup_hierarchy=1"

2)然后执行以下命令更新 GRUB 配置

sudo update-grub

3)最后查看一下启动参数,确认配置修改上了

cat /boot/grub/grub.cfg | grep "systemd.unified_cgroup_hierarchy=1"

4)然后就是重启

reboot

重启后查看,不出意外切换到 cgroups v2 了

root@cgroupv2:~# stat -fc %T /sys/fs/cgroup/
cgroup2fs

发行版推荐

不过,推荐的方法仍是使用一个默认已启用 cgroup v2 的发行版。

有关使用 cgroup v2 的 Linux 发行版的列表,

  • Container-Optimized OS(从 M97 开始)
  • Ubuntu(从 21.10 开始,推荐 22.04+)
  • Debian GNU/Linux(从 Debian 11 Bullseye 开始)
  • Fedora(从 31 开始)
  • Arch Linux(从 2021 年 4 月开始)
  • RHEL 和类似 RHEL 的发行版(从 9 开始)

2. 基本使用

cgroup v2 使用上和 v1 版本基本一致,v2 版本也是默认在/sys/fs/cgroup/目录。

root@mydocker:~# ls /sys/fs/cgroup/
cgroup.controllers      cgroup.subtree_control  init.scope       system.slice
cgroup.max.depth        cgroup.threads          io.cost.model    user.slice
cgroup.max.descendants  cpu.pressure            io.cost.qos
cgroup.procs            cpuset.cpus.effective   io.pressure
cgroup.stat             cpuset.mems.effective   memory.pressure
  • 创建 sub-cgroup: 只需要创建一个子目录
cd /sys/fs/cgroup
mkdir $CGROUP_NAME
  • 将进程移动到指定 cgroup:将 PID 写入到相应 cgroup 的 cgroup.procs 文件即可,就像这样:
echo 1001 > /sys/fs/cgroup/test/cgroup.procs
  • 删除 cgroup/sub-cgroup: 也是直接删除对应目录即可
    • 如果一个cgroup 已经没有任何children或活进程,那直接删除对应的文件夹就删除该cgroup了
    • 如果一个cgroup已经没有children,但是还有僵尸进程,也认为这个cgroup是空的,可以直接删除
rmdir /sys/fs/cgroup/test
  • 修改 cpu、memory 限制:往对应配置文件写入配置内容即可
    • cpu.max 用于配置 cpu 使用限制
    • memory.max 则用于配置 内存使用限制
    • ...

创建 cgroup

接下来,以 cpu、memory 为例,简单演示一下 cgroup v2 版本使用

root@mydocker:~# cd /sys/fs/cgroup/
root@mydocker:/sys/fs/cgroup# mkdir test
root@mydocker:/sys/fs/cgroup# cd test
root@mydocker:/sys/fs/cgroup/test# ls
cgroup.controllers      cpu.uclamp.max         memory.current
cgroup.events           cpu.uclamp.min         memory.events
cgroup.freeze           cpu.weight             memory.events.local
cgroup.max.depth        cpu.weight.nice        memory.high
cgroup.max.descendants  cpuset.cpus            memory.low
cgroup.procs            cpuset.cpus.effective  memory.max
cgroup.stat             cpuset.cpus.partition  memory.min
cgroup.subtree_control  cpuset.mems            memory.oom.group
cgroup.threads          cpuset.mems.effective  memory.pressure
cgroup.type             io.max                 memory.stat
cpu.max                 io.pressure            pids.current
cpu.pressure            io.stat                pids.events
cpu.stat                io.weight              pids.max

CPU

启动一个死循环

root@mydocker:/sys/fs/cgroup/test# while : ; do : ; done &
[1] 90482

不出意外的话,应该占用了 100% cpu

PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND    
90482 root      20   0   10160   1772      0 R  99.3   0.1   0:05.01 bash 

接下来使用 cgroup v2 限制该进程只能使用 20% cpu

1)修改配置

echo 2000 10000 > cpu.max

含义是在 10000 微秒的 CPU 时间周期内,有 2000 微秒是分配给本 cgroup 的,也就是本 cgroup 管理的进程在单核 CPU 上的使用率不会超过 20%。

2)将进程加入当前 cgroup

echo 90482 > cgroup.procs

再次查看

PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND    
90482 root      20   0   10160   1772      0 R  20.2   0.1   2:07.78 bash 

可以看到,已经被限制到了 20%

Memory

接下来演示内存限制,使用以下代码来模拟内存消耗,

cat <<EOF > ~/mem-allocate.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define MB (1024 * 1024)

int main(int argc, char *argv[])
{
    char *p;
    int i = 0;
    while(1) {
        p = (char *)malloc(MB);
        memset(p, 0, MB);
        printf("%dM memory allocated\n", ++i);
        sleep(1);
    }

    return 0;
}
EOF

编译

gcc ~/mem-allocate.c -o ~/mem-allocate

然后启动该文件

root@mydocker:/sys/fs/cgroup/test# ~/mem-allocate
1M memory allocated
2M memory allocated
3M memory allocated
4M memory allocated
5M memory allocated
6M memory allocated
7M memory allocated
8M memory allocated
9M memory allocated
10M memory allocated
11M memory allocated
12M memory allocated
^C

可以看到,每秒会消耗 1M 内存,若不停止会一直运行直到 OOM。

接下来使用 cgroup v2 限制最多消耗 10M 内存。

1)修改配置

单位为字节 10485760= 10 * 1024 * 1024

echo 10485760 > memory.max

也就是本 cgroup 管理的进程内存使用不会超过 10M

2)将进程加入当前 cgroup

#将当前bash加入到test中,这样这个bash创建的所有进程都会自动加入到test中
sh -c "echo $$ >> cgroup.procs"

再次查看

root@mydocker:/sys/fs/cgroup/test# ~/mem-allocate
1M memory allocated
2M memory allocated
3M memory allocated
4M memory allocated
5M memory allocated
6M memory allocated
7M memory allocated
8M memory allocated
9M memory allocated
Killed

可以看到,到 10M 时就因为达到内存上限而被 Kill 了。

删除 cgroup

演示完成,把 cgroup 删除。

首先把进程 kill 一下

root@mydocker:/sys/fs/cgroup# cat test/cgroup.procs 
90444
90630
root@mydocker:/sys/fs/cgroup# kill -9 90630
root@mydocker:/sys/fs/cgroup# kill -9 90444

然后删除目录

root@mydocker:/sys/fs/cgroup# rmdir test

这样 cgroup 就删除了。

3. v1 v2 对比

v1 的 cgroup 为每个控制器都使用独立的树(目录)

[root@docker cgroup]# ls /sys/fs/cgroup/
blkio  cpu  cpuacct  cpuacct,cpu  cpu,cpuacct  cpuset  devices  freezer  hugetlb  memory  net_cls  net_cls,net_prio  net_prio  perf_event  pids  rdma  systemd

每个目录就代表了一个 cgroup subsystem,比如要限制 cpu 则需要到 cpu 目录下创建子目录(树),限制 memory 则需要到 memory 目录下去创建子目录(树)。

比如 Docker 就会在 cpu、memory 等等目录下都创建一个名为 docker 的目录,在 docker 目录下在根据 containerID 创建子目录来实现资源限制。

各个 Subsystem 各自为政,看起来比混乱,难以管理

因此最终的结果就是:

  1. 用户空间最后管理着多个非常类似的 hierarchy
  2. 在执行 hierarchy 管理操作时,每个 hierarchy 上都重复着相同的操作

v2 中对 cgroups 的最大更改是将重点放在简化层次结构上

  • v1 为每个控制器使用独立的树(例如 /sys/fs/cgroup/cpu/GROUPNAME /sys/fs/cgroup/memory/GROUPNAME)。
  • v2 将统一/sys/fs/cgroup/GROUPNAME中的树,如果进程 X 加入/sys/fs/cgroup/test,则启用 test 的每个控制器都将控制进程 X。

更多 v1 和 v2 差异见 v1 存在的问题及 v2 的设计考虑


【从零开始写 Docker 系列】持续更新中,搜索公众号【探索云原生】订阅,阅读更多文章。


4. 小结

本文主要分享了 Linux cgroup v2 版本的基本使用,以及 v1 和 v2 版本的差异。

更多 cgroup v2 信息推荐阅读:Control Group v2 及其译文 Control Group v2(cgroupv2 权威指南)(KernelDoc, 2021)

与Linux-Cgroup V2 初体验相似的内容:

Linux-Cgroup V2 初体验

本文主要记录 Linux Cgroup V2 版本基本使用操作,包括 cpu、memory 子系统演示。 1. 开启 Cgroup V2 版本检查 通过下面这条命令来查看当前系统使用的 Cgroups V1 还是 V2 stat -fc %T /sys/fs/cgroup/ 如果输出是cgroup2

[转帖]docker 容器基础技术:linux cgroup 简介

https://cizixs.com/2017/08/25/linux-cgroup/ Linux cgroups 的全称是 Linux Control Groups,它是 Linux 内核的特性,主要作用是限制、记录和隔离进程组(process groups)使用的物理资源(cpu、memory、

K8s如何启用cgroup2支持?

什么是 cgroup 📚️Reference: control groups(控制组),通常被称为cgroup,是Linux内核的一项功能。它允许将进程组织成分层的组,然后限制和监控各种资源的使用。 内核的cgroup接口是通过一个叫做cgroupfs的伪文件系统提供的。 分组是在核心的cgrou

[转帖]Docker资源(CPU/内存/磁盘IO/GPU)限制与分配指南

https://zhuanlan.zhihu.com/p/417472115 什么是cgroup? cgroups其名称源自控制组群(control groups)的简写,是Linux内核的一个功能,用来限制、控制与分离一个进程组(如CPU、内存、磁盘输入输出等)。 什么是Docker资源限制? 默

[转帖]Docker相关的概念和原理

https://www.jianshu.com/p/9737cbe33304 chroot chroot就是可以改变某进程的根目录,使这个程序不能访问目录之外的其他目录。Docker是利用Linux的Namespace、Cgroups和联合文件系统三大机制来保证实现的,它的原理是使用Namespac

一文全懂:Linux磁盘分区

本篇文章讲了linux磁盘管理中的分区相关知识,mbr和gpt分区有何不同?从添加一块硬盘到最后挂载到系统,经历了哪些步骤?如何创建交换分区并给交换分区扩容?

Linux 提权-密码搜寻

本文通过 Google 翻译 Password Hunting – Linux Privilege Escalation 这篇文章所产生,本人仅是对机器翻译中部分表达别扭的字词进行了校正及个别注释补充。 导航 0 前言 1 密码搜寻 – 文件名和文件内容 1.1 寻找有趣的文件名 1.2 寻找有趣的

玄机-第一章 应急响应- Linux入侵排查

玄机-第一章 应急响应- Linux入侵排查 简介 账号:root 密码:linuxruqin ssh root@IP 1.web目录存在木马,请找到木马的密码提交 2.服务器疑似存在不死马,请找到不死马的密码提交 3.不死马是通过哪个文件生成的,请提交文件名 4.黑客留下了木马文件,请找出黑客的服...

Linux 文件夹和文件操作【Linux 常用命令系列一】

本文首先介绍了 Linux 中文件的结构,将全部文件夹罗列并介绍了大概的用途,然后通过实例介绍了文件夹相关的常用操作,仅供参考。

玄机-第一章 应急响应-Linux日志分析

前言 又花了一块rmb玩玄机。。。啥时候才能5金币拿下一个应急靶机,只能说功底还没到家,唯有继续加油了。。。 简介 账号root密码linuxrz ssh root@IP 1.有多少IP在爆破主机ssh的root帐号,如果有多个使用","分割 2.ssh爆破成功登陆的IP是多少,如果有多个使用","...