文章導(dǎo)讀
本文記錄學(xué)習(xí)cgroup的一些歷程,由淺入深,從面到點(diǎn)的介紹了cgroup的相關(guān)知識(shí),并以kubernetes使用cpu,memory cgroup為切入點(diǎn)進(jìn)行分析,破除對(duì)于cgroup技術(shù)的恐懼心理,讓cgroup能夠?yàn)槲宜?。本文包含以下?nèi)容 :
- 為什么需要cgroup
- cgroup的使用方法
- cgroup的子系統(tǒng)介紹
- cgroup v1的局限性
- cgroup v2
- 查看cgroup的一些方法
- systemd的slice,sope,unit介紹
- kubelet使用cgroup的一些坑
cgroup的需求來源
計(jì)算機(jī)的硬件資源是有限的,如cpu,memory,io,network等,然而軟件對(duì)于資源的需求是貪婪的。按照我的理解,cgroup就是來實(shí)現(xiàn)優(yōu)先保證高優(yōu)先級(jí)應(yīng)用的資源需求,并確保應(yīng)用對(duì)于資源的使用不會(huì)超量。所以cgroup就是限制進(jìn)程的資源使用,并對(duì)資源的使用情況做統(tǒng)計(jì)。
說出來一些具體的事項(xiàng),才能更好的理解cgroup。
- DPDK綁定cpu,提高程序的運(yùn)行效率,這就可以用到cpuset。
- 之前面試時(shí),面試官問到監(jiān)控工具對(duì)于系統(tǒng)有沒有什么影響,如執(zhí)行ansible,top,pidstat,vmstat等等工具。現(xiàn)在就有一些思路了,可以使用cgroup來限制這些監(jiān)控程序的資源使用,來保證系統(tǒng)的穩(wěn)定性。
- 一個(gè)節(jié)點(diǎn)上多個(gè)pod,共享cpu資源,就可以用cgroup來限制pod的cpu使用情況,設(shè)置某個(gè)pod最多可以用到5C等。
- 付費(fèi)用戶可以使用更多內(nèi)存資源(資源統(tǒng)計(jì)),就可以使用cgroup 的memory來限制普通用戶的資源使用。
- 某些程序會(huì)有bug,有內(nèi)存泄露,也可以利用cgroup的memory來限制資源使用,不會(huì)對(duì)系統(tǒng)造成太大的影響。
- 以上都是強(qiáng)行編造....
cgroup子系統(tǒng)分類
以5.4的內(nèi)核為例,cgroup包括cpu,memory,blokio,network...,這里的每一個(gè)文件夾都表示cgroup的一個(gè)子系統(tǒng),這里只以cpu,memory為例進(jìn)行介紹。
root@iZt4n1u8u50jg1r5n6myn2Z:~# mount -t tmpfs |grep cgroup
tmpfs on /sys/fs/cgroup type tmpfs (ro,nosuid,nodev,noexec,mode=755)
root@iZt4n1u8u50jg1r5n6myn2Z:~# mount -t cgroup
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,name=systemd)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct)
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
cgroup on /sys/fs/cgroup/rdma type cgroup (rw,nosuid,nodev,noexec,relatime,rdma)
cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,net_cls,net_prio)
root@iZt4n1u8u50jg1r5n6myn2Z:~# ls /sys/fs/cgroup/
blkio cpu cpuacct cpu,cpuacct cpuset devices freezer hugetlb memory net_cls net_cls,net_prio net_prio perf_event pids rdma systemd unified
root@iZt4n1u8u50jg1r5n6myn2Z:~# uname -a
Linux iZt4n1u8u50jg1r5n6myn2Z 5.4.0-91-generic #102-Ubuntu SMP Fri Nov 5 16:31:28 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
root@iZt4n1u8u50jg1r5n6myn2Z:~#
這里請(qǐng)注意一個(gè)細(xì)節(jié),這里有三層掛載,一個(gè)是sysfs,掛載點(diǎn)是/sys/,一個(gè)是tmpfs內(nèi)存文件系統(tǒng),掛載點(diǎn)是/sys/fs/cgroup,另一個(gè)是子系統(tǒng)的掛載,如cpu掛載點(diǎn)是/sys/fs/cgroup/cpu。三層掛載就是三個(gè)文件系統(tǒng),一個(gè)是kernfs,一個(gè)是tmpfs,一個(gè)是cgroup文件系統(tǒng)。即使是基于內(nèi)存的文件系統(tǒng),也都有superblock,dentry,inode等這些vfs的概念。
cgroup的使用
常規(guī)使用
1、創(chuàng)建cgroup子系統(tǒng)的子目錄
2、設(shè)置資源配額
3、將需要限制的進(jìn)程號(hào)寫入子目錄
以cpu限額為例,限制當(dāng)前shell最多使用1C。這里有個(gè)知識(shí)點(diǎn),tasks和cgroup.procs有什么區(qū)別呢?按照官方文檔的描述,將pid寫入cgroup.procs,則該pid所在的線程組及該pid的子進(jìn)程等都會(huì)自動(dòng)加入到cgroup中。將pid寫入tasks,則只限制該pid。
root@iZt4n1u8u50jg1r5n6myn2Z:~# mkdir /sys/fs/cgroup/cpu/myshell -p
root@iZt4n1u8u50jg1r5n6myn2Z:~# echo 100000 > /sys/fs/cgroup/cpu/myshell/cpu.cfs_quota_us
root@iZt4n1u8u50jg1r5n6myn2Z:~# echo $$ > /sys/fs/cgroup/cpu/myshell/cgroup.procs
cg工具集
cgcreate創(chuàng)建,cgdelete刪除,cgget查詢,cgset設(shè)置,cgexec執(zhí)行等
root@iZt4n1u8u50jg1r5n6myn2Z:~# cgcreate -g cpu:mycg
root@iZt4n1u8u50jg1r5n6myn2Z:~# cgset -r cpu.cfs.cfs_quota_us=10000 /mycg
root@iZt4n1u8u50jg1r5n6myn2Z:~# cgexec -g cpu:mycg df -h -t ext4
Filesystem Size Used Avail Use% Mounted on
/dev/vda1 40G 29G 9.0G 77% /
root@iZt4n1u8u50jg1r5n6myn2Z:~# cgdelete -g cpu:mycg
systemd
通過systemd的接口設(shè)置服務(wù)的配額,與上訴兩種方式的使用原理是一樣的。systemcg-top的展示也不錯(cuò)。
root@iZt4n1u8u50jg1r5n6myn2Z:~# systemctl set-property sshd.service CPUShares=2048
root@iZt4n1u8u50jg1r5n6myn2Z:~# cat /sys/fs/cgroup/cpu/system.slice/ssh.service/cpu.shares
2048
root@iZt4n1u8u50jg1r5n6myn2Z:~# systemd-cgtop
Control Group Tasks %CPU Memory Input/s Output/s
/ 206 - 841.2M - -
assist - - 3.1M - -
docker 1 - 11.7M - -
docker/cbf77eadcd1bd5b4810eceeee1faa643a7d05bce9ca45d60f01813d15251c135 1 - 11.7M - -
system.slice 135 - 584.0M - -
system.slice/AssistDaemon.service 8 - 2.6M - -
system.slice/accounts-daemon.service 3 - 3.0M - -
system.slice/aegis.service 28 - 130.3M - -
system.slice/aliyun.service 9 - 15.0M - -
system.slice/atd.service 1 - 516.0K - -
system.slice/chrony.service 2 - 1.8M - -
kubelet使用systemd的cgroup驅(qū)動(dòng)目錄層級(jí)
這里kubelet使用systemd是指kubelet調(diào)用systemd的cgroup接口去管理cgroup,systemd管理cgroup與上面的幾種cgroup的方法本質(zhì)上是一致的
這里有三個(gè)slice。
kubepods.slice 所有pod的資源配額,下面還有pod級(jí)別的配額,容器級(jí)別的配額等。
system.slice systemd管理的服務(wù)的資源配額
user.slice ?
[root@10 ~]# ls /sys/fs/cgroup/cpu
cgroup.clone_children cpuacct.stat cpuacct.usage_percpu cpuacct.usage_sys cpu.cfs_quota_us cpu.shares notify_on_release tasks
cgroup.procs cpuacct.usage cpuacct.usage_percpu_sys cpuacct.usage_user cpu.rt_period_us cpu.stat release_agent user.slice
cgroup.sane_behavior cpuacct.usage_all cpuacct.usage_percpu_user cpu.cfs_period_us cpu.rt_runtime_us kubepods.slice system.slice
# pod級(jí)別配額
[root@10 ~]# ls -l /sys/fs/cgroup/cpu/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-pod41c19abf_8aaa_4b4f_9b4a_512194662502.slice/
total 0
-rw-r--r--. 1 root root 0 Nov 28 11:16 cgroup.clone_children
-rw-r--r--. 1 root root 0 Nov 28 11:16 cgroup.procs
-r--r--r--. 1 root root 0 Nov 28 11:16 cpuacct.stat
-rw-r--r--. 1 root root 0 Nov 28 11:16 cpuacct.usage
-r--r--r--. 1 root root 0 Nov 28 11:16 cpuacct.usage_all
-r--r--r--. 1 root root 0 Nov 28 11:16 cpuacct.usage_percpu
-r--r--r--. 1 root root 0 Nov 28 11:16 cpuacct.usage_percpu_sys
-r--r--r--. 1 root root 0 Nov 28 11:16 cpuacct.usage_percpu_user
-r--r--r--. 1 root root 0 Nov 28 11:16 cpuacct.usage_sys
-r--r--r--. 1 root root 0 Nov 28 11:16 cpuacct.usage_user
-rw-r--r--. 1 root root 0 Nov 28 11:16 cpu.cfs_period_us
-rw-r--r--. 1 root root 0 Nov 28 11:16 cpu.cfs_quota_us
-rw-r--r--. 1 root root 0 Nov 28 11:16 cpu.rt_period_us
-rw-r--r--. 1 root root 0 Nov 28 11:16 cpu.rt_runtime_us
-rw-r--r--. 1 root root 0 Nov 28 11:16 cpu.shares
-r--r--r--. 1 root root 0 Nov 28 11:16 cpu.stat
drwxr-xr-x. 2 root root 0 Nov 28 11:18 docker-095cb69032f07a3848e130014b2b574fda73818261ca3074065e3ae53b8f564d.scope
drwxr-xr-x. 2 root root 0 Nov 28 11:18 docker-f791c73f1fb7841079ea2ad89cee7c10f2926f6410f1ab2a01fbf8a65d9d1068.scope
# 容器級(jí)別配額
[root@10 ~]# ls -l /sys/fs/cgroup/cpu/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-pod41c19abf_8aaa_4b4f_9b4a_512194662502.slice/docker-095cb69032f07a3848e130014b2b574fda73818261ca3074065e3ae53b8f564d.scope/
total 0
-rw-r--r--. 1 root root 0 Nov 28 11:18 cgroup.clone_children
-rw-r--r--. 1 root root 0 Nov 28 11:18 cgroup.procs
-r--r--r--. 1 root root 0 Nov 28 11:18 cpuacct.stat
-rw-r--r--. 1 root root 0 Nov 28 11:18 cpuacct.usage
-r--r--r--. 1 root root 0 Nov 28 11:18 cpuacct.usage_all
-r--r--r--. 1 root root 0 Nov 28 11:18 cpuacct.usage_percpu
-r--r--r--. 1 root root 0 Nov 28 11:18 cpuacct.usage_percpu_sys
-r--r--r--. 1 root root 0 Nov 28 11:18 cpuacct.usage_percpu_user
-r--r--r--. 1 root root 0 Nov 28 11:18 cpuacct.usage_sys
-r--r--r--. 1 root root 0 Nov 28 11:18 cpuacct.usage_user
-rw-r--r--. 1 root root 0 Nov 28 11:18 cpu.cfs_period_us
-rw-r--r--. 1 root root 0 Nov 28 11:18 cpu.cfs_quota_us
-rw-r--r--. 1 root root 0 Nov 28 11:18 cpu.rt_period_us
-rw-r--r--. 1 root root 0 Nov 28 11:18 cpu.rt_runtime_us
-rw-r--r--. 1 root root 0 Nov 28 11:18 cpu.shares
-r--r--r--. 1 root root 0 Nov 28 11:18 cpu.stat
-rw-r--r--. 1 root root 0 Nov 28 11:18 notify_on_release
-rw-r--r--. 1 root root 0 Nov 28 11:18 tasks
查看cgroup個(gè)數(shù)
/proc/cgroups可以查看當(dāng)前系統(tǒng)掛載了多少子系統(tǒng),每個(gè)子系統(tǒng)的cgroup個(gè)數(shù)。
其中hierarchy一列是按照mount的順序生成的一個(gè)編號(hào)。num_cgroups表示該子系統(tǒng)下有多少個(gè)cgroup目錄,可以使用find命令查看。
內(nèi)核函數(shù)入口 :proc_cgroupstats_show
[root@10 ~]# cat /proc/cgroups |column -t
#subsys_name hierarchy num_cgroups enabled
cpuset 7 308 1
cpu 4 310 1
cpuacct 4 310 1
blkio 5 310 1
memory 10 314 1
devices 6 310 1
freezer 13 308 1
net_cls 2 308 1
perf_event 12 308 1
net_prio 2 308 1
hugetlb 3 308 1
pids 8 310 1
rdma 11 1 1
misc 9 1 1
// 與上面/proc/cgroups的輸出是一致的。
[root@10 ~]# find /sys/fs/cgroup/cpu/ -type d | wc -l
310
[root@10 ~]# find /sys/fs/cgroup/blkio/ -type d | wc -l
310
查看進(jìn)程的所有cgroup信息
內(nèi)核函數(shù)入口 :proc_cgroup_show
root@iZt4n1u8u50jg1r5n6myn2Z:~# cat /proc/38538/cgroup
12:net_cls,net_prio:/
11:devices:/system.slice/ssh.service
10:hugetlb:/
9:rdma:/
8:memory:/system.slice/ssh.service
7:pids:/system.slice/ssh.service
6:blkio:/system.slice/ssh.service
5:cpuset:/
4:freezer:/
3:cpu,cpuacct:/system.slice/ssh.service
2:perf_event:/
1:name=systemd:/system.slice/ssh.service
0::/system.slice/ssh.service
kubelet使用cgroup的坑
宿主機(jī)上除了跑pod的應(yīng)用,還有其他系統(tǒng)組件,如sshd,kubelet,docker,containerd等服務(wù),且系統(tǒng)組件的優(yōu)先級(jí)應(yīng)該比pod應(yīng)用更高,所以可以通過kubelet的資源預(yù)留功能為系統(tǒng)組件預(yù)留一部分的cpu和memory資源。既可以為system預(yù)留資源,也可以單獨(dú)為kubelet應(yīng)用預(yù)留資源,這里只以system預(yù)留為例說明。
- systemReserved 配置為系統(tǒng)組件的預(yù)留資源,cpu和memory
- systemReservedCgroup 配置預(yù)留資源的cgroup路徑
- enforceNodeAllocatable 這里要配置上pods,systemReserved,高版本的kubernetes,如果這里不加上pods這個(gè)配置項(xiàng),將導(dǎo)致預(yù)留項(xiàng)不生效。
驗(yàn)證cgroup預(yù)留資源是否生效的方法也很簡(jiǎn)單,以memory為例,kubepods的memorylimit + system的memorylimt = 宿主機(jī)的memory即表明預(yù)留資源生效。
cgroupv2
眾所周知,cgroupv1無法限制bufferio的寫入。下面將演示如何啟用cgroupv2以及使用cgroupv2限制bufferio的寫入。從使用體驗(yàn)上,cgroupv2比cgroupv1更簡(jiǎn)單。
關(guān)閉cgroupv1的內(nèi)核入口函數(shù) __setup("cgroup_no_v1=", cgroup_no_v1);
// 關(guān)閉cgroupv1
root@iZt4n1u8u50jg1r5n6myn2Z:~/lugl# cat /boot/grub/grub.cfg | grep cgroup
linux /boot/vmlinuz-5.4.0-91-generic root=UUID=12e5697d-887b-4790-a160-75cf814081a6 ro vga=792 console=tty0 console=ttyS0,115200n8 net.ifnames=0 noibrs quiet cgroup_no_v1=all
// 創(chuàng)建cgroup
root@iZt4n1u8u50jg1r5n6myn2Z:~/lugl# mkdir /sys/fs/cgroup/unified/iotest
// 使能io + memory
root@iZt4n1u8u50jg1r5n6myn2Z:~/lugl# echo "+io +memory" > /sys/fs/cgroup/unified/cgroup.subtree_control
// 將當(dāng)前進(jìn)程挪到iotest的cgroup中
root@iZt4n1u8u50jg1r5n6myn2Z:~/lugl# echo $$ >/sys/fs/cgroup/unified/iotest/cgroup.procs
// 設(shè)置最大寫入速度10M/s
root@iZt4n1u8u50jg1r5n6myn2Z:~/lugl# echo "252:0 wbps=10485760" > /sys/fs/cgroup/unified/iotest/io.max
root@iZt4n1u8u50jg1r5n6myn2Z:~/lugl# fio -iodepth=1 -rw=write -ioengine=libaio -bs=4k -size=300M -numjobs=1 -name=./fio.test
./fio.test: (g=0): rw=write, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) 4096B-4096B, ioengine=libaio, iodepth=1
fio-3.16
Starting 1 process
Jobs: 1 (f=1): [W(1)][47.8%][w=11.4MiB/s][w=2928 IOPS][eta 00m:12s]