Docker 資源限制

默認情況下,一個容器並沒有資源限制,並且該容器可以使用內核調度的所有資源。Docke提供了在啓動容器時設置一些參數來控制該容器使用的內存、CPU和block IO。

真正可以控制的只有內存和CPU。。

內存

內存是不可壓縮資源

OOME

在Linxu系統中,如果內核探測到宿主機沒有足夠的內存來調用執行系統的某些重要功能的時候,那麼會拋出一個OOME(Out Of Memory Exception:內存異常)殺死某些進程,以此來釋放內存。
一旦發生OOME,任何進程都有可能被殺死,包括docker daemon在內。爲此,Docker特地調整了docker daemon的OOM優先級,防止其被殺死,但是容器的優先級沒有被調整。在內存不足時,內核會根據自己的調度算法,爲每個進程得出一個評分,然後殺死分數最高的進程來釋放內存。
可以在docker run的時候指定--oom-score-adj參數(默認爲0)。這個是容器被殺死的優先級,會影響評分,值越大越容易被殺死。這個參數只是影響最終的評分,優先殺死進程是看評分,參數小的可能計算後分數仍然最高,依然會被優先殺掉。
可以指定–oom-kill-disable=true參數,指定一些特定的重要的容器禁止被OOM殺掉。

--oom-kill-disable               Disable OOM Killer
--oom-score-adj int              Tune host's OOM preferences (-1000 to 1000)

內存限制

選項 描述
-m,--memory 內存限制,格式是數字加單位,單位可以爲 b,k,m,g。最小爲4M
--memory-swap 內存+交換分區大小總限制。格式同上。必須比-m設置的大
--memory-swappiness 默認情況下,主機可以把容器使用的匿名頁(anonymous page)swap 出來,你可以設置一個 0-100 之間的值,代表允許 swap 出來的比例
--memory-reservation 設置一個內存使用的 soft limit,如果 docker 發現主機內存不足,會執行 OOM 操作。這個值必須小於 --memory 設置的值
--kernel-memory 容器能夠使用的 kernel memory 大小,最小值爲 4m
--oom-kill-disable 是否運行 OOM 的時候殺死容器。只有設置了 -m,纔可以把這個選項設置爲 false,否則容器會耗盡主機內存,而且導致主機應用被殺死

--memory-swap參數
這個參數要結合-m一起生效,表格中的描述比較簡單,是一般的用法。
一般用法:比-m大,內存+交換分區大小總限制
禁用swap:和-m一樣大,這樣--memory和--memory-swap的限制是一樣大,可用的swap資源爲0,相當於禁用。
默認設置:設置爲0或者不設置,如果主機(Docker Host)啓用了swap,則容器可用的swap爲內存限制的2倍。
無限制:設置爲-1,如果主機(Docker Host)啓用了swap,則容器可使用宿主機所有的swap資源。

在容器內使用free命令,看到的swap空間沒有體現出上面這些限制,沒有參考價值。

CPU

CPU是可壓縮資源。

默認情況下,每一個容器可以使用宿主機上的所有cpu資源。大多數系統使用的資源調度算法是CFS(完全公平調度器),它公平調度每一個工作進程。進程可以分2類:CPU密集型(低優先級)和IO密集型(高優先級)。系統內核實時監測系統進程,當某個進程佔用cpu資源時間過長時,內核會調整該進程的優先級。
docker 1.13 之後還支持realtime調度。

有如下的3種CPU資源分配策略:

  1. 按壓縮方式比例分配
  2. 限定最多隻能幾個核
  3. 限定只能使用哪個或哪幾個核
選項 描述
-c, --cpu-shares int cpu資源提供給一組容器使用,組內的容器按比例使用cpu資源,當容器處於空閒狀態時,cpu資源被負載大的容器佔用,(按壓縮方式比例分配),當空閒進行運行起來時,cpu資源會被分配到其他容器
--cpus decimal 指定 cpu的核心數量,這種方式直接限定了容器可用的cpu資源
--cpuset-cpus string 指定容器只能運行在哪個cpu核心上(綁定cpu);核心使用0,1,2,3編號

CPU Share

docker 爲容器設置 CPU share 的參數是 -c, --cpu-shares,它的值是一個整數。

docker 允許用戶爲每個容器設置一個數字,代表容器的 CPU share,默認情況下每個容器的 share 是 1024。當主機上有多個容器運行時,每個容器佔用的 CPU 時間比例爲它的 share 在總額中的比例。舉個例子,如果主機上有兩個一直使用 CPU 的容器(爲了簡化理解,不考慮主機上其他進程),其 CPU share 都是 1024,那麼兩個容器 CPU 使用率都是 50%;如果把其中一個容器的 share 設置爲 512,那麼兩者 CPU 的使用率分別爲 67% 和 33%;如果刪除 share 爲 1024 的容器,剩下來容器的 CPU 使用率將會是 100%。

