码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • Linux-Cgroup V2 初体验


    合集 - Docker(27)
    1.深入理解 Docker 核心原理:Namespace、Cgroups 和 Rootfs2023-12-262.探索 Linux Namespace:Docker 隔离的神奇背后01-043.初探 Linux Cgroups:资源控制的奇妙世界01-094.深入剖析 Linux Cgroups 子系统:资源精细管理01-125.Docker 与 Linux Cgroups:资源隔离的魔法之旅01-166.Docker 魔法解密:探索 UnionFS 与 OverlayFS01-197.从零开始写 Docker(一)---实现 mydocker run 命令02-228.从零开始写 Docker(二)---优化:使用匿名管道传递参数02-269.从零开始写 Docker(三)---基于 cgroups 实现资源限制03-0110.从零开始写 Docker(四)---使用 pivotRoot 切换 rootfs 实现文件系统隔离03-0511.从零开始写 Docker(五)---基于 overlayfs 实现写操作隔离03-1212.从零开始写 Docker(六)---实现 mydocker run -v 支持数据卷挂载03-1413.从零开始写 Docker(七)---实现 mydocker commit 打包容器成镜像03-1914.从零开始写 Docker(八)---实现 mydocker run -d 支持后台运行容器03-2115.从零开始写 Docker(九)---实现 mydocker ps 查看运行中的容器03-2616.从零开始写 Docker(十)---实现 mydocker logs 查看容器日志04-0917.从零开始写 Docker(十一)---实现 mydocker exec 进入容器内部04-1618.从零开始写 Docker(十二)---实现 mydocker stop 停止容器04-2519.从零开始写 Docker(十三)---实现 mydocker rm 删除容器05-0920.从零开始写 Docker(十四)---重构:实现容器间 rootfs 隔离05-1021.从零开始写 Docker(十五)---实现 mydocker run -e 支持环境变量传递05-2422.从零开始写 Docker(十六)---容器网络实现(上):为容器插上”网线”05-2823.从零开始写 Docker(十七)---容器网络实现(中):为容器插上”网线“06-0524.从零开始写 Docker(十八)---容器网络实现(下):为容器插上”网线“06-1325.基于 Cloudflare Workers 和 cloudflare-docker-proxy 搭建镜像加速服务06-24
    26.Linux-Cgroup V2 初体验07-11
    27.从零开始写 Docker(十九)---增加 cgroup v2 支持07-24
    收起

    本文主要记录 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 
    #include 
    #include 
    #include 
    
    #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)

  • 相关阅读:
    LeetCode_485_最大连续1的个数
    C#进程调用FFmpeg操作音视频
    KubeSphere DevOps流水线部署
    uni-app scroll-view设置scrollTop为0返回顶部不生效
    Windows终端配置emoji
    Cookie与Session组件
    git fatal: detected dubious ownership in repository 解决方法
    服从正态分布的正弦函数、余弦函数期望
    地图与WebGIS、地图的作用、数字地图的应用
    17.Excel vba开发-根据分数判断等级
  • 原文地址:https://www.cnblogs.com/KubeExplorer/p/18296084
  • 最新文章
  • 攻防演习之三天拿下官网站群
    数据安全治理学习——前期安全规划和安全管理体系建设
    企业安全 | 企业内一次钓鱼演练准备过程
    内网渗透测试 | Kerberos协议及其部分攻击手法
    0day的产生 | 不懂代码的"代码审计"
    安装scrcpy-client模块av模块异常,环境问题解决方案
    leetcode hot100【LeetCode 279. 完全平方数】java实现
    OpenWrt下安装Mosquitto
    AnatoMask论文汇总
    【AI日记】24.11.01 LangChain、openai api和github copilot
  • 热门文章
  • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
    奉劝各位学弟学妹们,该打造你的技术影响力了!
    五年了,我在 CSDN 的两个一百万。
    Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
    面试官都震惊,你这网络基础可以啊!
    你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
    心情不好的时候,用 Python 画棵樱花树送给自己吧
    通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
    13 万字 C 语言从入门到精通保姆级教程2021 年版
    10行代码集2000张美女图,Python爬虫120例,再上征途
Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1
正则表达式工具 cron表达式工具 密码生成工具

京公网安备 11010502049817号