docker如何利用cgroup對容器資源進(jìn)行限制

同步文件:https://blog.haohtml.com/archives/29974

在容器里有兩個非常重要的概念,一個是namespace,用來進(jìn)行對容器里所有進(jìn)程的隔離;另一個就是cgroup,用來對容器資源進(jìn)行限制。那cgroup又是如何實(shí)現(xiàn)對進(jìn)行資源的限制呢,今天我們來了解一下它的實(shí)現(xiàn)原理。

什么是cgroup

cgroup 是 Control Groups 的縮寫,是 Linux 內(nèi)核提供的一種可以限制、記錄、隔離 進(jìn)程組 所使用的物理資源(如 cpu、memory、磁盤IO等等) 的機(jī)制,被 LXC、docker 等很多項(xiàng)目用于實(shí)現(xiàn)進(jìn)程資源控制。cgroup 將任意進(jìn)程進(jìn)行分組化管理的 Linux 內(nèi)核功能。
cgroup 本身是提供將進(jìn)程進(jìn)行分組化管理的功能和接口的基礎(chǔ)結(jié)構(gòu),I/O 或內(nèi)存的分配控制等具體的資源管理功能是通過這個功能來實(shí)現(xiàn)的。 一定要切記,這里的限制單元為進(jìn)程組,而不是進(jìn)程。

子系統(tǒng)

上面這些具體的資源管理功能統(tǒng)稱為 cgroup 子系統(tǒng),所有子系統(tǒng)列表可以通過 cat /proc/cgroups 命令查看,主要有以下幾大子系統(tǒng):

# cat /proc/cgroups
#subsys_name    hierarchy   num_cgroups enabled
cpuset          4           7           1
cpu             2           89          1
cpuacct         2           89          1
blkio           3           86          1
memory          7           150         1
devices         6           84          1
freezer         5           7           1
net_cls         10          7           1
perf_event      12          7           1
net_prio        10          7           1
hugetlb         8           7           1
pids            9           94          1
rdma            11          1           1

子系統(tǒng)功能

  • cpuset:若是是多核心的CPU, 這個子系統(tǒng)會為cgroup 任務(wù)分配單獨(dú)的CPU和內(nèi)存。
  • cpu:使用調(diào)度程序?yàn)閏group任務(wù)提供CPU的訪問。
  • cpuacct:產(chǎn)生cgroup, 任務(wù)的CPU資源報(bào)告
  • blkio:設(shè)置限制每一個塊設(shè)備的輸入輸出控制。例如:磁盤,光盤以及usb 等等。
  • memory: 設(shè)置每一個cgroup 的內(nèi)存限制以及產(chǎn)生內(nèi)存資源報(bào)告。
  • devices:容許或拒絕cgroup任務(wù)對設(shè)備的訪問。
  • freezer:暫停和恢復(fù)cgroup任務(wù)。
  • net_cls: 標(biāo)記每一個網(wǎng)絡(luò)包以供cgroup 方便使用。
  • ns:命名空間子系統(tǒng),能夠設(shè)置一個子系統(tǒng)的上限配額。
  • perf_event: 增加了對每一個group 的監(jiān)測跟蹤的能力,能夠監(jiān)測屬于某個特定的group 的全部線程以及運(yùn)行在特定,監(jiān)控能力超出限制則進(jìn)行終止。
  • net_prio 設(shè)置cgroup中進(jìn)程產(chǎn)生的網(wǎng)絡(luò)流量的優(yōu)先級
  • hugetlb 限制使用的內(nèi)存頁數(shù)量
  • pids 限制任務(wù)的數(shù)量

目前 docker 只是用了其中一部分子系統(tǒng),實(shí)現(xiàn)對資源配額和使用的控制。如可以使用 freezer 子系統(tǒng)對 進(jìn)行組 進(jìn)行掛起和恢復(fù)。