總結下來,這種情況下,docker 會根據主機上運行的容器和進程動態調整每個容器使用 CPU 的時間比例。這樣的好處是能保證 CPU 儘可能處於運行狀態,充分利用 CPU 資源,而且保證所有容器的相對公平;缺點是無法指定容器使用 CPU 的確定值。

CPU 核數

從 1.13 版本之後,docker 提供了 --cpus 參數可以限定容器能使用的 CPU 核數。這個功能可以讓我們更精確地設置容器 CPU 使用量,是一種更容易理解也因此更常用的手段。

--cpus 後面跟着一個浮點數,代表容器最多使用的核數,可以精確到小數點二位,也就是說容器最小可以使用 0.01 核 CPU。比如,我們可以限制容器只能使用 1.5 核數 CPU。

如果設置的 --cpus 值大於主機的 CPU 核數,docker 會直接報錯。
如果多個容器都設置了 --cpus,並且它們之和超過主機的 CPU 核數,並不會導致容器失敗或者退出,這些容器之間會競爭使用 CPU,具體分配的 CPU 數量取決於主機運行情況和容器的 CPU share 值。也就是說 --cpus 只能保證在 CPU 資源充足的情況下容器最多能使用的 CPU 數,docker 並不能保證在任何情況下容器都能使用這麼多的 CPU(因爲這根本是不可能的)。

CPU 指定核心

Docker 允許調度的時候限定容器運行在哪個 CPU 上。可以通過 --cpuset-cpus 參數讓容器只運行在某個或某幾個核上。

--cpuset-cpus、-cpus 參數可以和 -c, --cpu-shares 一起使用,限制容器只能運行在某些 CPU 核上,並且配置了使用率。

限制容器運行在哪些核上並不是一個很好的做法,因爲它需要事先知道主機上有多少 CPU 核,而且非常不靈活。除非有特別的需求,一般並不推薦在生產中這樣使用。

其他CPU參數

選項 描述
--cpu-period int 指定CFS調度的週期,一般與--cpu-quota一起使用。默認情況下週期爲1 秒,以微秒爲單位表示,一般使用默認值。1.13或者更高版本推薦使用 --cpus 標誌代替。
--cpu-quota int 在CFS調度中容器一個週期的cpu時間配額,即每個--cpu-period週期容器可獲得的cpu時間(微秒),cpu-quota/cpu-period。1.13或者更高版本推薦使用 --cpus 標誌代替。

壓力測試

資源限制的演示

查詢宿主機上的資源

這裏用了lscpu和free命令:

[root@Docker ~]# lscpu
Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
Byte Order:            Little Endian
CPU(s):                1
On-line CPU(s) list:   0
Thread(s) per core:    1
Core(s) per socket:    1
Socket(s):             1
NUMA node(s):          1
Vendor ID:             GenuineIntel
CPU family:            6
Model:                 60
Model name:            Intel(R) Core(TM) i7-4790K CPU @ 4.00GHz
Stepping:              3
CPU MHz:               3999.996
BogoMIPS:              7999.99
Hypervisor vendor:     Microsoft
Virtualization type:   full
L1d cache:             32K
L1i cache:             32K
L2 cache:              256K
L3 cache:              8192K
NUMA node0 CPU(s):     0
Flags:                 fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss syscall nx pdpe1gb rdtscp lm constant_tsc rep_good nopl xtopology eagerfpu pni pclmulqdq ssse3 fma cx16 sse4_1 sse4_2 movbe popcnt aes xsave avx f16c rdrand hypervisor lahf_lm abm ssbd ibrs ibpb stibp fsgsbase bmi1 avx2 smep bmi2 erms invpcid xsaveopt spec_ctrl intel_stibp flush_l1d
[root@Docker ~]# free -h
              total        used        free      shared  buff/cache   available
Mem:           936M        260M        340M        6.7M        334M        592M
Swap:          1.6G          0B        1.6G
[root@Docker ~]# 

下載鏡像

可以在docker hub上搜索stress(壓測)。
下載鏡像,運行查看幫助:

[root@Docker ~]# docker pull lorel/docker-stress-ng
[root@Docker ~]# docker run -it --rm lorel/docker-stress-ng
stress-ng, version 0.03.11

Usage: stress-ng [OPTION [ARG]]
 --h,  --help             show help
......省略......
Example: stress-ng --cpu 8 --io 4 --vm 2 --vm-bytes 128M --fork 4 --timeout 10s

Note: Sizes can be suffixed with B,K,M,G and times with s,m,h,d,y
[root@Docker ~]# 

主要命令參數:

  • --h, --help: 默認啓動容器就是這個命令參數
  • -c N, --cpu N: 啓動N個子進程對CPU進行壓測
  • -m N, --vm N: 啓動N個進程對內存進行壓測
  • --vm-bytes N: 每個子進程使用多少內存(默認256MB)

測試內存限制

查看lorel/docker-stress-ng裏內存相關的參數說明:

 -m N, --vm N             start N workers spinning on anonymous mmap
       --vm-bytes N       allocate N bytes per vm worker (default 256MB)

