docker的資源控制(CPU、記憶體、IO)

huhaiyangFIVE發表於2020-12-02


為什麼要Docker要做資源分配,虛擬機器不需要?

容器和虛擬機器的區別:

虛擬機器不需要做,因為虛擬機器在建立的時候已經做了資源分配(配額),(虛擬CPU,虛擬記憶體,虛擬磁碟等)
而容器共享核心資源,所以需要做Cgroup,按照往年監控的資料,檢視cpu等資源的耗用情況來進行分配

一、Cgroup資源配置方法

Docker是通過Cgroup來控制容器使用的資源配額,包括CPU、記憶體、磁碟i/o三大方面,基本覆蓋了常見的資源配額和使用量控制。

Cgroup是Control Groups的縮寫,是Linux核心提供的一種可以限制、記錄、隔離程式組所使用的物理資源(如CPU、記憶體、磁碟IO等)的機制,被docker等很多專案用於實現程式資源控制。Cgroup本身是提供將程式進行分組化管理的功能和介面的基礎結構,I/O或記憶體的分配控制等具體的資源管理功能。

這些具體的資源管理功能稱為Cgroup子系統,有以下幾大子系統實現:

  • blkio:設定限制每個塊裝置的輸入輸出控制。例如:磁碟,usb等
  • 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上的執行緒。

二、使用stress工具測試CPU和記憶體

使用Dockerfile來建立一個基於Centos的stress工具映象

[root@server1 ~]# mkdir stress
[root@server1 ~]# vim stress/Dockerfile
[root@server1 ~]# cd stress/
[root@server1 stress]# vim Dockerfile
FROM centos:7
MAINTAINER chen
RUN yum -y install wget
RUN wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
RUN yum -y install stress

[root@server1 stress]# docker build -t centos:stress .

使用如下命令建立容器,命令中的–cpu-shares引數值不能保證可以獲得1個vcpu或者多少GHz的CPU資源,它僅是一個彈性的加權值。

[root@server1 ~]# docker run -itd --cpu-shares 100 centos:stress

預設情況下,每個Docker容器的CPU份額都是1024。單獨一個容器的份額是沒有意義的。只有在同時執行容器時,容器的cpu加權的效果才能顯現。

例如:兩個容器A、B的cpu份額分別為1000和500,在cpu進行實際片分配的時候,容器A比容器B多一倍的機會獲得cpu的時間片。但分配的結果取決於當時主機和其他容器的執行狀態,實際上也無法保證容器A一定能獲得cpu時間片。比如容器A的程式一直是空閒的,那麼容器B是可以獲取比容器A更多的cpu時間片的。極端情況下,例如主機上只執行了一個容器,即使它的cpu份額只有50,它也可以獨佔整個主機的cpu。
例如:cpu時間片:1秒
容器A:50% 0.5秒
容器B:25% 0.25秒
容器C:25% 0.25秒
CPU給容器充電是在平均值層面:CPU給A容器充0.5秒,給B容器充0.25秒

可以通過cpu share可以設定容器使用cpu的優先順序,比如啟動了兩個容器及執行檢視cpu使用百分比。

[root@server1 ~]# docker run -itd --name cpu512 --cpu-shares 512 centos:stress stress -c 10               #stress -c 10:容器產生10個子函式程式
[root@server1 ~]# docker exec -it d915d8464584 /bin/bash
[root@d915d8464584 /]# top

在這裡插入圖片描述

[root@server1 ~]# docker run -itd --name cpu1024 --cpu-shares 1024 centos:stress stress -c 10  
[root@server1 ~]# docker exec -it 75af41079bdd /bin/bash
[root@75af41079bdd /]# top

在這裡插入圖片描述
可以發現兩個容器cpu使用率是2:1

三、CPU週期限制

Docker提供了–cpu-period、–cpu-quota兩個引數控制容器可以分配到的CPU時鐘週期。

  • –cpu-period是用來指定容器對CPU的使用要在多長時間內做一次重新分配。
  • –cpu-quota是用來指定在這個週期內,最多可以有多少時間來跑這個容器。
  • 與–cpu-shares不同的是,這種配置是指定一個絕對值,容器對CPU資源的使用絕對不會超過配置的值。

cpu-period和cpu-quota的單位為微秒(μs)。cpu-period的最小值為1000微秒,最大值為1秒,預設值為0.1秒(100000μs)
cpu-quota的值預設為-1,表示不做控制。cpu-period和cpu-quota引數一般聯合使用。
例如:容器程式需要每1秒使用單個cpu的0.2秒時間,可以將cpu-period設定為1000000即1秒,cpu-quota設定為200000(0.2秒)。
在多核情況下,如果允許容器程式完全佔用兩個cpu,則可以將cpu-period設定為100000即0.1秒,cpu-quota設定為200000即0.2秒

[root@server1 ~]# docker run -itd --cpu-period 100000 --cpu-quota 200000 centos:stress 
fc40fe4a887829ea1c4c3de476ca550004d408aec0c1d8212f79713869543c55
[root@server1 ~]# docker ps -a