cgroup組件術(shù)語

  • task:在cgroup中,任務(wù)就是系統(tǒng)的一個進(jìn)程
  • subsystem:一個子系統(tǒng)就是一個資源控制器,比如 cpu 子系統(tǒng)就是控制 cpu 時間分配的一個控制器。子系統(tǒng)必須附加(attach)到一個層級上才能起作用,一個子系統(tǒng)附加到某個層級以后,這個層級上的所有控制族群都受到這個子系統(tǒng)的控制。
  • control group:控制族群就是按照某種標(biāo)準(zhǔn)劃分的進(jìn)程。Cgroups 中的資源控制都是以控制族群為單位實(shí)現(xiàn)。一個進(jìn)程可以加入到某個控制族群,也從一個進(jìn)程組遷移到另一個控制族群。一個進(jìn)程組的進(jìn)程可以使用 cgroups 以控制族群為單位分配的資源,同時受到 cgroups 以控制族群為單位設(shè)定的限制;
  • hierarchy:樹形結(jié)構(gòu)的 CGroup 層級,每個子 CGroup 節(jié)點(diǎn)會繼承父 CGroup 節(jié)點(diǎn)的子系統(tǒng)配置,每個 Hierarchy 在初始化時會有默認(rèn)的 CGroup(Root CGroup);
    控制族群可以組織成 hierarchical 的形式,既一顆控制族群樹。控制族群樹上的子節(jié)點(diǎn)控制族群是父節(jié)點(diǎn)控制族群的孩子,繼承父控制族群的特定的屬性。比如一組task進(jìn)程通過cgroup1限制了CPU使用率,然后其中一個日志進(jìn)程還需要限制磁盤IO,為了避免限制磁盤IO影響到其他進(jìn)程,就可以創(chuàng)建cgroup2,使其繼承cgroup1并限制磁盤IO,這樣這樣cgroup2便繼承了cgroup1中對CPU使用率的限制并且添加了磁盤IO的限制而不影響到cgroup1中的其他進(jìn)程;

組件關(guān)系

遵循原則:

  • 每次在系統(tǒng)中創(chuàng)建新層級時,該系統(tǒng)中的所有任務(wù)都是那個層級的默認(rèn) cgroup(我們稱之為 root cgroup,此 cgroup 在創(chuàng)建層級時自動創(chuàng)建,后面在該層級中創(chuàng)建的 cgroup 都是此 cgroup 的后代)的初始成員;
  • 一個 subsystem 最多只能附加到一個層級 hierarchy;
  • 一個層級 hierarchy 可以附加多個子系統(tǒng) subsystem;
  • 一個任務(wù) task 可以是多個 cgroup 的成員,但是這些 cgroup 必須在不同的層級hierarchy;
    系統(tǒng)中的進(jìn)程(任務(wù))創(chuàng)建子進(jìn)程(任務(wù))時,該子任務(wù)自動成為其父進(jìn)程所在 cgroup 的成員。然后可根據(jù)需要將該子任務(wù)移動到不同的 cgroup 中,但開始時它總是繼承其父任務(wù)的 cgroup。
  • 一個進(jìn)程fork出子進(jìn)程時,該子進(jìn)程默認(rèn)自動成為父進(jìn)程所在的cgroup的成員,也可以根據(jù)情況將其移動到到不同的cgroup中.

如圖所示,CPU 和 Memory 兩個子系統(tǒng)有自己獨(dú)立的層級系統(tǒng),而又通過 Task Group 取得關(guān)聯(lián)關(guān)系

關(guān)聯(lián)圖
CGroup 典型應(yīng)用架構(gòu)圖

CGroup 技術(shù)可以被用來在操作系統(tǒng)底層限制物理資源,起到 Container 的作用。上圖中每一個 JVM 進(jìn)程對應(yīng)一個 Container Cgroup 層級,通過 CGroup 提供的各類子系統(tǒng),可以對每一個 JVM 進(jìn)程對應(yīng)的線程級別進(jìn)行物理限制,這些限制包括 CPU、內(nèi)存等等許多種類的資源。

cgroup實(shí)戰(zhàn)

在 Linux 中,cgroups 給用戶暴露出來的操作接口是文件系統(tǒng),即它以文件和目錄的方式組織在操作系統(tǒng)的 /sys/fs/cgroup 路徑下。在 Ubuntu 16.04 機(jī)器里,可以用 mount 指令把它們展示出來:

$ mount -t cgroup
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,name=systemd)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct)
cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb)
cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,net_cls,net_prio)
cgroup on /sys/fs/cgroup/rdma type cgroup (rw,nosuid,nodev,noexec,relatime,rdma)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)

它的輸出是一些文件系統(tǒng)目錄,這些目錄名就是當(dāng)前系統(tǒng)所支持的子系統(tǒng),這些子系統(tǒng)都在 /sys/fs/cgroup/目錄內(nèi),如對于cpu子系統(tǒng)來說,相關(guān)的幾個配置文件為

$ ls /sys/fs/cgroup/cpu
aegis                  cgroup.procs          cpu.cfs_quota_us  cpuacct.stat       cpuacct.usage_percpu       cpuacct.usage_sys   kubepods.slice     system.slice  user.slice
assist                 cgroup.sane_behavior  cpu.shares        cpuacct.usage      cpuacct.usage_percpu_sys   cpuacct.usage_user  notify_on_release  tasks
cgroup.clone_children  cpu.cfs_period_us     cpu.stat          cpuacct.usage_all  cpuacct.usage_percpu_user  init.scope          release_agent      test