默認每個worker是256MB的內存,這個保持默認。然後指定--vm,開啓2個worker,並且限制容器的內存只能使用256MB,啓動容器:

[root@Docker ~]# docker run --name stress1 -it --rm -m 256m lorel/docker-stress-ng --vm 2
stress-ng: info: [1] defaulting to a 86400 second run per stressor
stress-ng: info: [1] dispatching hogs: 2 vm

這個終端已經被佔用了,另起一個終端使用docker top命令查看容器內部正在運行的進程:

[root@Docker ~]# docker top stress1
UID                 PID                 PPID                C                   STIME               TTY                 TIME                CMD
root                5922                5907                0                   21:06               pts/0               00:00:00            /usr/bin/stress-ng --vm 2
root                6044                5922                0                   21:06               pts/0               00:00:00            /usr/bin/stress-ng --vm 2
root                6045                5922                0                   21:06               pts/0               00:00:00            /usr/bin/stress-ng --vm 2
root                6086                6044                13                  21:06               pts/0               00:00:00            /usr/bin/stress-ng --vm 2
root                6097                6045                47                  21:06               pts/0               00:00:00            /usr/bin/stress-ng --vm 2
[root@Docker ~]# 

這裏可以看一下PID和PPID,這裏一共5個進程,一個父進程創建了2個子進程,這2個子進程又分別各創建了一個進程。

另外還可以使用命令docker stats查看容器的資源實時使用的情況:

$ docker stats
CONTAINER ID        NAME                CPU %               MEM USAGE / LIMIT   MEM %               NET I/O             BLOCK I/O           PIDS
626f38c4a4ad        stress1             18.23%              256MiB / 256MiB     100.00%             656B / 0B           17.7MB / 9.42GB     5

這個是實時刷新的。

測試CPU限制

限制容器最大隻能使用2核,然後同時開啓8個CPU進行壓測,使用下面的命令:

docker run -it --rm --cpus 2 lorel/docker-stress-ng --cpu 8

限制只用0.5核,開啓4個CPU進行壓測:

[root@Docker ~]# docker run --name stress2 -it --rm --cpus 0.5 lorel/docker-stress-ng --cpu 4
stress-ng: info: [1] defaulting to a 86400 second run per stressor
stress-ng: info: [1] dispatching hogs: 4 cpu

另起一個終端使用docker top命令查看容器內部正在運行的進程:

[root@Docker ~]# docker top stress2
UID                 PID                 PPID                C                   STIME               TTY                 TIME                CMD
root                7198                7184                0                   22:35               pts/0               00:00:00            /usr/bin/stress-ng --cpu 4
root                7230                7198                12                  22:35               pts/0               00:00:02            /usr/bin/stress-ng --cpu 4
root                7231                7198                12                  22:35               pts/0               00:00:02            /usr/bin/stress-ng --cpu 4
root                7232                7198                12                  22:35               pts/0               00:00:02            /usr/bin/stress-ng --cpu 4
root                7233                7198                12                  22:35               pts/0               00:00:02            /usr/bin/stress-ng --cpu 4
[root@Docker ~]# 

一個父進程,創建了4個子進程。
然後再用docker stats命令查看資源佔用:

$ docker stats
CONTAINER ID        NAME                CPU %               MEM USAGE / LIMIT     MEM %               NET I/O             BLOCK I/O           PIDS
14a341dd23d1        stress2             50.02%              13.75MiB / 908.2MiB   1.51%               656B / 0B           0B / 0B             5

因爲限制了0.5核,所以基本不會超過50%。

測試 CPU Share

開啓3個容器,分別指定不同的--cpu-shares參數,不指定的話默認是1024:

[root@Docker ~]# docker run --name stress3.1 -itd --rm --cpu-shares 512 lorel/docker-stress-ng --cpu 4
800d756f76ca4cf20af9fa726349f25e29bc57028e3a1cb738906a68a87dcec4
[root@Docker ~]# docker run --name stress3.2 -itd --rm lorel/docker-stress-ng --cpu 4
4b88007191812b239592373f7de837c25f795877d314ae57943b5410074c6049
[root@Docker ~]# docker run --name stress3.3 -itd --rm --cpu-shares 2048 lorel/docker-stress-ng --cpu 4
8f103395b6ac93d337594fdd1db289b6462e01c3a208dcd3788332458ec03b98
[root@Docker ~]#

查看3個容器的CPU佔用率:

$ docker stats
CONTAINER ID        NAME                CPU %               MEM USAGE / LIMIT     MEM %               NET I/O             BLOCK I/O           PIDS
800d756f76ca        stress3.1           14.18%              14.53MiB / 908.2MiB   1.60%               656B / 0B           0B / 0B             5
4b8800719181        stress3.2           28.60%              15.78MiB / 908.2MiB   1.74%               656B / 0B           0B / 0B             5
8f103395b6ac        stress3.3           56.84%              15.38MiB / 908.2MiB   1.69%               656B / 0B           0B / 0B             5

佔用率基本就是1/2/4,符合期望。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章