前面我们简单说了下namespace, 现在我们来接着简单说说cgroup。通过docker-简单说说namespace文章我们知道: namespace 是为了隔离进程组之间的资源,那cgroup就是为了对进程组的监控和限制资源。Cgroup 可以限制进程组使用的资源数量和分配(包括CPU、内存、网络带宽、磁盘I/O等),并将它们隔离到一个或多个分层的分组中,以实现对进程、任务或用户组的资源限制。这使得 Cgroup 成为用于容器隔离的关键技术,并可以帮助保护系统免受不安全或恶意代码的破坏
cgroup(control groups)是Linux下的一种将进程按组进行管理的机制,在用户层看来,cgroup技术就是把系统中的所有进程组织成一颗一颗独立的树,每棵树都包含系统的所有进程,树的每个节点是一个进程组,而每颗树又和一个或者多个subsystem关联,树的作用是将进程分组,而subsystem的作用就是对这些组进行操作。
它主要提供了如下功能:
1- subsystem
cgroup中的subsystem就是一个资源调度控制器(Resource Controller)。subsystem被关联到一颗cgroup 树上,就会在树上节点做具体操作(用来调度或者限制进程的资源)。比如CPU子系统可以控制CPU时间分配,内存子系统可以限制cgroup内存使用量
2- hierarchy
hierarchy由一系列cgroup以一个树状结构排列而成,树的每个节点就是一个进程组,每个hierarchy通过绑定对应的subsystem进行资源调度。hierarchy中的cgroup节点可以包含零或多个子节点,子节点继承父节点的属性。
3- task
在Cgroup中,task就是系统的一个进程
本文使用环境centos3.10.0 , cgroup v1
[root@linjian ~]# cat /proc/cgroups
#subsys_name hierarchy num_cgroups enabled
cpuset 6 9 1
cpu 5 81 1
cpuacct 5 81 1
memory 8 79 1
devices 11 78 1
freezer 10 9 1
net_cls 3 9 1
blkio 2 78 1
perf_event 7 9 1
hugetlb 4 9 1
pids 9 78 1
net_prio 3 9 1
subsys_name: subsystem的名字
hierarchy: subsystem关联的cgroup树的id,如果多个subsystem关联到同一颗cgroup树,那么他们的hierarchy数据一样。
当以下情况,hierarchy 字段将为0:
num_cgroups:subsystem关联cgroup树中进程组的个数(树上节点的个数)。
enabled:1:开启,0:关闭
[root@linjian ~]# uname -r
3.10.0-1160.24.1.el7.x86_64
[root@linjian ~]# cat /boot/config-3.10.0-1160.24.1.el7.x86_64 | grep CGROUP
CONFIG_CGROUPS=y # y 已经开启了
# CONFIG_CGROUP_DEBUG is not set
CONFIG_CGROUP_FREEZER=y
CONFIG_CGROUP_PIDS=y
CONFIG_CGROUP_DEVICE=y
CONFIG_CGROUP_CPUACCT=y
CONFIG_CGROUP_HUGETLB=y
CONFIG_CGROUP_PERF=y
CONFIG_CGROUP_SCHED=y
CONFIG_BLK_CGROUP=y
# CONFIG_DEBUG_BLK_CGROUP is not set
CONFIG_NETFILTER_XT_MATCH_CGROUP=m
CONFIG_NET_CLS_CGROUP=y
CONFIG_NETPRIO_CGROUP=y
stat -fc %T /sys/fs/cgroup/ 如果v2,输出为 cgroup2fs ;v1 输出 tmpfs
[root@linjian ~]# stat -fc %T /sys/fs/cgroup/
tmpfs
[root@linjian ~]# cat /proc/$$/cgroup
11:devices:/user.slice
10:freezer:/
9:pids:/user.slice
8:memory:/user.slice
7:perf_event:/
6:cpuset:/
5:cpuacct,cpu:/user.slice
4:hugetlb:/
3:net_prio,net_cls:/
2:blkio:/user.slice
1:name=systemd:/user.slice/user-0.slice/session-1422.scope
冒号隔开
第一个:cgroup树的ID与/proc/cgroups文件中的ID一一对应。
第二个:和cgroup树绑定的所有subsystem(多个subsystem用逗号隔开)。如果name=systemd,表示没有和任何subsystem绑定。
第三个:进程在cgroup树中的路径(挂载点的相对路径),即进程所属的cgroup。
[root@linjian ~]# ls -lh /sys/fs/cgroup
total 0
drwxr-xr-x 5 root root 0 Dec 26 23:00 blkio
lrwxrwxrwx 1 root root 11 Dec 26 23:00 cpu -> cpu,cpuacct
lrwxrwxrwx 1 root root 11 Dec 26 23:00 cpuacct -> cpu,cpuacct
drwxr-xr-x 8 root root 0 Jan 2 10:01 cpu,cpuacct
drwxr-xr-x 3 root root 0 Dec 26 23:00 cpuset
drwxr-xr-x 5 root root 0 Dec 26 15:02 devices
drwxr-xr-x 3 root root 0 Dec 26 23:00 freezer
drwxr-xr-x 3 root root 0 Dec 26 23:00 hugetlb
drwxr-xr-x 6 root root 0 Jan 2 10:01 memory
lrwxrwxrwx 1 root root 16 Dec 26 23:00 net_cls -> net_cls,net_prio
drwxr-xr-x 3 root root 0 Dec 26 23:00 net_cls,net_prio
lrwxrwxrwx 1 root root 16 Dec 26 23:00 net_prio -> net_cls,net_prio
drwxr-xr-x 3 root root 0 Dec 26 23:00 perf_event
drwxr-xr-x 5 root root 0 Dec 26 23:00 pids
drwxr-xr-x 5 root root 0 Dec 26 23:00 systemd
挂载cgroup
[root@linjian home]# mkdir cgroupTest
[root@linjian home]# cd cgroupTest/
[root@linjian cgroupTest]# ls
[root@linjian cgroupTest]# mkdir demo01
# 创建一颗新的cgroup树,然后挂载到demo01目录
[root@linjian cgroupTest]# mount -t cgroup -o none,name=demo01 demo01 ./demo01
[root@linjian cgroupTest]# cd demo01/
[root@linjian demo01]# ls -lha
total 4.0K
drwxr-xr-x 2 root root 0 Jan 3 20:47 .
drwxr-xr-x 3 root root 4.0K Jan 3 20:44 ..
-rw-r--r-- 1 root root 0 Jan 3 20:47 cgroup.clone_children
--w--w--w- 1 root root 0 Jan 3 20:47 cgroup.event_control
-rw-r--r-- 1 root root 0 Jan 3 20:47 cgroup.procs
-r--r--r-- 1 root root 0 Jan 3 20:47 cgroup.sane_behavior
-rw-r--r-- 1 root root 0 Jan 3 20:47 notify_on_release
-rw-r--r-- 1 root root 0 Jan 3 20:47 release_agent
-rw-r--r-- 1 root root 0 Jan 3 20:47 tasks
[root@linjian demo01]# wc -l cgroup.procs
131 cgroup.procs
创建/删除cgroup
[root@linjian demo01]# mkdir cgroupT01 // 创建子cgroup
[root@linjian demo01]# cd cgroupT01/
[root@linjian cgroupT01]# ls
cgroup.clone_children cgroup.event_control cgroup.procs notify_on_release tasks
[root@linjian cgroupT01]# wc -l cgroup.procs
0 cgroup.procs
[root@linjian cgroupT01]# cd ..
[root@linjian demo01]# rmdir cgroupT01 // 删除
[root@linjian demo01]# ls
cgroup.clone_children cgroup.event_control cgroup.procs cgroup.sane_behavior notify_on_release release_agent tasks
客户端1
[root@linjian ~]# mount|grep pids
cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
[root@linjian ~]# cd /sys/fs/cgroup/pids/
[root@linjian pids]# mkdir limitTest
[root@linjian pids]# cd limitTest/
[root@linjian limitTest]# ls
cgroup.clone_children cgroup.event_control cgroup.procs notify_on_release pids.current pids.max tasks
[root@linjian limitTest]# cat pids.max
max
[root@linjian limitTest]# cat pids.current
0
[root@linjian limitTest]# echo 1 > pids.max
[root@linjian limitTest]# echo $$ > cgroup.procs
pids.current: 表示当前cgroup及其所有子孙cgroup中现有的总的进程数量
pids.max: 当前cgroup及其所有子孙cgroup中所允许创建的总的最大进程数量
客户端2
[root@linjian ~]# cd /sys/fs/cgroup/pids/
[root@linjian pids]# mkdir limitTest
[root@linjian pids]# cd limitTest/
[root@linjian limitTest]# ls
cgroup.clone_children cgroup.event_control cgroup.procs notify_on_release pids.current pids.max tasks
[root@linjian limitTest]# cat pids.max
max
[root@linjian limitTest]# cat pids.current
0
客户端1
# 创建新进程失败
[root@linjian limitTest]# ls
-bash: fork: retry: No child processes
-bash: fork: retry: No child processes
-bash: fork: retry: No child processes
[root@linjian ~]# mount|grep memory
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
[root@linjian ~]# cd /sys/fs/cgroup/memory
# 创建子group
[root@linjian memory]# mkdir limitTest
[root@linjian memory]# cd limitTest/
[root@linjian limitTest]# ls
cgroup.clone_children memory.kmem.limit_in_bytes memory.kmem.tcp.usage_in_bytes memory.memsw.max_usage_in_bytes memory.soft_limit_in_bytes tasks
cgroup.event_control memory.kmem.max_usage_in_bytes memory.kmem.usage_in_bytes memory.memsw.usage_in_bytes memory.stat
cgroup.procs memory.kmem.slabinfo memory.limit_in_bytes memory.move_charge_at_immigrate memory.swappiness
memory.failcnt memory.kmem.tcp.failcnt memory.max_usage_in_bytes memory.numa_stat memory.usage_in_bytes
memory.force_empty memory.kmem.tcp.limit_in_bytes memory.memsw.failcnt memory.oom_control memory.use_hierarchy
memory.kmem.failcnt memory.kmem.tcp.max_usage_in_bytes memory.memsw.limit_in_bytes memory.pressure_level notify_on_release
[root@linjian limitTest]#
# 查看使用的情况
[root@linjian limitTest]# cat memory.usage_in_bytes
0
# 查看限定额度
[root@linjian limitTest]# cat memory.limit_in_bytes
9223372036854771712
# 限定64k
[root@linjian limitTest]# echo 64k > memory.limit_in_bytes
[root@linjian memory]# mount|grep cpu
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpuacct,cpu)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
[root@linjian memory]# cd /sys/fs/cgroup/cpu,cpuacct
[root@linjian cpu,cpuacct]# mkdir limitTest
[root@linjian cpu,cpuacct]# cd limitTest/
[root@linjian limitTest]# ls
cgroup.clone_children cgroup.procs cpuacct.usage cpu.cfs_period_us cpu.rt_period_us cpu.shares notify_on_release
cgroup.event_control cpuacct.stat cpuacct.usage_percpu cpu.cfs_quota_us cpu.rt_runtime_us cpu.stat tasks
[root@linjian limitTest]# cat cpu.cfs_quota_us
-1
# 设置只能使用1个cpu的20%的时间
[root@linjian limitTest]# echo 20000 > cpu.cfs_quota_us
[root@linjian limitTest]# cat cpu.cfs_quota_us
20000
[root@linjian limitTest]# echo $$
12649
[root@linjian limitTest]# echo 12649 > cgroup.procs
[root@linjian limitTest]# while :; do echo limitTest > /dev/null; done
客户端2
# 可以看到已经占满了
[root@linjian ~]# top
top - 21:43:19 up 8 days, 6:42, 8 users, load average: 0.01, 0.02, 0.05
Tasks: 135 total, 2 running, 133 sleeping, 0 stopped, 0 zombie
%Cpu(s): 8.0 us, 4.7 sy, 0.0 ni, 86.8 id, 0.0 wa, 0.0 hi, 0.5 si, 0.0 st
KiB Mem : 3880104 total, 112104 free, 1317032 used, 2450968 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 2281320 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
12649 root 20 0 115648 2196 1716 R 20.3 0.1 0:07.64 bash
[root@linjian ~]# cat /sys/fs/cgroup/cpu,cpuacct/limitTest/cpu.stat
nr_periods 462 #表示过去了多少个cpu.cfs_period_us里面配置的时间周期
nr_throttled 460 # 在上面的这些周期中,有多少次是受到了限制
throttled_time 36266699145 # cgroup中的进程被限制使用CPU持续了多长时间(纳秒)
namespace:为了隔离进程组之间的资源
cgroup:为了对一组进程进行的资源监控和限制。