其中 cpu.cfs_quota_uscpu.cfs_period_us 是經(jīng)常使用的兩個配置項(xiàng),兩者必須組合使用,表示一個進(jìn)程組在 cpu.cfs_period_us 段時間內(nèi),分配給CPU的時間比例為 cpu.cfs_quota_us

另外輸出結(jié)果中包含一些子目錄,如 aegis、assist、kubepods.slice、system.slice、user.slice、test 和 init.scope。

現(xiàn)在我們看下這些子系統(tǒng)配置文件如何使用,首先我們在 /sys/fs/cgroup/cpu/ 目錄下創(chuàng)建一個目錄 mycontainer,這個目錄稱為cgroup,即"控制組"。

$ cd /sys/fs/cgroup/cpu/
$ mkdir mycontainer
$ sys/fs/cgroup/cpu# ls mycontainer/
cgroup.clone_children  cpu.cfs_period_us  cpu.shares  cpu.uclamp.max  cpuacct.stat   cpuacct.usage_all     cpuacct.usage_percpu_sys   cpuacct.usage_sys   notify_on_release
cgroup.procs           cpu.cfs_quota_us   cpu.stat    cpu.uclamp.min  cpuacct.usage  cpuacct.usage_percpu  cpuacct.usage_percpu_user  cpuacct.usage_user  tasks

會發(fā)現(xiàn)mycontainer目錄時會自動出現(xiàn)一些cpu配置文件,有些配置文件內(nèi)容為-1,表示不限制,其中tasks文件里表示要控制的進(jìn)程pid。
我們現(xiàn)在做個實(shí)現(xiàn)執(zhí)行一下死循環(huán)腳本,便其完全占用CPU達(dá)到100%,然后再對此PID進(jìn)行CPU限制,看下效果如果。

$ while : ; do : ; done &
[1] 1626025

執(zhí)行top查看

PID     USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1626025 root      20   0   12724   1768      0 R 100.0   0.0   0:28.60 bash

發(fā)現(xiàn)這個進(jìn)程的CPU已經(jīng)達(dá)到了100%,下面我們對其進(jìn)行一下限制。先將進(jìn)程PID寫到 mycontainer 控制組下的tasks文件里,然后限制cpu使用率

$ echo 1626025 > /sys/fs/cgroup/cpu/mycontainer/tasks
$ cat /sys/fs/cgroup/cpu/mycontainer/tasks
1626025

現(xiàn)在我們已成功將其進(jìn)程號寫入tasks文件。上面我們提到過對cpu的限制主要使用兩個文件,分別為cpu.cfs_quota_us 和 cpu.cfs_quota_us, 先看一下他們的默認(rèn)值。

$ cat /sys/fs/cgroup/cpu/mycontainer/cpu.cfs_quota_us 
-1
$ cat /sys/fs/cgroup/cpu/mycontainer/cpu.cfs_period_us 
100000

表示在100ms內(nèi)分配給cpu的機(jī)會為不限制,也就是表示100%的資源。我們要做一下限制,讓其在100ms時間內(nèi),只分配給 20% 的cpu機(jī)會

$ echo 20000 > /sys/fs/cgroup/cpu/mycontainer/cpu.cfs_quota_us

然后再執(zhí)行一下top命令發(fā)現(xiàn)cpu使用率立即降下來了,最多為20%左右,可能會有一點(diǎn)點(diǎn)的超出,這個很正常。

PID     USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1626025 root      20   0   12724   1768      0 R  20.0   0.0  12:43.38 bash

這里我們只對cpu做了限制,你也可以做內(nèi)在memory做一下限制,由于這里的腳本只會占用cpu,所以不再演示。對于我們經(jīng)常使用docker run 命令啟動一個容器的時候,其實(shí)都有一個配置參數(shù)與配置文件相對應(yīng),如

$ docker run -it --cpu-period=100000 --cpu-quota=20000 ubuntu /bin/bash

如果你到容器目錄查看配置文件會發(fā)現(xiàn)相應(yīng) cpu.cfs_period_us 和 cpu.vfs_quota_us 的值都已被修改。

參考鏈接

https://blog.csdn.net/xwy9526/article/details/110594876
http://edsionte.com/techblog/archives/4322
https://www.cnblogs.com/plxx/p/5129245.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容