该文档已作废。新文档见 cgroups: 入门指引、基本概念和 cgroup v1 基础使用
主要来自Linux手册:man 7 cgroups(centos7 上没有该页)cgroups - Linux control groups。
cgroup 的管理操作接口以文件目录的方式呈现,目录中可以创建子目录,目录中的文件是 cgroup 控制器的文件接口,通过修改文件内容来调整资源限制。使用 mount -t cgroup /xxx
命令创建 cgroup 操作目录。
cgroup 支持的每类资源通过对应的 subsystem
或者 resource controllers
管理,例如管理 cpu 的是 cpu controller,管理内存的是 memory controller。
从 linux kernel 4.14 开始,cgroup v2 引入了 thread mode(线程模式),controller 被分为 domain controller
和 threaded controller
。cgroup 目录分成了两大类,用于管理进程/process 资源的目录是 domain cgroup
,称为“进程目录”,用于管理线程/task 的目录是 threaded cgroup
,称为“线程目录”。
一句话介绍 cgroup:把一个 cgroup 目录中的资源划分给它的子目录,子目录可以把资源继续划分给它的子目录,为子目录分配的资源之和不能超过父目录,进程或者线程可以使用的资源受到它们委身的目录中的资源的限制。
cgroup 有 v1 和 v2 两个版本,使用上差异比较大。
v1 版本是最早的实现,当时 resource controllers 的开发各自为政,导致 controller 间存在不一致,并且 controller 的嵌套挂载使 cgroup 的管理非常复杂。
Linux kernel 3.10 开始提供 cgroup v2(Linux Control Group v2),需要通过挂载时的参数 -o __DEVEL__sane_behavior
启用。Linuxe Kernel 4.5.0
开始,cgroup v2 成为正式特性。
cgroup v1 和 cgroup v2 可以同时使用,但一个 controller 不能既在 cgroup v1 中使用又在 cgroup v2 中使用。 cgroup v2 支持的 controller 是 cgroup v1 的子集,cgroup v2 本来希望完全取代 cgroup v1,但是为了兼容,cgroup v1 没有被移除。
cgroup v1 中,controller 可以独立挂载到一个目录中,也可以和其它 controller 联合挂载到同一个目录。
在 cgroup v1 中,task 也就是线程可以被划分到不同的 cgroup 组中。在一些场景中,这样做是有问题的。例如在 memory controller 中,所有 task 使用的都是同样的内存地址空间,为它们设置不同 memory cgroup 是没有意义的。
00-INDEX
- this file
blkio-controller.txt
- Description for Block IO Controller, implementation and usage details.
cgroups.txt
- Control Groups definition, implementation details, examples and API.
cpuacct.txt
- CPU Accounting Controller; account CPU usage for groups of tasks.
cpusets.txt
- documents the cpusets feature; assign CPUs and Mem to a set of tasks.
admin-guide/devices.rst
- Device Whitelist Controller; description, interface and security.
freezer-subsystem.txt
- checkpointing; rationale to not use signals, interface.
hugetlb.txt
- HugeTLB Controller implementation and usage details.
memcg_test.txt
- Memory Resource Controller; implementation details.
memory.txt
- Memory Resource Controller; design, accounting, interface, testing.
net_cls.txt
- Network classifier cgroups details and usages.
net_prio.txt
- Network priority cgroups details and usages.
pids.txt
- Process number cgroups details and usages.
内核文档 cgroup-v1/00-INDEX 似乎是仅有的介绍 cgroup 挂载参数的资料,各个 controller 的用法也在该文档目录中。
controller 以 tmpfs
文件系统的方式挂载到任意目录,挂载命令中用 -t cgroup
指定要挂载的是 cgroup,-o
指定要挂载哪些 controller,多个 controller 用“,”间隔。
linux 系统通常已经将 controller 挂载在 /sys/fs/cgroup,下面用一个新的目录演示 cgroup 挂载操作。
-o memory
单独挂载 memory controller:
mkdir /tmp/cgroup/memory
mount -t cgroup -o memory none /tmp/cgroup/memory/
-o cpu,cpuacct
同时挂载 cpu 和 cpuacct:
mkdir -p /tmp/cgroup/cpu,cpuacct
mount -t cgroup -o cpu,cpuacct none /tmp/cgroup/cpu,cpuacct
-o all
挂载所有的 controller:
mkdir -p /tmp/cgroup/all
mount -t cgroup -o all cgroup /tmp/cgroup/all
-o none
不挂载任何 controller(没有挂载 controller 的 cgroup 可以用来跟踪进程,例如在进程消失导致 cgroup 为空时,cgroup 的通知回调会被触发):
mkdir -p /tmp/cgroup/none
mount -t cgroup -o none,name=somename none /tmp/cgroup/none
在挂载目录中能看到 controller 的文件接口:
$ ls -F /tmp/cgroup/cpu,cpuacct/
cgroup.clone_children cpuacct.stat cpu.cfs_quota_us cpu.stat kube-proxy/ tasks
cgroup.event_control cpuacct.usage cpu.rt_period_us docker/ notify_on_release user.slice/
cgroup.procs cpuacct.usage_percpu cpu.rt_runtime_us kubelet/ release_agent
cgroup.sane_behavior cpu.cfs_period_us cpu.shares kubepods/ system.slice/
单独挂载 cpu 时,提示 “已经挂载或者/tmp/cgroup/cpu is busy,暂时不清楚是怎么回事,
$ mkdir -p /tmp/cgroup/cpu
$ mount -t cgroup -o cpu none /tmp/cgroup/cpu
mount: none is already mounted or /tmp/cgroup/cpu busy
直接用 umount 卸载:
umount /sys/fs/cgroup/pids
卸载的时候要注意,需要先将所有子目录卸载,否则,umount 只会让挂载点不可见,而不是真正将其卸载。
cpu,
CFS Scheduler、 CFS Bandwidth Control
since 2.6.24,限制CPU份额,只会在cpu忙碌的时候限制cpu使用,如果cpu空闲不做限制。
since 3.2.0, 引入了`CON‐FIG_CFS_BANDWIDTH`编译选项,限制进程在每个调度周期占用的时间,无论CPU是否空闲。
cpuacct,Documentation/cgroup-v1/cpuacct.txt:
since 2.6.24,统计一组task的cpu使用情况。
cpuset,Documentation/cgroup-v1/cpusets.txt:
since 2.6.24,绑定到特定的cpu
memory,Documentation/cgroup-v1/memory.txt:
since 2.6.25,报告和限制内存使用情况
devices,Documentation/cgroup-v1/devices.txt:
since 2.6.26,限制设备文件的创建,和对设备文件的读写
freezer,Documentation/cgroup-v1/freezer-subsystem.txt:
since 2.6.28,暂停、重载指定cgroup目录中的、以及它的子目录中的task
net_cls,Documentation/cgroup-v1/net_cls.txt:
since 2.6.29,为该cgroup内的task产生的报文打上classid
blkio,Documentation/cgroup-v1/blkio-controller.txt:
since 2.6.33,限制和控制对块设备的读写
perf_event,tools/perf/Documentation/perf-record.txt:
since 2.6.39,允许perf观测cgroup中的task
net_prio,Documentation/cgroup-v1/net_prio.txt:
since 3.3,设置net优先级
hugetlb,Documentation/cgroup-v1/hugetlb.txt:
since 3.5,限制huge page的使用
pids,Documentation/cgroup-v1/pids.txt:
since 4.3,限制cgroup中可创建的进程数
rdma,Documentation/cgroup-v1/rdma.txt:
since 4.11,限制RDMA/IB 资源
cgroup是以目录的形式呈现的,/
是cgroup的根目录,注意cgroup的根目录和挂载目录不是一回事,cgroup可能挂载在/sys/fs/cgroup或者/tmp/cgroup等任意目录,无论挂载在哪里,cgroup的根目录都是“/
”。
假设cgroup的cpu controller的挂载点是/sys/fs/cgroup/cpu,那么目录/sys/fs/cgroup/cpu/cg1
对应的cgroup的目录是/cg1
。
为什么要强调这个,因为在调查一个kubelet的问题的时候,不确定--runtime-cgroups
参数值中要不要包含挂载点路径,直到用cadvisor查出所有cgroup后,才确定不应该带有挂载路径。现在从Linux手册中找到支持了:
A cgroup filesystem initially contains a single root cgroup, '/',
which all processes belong to. A new cgroup is created by creating a
directory in the cgroup filesystem:
mkdir /sys/fs/cgroup/cpu/cg1
将进程的进程号直接写入到对应cgroup.procs
文件中,就完成了进程与cgroup的绑定,例如:
echo $$ > /sys/fs/cgroup/cpu/cg1/cgroup.procs
将进程绑定到cgroup之后,该进程创建的线程也一同被绑定到同一个cgroup。
每个进程只能绑定每个controller的一个cgroup目录,把进程的ID加到controller中的另一个cgroup目录的cgroup.procs文件中时,会自动将其从原先的cgroup.procs文件中移除。
每次只能向cgroup.procs
中添加一个进程号,不能批量添加。
从cgroup.procs中读取的进程号的顺序是随意的,并且是可以重复的。
cgroup v1支持将线程(task)绑定到cgroup目录,只需将线程的线程ID写入目标cgroup目录的tasks
文件中。
注意,tasks
文件中是线程ID,cgroup.procs
文件中是进程ID。
在cgroup子目录已经全部删除,并且没有绑定任何进程、线程的情况下,直接删除cgroup目录即可。
每个cgroup中目录中都有下面两个文件:
release_agent notify_on_release
notify_on_release
的内容是0或者1,指示kernel是否要在cgroup为空时(没有cgroup子目录、没有绑定任何进程)发出通知,0为不通知,1为通知。
release_agent
是自行设置的、kernel通知时调用的命令, 它的命令行参数有且只有一个,就是当前为空的cgroup目录。
release_agent也可以在挂载cgroup的时候设置:
mount -o release_agent=pathname ...
cgroups v2支持的所有controller使用统一约定的、固定格式的cgroup目录,并且进程只能绑定到cgroup的“/
”目录和目录树中的叶子节点,不能绑定到中间目录
。变化还是比较大的,需要特别注意:
/
”目录和cgroup目录树中的叶子节点
cgroup.events
文件通知内核文档Documentation/cgroup-v2.txt中有更详细的描述。
类型为cgroup2
:
mount -t cgroup2 none /mnt/cgroup2
一个controller如果已经在cgroup v1中挂载了,那么在cgroup v2中就不可用。如果要在cgroup v2中使用,需要先将其从cgroup v1中卸载。
systemd用到了cgroup v1,会在系统启动时自动挂载controller,因此要在cgroup v2中使用的controller,最好通过内核启动参数cgroup_no_v1=list
禁止cgroup v1使用:
cgroup_no_v1=list # list是用逗号间隔的多个controller
cgroup_no_v1=all # all 将所有的controller设置为对cgroup v1不可用
从Linux kernel 4.14开始,cgroup v2支持线程模式(thread mode),引入该特性后,controller开始分为两类:domain controller
(以进程为管理目标的控制器)和 threaded controller
(以线程为管理目标的控制器)。
io
since 4.5,cgroup v1 的 blkio 的继任者
memory
since 4.5,cgroup v1 的 memory 的继任者
pids
since 4.5,与 cgroup v1 中的 pids 是同一个
perf_event
since 4.5,与 cgroup v1 中的 perf_event 是同一个
rdma
since 4.11,与 cgroup v1 中的 rdma 是同一个
cpu
since 4.15,cgroup v1 的 cpu、cpuacct 的继任者
cpu
perf_event
pids
cgroup v2的cgroup目录中有一个cgroup.controllers文件和cgroup.subtree_control文件。
cgroup.controllers
文件是只读的,内容是当前目录可用
的controller。
cgroup.subtree_control
是当前目录中可用的controller的子集,规定了直接子目录可用
的controller,即定义了直接子目录中的cgroup.controllers
文件的内容。
cgroup.subtree_control的内容格式如下,列出的controller用空格间隔,前面用“+”表示启用,用“-”表示不启用:
echo '+pids -memory' > x/y/cgroup.subtree_control
如果向cgroup.subtree_control中写入cgroup.controllers中不存在的controller,会得到ENOENT
错误。
在cgroup v2中,所有进程都只能绑定到cgroup的叶子目录中。假设cgroup的目录如下,这时候只能在CG1.1、CG1.2和CG2.1中绑定进程:
/
__ __
___/ \___
__/ \__
CG1 CG2
__ __ __
___/ \___ \_
__/ \__ \_
CG1.1 CG1.2 CG2.1
man 7 cgroups建议在每个目录下都建立一个名为leaf的目录,这个目录没有任何子目录,专门用来绑定进程。
根据这个建议,上面的目录应该调整成:
/
_______
_____/ \_____
___/ \___
CG1 CG2
__|__ ____
___/ | \___ ___/ \___
__/ | \__ __/ \__
CG1.1 leaf CG1.2 CG2.1 leaf
| | |
leaf leaf leaf
需要绑定cgroup进程的进程号都写在名为leaf的目录中。
进程只能绑定到目录树的叶子结点只是一个表面规则,本质规则是:
一个cgroup目录如果绑定了进程,那么它的cgroup.subtree_control
必须为空,或者反过来必须不绑定进程,cgroup.subtree_control
中才可以有内容。
More precisely, the rule is that a (nonroot) cgroup can’t both (1) have member processes, and (2) distribute resources into child cgroups—that is, have a nonempty cgroup.subtree_control file.
cgroup v1 中的release_agent和notify_on_release被移除了,cgroup v2 提供一个更通用的cgroup.events
。
cgroup.events
文件是只读
的,每行一个key-value对,key和value之间用空格间隔。
现在(2019-01-29 17:39:09),cgroup.events文件中只存在一个名为populated
的key,这个key对应的value是这个cgroup中包含的进程数。
如果使用cgroup v2,要用监控cgroup.events文件的方式感知cgroup的变化。
When monitoring this file using inotify(7), transitions generate IN_MODIFY events When monitoring the file using poll(2), transitions cause the bits POLLPRI and POLLERR to be returned in the revents field.
前面已经接触到文件有:
cgroup.controllers
只读,当前目录中可用的controller
cgroup.subtree_control
读写,子目录中可用的controller
cgroup.events
只读,事件文件,每行一对key value,现在只有一个key
populated:value是cgroup中包含的进程数
除此之外还有:
cgroup.stat
只读,since 4.14,每行一对key value
nr_descendants: 该cgroup中存活的子cgroup的数量
nr_dying_descendants: 该cgroup中已经死亡的cgroup的数量
一个cgroup目录被删除后,先进入dying状态,等待系统回收。
cgroup.max.depth
since 4.14,当前目录的子目录的最大深度,0表示不能创建子目录,默认值"max"表示不限制
超过限制,返回EAGAIN
cgroup.max.descendants
since 4.14,当前目录中可以创建的活跃cgroup目录的最大数量,默认值"max"表示不限制
超过限制,返回EAGAIN
cgroup.type
since 4.14,位于"/"以外的cgroup目录,标记当前cgroup目录的类型,支持修改,支持以下类型:
domain: 进程子目录,控制进程资源的cgroup
threaded: 线程子目录,控制同一个进程下的线程资源
domain threaded: 线程子目录的根目录,threaded root
domain invalid: 线程子目录中处于无效状态的cgroup目录
domain invalid是一个中间状态,对类型为domain invalid的cgroup目录,只能做一个操作:将其类型修改threaded。 它存在的目的是为线程模式的扩展预留空间。
特权用户(root用户)可以授予非特权用户(普通用户)管理某个cgroup的权利。
授予方法很简单,直接将一些文件或目录的所有者改成被授权人就可以了,修改的文件或目录不同,被授权人拥有的权限不同。
按照文档中中例子,将cgroup目录/dlgt_grp
的管理权授予普通用户时,可以有以下几种授权方式:
/dlgt_grp
目录的所有者改为被授权人,被授权人拥有该目录下所有新建cgroup目录的管理权。
/dlgt_grp/cgroup.procs
文件的所有者改为被授权人,被授权人拥有将进程绑定到该cgroup的权利。
/dlgt_grp/cgroup.subtree_control
文件的所有者改为被授权人,被授权人可以决定在子目录中启用哪些出现在/dlgt_grp/cgroup.controllers
中controller。
/dlgt_grp/cgroup.threads
文件的所有者改为被授权人,线程模式下用到,授予将线程绑定到线程子目录的权利。
需要注意的是/dlgt_grp目录中controller的接口文件的所有者
不应当被修改,这是上层cgroup目录授予当前目录的。
在挂载cgroup v2的时候,使用参数nsdelegate
开启授权边界,如果cgroup v2已经挂载,可以remount
开启,如下:
mount -t cgroup2 -o remount,nsdelegate none /sys/fs/cgroup/unified
使用该选项之后,cgroup namespace成为授权边界,会对cgroup中的进程进行下面的限制:
1. cgroup中的进程不能对所属cgroup目录中的controller接口文件进行写操作,否则报错`EPERM`
2. cgroup中的进程不能设置namespace边界外的cgroup中的绑定进程,否则报错`ENOENT`
cgroup namespace是个什么鬼?? 2019-01-30 14:28:27
引入cgroup namespace作为授权边界是为了应对下面的情况:
1. 用户用cecilia得到了一个cgroup目录的管理权限,这个目录这里称为当前目录
2. 普通用户cecilia,在当前目录下创建了一个cgroup子目录,并将这个子目录授权给另一个人
这种情况下,cecilia同时拥有当前目录和子目录的操作权限,子目录中的进程也是cecilia用户的进程,会出现下面两种非法的操作:
1. 绑定到cecilia的cgroup子目录中的进程能够更改所属cgroup子目录中的controller接口文件
2. 绑定到cecilia的cgroup子目录中的进程能够将进程移出所在cgroup子目录,绑定到cecilia的当前cgroup目录
文档中举的例子是,cecilia创建一个容器,容器内的进程绑定到cecilia创建的cgroup子目录。意思似乎是在说:
如果不以namespace为授权边界,那么容器内的进程就能够自己修改controller接口,并且具备脱离所属的cgroup目录、将自己绑定到上层cgroup目录的能力。
这样一来cecilia对容器内进程所做的cgroup限制就形同虚设。这样理解正好和授权边界引入的两个限制对应(或许正确 2019-01-30 14:36:38)。
nsdelegate
只在最初挂载的mount namespace中有效,在其它mount namespace中默认忽略:
The nsdelegate mount option only has an effect when performed in the
initial mount namespace; in other mount namespaces, the option is
silently ignored.
一个非特权进程只有下面的情况都满足时,才能向cgroup.procs
中添加进程:
1. 拥有cgroup.procs文件的写权限
2. 拥有进程原先所属cgroup目录和将要加入的cgroup目录的共同上级目录中cgroup.procs文件的写权限
3. 如果启用了授权边界(nsdelegate),执行操作的进程必须能够看到被操作的进程原先所属cgroup目录和将要加入的cgroup目录
4. Linux kernel 4.11之前,执行操作的进程的UID和被操作进程的User ID或者Set-User-ID匹配
以上四条约束带来的直接结果是:被授权给非特权用户的cgroup绑定的第一个进程,只能是授权者设置的,不能由被授权者添加。因为被授权者不能对cgroup子目录中的第一个进程原先所在的cgroup中的cgroup.procs文件进行写操作。
Linux kernerl 4.14开始,cgroup v2支持线程模式。
线程模式是指:
线程子目录
(threaded subtrees),容纳绑定到该线程子目录的进程创建的所有线程,每个线程可以绑定线程子目录的cgroup子目录。非叶子目录可以绑定线程
,注意,“只能绑定到叶子目录”的限制在这里放松了。cpu
perf_event
pids
在线程子目录中不能使用
domain controllers。
方法1
cgroup.type
,写入threaded
/
目录除外)的类型自动变为domain threaded
domain invalid
,需要自行将其修改为threaded
方法2
domain threaded
threaded
类型的子目录类型自动变成domain invalid
,需要自行将其修改为threaded
注意如果上层目录的类型是domain invalid
,当前目录的类型不能被修改。此外,将当前目录的类型修改为threaded
时,需要满足两个条件:
cgroup.subtree_control
文件中没有启用domain controller配置,否则报错ENOTSUP
。即domain controllers不能在线程子目录中使用。
将进程ID直接写入线程子目录的cgroup.procs
文件中,该进程以及它的线程就都一同绑定到了线程子目录中。
然后可以将这个进程创建的多个线程ID,写入到它绑定的线程子目录的以及子目录的子目录中的cgroup.threads
文件,实现线程的绑定。
线程只能绑定到创建它的进程
所在的线程
子目录树。
domain controller是不关心线程的,它看到的都是进程。
实行线程绑定操作时,需要满足以下条件:
cgroup.threads
文件的写权限cgroup.procs
文件的写权限EOPNOTSUPP
。进程子目录中的根目录中cgroup.procs
是可读写的,进程子目录中非根目录中的cgroup.procs
文件是不可读写的。
cgroup.threads
在每个cgroup目录中都存在,包括类型为domain的cgroup目录。
/proc/cgroups(since 2.6.24)列出了内核支持的cgroup contoller,以及它们的使用情况:
#subsys_name hierarchy num_cgroups enabled
cpuset 4 1 1
cpu 8 1 1
cpuacct 8 1 1
blkio 6 1 1
memory 3 1 1
devices 10 84 1
freezer 7 1 1
net_cls 9 1 1
perf_event 5 1 1
net_prio 9 1 1
hugetlb 0 1 0
pids 2 1 1
四列数据的含义分别是:controller名称、挂载位置ID(在cgroup v2中都为0)、使用该controller的cgroup数量、是否启用。
/proc/[pid]/cgroup(since 2.6.24)进程所属的cgroup,内容格式如下:
hierarchy-ID:controller-list:cgroup-path
例如一个容器内进程的cgroup:
# cat /proc/1427/cgroup
11:blkio:/kubepods/besteffort/pode4f8b737-1ad1-11e9-a3a2-5254003b4ace/3647f5a8960c6c003fda011ea26dedcb8d45ce3b4c03cbec31b4f2c9cab7d221
10:freezer:/kubepods/besteffort/pode4f8b737-1ad1-11e9-a3a2-5254003b4ace/3647f5a8960c6c003fda011ea26dedcb8d45ce3b4c03cbec31b4f2c9cab7d221
9:net_prio,net_cls:/kubepods/besteffort/pode4f8b737-1ad1-11e9-a3a2-5254003b4ace/3647f5a8960c6c003fda011ea26dedcb8d45ce3b4c03cbec31b4f2c9cab7d221
8:devices:/kubepods/besteffort/pode4f8b737-1ad1-11e9-a3a2-5254003b4ace/3647f5a8960c6c003fda011ea26dedcb8d45ce3b4c03cbec31b4f2c9cab7d221
7:cpuset:/kubepods/besteffort/pode4f8b737-1ad1-11e9-a3a2-5254003b4ace/3647f5a8960c6c003fda011ea26dedcb8d45ce3b4c03cbec31b4f2c9cab7d221
6:memory:/kubepods/besteffort/pode4f8b737-1ad1-11e9-a3a2-5254003b4ace/3647f5a8960c6c003fda011ea26dedcb8d45ce3b4c03cbec31b4f2c9cab7d221
5:perf_event:/kubepods/besteffort/pode4f8b737-1ad1-11e9-a3a2-5254003b4ace/3647f5a8960c6c003fda011ea26dedcb8d45ce3b4c03cbec31b4f2c9cab7d221
4:pids:/kubepods/besteffort/pode4f8b737-1ad1-11e9-a3a2-5254003b4ace/3647f5a8960c6c003fda011ea26dedcb8d45ce3b4c03cbec31b4f2c9cab7d221
3:cpuacct,cpu:/kubepods/besteffort/pode4f8b737-1ad1-11e9-a3a2-5254003b4ace/3647f5a8960c6c003fda011ea26dedcb8d45ce3b4c03cbec31b4f2c9cab7d221
2:hugetlb:/kubepods/besteffort/pode4f8b737-1ad1-11e9-a3a2-5254003b4ace/3647f5a8960c6c003fda011ea26dedcb8d45ce3b4c03cbec31b4f2c9cab7d221
1:name=systemd:/kubepods/besteffort/pode4f8b737-1ad1-11e9-a3a2-5254003b4ace/3647f5a8960c6c003fda011ea26dedcb8d45ce3b4c03cbec31b4f2c9cab7d221
第一列hierarchy-ID
与/proc/cgroups的第二列对应,在cgroups v2中hierarchy-ID都为0;第二列是controller名称
;第三列是cgroup目录路径
。
/sys/kernel/cgroup/delegate(since 4.15):cgroups v2 中可以授权给其它用户的cgroup文件。
/sys/kernel/cgroup/features(since 4.15):cgroups v2 支持的功能特性。
手上没有kernel 4.15的环境,下面是文档中的例子:
$ cat /sys/kernel/cgroup/delegate
cgroup.procs
cgroup.subtree_control
cgroup.threads
$ cat /sys/kernel/cgroup/features
nsdelegate