淺談Cgroups
在開發(fā)一款軟件時,為了延長軟件的生命周期,需要一款配套軟件來對發(fā)布的軟件進(jìn)行監(jiān)控。隨著容器技術(shù)的成熟,系統(tǒng)的定制和軟件的打包變得越來越容易,同時,對容器進(jìn)行監(jiān)控成為了容器使用者所必備的技能。下來,作者將帶領(lǐng)大家認(rèn)識一下容器的資源管理工具Cgroups。
說起容器監(jiān)控,首先會想到通過Cadvisor, Docker stats等多種方式獲取容器的監(jiān)控數(shù)據(jù),并同時會想到容器通過Cgroups實(shí)現(xiàn)對容器中的資源進(jìn)行限制。但是這些數(shù)據(jù)來自哪里,并且如何計算的?答案是Cgroups。最近在寫docker容器監(jiān)控組件,在深入Cadvisor和Docker stats源碼發(fā)現(xiàn)數(shù)據(jù)都來源于Cgroups。了解之余,并對Cgroups做下筆記。
一、Cgroups介紹
Cgroups 是 control groups 的縮寫,是Linux內(nèi)核提供的一種可以限制,記錄,隔離進(jìn)程組(process groups)所使用物理資源的機(jī)制。最初有g(shù)oogle工程師提出,后來被整合進(jìn)Linux的內(nèi)核。因此,Cgroups為容器實(shí)現(xiàn)虛擬化提供了基本保證,是構(gòu)建Docker,LXC等一系列虛擬化管理工具的基石。
二、Cgroups作用
- 資源限制(Resource limiting): Cgroups可以對進(jìn)程組使用的資源總額進(jìn)行限制。如對特定的進(jìn)程進(jìn)行內(nèi)存使用上限限制,當(dāng)超出上限時,會觸發(fā)OOM。
- 優(yōu)先級分配(Prioritization): 通過分配的CPU時間片數(shù)量及硬盤IO帶寬大小,實(shí)際上就相當(dāng)于控制了進(jìn)程運(yùn)行的優(yōu)先級。
- 資源統(tǒng)計(Accounting): Cgroups可以統(tǒng)計系統(tǒng)的資源使用量,如CPU使用時長、內(nèi)存用量等等,這個功能非常適用于計費(fèi)。
- 進(jìn)程控制(ControlCgroups): 可以對進(jìn)程組執(zhí)行掛起、恢復(fù)等操作。
三、Cgroups 組成
Cgroups主要由task,cgroup,subsystem及hierarchy構(gòu)成。下面分別介紹下各自的概念。
- task::在Cgroups中,task就是系統(tǒng)的一個進(jìn)程。
- cgroup: :Cgroups中的資源控制都以cgroup為單位實(shí)現(xiàn)的。cgroup表示按照某種資源控制標(biāo)準(zhǔn)劃分而成的任務(wù)組,包含一個或多個子系統(tǒng)。一個任務(wù)可以加入某個cgroup,也可以從某個cgroup遷移到另外一個cgroup。
- subsystem::Cgroups中的subsystem就是一個資源調(diào)度控制器(Resource Controller)。比如CPU子系統(tǒng)可以控制CPU時間分配,內(nèi)存子系統(tǒng)可以限制cgroup內(nèi)存使用量。
- hierarchy::hierarchy由一系列cgroup以一個樹狀結(jié)構(gòu)排列而成,每個hierarchy通過綁定對應(yīng)的subsystem進(jìn)行資源調(diào)度。hierarchy中的cgroup節(jié)點(diǎn)可以包含零或多個子節(jié)點(diǎn),子節(jié)點(diǎn)繼承父節(jié)點(diǎn)的屬性。整個系統(tǒng)可以有多個hierarchy。
組件之間的關(guān)系:
Subsystems, Hierarchies,Control Group和Tasks之間有許多的規(guī)則,下面介紹下:
(1) 同一個hierarchy能夠附加一個或多個subsystem。
如下圖,將cpu和memory subsystems(或者任意多個subsystems)附加到同一個hierarchy。
(2) 一個subsystem只能附加到一個hierarchy上。
如下圖,cpu subsystem已經(jīng)附加到了hierarchy A,并且memory subsystem已經(jīng)附加到了hierarchy B。因此cpusubsystem不能在附加到hierarchy B。
(3) 系統(tǒng)每次新建一個hierarchy時,該系統(tǒng)上的所有task默認(rèn)構(gòu)成了這個新建的hierarchy的初始化cgroup,這個cgroup也稱為root cgroup。對于你創(chuàng)建的每個hierarchy,task只能存在于其中一個cgroup中,即一個task不能存在于同一個hierarchy的不同cgroup中,但是一個task可以存在在不同hierarchy中的多個cgroup中。如果操作時把一個task添加到同一個hierarchy中的另一個cgroup中,則會從第一個cgroup中移除。
如下圖,cpu和memory被附加到cpu_mem_cg的hierarchy。而net_cls被附加到net_cls hierarchy。并且httpd進(jìn)程被同時加到了cpu_mem_cg hierarchy的cg1 cgroup中和net hierarchy的cg3 cgroup中。并通過兩個hierarchy的subsystem分別對httpd進(jìn)程進(jìn)行cpu,memory及網(wǎng)絡(luò)帶寬的限制。
(4) 系統(tǒng)中的任何一個task(Linux中的進(jìn)程)fork自己創(chuàng)建一個子task(子進(jìn)程)時,子task會自動的繼承父task cgroup的關(guān)系,在同一個cgroup中,但是子task可以根據(jù)需要移到其它不同的cgroup中。父子task之間是相互獨(dú)立不依賴的。
如下圖,httpd進(jìn)程在cpu_and_mem hierarchy的/cg1 cgroup中并把PID 4537寫到該cgroup的tasks中。之后httpd(PID=4537)進(jìn)程fork一個子進(jìn)程httpd(PID=4840)與其父進(jìn)程在同一個hierarchy的統(tǒng)一個cgroup中,但是由于父task和子task之間的關(guān)系獨(dú)立不依賴的,所以子task可以移到其它的cgroup中。
四、Cgroups使用
我們直接使用shell 命令直接操作hierarchy并設(shè)置cgroup參數(shù)。在centos6上也可以直接使用libcgroup提供的工具可簡化對cgroup的使用。
(1) Create a Hierarchy
使用shell命令創(chuàng)建hierarchy并附加subsystems到該hierarchy上。 作為root為hierarchy創(chuàng)建一個mount point。并且在mount point中包含cgrou的名字。
例如:
接下來使用mount命令去掛載hierarchy并附加一個或多個subsystem到該hierarchy上。
例如:
如果想在已有的hierarchy上attch或detach subsystem,可以使用remount操作,例如我們想detach掉memory subsystem。
(2) Unmounting a Hierarchy
可以直接用umount命令來unmount一個已有的Hierarchy:
例如:
(3) Creating Control Groups
直接使用shell命令mkdir創(chuàng)建一個子cgroup:
例如:
(4) Setting Control Cgroup Parameters
在group1中使用echo命令插入0-1到cpuset.cpus,來限制該cgroup中的tasks只能跑在0和1的cpu core上。如下:
(5) Moving a Process to a Control Group
只要將想要限制的進(jìn)程PID,追加到想要的cgroup的tasks文件中就可以了。例如:將PID=1701的進(jìn)程放到“/cgroup/cpu_and_mem/group1/”的cgroup中。
五、Subsystem 介紹
- blkio: blkio 子系統(tǒng)控制并監(jiān)控cgroup中的task對塊設(shè)備的I/O的訪問。如:限制訪問及帶寬等。
- cpu: 主要限制進(jìn)程的cpu使用率。
- cpuacct: 可以統(tǒng)計cgroup中進(jìn)程的cpu使用報告。
- cpuset: 可以為cgroup中的進(jìn)程分配獨(dú)立的cpu和內(nèi)存節(jié)點(diǎn)。
- memory: 自動生成cgroup中task使用的內(nèi)存資源報告,并對該cgroup的task進(jìn)行內(nèi)存使用限制。
- devices: 可以控制進(jìn)程能否訪問某些設(shè)備。
- net_cls: 使用等級標(biāo)識符(clssid)標(biāo)記網(wǎng)絡(luò)數(shù)據(jù)包,可允許Linux流量控制程序(tc)識別從具體cgroup中生成的數(shù)據(jù)包。
- freezer: 可以掛起或回復(fù)cgroup中的進(jìn)程。
- ns: 可以使不同cgroup中的進(jìn)程使用不同的namespace。
六、容器使用Cgroups進(jìn)行資源限制
無論是使用docker run方式直接創(chuàng)建容器,還是通過各類容器編排工具(如:Kubernetes)創(chuàng)建容器,對于容器的限制本質(zhì)都是通過Cgroups。我們分別使用這兩種方式來創(chuàng)建容器并觀察cgroups:
測試環(huán)境:
1. 使用docker run方式創(chuàng)建容器
(1) 限制CPU share,創(chuàng)建兩個容器,則會在運(yùn)行該容器宿主的/sys/fs/cgroup/cpu/docker/ 下分別創(chuàng)建兩個子cgroup,格式如下。
(2) 創(chuàng)建一個容器,并設(shè)置--cpu-shares參數(shù)為:1024*10。
查看該容器cgroup的cpu.shares文件內(nèi)容如下。
(3) 創(chuàng)建一個容器,并設(shè)置--cpu-shares參數(shù)為: 1024*14。
查看該容器cgroup的cpu.shares文件內(nèi)容如下。
(4) 兩個容器使用cpu的stats,一個容器分到14核的相對cpu計算時間,另一個容器分到10核的相對cpu計算時間:
2. 限制容器內(nèi)存使用量
(1) 創(chuàng)建一個容器,限制容器能使用的內(nèi)存上限為1024M。
(2) 查看容器memory的stats,內(nèi)存使用率100%。
(3) 當(dāng)容器使用的內(nèi)存量超過1024M,則容器會被kill -9掉。
3. 使用Kubenetes容器編排工具創(chuàng)建容器
使用kubernetes編排工具創(chuàng)建的容器,則與容器關(guān)聯(lián)的cgroup均在運(yùn)行該容器宿主機(jī)的/sys/fs/cgroup/cpu/kubepods/下,具體的格式如下所示:
使用Pod創(chuàng)建一個容器,對應(yīng)的yaml文件內(nèi)容如下:
在運(yùn)行該容器的宿主機(jī)上查看該容器的cgroup信息,會觀察到cpu.shares為1核,memory.limit_in_bytes為2G。
相關(guān)文章:
- https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/resource_management_guide/ch01
- https://www.kernel.org/doc/Documentation/cgroup-v1/cgroups.txt
- http://www.infoq.com/cn/articles/docker-kernel-knowledge-cgroups-resource-isolation
【本文是51CTO專欄機(jī)構(gòu)360技術(shù)的原創(chuàng)文章,微信公眾號“360技術(shù)( id: qihoo_tech)”】