Docker cgroup资源限制Linux内核机制深入剖析-Docker商业环境实战
2010 年 10 月 19 日
专注于大数据及容器云核心技术解密,可提供全栈的大数据+云原生平台咨询方案,请持续关注本套博客。如有任何学术交流,可随时联系。更多内容请关注《数据云技术社区》公众号。

1 cgroup 核心概念
- subsystem:基于cgroup的资源管理器,可以看作一种资源(比如CPU,Memory, I/O等),实现对一个cgroup的task的调度和控制
- cgroup:以某种方式,将某些任务和subsystem进行关联。一个subsystem就是一个内核模块,他被关联到一颗cgroup树之后,就会在树的每个节点(进程组)上做具体的操作。subsystem经常被称作”resource controller”,因为它主要被用来调度或者限制每个进程组的资源。
- hierarchy:对crgoups和subsystems以某种形式进行的组织,cgroup组织形式是树结构,subsystem会关联连接到hierarchy上。
- 上面的就是一个1个hierarchy,有两个subsystem(cpu和memory) attach上,其中的cgroups以tree的结构组织。
- 上面的就是CPU 和 Memory 两个子系统有自己独立的层级系统, 而又通过 Task 取得关联关系, 该task既有CPU的限制又有Memory的限制。
- 有时我们将进程分组只是为了做一些监控,观察一下他们的状态,比如perf_event subsystem。到目前为止,Linux支持12种subsystem,比如限制CPU的使用时间,限制使用的内存,统计CPU的使用情况,冻结和恢复一组进程等。
1.1 subsystem相关的资源控制
- blkio: 这个subsystem可以为块设备设定输入/输出限制,比如物理驱动设备(包括磁盘、固态硬盘、USB等)。 - cpu: 这个subsystem使用调度程序控制task对CPU的使用。 - cpuacct: 这个subsystem自动生成cgroup中task对CPU资源使用情况的报告。 - cpuset: 这个subsystem可以为cgroup中的task分配独立的CPU(此处针对多处理器系统)和内存。 - devices 这个subsystem可以开启或关闭cgroup中task对设备的访问。 - freezer 这个subsystem可以挂起或恢复cgroup中的task。 - memory 这个subsystem可以设定cgroup中task对内存使用量的限定,并且自动生成这些task对内存资源使用情况的报告。 - perf_event 这个subsystem使用后使得cgroup中的task可以进行统一的性能测试。{![perf: Linux CPU性能探测器,详见https://perf.wiki.kernel.org/index.php/Main_Page]} - *net_cls 这个subsystem Docker没有直接使用,它通过使用等级识别符(classid)标记网络数据包,从而允许 Linux 流量控制程序(TC:Traffic Controller)识别从具体cgroup中生成的数据包。 复制代码
2 cgroup基本操作
2.1 挂载cgroup
#尝试将cpu subsystem重新关联一颗cgroup树并且将这棵树mount到./cpu目录 dev@ubuntu:~/cgroup$ mkdir cpu dev@ubuntu:~/cgroup$ sudo mount -t cgroup -o cpu new-cpu ./cpu #由于name=test的cgroup树在系统中不存在,所以这里会创建一颗新的name=test的cgroup树,并且将这棵树mount到./test目录 dev@ubuntu:~$ mkdir -p cgroup/test && cd cgroup dev@ubuntu:~/cgroup$ sudo mount -t cgroup -o none,name=test test ./test #挂载一棵cgroup树,但不关联任何subsystem,下面就是systemd所用到的方式 mkdir /sys/fs/cgroup/systemd mount -t cgroup -o none,name=systemd xxx /sys/fs/cgroup/systemd #创建和删除子cgroup root@nicktming:~/cgroup# cd demo/ root@nicktming:~/cgroup/demo# mkdir cgroup1 root@nicktming:~/cgroup/demo# ls cgroup1/ cgroup.clone_children cgroup.event_control cgroup.procs notify_on_release tasks root@nicktming:~/cgroup/demo# mkdir cgroup2 root@nicktming:~/cgroup/demo# tree . |-- cgroup1 | |-- cgroup.clone_children | |-- cgroup.event_control | |-- cgroup.procs | |-- notify_on_release | `-- tasks |-- cgroup2 | |-- cgroup.clone_children | |-- cgroup.event_control | |-- cgroup.procs | |-- notify_on_release | `-- tasks |-- cgroup.clone_children |-- cgroup.event_control |-- cgroup.procs |-- cgroup.sane_behavior |-- notify_on_release |-- release_agent `-- tasks root@nicktming:~/cgroup/demo# sh -c "echo $$ > cgroup1/tasks" root@nicktming:~/cgroup/demo# cat cgroup1/tasks 11749 14172 root@nicktming:~/cgroup/demo# cat cgroup2/tasks // 删除子cgroup 直接删除其文件夹即可 root@nicktming:~/cgroup/demo# rmdir cgroup2 // 如果子cgroup中tasks中有进程的时候删除不了, 必须把进程移到别的cgroup中才可以删除 root@nicktming:~/cgroup/demo# rmdir cgroup1 rmdir: failed to remove ‘cgroup1’: Device or resource busy // 将该进程从cgroup1移到demo cgroup中 root@nicktming:~/cgroup/demo# sh -c "echo 11749 > tasks" root@nicktming:~/cgroup/demo# cat cgroup1/tasks root@nicktming:~/cgroup/demo# rmdir cgroup1 root@nicktming:~/cgroup/demo# tree . |-- cgroup.clone_children |-- cgroup.event_control |-- cgroup.procs |-- cgroup.sane_behavior |-- notify_on_release |-- release_agent `-- tasks 复制代码
2.2 cgroup资源配额限制
参考:https://blog.51cto.com/wzlinux/2046566 参考:https://www.jianshu.com/p/b02bf3b3f265 参考:https://www.jianshu.com/p/262d86b82e4c root@nicktming:~# cat memory.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; } root@nicktming:/sys/fs/cgroup/memory# mkdir test-limit-memory && cd test-limit-memory root@nicktming:/sys/fs/cgroup/memory/test-limit-memory# sh -c "echo $$ > tasks" root@nicktming:/sys/fs/cgroup/memory/test-limit-memory# sh -c "echo 5M > memory.limit_in_bytes" root@nicktming:/sys/fs/cgroup/memory/test-limit-memory# cd /root // 可以看到在加入5M的限制后 运行程序在申请5M内存时候被killed. root@nicktming:~# gcc memory.c -o memory root@nicktming:~# ./memory 1M memory allocated 2M memory allocated 3M memory allocated 4M memory allocated Killed docker run -itd --name stress polinux/stress:1.0.4 stress --cpu 1 --vm-bytes 200M 1633f77703ac680c6c9ff77ce5072b6c4d239a546151f945c87f57bb7011e17f cat /sys/fs/cgroup/cpu/docker/1633f77703ac680c6c9ff77ce5072b6c4d239a546151f945c87f57bb7011e17f/cpu.cfs_period_us 100000 cat /sys/fs/cgroup/cpu/docker/1633f77703ac680c6c9ff77ce5072b6c4d239a546151f945c87f57bb7011e17f/cpu.cfs_quota_us -1 可见没有对stress容器做cpu限制 top命令 PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 47864 root 20 0 736 36 0 R 99.3 0.0 3:00.90 stress cpu吃到约100% 复制代码
3 总结
时间因素,暂时总结到此,
专注于大数据及容器云核心技术解密,可提供全栈的大数据+云原生平台咨询方案,请持续关注本套博客。如有任何学术交流,可随时联系。更多内容请关注《数据云技术社区》公众号。
