CGroup 是 Control Groups 的縮寫,是 Linux 核心提供的一種可以限制、記錄、隔離行程群組 (process
groups) 所使用的物力資源 (如 cpu memory i/o 等等) 的機制。2007 年進入 Linux 2.6.24
核心,CGroups 不是全新創造的,它將程序管理從 cpuset 中剝離出來,作者是 Google 的 Paul
Menage。CGroups 也是 LXC 為實現虛擬化所使用的資源管理手段。
檔名 | R/W | 用途 |
---|---|---|
Release_agent | RW | 刪除分組時執行的命令,這個檔案只存在於根分組 |
Notify_on_release | RW | 設定是否執行 release_agent。為 1 時執行 |
Tasks | RW | 屬於分組的執行緒 TID 列表 |
Cgroup.procs | R | 屬於分組的程序 PID 列表。僅包括多執行緒程序的執行緒 leader 的 TID,這點與 tasks 不同 |
Cgroup.event_control | RW | 監視狀態變化和分組刪除事件的組態檔 |
如圖所示的 CGroup 層級關係顯示,CPU 和 Memory 兩個子系統有自己獨立的層級系統,而又通過 Task Group 取得關聯關係。
在 cgroups 中,任務就是系統的一個程序。
控制族群(control group)。控制族群就是一組按照某種標準劃分的程序。Cgroups
中的資源控制都是以控制族群為單位實現。一個程序可以加入到某個控制族群,也從一個行程群組遷移到另一個控制族群。一個行程群組的程序可以使用
cgroups 以控制族群為單位分配的資源,同時受到 cgroups 以控制族群為單位設定的限制。層級(hierarchy)。控制族群可以組織成 hierarchical
的形式,既一顆控制族群樹。控制族群樹上的子節點控制族群是父節點控制族群的孩子,繼承父控制族群的特定的屬性。子系統(subsytem)。一個子系統就是一個資源控制器,比如 cpu 子系統就是控制 cpu
時間分配的一個控制器。子系統必須附加(attach)到一個層級上才能起作用,一個子系統附加到某個層級以後,這個層級上的所有控制族群都受到這個子系統的控制。
CPU
:使用排程程式為cgroup任務提供 CPU 的存取。cpuacct
:產生cgroup任務的 CPU 資源報告。cpuset
:如果是多核心的CPU,這個子系統會為cgroup任務分配單的CPU和記憶體。devices
:允許或拒絕cgroup任務對裝置的存取。freezer
:暫停和恢復cgroup任務。memory
:設定每個cgroup 的記憶體限制以及產生記憶體資源報告。net_cls
:標記每個網路包以供 cgroup方便使用。ns
:名稱空間子系統。perf event
:增加了對每個group的監測跟蹤的能力,可以監測屬於某個特定的group 的所有執行緒以及執行在特定CPU上的執行緒。:
[root@localhost ~]# iptables -F
[root@localhost ~]# setenforce 0
[root@localhost ~]# mkdir /opt/stress
[root@localhost ~]# vim /opt/stress/Dockerfile
FROM centos:7
MAINTAINER shuai "shuai.@tom.com"
RUN yum install -y wget
RUN wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
RUN yum install -y stress
[root@localhost ~]# cd /opt/stress/
[root@localhost stress]# docker build -t centos:stress .
[root@localhost stress]# docker images
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
centos stress 0cc400af48ae 23 hours ago 426MB
centos 7 7e6257c9f8d8 6 weeks ago 203MB
命令中的–cpu–shares引數值不能保證可以獲得個vcpu或者多少GHz的CPU資源,它僅是一個彈性的加權值
[root@localhost stress]# docker run -itd --cpu-shares 100 centos:stress
[root@localhost stress]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
84fff47241b6 centos:stress "/bin/bash" 38 seconds ago Up 37 seconds compassionate_brahmagupta
預設情況下,Docker容器的CPU份額都是1024.單獨一個容器的份額是沒有意義的,只有在同時執行多個容器時,容器的CPU加權才能能體現出來。
例如:兩個容器A、B的CPU權重份額分別是1000和500,在CPU進行時間分片分配的時候,容器A比B多一倍的機會獲得CPU的時間片.
單分配的結果取決於當時主機和其他容器的執行狀態,實際上也無法保證容器A一定能獲得cpu時間片。比如容器A的程序一直是空閒的,那麼容器B是可以獲取比容器A更多的CPU時間片的,極端情況下,列如主機上只執行了一個容器,即使它的CPU份額只有50,它也獨佔整個主機的CPU資源。
比如,啟動了兩個容器及執行檢視 CPU 使用百分比
[root@localhost stress]# docker run -itd --name cpu512 --cpu-shares 512 centos:stress stress -c 10 '//容器產生的十個函數子程序'
#進入容器使用top檢視CPU使用情況
[root@localhost stress]# docker exec -it 23bbe8182b5c bash
如圖所示
2.再開一個容器做比較
[root@localhost ~]# docker run -tid --name cpu1024 --cpu-shares 1024 centos:stress stress -c 10
[root@localhost ~]# docker ps -a
[root@localhost ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
605fc2d70557 centos:stress "stress -c 10" 3 seconds ago Up 2 seconds cpu1024
23bbe8182b5c centos:stress "stress -c 10" 5 minutes ago Up 5 minutes cpu512
#進入容器檢視top 按1檢視核心的負載
[root@localhost ~]# docker exec -it 605fc2d70557 bash #入容器使用top對比兩個容器的%CPU,比例是1:2
[root@605fc2d70557 /]# top '//檢視程序'
如圖
Docker 提供了 --cpu-period、–cpu-quota 兩個引數控制容器可以分配到的 CPU 時鐘週期。
–cpu-period :是用來指定容器對 CPU 的使用要在多長時間內做一次重新分配。
–cpu-quota :是用來指定在這個週期內,最多可以有多少時間用來跑這個容器。
與 --cpu-shares 不同的是。這種設定是指定一個絕對值,容器對 CPU 資源的使用絕對不會超過設定的值。
注意:
cpu-period 和 cpu-quota 的單位是微秒;
cpu-period 的最小值是1000微秒,最大值為1秒,預設值為0.1秒。
cpu-quota 的值預設是 -1 ,表示不做控制;
cpu-period 和 cpu-quota 引數一般聯合使用。
例如:
容器程序需要每一秒使用單個 CPU 的0.2秒時間,可以將 cpu-period 設定為 1000000(即1秒),cpu-quota
設定為 200000(0.2秒),當然,在多核情況下,如果允許容器程序完全佔有兩個 CPU,則可以將 cpu-period 設定為
100000(即0.1秒),cpu-quota 設定為 200000(0.2秒)。
[root@localhost stress]# docker run -itd --name cpushuai --cpu-period 100000 --cpu-quota 200000 centos:stress
[root@localhost stress]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5faae11dd9d1 centos:stress "/bin/bash" 5 seconds ago Up 4 seconds cpushuai
605fc2d70557 centos:stress "stress -c 10" 51 minutes ago Exited (137) About a minute ago cpu1024
23bbe8182b5c centos:stress "stress -c 10" 56 minutes ago Exited (137) About a minute ago cpu512
#進入容器
[root@localhost stress]# docker exec -it 5faae11dd9d1 bash
[root@5faae11dd9d1 /]# cat /sys/fs/cgroup/cpu/cpu.cfs_period_us
100000
[root@5faae11dd9d1 /]# cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us
200000
#檢視CPU
[root@5faae11dd9d1 cpu]# top
對於多核 CPU 的伺服器,Docker 還可以控制容器執行使用哪些 CPU 核心,即使用 --cpuset-cpus 引數。這對具有多 CPU 的伺服器尤其有用,可以對需要高效能運算的容器進行效能最優設定。
#建立容器
[root@localhost stress]# docker run -itd --name cpu02 --cpuset-cpus=0-2 centos:stress
//執行該命令(需要宿主機為四核),表示建立的容器只能使用0、1、2 三個核心。 不會影響其他核心來搶佔資源
#檢視容器列表
[root@localhost stress]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8b65ddbb9c85 centos:stress "/bin/bash" 52 seconds ago Up 51 seconds cpu02
#進入容器
[root@localhost stress]# docker exec -it 8b65ddbb9c85 bash
#檢視核心
[root@8b65ddbb9c85 /]# cat /sys/fs/cgroup/cpuset/cpuset.cpus
0-2
如圖
#容器內部的第一個程序號pid為1被繫結到指定CPU執行
[root@localhost stress]# docker exec 8b65ddbb9c85 taskset -c -p 1
pid 1's current affinity list: 0-2
如圖
[root@localhost stress]# docker exec -it 8b65ddbb9c85 bash
[root@8b65ddbb9c85 /]# stress -c 10
stress: info: [47] dispatching hogs: 10 cpu, 0 io, 0 vm, 0 hdd
通過 cpuset-cpus 引數指定容器 A 使用 CPU 核心 0,容器B 只是用 CPU 核心1;在主機上只有這兩個容器使用對應
CPU 核心的情況,它們各自佔有全部的核心資源,cpu-shares 沒有明顯效果。cpuset-cpus、cpuset-mems
引數只在多核、多記憶體節點上的伺服器上有效,並且必須與實際的物理設定匹配,否則也無法達到資源控制的目的。在系統具有多個 CPU
核心的情況下,需要通過 cpuset-cpus 引數為設定容器 CPU 核心才能方便地進行測試。
#新建容器cpu3 只使用cpu 1 權重為512
[root@localhost stress]# docker run -itd --name cpu3 --cpuset-cpus 1 --cpu-shares 512 centos:stress stress -c 1
25cffab0395c791d7467ac20433bb6c75b6e56ca6bf1df4c3e943e4eb3d63ef5
#檢視容器列表
[root@localhost stress]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
25cffab0395c centos:stress "stress -c 1" 7 seconds ago Up 6 seconds cpu3
#進入容器
[root@localhost stress]# docker exec -it 25cffab0395c bash
[root@25cffab0395c /]# top '//檢視程序 按1可以看到每個核心的佔用情況'
如圖
我們在建立一個容器做比較
#這次的權重為1024
[root@localhost ~]# docker run -itd --name cpu4 --cpuset-cpus 3 --cpu-shares 1024 centos:stress stress -c 1
[root@localhost ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2259964f13bb centos:stress "stress -c 1" 6 seconds ago Up 5 seconds cpu4
25cffab0395c centos:stress "stress -c 1" 9 minutes ago Up 9 minutes
#進入容器檢視程序
[root@localhost ~]# docker exec -it 2259964f13bb bash
[root@2259964f13bb /]# top
如圖
與作業系統類似,容器可使用的記憶體包括兩部分:實體記憶體 和 Swap;
docker 通過下面兩組引數來控制容器記憶體的使用量:
-m 或 --memory:設定記憶體的使用限額,例如 100M、1024M; –memory-swap:設定記憶體 +swap 的使用限額。 例如:執行如下命令允許該容器最多使用 200M的記憶體,300M 的swap:
[root@localhost stress]# docker run -it -m 200M --memory-swap=300M progrium/stress --vm 1 --vm-bytes 280M
Unable to find image 'progrium/stress:latest' locally
# --vm 1:啟動1個記憶體工作執行緒;
--vm-bytes 280M :每個執行緒分配280M記憶體;
如果讓工作執行緒分配的記憶體超過 300M,分配的記憶體超過限額,stress執行緒報錯,容器退出:
[root@localhost stress]# docker run -it -m 200M --memory-swap=300M progrium/stress --vm 1 --vm-bytes 310M
如圖
預設情況下,所有容器能平等地讀寫磁碟,可以通過設定 --blkio-weight 引數來改變容器 block IO 的優先順序。
–blkio-weight 與 --cpu-shares 類似,設定的是相對權重值,預設為500 在下面的例子中,容器 A
讀寫磁碟的頻寬是容器 B 的兩倍:
[root@localhost stress]# docker run -it --name container_A --blkio-weight 600 centos:stress
[root@9cae2ee0165a /]# cat /sys/fs/cgroup/blkio/blkio.weight
600
[root@localhost stress]# docker run -it --name container_B --blkio-weight 300 centos:stress
[root@6ed938c0086b /]# cat /sys/fs/cgroup/blkio/blkio.weight
300
(1)bps :是 byte per second,每秒讀寫的資料量;
(2)iops :是 io per second,每秒 IO 的次數;
(3)可以通過以下的引數來控制 bps 和 iops:
–device-read-bps:限制讀某個裝置的 bps; device-write-bps:限制寫某個裝置的 bps;
device-read-iops:限制讀某個裝置的 iops; device-write-iops:限制寫某個裝置的 iops。 例如:
[root@localhost stress]# docker run -it --device-write-bps /dev/sda:5MB centos:stress
#通過dd命令測試在容器中寫磁碟的速度。因為容器的檔案系統在host/dev/sda上的 在容器中寫檔案相當於對host/dev/sda進行寫操作。另外,oflag=direct=direct指定用direct IO方式寫檔案
[root@11993eca702e /]# dd if=/dev/zero of=test bs=1M count=1024 oflag=direct
#ctrl+c中斷
167+0 records out
175112192 bytes (175 MB) copied, 33.4011 s, 5.2 MB/s
[root@11993eca702e /]# exit
exit
#結果表明限速為5M/s左右。
#為了對比,我們不限速測試,如下
[root@localhost stress]# docker run -it centos:stress
[root@7e98a3cbc23e /]# dd if=/dev/zero of=test bs=1M count=1024 oflag=direct
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 1.01742 s, 1.1 GB/s
如圖
是不是每天更加努力一點呢?