Linux CGroups 资源控制实战(CPU+内存)超详细教程
🔥 前言:在Linux容器化技术(如Docker、K8s)中,CGroups(Control Groups)是实现资源隔离与控制的核心内核特性,它能精准限制进程对CPU、内存、IO等系统资源的使用,避免单个进程过度占用资源导致系统崩溃。本文将基于实战视角,从基础工具安装、CGroups信息查看,到CPU、内存的精准控制,一步步拆解操作流程,每一步均附带完整命令、注释及效果说明,新手也能轻松上手,全程可直接复制执行!
📌 适用场景:Linux运维、容器学习入门、资源管控实战、面试相关实操准备
💻 环境说明:Ubuntu 20.04 LTS / CentOS 7/8(两种系统命令均提供,适配不同环境)
一、实战准备:核心工具安装
本次实战需用到两个核心工具:pidstat(资源监控工具,用于查看进程CPU、内存占用)和stress(压力测试工具,用于模拟高CPU、高内存负载),先完成工具安装,避免后续实操报错。
1. pidstat 工具(资源监控)
工具概述
pidstat 是 sysstat 工具集的一员,核心作用是监控全部或指定进程的CPU、内存、线程、设备IO等系统资源占用情况。其特点是:第一次采样显示自系统启动开始的统计信息,后续采样显示自上次运行命令后的统计信息,可通过指定采样间隔和次数,精准获取所需监控数据。
语法格式
shell
pidstat [ 选项 ] [ <时间间隔> ] [ <次数> ]
常用参数(实战高频)
-
-u:默认参数,显示各进程的CPU使用统计(重点,CPU控制实战必用); -
-r:显示各进程的内存使用统计(重点,内存控制实战必用); -
-d:显示各进程的IO使用情况(本次实战暂不用); -
-p:指定进程号,ALL表示监控所有进程; -
-C:指定命令,仅监控与该命令相关的进程(实战高频,精准过滤); -
-l:显示命令名和所有参数(辅助排查,避免混淆进程)。
安装命令(Ubuntu + CentOS)
shell
# ================== Ubuntu 系统 ==================
# 卸载旧版本(若有)
apt remove sysstat -y
# 安装新版本
apt install sysstat -y
# ================== CentOS 系统 ==================
# 卸载旧版本(若有)
yum remove sysstat -y
# 安装新版本
yum install sysstat -y
2. stress 工具(压力测试)
工具概述
stress 是Linux常用的压力测试工具,核心作用是模拟进程对CPU、内存、IO、磁盘的高负载场景,用于验证CGroups资源控制策略是否生效。本次实战将用它模拟高CPU占用、高内存占用的进程,配合pidstat监控控制效果。
语法格式
shell
stress [OPTION [ARG]]
常用参数(实战高频)
-
-c, --cpu N:产生N个进程,每个进程循环调用sqrt函数,模拟CPU高负载(CPU控制实战必用); -
-i, --io N:产生N个进程,循环调用sync函数(将内存缓冲区内容写入磁盘),模拟IO压力(本次暂不用); -
-m, --vm N:产生N个进程,每个进程循环调用malloc/free函数,模拟内存分配与释放(内存控制实战必用); -
--vm-bytes B:指定每个内存压力进程分配的内存大小(如50M、100M,内存控制实战必用); -
--vm-keep:一直占用内存,区别于默认的"不断释放并重新分配内存"(可选,增强内存压力); -
-d, --hdd N:产生N个进程,循环执行write/unlink函数(创建文件→写入内容→删除文件),模拟磁盘压力(本次暂不用); -
-t, --timeout N:指定压力测试持续时间(单位:秒),到期后自动结束程序(可选,避免进程长期占用资源); -
-q, --quiet:压力测试过程中不输出多余信息(可选,简化终端输出)。
注意:使用-i(IO压力)时,若SSD磁盘环境或内存缓冲区数据较少,可能无法产生明显IO压力,反而会导致系统CPU的sys使用率升高,属于正常现象。
安装命令(Ubuntu + CentOS)
shell
# ================== Ubuntu 系统 ==================
# 卸载旧版本(若有)
apt remove stress -y
# 安装新版本
apt install stress -y
# ================== CentOS 系统 ==================
# 卸载旧版本(若有)
yum remove stress -y
# 安装新版本
yum install stress -y
工具验证
安装完成后,执行以下命令,确认工具可正常使用(无报错即生效):
shell
# 验证pidstat(查看版本/帮助,无需复杂操作)
pidstat --help
# 验证stress(查看版本/帮助)
stress --help
二、基础认知:CGroups 核心概念
在开始实操前,先快速了解CGroups的核心基础,避免只懂操作、不懂原理:
-
CGroups 全称 Control Groups,是Linux内核提供的一种资源隔离机制,用于限制、记录、隔离进程组(process groups)所使用的系统资源(CPU、内存、IO、磁盘等);
-
CGroups 支持两种版本:v1 和 v2,目前主流Linux系统(Ubuntu 20.04+、CentOS 8+)均支持v2版本,本文实操兼容两种版本;
-
CGroups 核心组成:
子系统(subsystem)和控制组(control group)。子系统对应具体的资源类型(如cpu子系统控制CPU,memory子系统控制内存),控制组是进程组的集合,用于应用具体的资源控制策略; -
CGroups 默认挂载路径:
/sys/fs/cgroup,所有子系统的配置文件、控制组目录均在此路径下,实操核心就是操作该路径下的文件。
三、实操一:CGroups 信息查看(必做,了解系统环境)
在进行资源控制前,先查看系统的CGroups版本、子系统、挂载信息,确认系统支持情况,为后续实操铺垫。全程使用root用户执行(切换root:su -,输入root密码即可)。
1. 查看CGroups版本
通过查看系统文件系统,判断是否支持CGroups v2版本(核心看是否有cgroup2):
shell
root@localhost:~# cat /proc/filesystems | grep cgroup
执行效果说明
正常输出如下(不同系统略有差异,核心看cgroup2):
shell
nodev
nodev cgroup
nodev cgroup2
nodev
若输出中包含cgroup2,表示系统支持CGroups v2;若仅包含cgroup,表示仅支持v1,两种版本实操流程一致,无需额外调整。
2. 查看CGroups子系统
子系统对应具体的可控制资源,查看系统支持的所有CGroups子系统,重点关注cpu(CPU控制)和memory(内存控制):
shell
root@localhost:~# cat /proc/cgroups
执行效果说明
输出为表格形式,各列含义如下:
-
subsys_name:子系统名称(核心关注cpu、memory); -
hierarchy:子系统对应的层级ID; -
num_cgroups:该子系统下的控制组数量; -
enabled:是否启用(1=启用,0=未启用)。
正常输出示例(重点关注cpu和memory的enabled为1,即已启用):
shell
#subsys_name hierarchy num_cgroups enabled
cpuset 8 2 1
cpu 2 100 1
cpuacct 2 100 1
blkio 6 98 1
memory 10 124 1
devices 12 98 1
freezer 7 2 1
net_cls 4 2 1
perf_event 3 2 1
net_prio 4 2 1
hugetlb 9 2 1
pids 5 107 1
rdma 11 2 1
3. 查看CGroups挂载信息
查看CGroups在系统中的挂载路径、挂载类型,确认默认挂载位置(核心是/sys/fs/cgroup):
shell
root@localhost:~# mount | grep cgroup
执行效果说明
正常输出会包含多个挂载记录,核心信息如下:
-
默认挂载路径:
/sys/fs/cgroup,挂载类型为tmpfs; -
cgroup2 挂载路径:
/sys/fs/cgroup/unified(v2版本特有); -
各子系统挂载路径:如cpu子系统挂载到
/sys/fs/cgroup/cpu,cpuacct,memory子系统挂载到/sys/fs/cgroup/memory(后续实操的核心路径)。
输出示例(简化版):
shell
tmpfs on /sys/fs/cgroup type tmpfs (ro,nosuid,nodev,noexec,mode=755)
cgroup2 on /sys/fs/cgroup/unified type cgroup2 (rw,nosuid,nodev,noexec,relatime,nsdelegate)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
4. 查看单个进程的CGroups限制
以当前shell进程为例,查看该进程所属的所有CGroups控制组,了解进程默认的资源限制情况:
shell
# 查看当前shell进程的CGroups信息($$ 表示当前shell进程的PID)
root@localhost:~# cat /proc/$$/cgroup
执行效果说明
输出每一行对应一个子系统,格式为「子系统ID:子系统名称:控制组路径」,示例如下:
shell
11:hugetlb:/
10:memory:/user.slice
9:freezer:/
8:cpuset:/
7:perf_event:/
6:net_prio,net_cls:/
5:devices:/user.slice/user-0.slice
4:pids:/user.slice
3:cpuacct,cpu:/user.slice
2:blkio:/user.slice
1:name=systemd:/user.slice/user-0.slice/session-354304.scope
重点关注:cpu子系统对应的控制组路径为/user.slice,memory子系统对应的控制组路径也为/user.slice,表示当前shell进程默认受/user.slice控制组的资源限制。
可进一步查看该控制组的详细限制配置(以cpu为例):
shell
root@localhost:~# ll /sys/fs/cgroup/cpu/user.slice/
输出会包含该控制组的所有CPU配置文件(如cpu.cfs_period_us、cpu.cfs_quota_us),后续实操会详细讲解这些文件的作用。
四、实操二:使用CGroups 对内存进行控制(核心实操)
本次实操目标:创建一个内存控制组,限制该组内的进程最大只能使用20M内存,通过stress模拟高内存进程,验证控制策略是否生效(进程超过内存限制后会被系统终止)。
📌 实操逻辑:创建内存控制组 → 配置内存限制策略 → 启动高内存压力进程 → 将进程加入控制组 → 监控进程状态(验证控制效果)。
步骤1:创建内存控制组
CGroups的控制组本质是/sys/fs/cgroup/对应子系统下的目录,创建目录即可自动生成该控制组的所有配置文件(系统自动创建,无需手动新建)。
shell
# 1. 进入内存子系统的挂载目录(核心路径)
cd /sys/fs/cgroup/memory
# 2. 创建内存控制组目录(控制组名称:test_memory,可自定义)
mkdir test_memory
# 3. 查看控制组目录下的配置文件(系统自动生成)
ll test_memory/
执行效果说明
-
执行
mkdir test_memory后,无报错即表示控制组创建成功; -
执行
ll test_memory/后,会看到大量配置文件,这些文件对应内存控制的各项策略,核心配置文件如下:
-
memory.limit_in_bytes:内存最大使用限制(核心配置文件,本次实操重点); -
memory.usage_in_bytes:当前控制组内进程的内存实际使用量(只读,用于查看); -
memory.max_usage_in_bytes:当前控制组内进程的内存最大使用峰值(只读); -
tasks:该控制组内的进程ID列表(将进程PID写入该文件,即可让进程受该控制组限制); -
cgroup.procs:该控制组内的进程组ID列表(本次暂不用)。
配置文件输出示例(简化版):
shell
total 0
-rw-r--r-- 1 root root 0 Mar 12 14:14 cgroup.clone_children
--w--w--w- 1 root root 0 Mar 12 14:14 cgroup.event_control
-rw-r--r-- 1 root root 0 Mar 12 14:14 cgroup.procs
-rw-r--r-- 1 root root 0 Mar 12 14:14 memory.failcnt
--w------- 1 root root 0 Mar 12 14:14 memory.force_empty
-rw-r--r-- 1 root root 0 Mar 12 14:14 memory.limit_in_bytes
-rw-r--r-- 1 root root 0 Mar 12 14:14 memory.max_usage_in_bytes
-r--r--r-- 1 root root 0 Mar 12 14:14 memory.usage_in_bytes
-rw-r--r-- 1 root root 0 Mar 12 14:14 tasks
步骤2:配置内存限制策略
本次目标是限制进程最大使用20M内存,需将内存大小(单位:字节)写入memory.limit_in_bytes文件中。
计算逻辑:20M = 20 × 1024 × 1024 = 20971520 字节(可通过命令自动计算,避免手动算错)。
shell
# 1. 计算20M对应的字节数(可选,手动输入20971520也可)
expr 20 \* 1024 \* 1024
# 2. 查看当前内存限制(默认无限制,值为9223372036854771712)
cat test_memory/memory.limit_in_bytes
# 3. 配置内存限制为20M(写入字节数)
echo "20971520" > test_memory/memory.limit_in_bytes
# 4. 验证配置是否生效(查看配置文件,确认值为20971520)
cat test_memory/memory.limit_in_bytes
执行效果说明
-
执行
expr 20 \* 1024 \* 1024后,输出20971520,确认计算正确; -
配置前,
memory.limit_in_bytes的值为9223372036854771712(表示无内存限制); -
配置后,再次查看该文件,输出
20971520,表示内存限制策略配置生效(最大只能使用20M内存)。
步骤3:启动高内存压力进程
使用stress工具启动一个内存压力进程,模拟进程占用50M内存(超过我们配置的20M限制),用于验证控制效果。
shell
# 启动1个内存压力进程,每个进程占用50M内存(--vm-bytes 50M)
stress -m 1 --vm-bytes 50M
执行效果说明
命令执行后,终端会输出如下信息,表示压力进程启动成功(进程正在占用50M内存):
shell
stress: info: [62106] dispatching hogs: 0 cpu, 0 io, 1 vm, 0 hdd
⚠️ 注意:此时不要关闭该终端窗口(该窗口为窗口A,用于运行压力进程),打开一个新的终端窗口(窗口B),用于后续监控。
步骤4:查看压力进程的PID
在窗口B(新终端)中,使用pidstat命令查看stress压力进程的PID(后续需将该PID加入控制组):
shell
# 监控所有stress相关进程的内存使用情况,采样间隔1秒,持续采样(直到手动终止)
pidstat -r -C stress -p ALL 1
执行效果说明
输出会持续刷新,重点关注PID列(进程ID)和RSS列(实际占用内存),示例如下:
shell
Linux 5.4.0-100-generic (139-159-150-152) 03/12/2023 _x86_64_ (1 CPU)
02:47:02 PM UID PID minflt/s majflt/s VSZ RSS %MEM Command
02:47:02 PM 0 62517 0.00 0.00 3856 988 0.05 stress
02:47:02 PM 0 62518 476597.03 0.00 55060 15156 0.75 stress
重点记录:内存占用较高的进程PID(本例中为62518),该进程就是我们启动的高内存压力进程,后续将其加入控制组。
步骤5:将压力进程加入内存控制组
打开一个新的终端窗口(窗口C),将步骤4记录的PID写入控制组的tasks文件,让该进程受内存限制策略管控:
shell
# 1. 进入内存控制组目录(确保路径正确)
cd /sys/fs/cgroup/memory
# 2. 将压力进程PID(62518)写入tasks文件(替换为自己的PID)
echo 62518 >> test_memory/tasks
# 3. 验证进程是否已加入控制组(查看tasks文件,确认PID存在)
cat test_memory/tasks
执行效果说明
-
执行
echo 62518 >> test_memory/tasks后,无报错即表示进程已成功加入控制组; -
执行
cat test_memory/tasks后,输出62518,确认进程已在控制组内。
步骤6:验证内存控制效果(核心验证)
此时,压力进程的内存占用超过了控制组配置的20M限制,系统会自动终止该进程,我们通过三个窗口观察效果:
-
窗口A(压力进程窗口):会输出报错信息,表示进程被终止(无法申请到足够内存),示例如下:
stress: FAIL: [62517] (415) <-- worker 62518 got signal 9 stress: WARN: [62517] (417) now reaping child worker processes stress: FAIL: [62517] (451) failed run completed in 176s说明:signal 9 表示进程被系统强制终止,原因是内存占用超过限制。 -
窗口B(pidstat监控窗口):会发现PID为62518的进程消失,不再输出该进程的内存占用信息,说明进程已被终止;
-
窗口C(控制组窗口):查看控制组的内存使用情况,确认进程终止后内存释放:
# 查看控制组内进程的内存实际使用量(已释放,值会大幅降低) cat test_memory/memory.usage_in_bytes
步骤7:清理环境(可选,避免占用资源)
实操完成后,可删除创建的内存控制组,清理残留资源:
shell
# 进入内存子系统目录
cd /sys/fs/cgroup/memory
# 删除内存控制组目录(需确保控制组内无进程,否则无法删除)
rm -rf test_memory
内存控制实战总结(重点记)
-
核心路径:
/sys/fs/cgroup/memory(内存子系统挂载目录); -
核心配置文件:
memory.limit_in_bytes(内存最大限制,单位:字节); -
核心操作:创建控制组目录 → 配置内存限制 → 将进程PID写入tasks文件;
-
控制效果:进程内存占用超过限制后,会被系统强制终止(signal 9);
-
避坑点:配置内存限制时,单位必须是字节,避免手动计算错误(可通过expr命令自动计算)。
五、实操三:使用CGroups 对CPU进行控制(核心实操)
本次实操目标:创建一个CPU控制组,限制该组内的进程CPU使用率最大为30%,通过stress模拟CPU满负载进程,验证控制策略是否生效(进程CPU使用率从100%降至30%)。
📌 实操逻辑:创建CPU控制组 → 配置CPU限制策略 → 启动CPU满负载进程 → 将进程加入控制组 → 监控进程CPU使用率(验证控制效果)。
CPU控制核心原理:CGroups通过cpu.cfs_period_us和cpu.cfs_quota_us两个配置文件控制CPU使用率,计算公式为:CPU使用率 = cfs_quota_us / cfs_period_us × 100%。
先理解两个核心配置文件
CPU控制的核心是两个配置文件(位于CPU控制组目录下),必须先理解其含义,否则无法正确配置:
-
cpu.cfs_period_us:CPU带宽周期,单位为微秒(μs),默认值为100000(即100毫秒),表示系统每100毫秒为该控制组分配一次CPU带宽; -
cpu.cfs_quota_us:该控制组可使用的CPU带宽,单位为微秒(μs),默认值为-1(表示无限制)。取值范围:最小值1000(1毫秒),最大值100000(100毫秒)。
示例计算:本次目标是限制CPU使用率为30%,则:
cfs_quota_us = 30% × cfs_period_us = 0.3 × 100000 = 30000(微秒),因此将cfs_quota_us配置为30000即可。
步骤1:创建CPU控制组
与内存控制组类似,CPU控制组也是/sys/fs/cgroup/cpu目录下的一个子目录,创建目录即可自动生成所有配置文件。
shell
# 1. 进入CPU子系统的挂载目录(核心路径)
cd /sys/fs/cgroup/cpu
# 2. 创建CPU控制组目录(控制组名称:test_cpu,可自定义)
mkdir test_cpu
# 3. 查看控制组目录下的配置文件(系统自动生成)
ll test_cpu/
执行效果说明
-
执行
mkdir test_cpu后,无报错即表示CPU控制组创建成功; -
执行
ll test_cpu/后,核心配置文件如下(重点关注两个cfs文件):
-
cpu.cfs_period_us:CPU带宽周期(默认100000微秒); -
cpu.cfs_quota_us:CPU带宽配额(默认-1,无限制); -
tasks:控制组内的进程PID列表(将进程写入该文件,即可受控制); -
cpuacct.usage:控制组内进程的CPU总使用时间(只读,用于查看)。
步骤2:启动CPU满负载压力进程
打开一个新的终端窗口(窗口A),使用stress工具启动一个CPU满负载进程(占用1个CPU核心,使用率100%):
shell
# 启动1个CPU压力进程,模拟CPU满负载(-c 1 表示1个进程)
stress -c 1
执行效果说明
命令执行后,终端输出如下信息,表示CPU压力进程启动成功:
shell
stress: info: [62576] dispatching hogs: 1 cpu, 0 io, 0 vm, 0 hdd
⚠️ 注意:不要关闭该窗口,打开新的终端窗口(窗口B),用于监控CPU使用率。
步骤3:监控CPU压力进程的使用率和PID
在窗口B中,使用pidstat命令监控stress进程的CPU使用率,确认进程当前CPU使用率为100%,并记录进程PID:
shell
# 监控所有stress相关进程的CPU使用情况,采样间隔1秒,持续采样
pidstat -u -C stress -p ALL 1
执行效果说明
输出持续刷新,重点关注PID列(进程ID)和%CPU列(CPU使用率),示例如下:
shell
Linux 5.4.0-100-generic (139-159-150-152) 03/12/2023 _x86_64_ (1 CPU)
02:59:39 PM UID PID %usr %system %guest %wait %CPU CPU Command
02:59:39 PM 0 62576 0.00 0.00 0.00 0.00 0.00 0 stress
02:59:39 PM 0 62577 99.01 0.00 0.00 0.99 99.01 0 stress
重点记录:
-
CPU使用率:
%CPU列值为99.01%(接近100%,符合预期); -
进程PID:CPU占用较高的进程PID(本例中为
62577),后续将其加入控制组。
步骤4:配置CPU限制策略(限制使用率30%)
打开一个新的终端窗口(窗口C),进入CPU控制组目录,配置cpu.cfs_quota_us的值为30000(对应30%使用率):
shell
# 1. 进入CPU控制组目录
cd /sys/fs/cgroup/cpu/test_cpu
# 2. 查看当前CPU带宽配额(默认-1,无限制)
cat cpu.cfs_quota_us
# 3. 配置CPU带宽配额为30000微秒(对应30%使用率)
echo 30000 > cpu.cfs_quota_us
# 4. 验证配置是否生效(查看配置文件,确认值为30000)
cat cpu.cfs_quota_us
# 5. 查看CPU带宽周期(默认100000微秒,无需修改)
cat cpu.cfs_period_us
执行效果说明
-
配置前,
cpu.cfs_quota_us的值为-1(无限制); -
配置后,再次查看该文件,输出
30000,表示CPU限制策略配置生效; -
cpu.cfs_period_us的值为100000(默认值,无需修改),验证计算公式:30000 / 100000 = 0.3 → 30%使用率。
步骤5:将CPU压力进程加入控制组
在窗口C中,将步骤3记录的CPU压力进程PID(62577)写入控制组的tasks文件,让该进程受CPU限制策略管控:
shell
# 1. 将进程PID(62577)写入tasks文件(替换为自己的PID)
echo 62577 > tasks
# 2. 验证进程是否已加入控制组(查看tasks文件,确认PID存在)
cat tasks
步骤6:验证CPU控制效果(核心验证)
此时,回到窗口B(pidstat监控窗口),观察进程的CPU使用率变化,核心验证效果:进程CPU使用率从100%降至30%左右。
执行效果说明
监控窗口输出示例(简化版):
shell
03:12:51 PM UID PID %usr %system %guest %wait %CPU CPU Command
03:12:51 PM 0 62577 30.00 0.00 0.00 70.00 30.00 0 stress
03:12:52 PM 0 62577 29.80 0.20 0.00 70.00 30.00 0 stress
03:12:53 PM 0 62577 30.20 0.00 0.00 69.80 30.20 0 stress
可以看到,进程的CPU使用率稳定在30%左右,与我们配置的限制策略一致,说明CPU控制生效。
步骤7:清理环境(可选,避免占用资源)
实操完成后,停止压力进程,删除创建的CPU控制组,清理残留资源:
shell
# 1. 停止stress压力进程(窗口A中按Ctrl+C,或在任意窗口执行kill命令)
kill -9 62577(替换为自己的PID)
# 2. 进入CPU子系统目录
cd /sys/fs/cgroup/cpu
# 3. 删除CPU控制组目录
rm -rf test_cpu
CPU控制实战总结(重点记)
-
核心路径:
/sys/fs/cgroup/cpu(CPU子系统挂载目录); -
核心配置文件:
cpu.cfs_period_us(周期,默认100000微秒)、cpu.cfs_quota_us(配额,配置30000对应30%使用率); -
核心公式:CPU使用率 = cfs_quota_us / cfs_period_us × 100%;
-
核心操作:创建控制组目录 → 配置配额文件 → 将进程PID写入tasks文件;
-
控制效果:进程CPU使用率被限制在配置值以内(稳定在30%左右);
-
避坑点:配置文件单位是微秒(μs),不要误写为毫秒或秒,否则控制效果异常。
六、实战总结与拓展思考
1. 核心总结
-
CGroups 是Linux内核的资源控制机制,核心作用是限制、隔离进程组的系统资源,是Docker、K8s等容器技术的底层核心;
-
本次实战重点:CPU控制(限制使用率)和内存控制(限制最大占用),两者实操流程相似,核心都是「创建控制组 → 配置策略 → 加入进程 → 验证效果」;
-
关键认知:CGroups的控制组本质是
/sys/fs/cgroup/子系统下的目录,配置文件是该目录下的系统文件,操作这些文件即可实现资源控制。
2. 拓展思考(对接容器技术)
我们手动配置CGroups的过程较为繁琐(需创建目录、写入配置、加入进程),而Docker本质上就是对CGroups的封装,简化了资源控制操作。
例如,使用Docker启动容器时,只需通过参数即可实现CPU、内存限制,无需手动操作CGroups文件:
shell
# Docker限制容器CPU使用率30%、内存20M
docker run -it --cpus 0.3 --memory 20M centos:7 /bin/bash
该命令底层就是创建了CPU、内存控制组,配置了对应的策略,将容器进程加入控制组,与我们本次手动实操的逻辑完全一致------掌握CGroups,就能理解Docker资源控制的底层原理。
3. 常见问题与避坑指南
-
问题1:执行命令时报「Permission denied」(权限不足)?
解决方案:切换到root用户执行(
su -),或在命令前加sudo(需配置sudo权限)。 -
问题2:配置内存限制后,进程未被终止?
解决方案:检查内存限制值是否正确(单位是否为字节),检查进程是否已加入控制组(查看tasks文件)。
-
问题3:配置CPU限制后,使用率未降至目标值?
解决方案:检查cfs_quota_us和cfs_period_us的值是否正确,计算是否有误,进程是否已加入控制组。
-
问题4:删除控制组时,报错「Device or resource busy」?
解决方案:先终止控制组内的所有进程(kill PID),再删除控制组目录。
4. 后续学习方向
本次实战仅覆盖了CGroups的CPU和内存控制,后续可深入学习:
-
CGroups 其他子系统:IO控制(blkio子系统)、磁盘控制(hdd子系统)、进程数控制(pids子系统);
-
CGroups v2 版本特性:与v1的差异、新的配置方式;
-
Docker 资源控制:结合本次实操,理解Docker参数与CGroups配置的对应关系,实操Docker的CPU、内存、IO限制。
📝 结尾:本文实操全程基于真实Linux环境,所有命令均可直接复制执行,新手建议一步步跟着操作,重点理解"控制组"和"配置文件"的核心逻辑,避免只记命令、不懂原理。如果操作过程中遇到问题,欢迎在评论区留言交流~