[root@server1 ~]# docker exec -it fc40fe4a8878 /bin/bash
[root@fc40fe4a8878 /]# cd /sys/fs/cgroup/cpu
[root@fc40fe4a8878 cpu]# ls
cgroup.clone_children  cpu.cfs_period_us  cpu.rt_runtime_us  cpuacct.stat          notify_on_release
cgroup.event_control   cpu.cfs_quota_us   cpu.shares         cpuacct.usage         tasks
cgroup.procs           cpu.rt_period_us   cpu.stat           cpuacct.usage_percpu
[root@fc40fe4a8878 cpu]# cat cpu.cfs_period_us 
100000
[root@fc40fe4a8878 cpu]# cat cpu.cfs_quota_us  
200000

四、CPU Core控制

對多核CPU的伺服器,Docker還可以控制容器執行使用哪些CPU核心,即使用–cpuset-cpus引數。這對具有多CPU的伺服器尤其有用,可以對需要高效能運算的容器進行效能最優的配置。

[root@server1 ~]# docker run -tid --name cpu1 --cpuset-cpus 0-1 centos:stress

執行以上命令表示建立的容器只能用0、1兩個cpu。最終生成的cgroup的cpu核心配置如下:

[root@server1 ~]# docker exec -it eefe294955f8 bash
[root@eefe294955f8 /]# cat /sys/fs/cgroup/cpuset/cpuset.cpus 
0-1
[root@eefe294955f8 /]# stress -c 5 &   #讓容器產生5個子函式程式,並在後臺執行
[root@eefe294955f8 /]# top    #使用top命令檢視cpu工作情況(top進去後按1,顯示每個cpu的工作情況)

在這裡插入圖片描述
通過下面指令可以看到容器中程式與cpu核心的繫結關係

[root@server1 ~]# docker exec eefe294955f8 taskset -c -p 1 表示容器中第一個程式pid為1被繫結到cpu1和2上
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 核心才能方便地進行測試。

#建立容器cpu10,僅使用cpu1核心,加權值為512

[root@server1 ~]# docker run -itd --name cpu10 --cpuset-cpus 1 --cpu-shares 512 centos:stress stress -c 1
f885714260cb56310b521d77f3f69db906ea582d28c843297f5d31be59b149d4
[root@server1 ~]# docker exec -it f885714260cb bash
[root@f885714260cb /]# top

在這裡插入圖片描述
建立容器cpu12,僅使用cpu1核心,加權值為1024

[root@server1 ~]# docker run -itd --name cpu12 --cpuset-cpus 1 --cpu-shares 1024 centos:stress stress -c 1

對比cpu使用佔比
在這裡插入圖片描述
在這裡插入圖片描述

六、記憶體限額

與作業系統類似,容器可使用的記憶體包括兩部分: 實體記憶體和Swap

Docker通過下面兩組引數來控制容器記憶體的使用量。

  • -m或–memory:設定記憶體的使用限額,例如100M、1024M
  • –memory-swap:設定記憶體+swap的使用限額

執行如下命令允許該容器最多使用200M的記憶體和300M的swap

[root@server1 ~]# docker run -it -m 200M --memory-swap=300M progrium/stress --vm 1 --vm-bytes 280M
--vm 1:啟動1個記憶體工作執行緒
--vm-bytes 280M:每個執行緒分配280M記憶體

預設情況下,容器可以使用主機上的所有空閒記憶體。
與cpu的cgroups配置類似,Docker會自動為容器在目錄/sys/fs/cgroup/memory/docker/<容器的完整長id>中建立相應cgroup配置檔案
注意:如果讓工作執行緒分配的記憶體超過300M,分配的記憶體超過限額,stress執行緒報錯,容器退出。

[root@server1 ~]# docker run -it -m 200M --memory-swap=300M progrium/stress --vm 1 --vm-bytes 310M

七、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的速率為5MB/s。

[root@server1 ~]# docker run -it --device-write-bps /dev/sda:5MB centos:stress
[root@b4bb0fbc1c44 /]# dd if=/dev/zero of=test bs=1M count=1024 oflag=direct
^C28+0 records in
28+0 records out
29360128 bytes (29 MB) copied, 5.60286 s, 5.2 MB/s

通過dd命令測試在容器中寫磁碟的速度是否為5MB/s。因為容器的檔案系統是在主機/dev/sda上的,在容器中寫檔案相當於對主機/dev/sda進行寫操作。另外,oflag=direct指定用direct IO方式寫檔案,這樣 --device-write-bps才能生效。
結果表明限速5MB/s左右。作為對比測試,如果不限速,結果如下:

[root@server1 ~]# docker run -it centos:stress
[root@34a3a0f91892 /]# 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, 0.830403 s, 1.3 GB/s

八、Block IO 的限制

預設情況下,所有容器能平等地讀寫磁碟,可以通過設定–blkio-weight 引數來改變 容器 block IO 的優先順序。
–blkio-weight 與 --cpu-shares 類似,設定的是相對權重值,預設為 500。
在下面 的例子中,容器 A 讀寫磁碟的頻寬是容器 B 的兩倍。

[root@server1 ~]# docker run -it --name nameA --blkio-weight 800 centos:stress 
[root@97a7d9a7893c /]# cat /sys/fs/cgroup/blkio/blkio.weight
800

[root@server1 ~]# docker run -it --name nameB --blkio-weight 300 centos:stress 
[root@ffab8c022b42 /]# cat /sys/fs/cgroup/blkio/blkio.weight
300

相關文章