一、Cgroup
(1)Docker通過 Cgroup 來控制容器使用的資源配額,包括 CPU、內存、磁盤三大方面,基本覆蓋了常見的資源配額和使用量控制。
(2)Cgroup 是 Linux 內核提供的一種可以限制、記錄、隔離進程組所使用的物理資源的機制。
Cgroup 子系統:
1、blkio:設置限制每個塊設備的輸入輸出控制;
2、cpu:使用調度程序爲 cgroup 任務提供 cpu 的訪問;
3、cpuacct:產生 cgroup 任務的 cpu 資源報告;
4、cpuset:如果是多核心的 cpu,這個子系統會爲 cgroup 任務分配單獨的 cpu 和內存;
5、devices:允許或拒絕 cgroup 任務對設備的訪問;
6、freezer:暫停和恢復 cgroup 任務;
7、memory:設置每個 cgroup 的內存限制以及產生內存資源報告;
8、net_cls:標記每個網絡包以供 cgroup 方便使用;
9、ns:命名空間子系統;
10、perf_event:增加了對每個 cgroup 的監測跟蹤能力,可以監測屬於某個特定的 cgroup 的所有線程及運行在特定 CPU 上的線程。
二、使用 stress 工具測試 CPU 和內存
首先使用 Dockerfile 來創建一個基於 Centos 的 stress 的工具鏡像:
[root@localhost ~]# mkdir /opt/stress
[root@localhost ~]# cd /opt/stress/
[root@localhost stress]# vim Dockerfile
FROM centos:7
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 stress]# docker build -t centos:stress . //創建鏡像
(1)使用如下命令創建容器,命令中的 --cpu-shares 參數值不能保證可以獲得 1 個 vcpu 或者多少 GHz 的CPU 資源,它僅是一個彈性的加權值。
[root@localhost stress]# docker run -itd --cpu-shares 100 centos:stress
08a203033c051098fd6294cd8ba4e2fa8baa18cefb793c6c4cd655c0f28cabc0
注意:默認情況下,每個 Docker 容器的CPU的份額都是1024,單獨一個容器的份額是沒有意義的。只有在同時運行多個容器時,容器的 CPU 加權的效果才能體現出來。
例如,兩個容器 A、B 的CPU份額分別是 1000 和 500 ,在 CPU 進行時間片分配的時候,容器A比容器B多一倍的機會獲得 CPU 的時間片。但分配的結果取決於當時主機和其他容器的運行狀態,實際上也無法保證容器 A 一定能獲得CPU 時間片。比如容器 A 的進程一直是空閒的,那麼容器 B 是可以獲取比容器 A 更多的 CPU 時間片。極端情況下,例如主機上只運行了一個容器,即使它的 CPU 份額只有 50,它也可以獨佔整個主機的 CPU 資源。
比如:Cgroup 只在容器分配的資源緊缺時,即在需要對容器使用的資源進行限制時,纔會生效。因此,無法單純根據某個容器的 CPU 份額來確定有多少 CPU 資源分配給它,資源分配結果取決於同時運行的其他容器的 CPU 分配和容器中進程運行情況。可以通過 cpu share 可以設置容器使用 CPU 的優先級。
比如,啓動了兩個容器及運行查看 CPU 使用百分比:
1、
//容器產生10個子函數進程:
[root@localhost stress]# docker run -itd --name cpu512 --cpu-shares 512 centos:stress stress -c 10
99086cce962308fdb5417df189571e39f375ab2c067887cbac48e773225f25c7
//進入容器再使用top命令查看cpu使用情況:
[root@localhost stress]# docker exec -it 99086cce9623 bash
[root@99086cce9623 /]# top
.. ..
.. ..
.. ..
.. ..
按 q 退出,
[root@99086cce9623 /]# exit //退出整個容器
2、此時,我們可以再開啓另外一個容器做比較:
[root@localhost stress]# docker run -itd --name cpu1024 --cpu-shares 1024 centos:stress stress -c 10
81e29988fce779c6b3e10fb8570ae2358db4090e1987202bb7919260287eca66
[root@localhost stress]# docker exec -it 81e29988fce7 bash
[root@81e29988fce7 /]# top
..
..
..
通過進入容器,觀察兩個容器的 %CPU,可以發現比例是 1:2
三、CPU 週期限制:
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 --cpu-period 100000 --cpu-quota 200000 centos:stress
3f2a577cf6a281347338cbf9734440b3b8a29e771dc4890a9f243eb0773f6c09
[root@localhost stress]# docker exec -it 3f2a577cf6a2 bash
[root@3f2a577cf6a2 /]# cat /sys/fs/cgroup/cpu/cpu.cfs_period_us
100000
[root@3f2a577cf6a2 /]# cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us
200000
四、CPU Core 控制:
對於多核 CPU 的服務器,Docker 還可以控制容器運行使用哪些 CPU 內核,即使用 --cpuset-cpus 參數。這對具有多 CPU 的服務器尤其有用,可以對需要高性能計算的容器進行性能最優配置。
[root@localhost ~]# docker run -itd --name cpu02 --cpuset-cpus=0-2 centos:stress
76994f5d310de48ee635f69270f7c9b4cba1e65aad935ff1e0d6e098441104eb
//執行該命令(需要宿主機爲四核),表示創建的容器只能使用0、1、2 三個內核。
[root@localhost ~]# docker exec -it 76994f5d310d bash //進入容器
[root@76994f5d310d /]# cat /sys/fs/cgroup/cpuset/cpuset.cpus
0-2
通過下面指令可以看到容器中進程與 CPU 內核的綁定關係,達到 CPU 內核的目的:
[root@localhost ~]# docker exec 76994f5d310d taskset -c -p 1
pid 1's current affinity list: 0-2
//容器內部第一個進程號 pid爲1,被綁定到指定CPU上運行。
五、CPU 配額控制參數的混合使用:
通過 cpuset-cpus 參數指定容器 A 使用 CPU 內核 0,容器B 只是用 CPU 內核1;在主機上只有這兩個容器使用對應 CPU 內核的情況,它們各自佔有全部的內核資源,cpu-shares 沒有明顯效果。cpuset-cpus、cpuset-mems 參數只在多核、多內存節點上的服務器上有效,並且必須與實際的物理配置匹配,否則也無法達到資源控制的目的。在系統具有多個 CPU 內核的情況下,需要通過 cpuset-cpus 參數爲設置容器 CPU 內核才能方便地進行測試。
[root@localhost ~]# docker run -itd --name cpu3 --cpuset-cpus 1 --cpu-shares 512 centos:stress stress -c 1
d6e122af832297a05b6993ea3146a2a62969557989933ac9f1bf59f2a1de5c50
[root@localhost ~]# docker exec -it d6e122af8322 bash
[root@d6e122af8322 /]# top //top查看後,按1可以看到每個核心的佔用情況
我們再創建一個容器:
[root@localhost ~]# docker run -itd --name cpu4 --cpuset-cpus 3 --cpu-shares 1024 centos:stress stress -c 1
d375a1ba761a711d55a01d95c7a5d494e62f86d447d36422be666cacf6483ca1
[root@localhost ~]# docker exec -it d375a1ba761a bash
[root@d375a1ba761a /]# top
六、內存限額:
與操作系統類似,容器可使用的內存包括兩部分:物理內存 和 Swap;
docker 通過下面兩組參數來控制容器內存的使用量:
-m 或 --memory:設置內存的使用限額,例如 100M、1024M;
–memory-swap:設置內存 +swap 的使用限額。
例如:執行如下命令允許該容器最多使用 200M的內存,300M 的swap:
[root@localhost ~]# docker run -it -m 200M --memory-swap=300M progrium/stress --vm 1 --vm-bytes 280M
// --vm 1:啓動1個內存工作線程;
--vm-bytes 280M :每個線程分配280M內存;
如果讓工作線程分配的內存超過 300M,分配的內存超過限額,stress線程報錯,容器退出:
[root@localhost ~]# docker run -it -m 200M --memory-swap=300M progrium/stress --vm 1 --vm-bytes 310M
七:Block IO 的限制:
默認情況下,所有容器能平等地讀寫磁盤,可以通過設置 --blkio-weight 參數來改變容器 block IO 的優先級。
–blkio-weight 與 --cpu-shares 類似,設置的是相對權重值,默認爲500
在下面的例子中,容器 A 讀寫磁盤的帶寬是容器 B 的兩倍:
[root@localhost ~]# docker run -it --name container_A --blkio-weight 600 centos:stress
[root@0f9b8d716206 /]# cat /sys/fs/cgroup/blkio/blkio.weight
[root@localhost ~]# docker run -it --name container_B --blkio-weight 300 centos:stress
[root@55bdce1cab5d /]# cat /sys/fs/cgroup/blkio/blkio.weight
八、bps 和 iops 的限制:
(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。
例如:
限制容器 寫 /dev/sda 磁盤的速率爲 5MB/s:
[root@localhost ~]# docker run -it --device-write-bps /dev/sda:5MB centos:stress