前言
Linux Cgroups
提供了對(duì)一組進(jìn)程及將來子進(jìn)程的資源限制、控制和統(tǒng)計(jì)的能力,這些資源包括CPU
、內(nèi)存、存儲(chǔ)、網(wǎng)絡(luò)等.
概念
tasks: 在
cgroups
中,任務(wù)就是系統(tǒng)的一個(gè)進(jìn)程.
cgroup(control group): 一組按照某種標(biāo)準(zhǔn)劃分的進(jìn)程.
hierarchy: 把一組cgroup
串成一個(gè)樹狀的結(jié)構(gòu), 可以做到繼承. 比如系統(tǒng)對(duì)一組定時(shí)的任務(wù)進(jìn)程通過cgroup1
限制了CPU
的使用率,然后其中有一個(gè)定時(shí)dump
日志的進(jìn)程還需要限制磁盤IO
,為了避免限制了磁盤IO
之后影響到其他進(jìn)程,就可以創(chuàng)建cgroup2
,使其繼承于cgroup1
井限制磁盤的IO
,這樣cgroup2
便繼承了cgroup1
中對(duì)CPU
使用率的限制,并且增加了磁盤IO
的限制而不影響到cgroup1
中的其他進(jìn)程.
subsystem: 一個(gè)子系統(tǒng)就是一個(gè)資源控制器.
他們直接的相互關(guān)系如下:
1. 每次在系統(tǒng)中創(chuàng)建新層級(jí)時(shí),該系統(tǒng)中的所有任務(wù)都是那個(gè)層級(jí)的默認(rèn)
cgroup
(稱之為root cgroup
,此cgroup
在創(chuàng)建層級(jí)時(shí)自動(dòng)創(chuàng)建,后面在該層級(jí)中創(chuàng)建的cgroup
都是此cgroup
的后代)的初始成員.
2. 一個(gè)子系統(tǒng)最多只能附加到一個(gè)層級(jí).
3. 一個(gè)層級(jí)可以附加多個(gè)子系統(tǒng).
4. 一個(gè)任務(wù)可以是多個(gè)cgroup
的成員,但是這些cgroup
必須在不同的層級(jí).
5. 系統(tǒng)中的進(jìn)程創(chuàng)建子進(jìn)程時(shí),該子任務(wù)自動(dòng)成為其父進(jìn)程所在cgroup
的成員。然后可根據(jù)需要將該子任務(wù)移動(dòng)到不同的cgroup
中,但開始時(shí)它總是繼承其父任務(wù)的cgroup
.
如下所示:
hierarchy-subsystem-cgroup-task.png
CPU 和 Memory 兩個(gè)子系統(tǒng)有自己獨(dú)立的層級(jí)系統(tǒng), 而又通過 Task 取得關(guān)聯(lián)關(guān)系, 該task
既有CPU
的限制又有Memory
的限制.
本機(jī)支持的subsystem
root@nicktming:~# cd /sys/fs/cgroup/
root@nicktming:/sys/fs/cgroup# ls
systemd
root@nicktming:/sys/fs/cgroup# apt-get install cgroup-bin
root@nicktming:/sys/fs/cgroup# lssubsys -a
cpuset
cpu
cpuacct
memory
devices
freezer
blkio
perf_event
hugetlb
root@nicktming:/sys/fs/cgroup# ls
blkio cpu cpuacct cpuset devices freezer hugetlb memory perf_event systemd
cgroup
root@nicktming:~# mkdir cgroup && cd cgroup
root@nicktming:~/cgroup# mkdir demo
root@nicktming:~/cgroup# mount -t cgroup -o none,name=demo demo ./demo
root@nicktming:~/cgroup# ls ./demo
cgroup.clone_children cgroup.event_control cgroup.procs cgroup.sane_behavior notify_on_release release_agent tasks
root@nicktming:~/cgroup# wc -l ./demo/cgroup.procs
80 ./demo/cgroup.procs
root@nicktming:~/cgroup# wc -l ./demo/tasks
95 ./demo/tasks
cgroup.clone_children:
cpuset
的subsystem
會(huì)讀取這個(gè)配置文件,如果這個(gè)值是1 (默認(rèn)是0 ), 子cgroup
才會(huì)繼承父cgroup
的cpuset
的配置.
cgroup.procs: 樹中當(dāng)前節(jié)點(diǎn)cgroup
中的進(jìn)程組ID
,現(xiàn)在的位置是在根節(jié)點(diǎn),這個(gè)文件中會(huì)有現(xiàn)在系統(tǒng)中所有進(jìn)程組的ID
.
tasks: 標(biāo)識(shí)該cgroup
下面的進(jìn)程ID
,如果把一個(gè)進(jìn)程ID
寫到tasks
文件中,便會(huì)將相應(yīng)的進(jìn)程加入到這個(gè)cgroup
中.
創(chuàng)建和刪除子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中有進(jìn)程的時(shí)候刪除不了, 必須把進(jìn)程移到別的cgroup中才可以刪除
root@nicktming:~/cgroup/demo# rmdir cgroup1
rmdir: failed to remove ‘cgroup1’: Device or resource busy
// 將該進(jìn)程從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
subsystem
memory
可以限制
cgroup
中所有進(jìn)程所能使用的物理內(nèi)存總量等等.
root@nicktming:/sys/fs/cgroup/memory# ls
cgroup.clone_children memory.kmem.failcnt memory.kmem.tcp.max_usage_in_bytes memory.numa_stat memory.usage_in_bytes
cgroup.event_control memory.kmem.limit_in_bytes memory.kmem.tcp.usage_in_bytes memory.oom_control memory.use_hierarchy
cgroup.procs memory.kmem.max_usage_in_bytes memory.kmem.usage_in_bytes memory.pressure_level notify_on_release
cgroup.sane_behavior memory.kmem.slabinfo memory.limit_in_bytes memory.soft_limit_in_bytes release_agent
memory.failcnt memory.kmem.tcp.failcnt memory.max_usage_in_bytes memory.stat tasks
memory.force_empty memory.kmem.tcp.limit_in_bytes memory.move_charge_at_immigrate memory.swappiness
了解一下幾個(gè)比較重要的概念
memory.usage_in_bytes #顯示當(dāng)前已用的內(nèi)存
memory.limit_in_bytes #設(shè)置/顯示當(dāng)前限制的內(nèi)存額度
memory.failcnt #顯示內(nèi)存使用量達(dá)到限制值的次數(shù)
memory.max_usage_in_bytes #歷史內(nèi)存最大使用量
memory.swappiness #設(shè)置和顯示當(dāng)前的swappiness
memory.oom_control #設(shè)置/顯示oom controls相關(guān)的配置
加入cgroup限制
當(dāng)物理內(nèi)存達(dá)到上限后,系統(tǒng)的默認(rèn)行為是
kill
掉cgroup
中繼續(xù)申請(qǐng)內(nèi)存的進(jìn)程. 通過memory.oom_control
來控制.
root@nicktming:/sys/fs/cgroup/memory/test-limit-memory# cat memory.oom_control
oom_kill_disable 0 // 0表明該進(jìn)程達(dá)到其limit時(shí)會(huì)被kill, 1表明會(huì)暫停該進(jìn)程
under_oom 0 // 0表明未進(jìn)入oom狀態(tài), 1表明該進(jìn)程被暫停
例子 oom_kill_disable = 0
root@nicktming:~# cat memory.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#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的限制后 運(yùn)行程序在申請(qǐng)5M內(nèi)存時(shí)候被killed.
root@nicktming:~# gcc memory.c -o memory
root@nicktming:~# ./memory
1M memory allocated
2M memory allocated
3M memory allocated
4M memory allocated
Killed
例子 oom_kill_disable = 1
------------------------------------打開終端0-------------------------------
root@nicktming:/sys/fs/cgroup/memory/test-limit-memory# sh -c "echo 0 > memory.swappiness"
root@nicktming:/sys/fs/cgroup/memory/test-limit-memory# sh -c "echo 1 >> memory.oom_control"
root@nicktming:/sys/fs/cgroup/memory/test-limit-memory# cat memory.oom_control
oom_kill_disable 1
under_oom 0
root@nicktming:/sys/fs/cgroup/memory/test-limit-memory# cd /root
// 運(yùn)行到申請(qǐng)5M的時(shí)候會(huì)暫停該進(jìn)程
root@nicktming:~# ./memory
1M memory allocated
2M memory allocated
3M memory allocated
4M memory allocated
------------------------------------打開終端1-------------------------------
root@nicktming:/sys/fs/cgroup/memory/test-limit-memory# cat memory.oom_control
oom_kill_disable 1
under_oom 1
root@nicktming:/sys/fs/cgroup/memory/test-limit-memory# sh -c "echo 15M > memory.limit_in_bytes"
------------------------------------打開終端0-------------------------------
// 該進(jìn)程繼續(xù)運(yùn)行
root@nicktming:~# ./memory
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
13M memory allocated
14M memory allocated
------------------------------------打開終端1-------------------------------
// 重新把oom_kill_disable打開
root@nicktming:/sys/fs/cgroup/memory/test-limit-memory# sh -c "echo 0 >> memory.oom_control"
root@nicktming:/sys/fs/cgroup/memory/test-limit-memory# cat memory.oom_control
oom_kill_disable 0
under_oom 0
// 可以看到該進(jìn)程超過內(nèi)存限制的次數(shù)
root@nicktming:/sys/fs/cgroup/memory/test-limit-memory# cat memory.failcnt
85194
------------------------------------打開終端0-------------------------------
// 由于oom_kill_disable被設(shè)置為0, 所以該進(jìn)程被kill.
root@nicktming:~# ./memory
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
13M memory allocated
14M memory allocated
Killed
參考
1. https://segmentfault.com/a/1190000006917884
2. https://www.ibm.com/developerworks/cn/linux/1506_cgroup/
3. 自己動(dòng)手寫docker.(基本參考此書,加入一些自己的理解,加深對(duì)docker
的理解)
全部?jī)?nèi)容
mydocker.png
1. [mydocker]---環(huán)境說明
2. [mydocker]---urfave cli 理解
3. [mydocker]---Linux Namespace
4. [mydocker]---Linux Cgroup
5. [mydocker]---構(gòu)造容器01-實(shí)現(xiàn)run命令
6. [mydocker]---構(gòu)造容器02-實(shí)現(xiàn)資源限制01
7. [mydocker]---構(gòu)造容器02-實(shí)現(xiàn)資源限制02
8. [mydocker]---構(gòu)造容器03-實(shí)現(xiàn)增加管道
9. [mydocker]---通過例子理解存儲(chǔ)驅(qū)動(dòng)AUFS
10. [mydocker]---通過例子理解chroot 和 pivot_root
11. [mydocker]---一步步實(shí)現(xiàn)使用busybox創(chuàng)建容器
12. [mydocker]---一步步實(shí)現(xiàn)使用AUFS包裝busybox
13. [mydocker]---一步步實(shí)現(xiàn)volume操作
14. [mydocker]---實(shí)現(xiàn)保存鏡像
15. [mydocker]---實(shí)現(xiàn)容器的后臺(tái)運(yùn)行
16. [mydocker]---實(shí)現(xiàn)查看運(yùn)行中容器
17. [mydocker]---實(shí)現(xiàn)查看容器日志
18. [mydocker]---實(shí)現(xiàn)進(jìn)入容器Namespace
19. [mydocker]---實(shí)現(xiàn)停止容器
20. [mydocker]---實(shí)現(xiàn)刪除容器
21. [mydocker]---實(shí)現(xiàn)容器層隔離
22. [mydocker]---實(shí)現(xiàn)通過容器制作鏡像
23. [mydocker]---實(shí)現(xiàn)cp操作
24. [mydocker]---實(shí)現(xiàn)容器指定環(huán)境變量
25. [mydocker]---網(wǎng)際協(xié)議IP
26. [mydocker]---網(wǎng)絡(luò)虛擬設(shè)備veth bridge iptables
27. [mydocker]---docker的四種網(wǎng)絡(luò)模型與原理實(shí)現(xiàn)(1)
28. [mydocker]---docker的四種網(wǎng)絡(luò)模型與原理實(shí)現(xiàn)(2)
29. [mydocker]---容器地址分配
30. [mydocker]---網(wǎng)絡(luò)net/netlink api 使用解析
31. [mydocker]---網(wǎng)絡(luò)實(shí)現(xiàn)
32. [mydocker]---網(wǎng)絡(luò)實(shí)現(xiàn)測(cè)試