一、Cgroup簡介
-
Cgroup 是Control Groups的縮寫,是Linux 內核提供的一種可以限制、記錄、隔離進程組所使用的物理資源(如CPU、 內存、磁盤IO等等)的機制,被LXC、docker等很多項目用於實現進程資源控制。
-
Cgroups提供了以下功能:
1、限制進程組可以使用的資源數量(Resource limiting )。比如:memory子系統可以爲進程組設定一個memory使用上限,一旦進程組使用的內存達到限額再申請內存,就會觸發OOM(out of memory)。
2、進程組的優先級控制(Prioritization )。比如:可以使用cpu子系統爲某個進程組分配特定cpu share。
3、記錄進程組使用的資源數量(Accounting )。比如:可以使用cpuacct子系統記錄某個進程組使用的cpu時間
4、進程組隔離(Isolation)。比如:使用ns子系統可以使不同的進程組使用不同的namespace,以達到隔離的目的,不同的進程組有各自的進程、網絡、文件系統掛載空間。
5、進程組控制(Control)。比如:使用freezer子系統可以將進程組掛起和恢復。
[root@master tls]# cat /proc/cgroups
#subsys_name hierarchy num_cgroups enabled
cpuset 4 1 1
cpu 6 85 1
cpuacct 6 85 1
memory 7 85 1
devices 10 85 1
freezer 9 1 1
net_cls 5 1 1
blkio 3 85 1
perf_event 8 1 1
hugetlb 11 1 1
pids 2 1 1
net_prio 5 1 1
cpuset:如果是多核心的CPU, 這個子系統會爲cgroup 任務分配單獨的CPU和內存。
CPU:使用調度程序爲cgroup任務提供CPU的訪問。
cpuacct:產生cgroup, 任務的CPU資源報告
memory: 設置每個cgroup 的內存限制以及產生內存資源報告。
devices:允許或拒絕cgroup任務對設備的訪問。
freezer:暫停和恢復cgroup任務。
net_cls: 標記每個網絡包以供cgroup 方便使用。
blkio:設置限制每個塊設備的輸入輸出控制。例如:磁盤,光盤以及usb 等等。
ns:命名空間子系統。
perf_event: 增加了對每個group 的監測跟蹤的能力,可以監測屬於某個特定的group 的所有線程以及運行在特定CPU上的線程。
二、基於Dockerfile創建安裝stress鏡像
stress是用來測試cpu內存的負載,通過在兩個容器分別執行stress -c 1,這將會給系統一個隨機負載,產生一個進程,這個進程會反覆不停地計算由rand()產生地隨機數的平方根,直到資源耗盡。
首先使用Dockerfile創建一個基於centos的stress的工具鏡像
[root@master tls]# mkdir /stress
[root@master tls]# cd /stress/
[root@master stress]# vi Dockerfile #文件內容在下圖中
//安裝鏡像
[root@master stress]# docker build -t centos:stress .
[root@master stress]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
centos stress d5b03b3a7589 2 minutes ago 466MB
nginx latest 602e111c06b6 2 days ago 127MB
centos 7 5e35e350aded 5 months ago 203MB
三、創建容器的CPU權重控制
-
默認情況下,每個docker容器的cpu份額都是1024,單獨一個容器的份額是沒有意義的,只有在同時運行多個容器時,容器cpu的加權效果才能體現出現。
-
例如,兩個容器A、B的cpu份額分別爲1000和500,在cpu進行時間片分配的時候,容器A比容器B多一倍的機會獲得cpu的時間片,但是分配的結果取決於當時主機和其他容器的運行狀態,實際上也無法保證容器A一定能夠獲得cpu的時間片。比如容器A的進程一直是空閒的,那麼容器B是可以獲取比容器A更多的cpu時間片的,極端情況下,例如主機上只運行的一個容器,即使它的cpu份額只有50,它也可以獨佔整個主機的cpu資源
-
cgroups只在容器分配的資源緊缺時,即需要對容器使用的資源進行限制時,纔會生效。因此,無法單純的根據某個容器的份額的cpu份額來確定有多少cpu資源分配給它,可以通過cpu share參數可以設置容器使用cpu的優先級,比如啓動了兩個容器及運行查看cpu的cpu的使用百分比
-
創建兩個容器,分別制定不同的權重比
// --cpu-shares 指定使用cpu的權重
// stress -c 指定產生子進程的個數
[root@master ~]# docker run -itd --name cpu512 --cpu-shares 512 centos:stress stress -c 10
[root@master ~]# docker run -itd --name cpu1024 --cpu-shares 1024 centos:stress stress -c 10
[root@master ~]# docker ps -a #查看容器
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f68bc1d06b72 centos:stress "stress -c 10" 10 seconds ago Up 8 seconds cpu1024
ab0e0020144b centos:stress "stress -c 10" 6 minutes ago Up 6 minutes cpu512
##進入容器使用top命令查看cpu的使用率
[root@master ~]# docker exec -it cpu512 bash
[root@ab0e0020144b /]# top
[root@master ~]# docker exec -it cpu1024 bash
[root@f68bc1d06b72 /]# top
分別進入cpu512和cpu1024之後可以看到,%cpu的比例差不多是1:2,符合我們設置的–cpu-shares參數。
四、cpu週期限制
- Docker提供了 --cpu-period、–cpu-quota兩個參數控制容器可以分配到cpu的時鐘週期。
// --cpu-period是用來指定容器對於cpu的使用要在多長時間內重新分配一次
// --cpu-quota是用來指定在這個週期內,最多可以有多少時間跑這個容器,
與--cpu-shares(權重)不同的是,這種配置指定一個絕對值,容器對cpu資源使用絕對不會超過配置的值。
- cpu-peiod和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秒)
//設置 --cpu-period爲0.1秒,--cpu-quota爲0.2秒
[root@master ~]# docker run -itd --cpu-period 100000 --cpu-quota 200000 centos:stress
7fc4d48428fa3fc7527e7ece2f504307f13d83414e3714aa187d86356ba596d2
[root@master ~]# docker ps -a #查看容器ID號
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7fc4d48428fa centos:stress "/bin/bash" 12 seconds ago Up 11 seconds priceless_bell
f68bc1d06b72 centos:stress "stress -c 10" 28 minutes ago Exited (137) 18 minutes ago cpu1024
ab0e0020144b centos:stress "stress -c 10" 35 minutes ago Exited (137) 18 minutes ago cpu512
[root@master ~]# docker exec -it 7fc4d48428fa bash #使用ID號進入容器
//查看容器cgroup參數
[root@7fc4d48428fa /]# cat /sys/fs/cgroup/cpu/cpu.cfs_period_us
100000
[root@7fc4d48428fa /]# cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us
200000
五、cpu core控制
- 對於多核cpu的服務器,docker還可以控制容器運行使用那些cpu內核,以及使用–cpuset-cpus參數,這對於具有多cpu服務器尤其有用,可以對需要高性能計算的容器進行性能最優的配置。
//執行以下命令需要宿主機爲雙核,表示創建的容器只能使用0、1兩個內核,最終生成cgroup的cpu內核配置如下:
[root@master ~]# docker run -itd --name cpu1 --cpuset-cpus 0-1 centos:stress
1c2e16cd9d63cf4e429b91cb41a357a91b03287234b9e123966e3871113d5ce2
[root@master ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1c2e16cd9d63 centos:stress "/bin/bash" 9 seconds ago Up 9 seconds cpu1
[root@master ~]# docker exec -it cpu1 bash
[root@1c2e16cd9d63 /]# cat /sys/fs/cgroup/cpuset/cpuset.cpus
0-1
//通過下列指令可以看到容器中進程與cpu內核的綁定關係,達到綁定cpu內核的目的
[root@master ~]# docker exec -it 1c2e16cd9d63 taskset -c -p 1 #容器內部的第一個進程號pid爲1,被綁定到指定到的cpu上運行
pid 1's current affinity list: 0,1
六、cpu配額控制參數的混合使用
- 通過cpuset-cpus參數指定容器A使用cpu內核0,容器B使用cpu內核1。
在主機上只有這個兩個容器使用對應的cpu內核情況,它們各自佔用全部的內核資源,cpu-shares沒有明顯的效果。 - cpuset-cpus、cpuset-mems參數只在多核、內存節點上服務器有效,並且必須與實際的物理配置匹配,否則也無法達到資源控制的目的。
- 在系統具有多個cpu內核的情況下,需要通過cpuset-cpus參數爲設置容器cpu內核才能方便進行測試
//宿主機系統修改爲4核心
[root@master ~]# docker run -itd --name cpu2 --cpuset-cpus 1 --cpu-shares 512 centos:stress stress -c 1
[root@master ~]# docker run -itd --name cpu3 --cpuset-cpus 3 --cpu-shares 1024 centos:stress stress -c 1
##分別進入cpu2和cpu3查看cpu使用率,有下面數據可知,cpu1和3使用率達到了100%,權重對它們沒有影響
[root@master ~]# docker exec -it cpu2 bash
[root@be8bf29e69a8 /]# top
[root@master ~]# docker exec -it cpu3 bash
[root@152fde97b135 /]# top
七、內存限制
-
與操作系統類似,容器可使用的內存包括兩部分:物理內存和swap
容器通過 -m或–memory設置內存的使用限額,例如:-m 300M;通過–memory-swap設置內存+swap的使用限額 -
實例如下,允許容器最多使用200M的內存和300M的swap
[root@master ~]# docker run -it -m 200M --memory-swap=300M progrium/stress --vm 1 --vm-bytes 280M
// --vm 1 ,代表啓動一個內存工作線程
// --vm-bytes 280 M ,代表每個線程可以分配280M內存
- 默認情況下,容器可以使用主機上的所有空閒內存。
上述配置與cpu的cgroup的配置類似,Docker會自動爲容器目錄/sys/fs/cgroup/memory/docker/<容器ID> 中創建相應的cgroup的配置文件
注:如果分配的內存超過限額,stress線程就會報錯,容器會自動退出
八、Block IO的限制
默認情況下,所有容器能平等地讀寫磁盤,可以通過設置–blkio-weight參數來改變容器block IO的優先級。
//--blkio-weight 與--cpu-shares 類似,設置的是相對權重值,默認爲500。
[root@master ~]# docker run -it --name container_A --blkio-weight 600 centos:stress #指定權重600
[root@c21c48529aed /]# cat /sys/fs/cgroup/blkio/blkio.weight
600
[root@c21c48529aed /]# exit
exit
[root@master ~]# docker run -it --name container_B --blkio-weight 300 centos:stress #指定權重值300
[root@a2a8cb6ddecc /]# cat /sys/fs/cgroup/blkio/blkio.weight
300
九、bps和iops 的限制
bps是byte per second,每秒讀寫的數據量。iops是io per second, 每秒IO的次數。
可通過以下參數控制容器的bps和iops:
--device-read-bps:限制讀某個設備的bps.
--device-write-bps:限制寫某個設備的bps.
--device-read-iops:限制讀某個設備的iops.
--device-write-iops:限制寫某個設備的iops。
下面的示例是限制容器寫/dev/sda 的速率爲5 MB/s
[root@master ~]# docker run -it --device-write-bps /dev/sda:5MB centos:stress
[root@da0e26f19149 /]# dd if=/dev/zero of=test bs=1M count=1024 oflag=direct
//按ctrl+c中斷查看
通過dd命令測試在容器中寫磁盤的速度。因爲容器的文件系統是在host /dev/sda 上的,
在容器中寫文件相當於對host /dev/sda進行寫操作。另外,oflag=direct 指定用direct IO方式寫文件,
這樣–device-write-bps 才能生效。
結果表明限速5MB/s 左右。作爲對比測試,創建一個普通容器,沒有做限速,查看其寫速度。
[root@master ~]# docker run -it centos:stress
[root@c157255f82d9 /]# dd if=/dev/zero of=test2 bs=1M count=1024 oflag=direct
在多個容器運行時,必須使用上述的參數設置優化,不能把所有的資源給其中一個容器,會造成資源浪費,容器不穩定。