本文將建立並掛載一顆不和任何subsystem綁定的cgroup樹,用來演示怎麼建立、刪除子cgroup,以及如何往cgroup中添加和刪除進程。shell
因爲不和任何subsystem綁定,因此這棵樹沒有任何實際的功能,但這不影響咱們的演示,還有一個好處就是咱們不會受subsystem功能的影響,能夠將精力集中在cgroup樹上。ubuntu
本篇全部例子都在ubuntu-server-x86_64 16.04下執行經過bash
開始使用cgroup前須要先掛載cgroup樹,下面先看看如何掛載一顆cgroup樹,而後再查看其根目錄下生成的文件線程
#準備須要的目錄 dev@ubuntu:~$ mkdir cgroup && cd cgroup dev@ubuntu:~/cgroup$ mkdir demo #因爲name=demo的cgroup樹不存在,因此係統會建立一顆新的cgroup樹,而後掛載到demo目錄 dev@ubuntu:~/cgroup$ sudo mount -t cgroup -o none,name=demo demo ./demo #掛載點所在目錄就是這顆cgroup樹的root cgroup,在root cgroup下面,系統生成了一些默認文件 dev@ubuntu:~/cgroup$ ls ./demo/ cgroup.clone_children cgroup.procs cgroup.sane_behavior notify_on_release release_agent tasks #cgroup.procs裏包含系統中的全部進程 dev@ubuntu:~/cgroup$ wc -l ./demo/cgroup.procs 131 ./demo/cgroup.procs
下面是每一個文件的含義:日誌
cgroup.clone_children
這個文件只對cpuset(subsystem)有影響,當該文件的內容爲1時,新建立的cgroup將會繼承父cgroup的配置,即從父cgroup裏面拷貝配置文件來初始化新cgroup,能夠參考這裏code
cgroup.procs
當前cgroup中的全部進程ID,系統不保證ID是順序排列的,且ID有可能重複server
notify_on_release
該文件的內容爲1時,當cgroup退出時(再也不包含任何進程和子cgroup),將調用release_agent裏面配置的命令。新cgroup被建立時將默認繼承父cgroup的這項配置。進程
release_agent
裏面包含了cgroup退出時將會執行的命令,系統調用該命令時會將相應cgroup的相對路徑看成參數傳進去。 注意:這個文件只會存在於root cgroup下面,其餘cgroup裏面不會有這個文件。rem
tasks
當前cgroup中的全部線程ID,系統不保證ID是順序排列的
後面在介紹如何往cgroup中添加進程時會介紹cgroup.procs和tasks的差異。
掛載好上面的cgroup樹以後,就能夠在裏面建子cgroup了
#建立子cgroup很簡單,新建一個目錄就能夠了 dev@ubuntu:~/cgroup$ cd demo dev@ubuntu:~/cgroup/demo$ sudo mkdir cgroup1 #在新建立的cgroup裏面,系統默認也生成了一些文件,這些文件的意義和root cgroup裏面的同樣 dev@ubuntu:~/cgroup/demo$ ls cgroup1/ cgroup.clone_children cgroup.procs notify_on_release tasks #新建立的cgroup裏沒有任何進程和線程 dev@ubuntu:~/cgroup/demo$ wc -l cgroup1/cgroup.procs 0 cgroup1/cgroup.procs dev@ubuntu:~/cgroup/demo$ wc -l cgroup1/tasks 0 cgroup1/tasks #每一個cgroup均可以建立本身的子cgroup,因此咱們也能夠在cgroup1裏面建立子cgroup dev@ubuntu:~/cgroup/demo$ sudo mkdir cgroup1/cgroup11 dev@ubuntu:~/cgroup/demo$ ls cgroup1/cgroup11 cgroup.clone_children cgroup.procs notify_on_release tasks #刪除cgroup也很簡單,刪除掉相應的目錄就能夠了 dev@ubuntu:~/cgroup/demo$ sudo rmdir cgroup1/ rmdir: failed to remove 'cgroup1/': Device or resource busy #這裏刪除cgroup1失敗,是由於它裏面包含了子cgroup,因此不能刪除, #若是cgroup1包含有進程或者線程,也會刪除失敗 #先刪除cgroup11,再刪除cgroup1就能夠了 dev@ubuntu:~/cgroup/demo$ sudo rmdir cgroup1/cgroup11/ dev@ubuntu:~/cgroup/demo$ sudo rmdir cgroup1/
建立新的cgroup後,就能夠往裏面添加進程了。注意下面幾點:
在一顆cgroup樹裏面,一個進程必需要屬於一個cgroup。
新建立的子進程將會自動加入父進程所在的cgroup。
從一個cgroup移動一個進程到另外一個cgroup時,只要有目的cgroup的寫入權限就能夠了,系統不會檢查源cgroup裏的權限。
用戶只能操做屬於本身的進程,不能操做其餘用戶的進程,root帳號除外。
#--------------------------第一個shell窗口---------------------- #建立一個新的cgroup dev@ubuntu:~/cgroup/demo$ sudo mkdir test dev@ubuntu:~/cgroup/demo$ cd test #將當前bash加入到上面新建立的cgroup中 dev@ubuntu:~/cgroup/demo/test$ echo $$ 1421 dev@ubuntu:~/cgroup/demo/test$ sudo sh -c 'echo 1421 > cgroup.procs' #注意:一次只能往這個文件中寫一個進程ID,若是須要寫多個的話,須要屢次調用這個命令 #--------------------------第二個shell窗口---------------------- #從新打開一個shell窗口,避免第一個shell裏面運行的命令影響輸出結果 #這時能夠看到cgroup.procs裏面包含了上面的第一個shell進程 dev@ubuntu:~/cgroup/demo/test$ cat cgroup.procs 1421 #--------------------------第一個shell窗口---------------------- #回到第一個窗口,運行top命令 dev@ubuntu:~/cgroup/demo/test$ top #這裏省略輸出內容 #--------------------------第二個shell窗口---------------------- #這時再在第二個窗口查看,發現top進程自動和它的父進程(1421)屬於同一個cgroup dev@ubuntu:~/cgroup/demo/test$ cat cgroup.procs 1421 16515 dev@ubuntu:~/cgroup/demo/test$ ps -ef|grep top dev 16515 1421 0 04:02 pts/0 00:00:00 top dev@ubuntu:~/cgroup/demo/test$ #在一顆cgroup樹裏面,一個進程必需要屬於一個cgroup, #因此咱們不能憑空從一個cgroup裏面刪除一個進程,只能將一個進程從一個cgroup移到另外一個cgroup, #這裏咱們將1421移動到root cgroup dev@ubuntu:~/cgroup/demo/test$ sudo sh -c 'echo 1421 > ../cgroup.procs' dev@ubuntu:~/cgroup/demo/test$ cat cgroup.procs 16515 #移動1421到另外一個cgroup以後,它的子進程不會隨着移動 #--------------------------第一個shell窗口---------------------- ##回到第一個shell窗口,進行清理工做 #先用ctrl+c退出top命令 dev@ubuntu:~/cgroup/demo/test$ cd .. #而後刪除建立的cgroup dev@ubuntu:~/cgroup/demo$ sudo rmdir test
上面咱們都是用sudo(root帳號)來操做的,但實際上普通帳號也能夠操做cgroup
#建立一個新的cgroup,並修改他的owner dev@ubuntu:~/cgroup/demo$ sudo mkdir permission dev@ubuntu:~/cgroup/demo$ sudo chown -R dev:dev ./permission/ #1421原來屬於root cgroup,雖然dev沒有root cgroup的權限,但仍是能夠將1421移動到新的cgroup下, #說明在移動進程的時候,系統不會檢查源cgroup裏的權限。 dev@ubuntu:~/cgroup/demo$ echo 1421 > ./permission/cgroup.procs #因爲dev沒有root cgroup的權限,再把1421移回root cgroup失敗 dev@ubuntu:~/cgroup/demo$ echo 1421 > ./cgroup.procs -bash: ./cgroup.procs: Permission denied #找一個root帳號的進程 dev@ubuntu:~/cgroup/demo$ ps -ef|grep /lib/systemd/systemd-logind root 839 1 0 01:52 ? 00:00:00 /lib/systemd/systemd-logind #由於該進程屬於root,dev沒有操做它的權限,因此將該進程加入到permission中失敗 dev@ubuntu:~/cgroup/demo$ echo 839 >./permission/cgroup.procs -bash: echo: write error: Permission denied #只能由root帳號添加 dev@ubuntu:~/cgroup/demo$ sudo sh -c 'echo 839 >./permission/cgroup.procs' #dev還能夠在permission下建立子cgroup dev@ubuntu:~/cgroup/demo$ mkdir permission/c1 dev@ubuntu:~/cgroup/demo$ ls permission/c1 cgroup.clone_children cgroup.procs notify_on_release tasks #清理 dev@ubuntu:~/cgroup/demo$ sudo sh -c 'echo 839 >./cgroup.procs' dev@ubuntu:~/cgroup/demo$ sudo sh -c 'echo 1421 >./cgroup.procs' dev@ubuntu:~/cgroup/demo$ rmdir permission/c1 dev@ubuntu:~/cgroup/demo$ sudo rmdir permission
上面提到cgroup.procs包含的是進程ID, 而tasks裏面包含的是線程ID,那麼他們有什麼區別呢?
#建立兩個新的cgroup用於演示 dev@ubuntu:~/cgroup/demo$ sudo mkdir c1 c2 #爲了便於操做,先給root帳號設置一個密碼,而後切換到root帳號 dev@ubuntu:~/cgroup/demo$ sudo passwd root dev@ubuntu:~/cgroup/demo$ su root root@ubuntu:/home/dev/cgroup/demo# #系統中找一個有多個線程的進程 root@ubuntu:/home/dev/cgroup/demo# ps -efL|grep /lib/systemd/systemd-timesyncd systemd+ 610 1 610 0 2 01:52 ? 00:00:00 /lib/systemd/systemd-timesyncd systemd+ 610 1 616 0 2 01:52 ? 00:00:00 /lib/systemd/systemd-timesyncd #進程610有兩個線程,分別是610和616 #將616加入c1/cgroup.procs root@ubuntu:/home/dev/cgroup/demo# echo 616 > c1/cgroup.procs #因爲cgroup.procs存放的是進程ID,因此這裏看到的是616所屬的進程ID(610) root@ubuntu:/home/dev/cgroup/demo# cat c1/cgroup.procs 610 #從tasks中的內容能夠看出,雖然只往cgroup.procs中加了線程616, #但系統已經將這個線程所屬的進程的全部線程都加入到了tasks中, #說明如今整個進程的全部線程已經處於c1中了 root@ubuntu:/home/dev/cgroup/demo# cat c1/tasks 610 616 #將616加入c2/tasks中 root@ubuntu:/home/dev/cgroup/demo# echo 616 > c2/tasks #這時咱們看到雖然在c1/cgroup.procs和c2/cgroup.procs裏面都有610, #但c1/tasks和c2/tasks中包含了不一樣的線程,說明這個進程的兩個線程分別屬於不一樣的cgroup root@ubuntu:/home/dev/cgroup/demo# cat c1/cgroup.procs 610 root@ubuntu:/home/dev/cgroup/demo# cat c1/tasks 610 root@ubuntu:/home/dev/cgroup/demo# cat c2/cgroup.procs 610 root@ubuntu:/home/dev/cgroup/demo# cat c2/tasks 616 #經過tasks,咱們能夠實現線程級別的管理,但一般狀況下不會這麼用, #而且在cgroup V2之後,將再也不支持該功能,只能以進程爲單位來配置cgroup #清理 root@ubuntu:/home/dev/cgroup/demo# echo 610 > ./cgroup.procs root@ubuntu:/home/dev/cgroup/demo# rmdir c1 root@ubuntu:/home/dev/cgroup/demo# rmdir c2 root@ubuntu:/home/dev/cgroup/demo# exit exit
當一個cgroup裏沒有進程也沒有子cgroup時,release_agent將被調用來執行cgroup的清理工做。
#建立新的cgroup用於演示 dev@ubuntu:~/cgroup/demo$ sudo mkdir test #先enable release_agent dev@ubuntu:~/cgroup/demo$ sudo sh -c 'echo 1 > ./test/notify_on_release' #而後建立一個腳本/home/dev/cgroup/release_demo.sh, #通常狀況下都會利用這個腳本執行一些cgroup的清理工做,但咱們這裏爲了演示簡單,僅僅只寫了一條日誌到指定文件 dev@ubuntu:~/cgroup/demo$ cat > /home/dev/cgroup/release_demo.sh << EOF #!/bin/bash echo \$0:\$1 >> /home/dev/release_demo.log EOF #添加可執行權限 dev@ubuntu:~/cgroup/demo$ chmod +x ../release_demo.sh #將該腳本設置進文件release_agent dev@ubuntu:~/cgroup/demo$ sudo sh -c 'echo /home/dev/cgroup/release_demo.sh > ./release_agent' dev@ubuntu:~/cgroup/demo$ cat release_agent /home/dev/cgroup/release_demo.sh #往test裏面添加一個進程,而後再移除,這樣就會觸發release_demo.sh dev@ubuntu:~/cgroup/demo$ echo $$ 27597 dev@ubuntu:~/cgroup/demo$ sudo sh -c 'echo 27597 > ./test/cgroup.procs' dev@ubuntu:~/cgroup/demo$ sudo sh -c 'echo 27597 > ./cgroup.procs' #從日誌能夠看出,release_agent被觸發了,/test是cgroup的相對路徑 dev@ubuntu:~/cgroup/demo$ cat /home/dev/release_demo.log /home/dev/cgroup/release_demo.sh:/test
本文介紹瞭如何操做cgroup,因爲沒有和任何subsystem關聯,因此在這顆樹上的全部操做都沒有實際的功能,不會對系統有影響。從下一篇開始,將介紹具體的subsystem。