docker容器資源限制:限制容器對記憶體/CPU的存取

2022-09-06 18:01:28

一.系統環境

伺服器版本 docker軟體版本 CPU架構
CentOS Linux release 7.4.1708 (Core) Docker version 20.10.12 x86_64

二.前言

預設情況下,容器沒有資源限制,並且可以使用主機核心排程程式允許的儘可能多的給定資源。Docker 提供了控制容器可以使用多少記憶體或 CPU 的方法。

三.docker對於CPU和記憶體的限制

3.1 限制容器對記憶體的存取

重要的是不要讓正在執行的容器消耗過多的主機記憶體。在 Linux 主機上,如果核心檢測到沒有足夠的記憶體來執行重要的系統功能,它會丟擲一個OOME或 Out Of Memory Exception,並開始殺死程序以釋放記憶體。任何程序都可能被殺死,包括 Docker 和其他重要的應用程式。如果錯誤的程序被殺死,這可以會導致關閉整個系統。

Docker 可以強制執行記憶體硬限制,允許容器使用不超過給定數量的使用者或系統記憶體,或軟限制,允許容器根據需要使用盡可能多的記憶體,除非滿足某些條件,例如何時核心檢測到主機記憶體不足或爭用。其中一些選項在單獨使用或設定多個選項時具有不同的效果。這些選項中的大多數採用正整數,後跟b, k, m, g, 字尾來表示位元組、千位元組、兆位元組或千兆位元組。

常用的引數有

引數 引數解釋
-m或者--memory= 容器可以使用的最大記憶體量。如果設定此選項,則允許的最小值為6m(6 兆位元組)。也就是說,您必須將該值設定為至少 6 兆位元組。
--memory-swap* 允許此容器交換到磁碟的記憶體量。
--memory-swappiness 預設情況下,主機核心可以換出容器使用的一定百分比的匿名頁面。您可以設定--memory-swappiness為 0 到 100 之間的值,以調整此百分比。
--memory-reservation 允許您指定一個小於--memory在 Docker 檢測到主機上的爭用或記憶體不足時啟用的軟限制。如果使用--memory-reservation,則必須將其設定為低於--memory它才能優先。因為是軟限制,所以不保證容器不超過限制。
--kernel-memory 容器可以使用的最大核心記憶體量。允許的最小值是4m。因為核心記憶體不能被換出,核心記憶體不足的容器可能會阻塞主機資源,這會對主機和其他容器產生副作用。
--oom-kill-disable 預設情況下,如果發生記憶體不足 (OOM) 錯誤,核心會終止容器中的程序。要更改此行為,請使用該--oom-kill-disable選項。僅在您還設定了該-m/--memory選項的容器上禁用 OOM kill。如果-m未設定該標誌,主機可能會耗盡記憶體,核心可能需要終止主機系統的程序以釋放記憶體。

本次主要使用hub.c.163.com/library/centos:latest映象測試,沒有該映象需要自己docker pull一下

[root@k8smaster harbor]# docker images
REPOSITORY                                                        TAG        IMAGE ID       CREATED         SIZE
hub.c.163.com/library/centos                                      latest     328edcd84f1b   4 years ago     193MB

上傳memload-7.0-1.r29766.x86_64.rpm安裝包,用於模擬記憶體的使用

[root@k8smaster ~]# mkdir /memload

[root@k8smaster ~]# mv memload-7.0-1.r29766.x86_64.rpm /memload/

使用centos建立一個臨時容器,-v /memload:/memload進行資料卷掛載,使容器/memload目錄下有memload-7.0-1.r29766.x86_64.rpm安裝包

[root@k8smaster ~]# docker run -it --rm -v /memload:/memload hub.c.163.com/library/centos:latest

#在容器裡安裝memload
[root@3c9083a7b318 /]# rpm -ivh /memload/memload-7.0-1.r29766.x86_64.rpm 
Preparing...                          ################################# [100%]
Updating / installing...
   1:memload-7.0-1.r29766             ################################# [100%]

#memload 1000使記憶體使用1000M
[root@3c9083a7b318 /]# memload 1000
Attempting to allocate 1000 Mebibytes of resident memory...
^C

[root@3c9083a7b318 /]# exit
exit

當在容器執行memload 1000時,開啟另外一個Linux終端,使用docker stats檢視該容器的記憶體使用,發現此容器使用了1013MiB記憶體,3.32GiB表示物理機的最大記憶體

CONTAINER ID   NAME                                                                                                            CPU %     MEM USAGE / LIMIT    MEM %     NET I/O           BLOCK I/O         PIDS
3c9083a7b318   friendly_roentgen                                                                                               100.71%   1013MiB / 3.32GiB    29.79%    648B / 0B         32.5MB / 19.5MB   2

使用-m對容器的記憶體進行限制,-m 512m:表示容器記憶體最大使用512M,這時如果我們執行memload 1000,使用docker stats檢視,最大記憶體也只能是512M

[root@k8smaster ~]# docker run -it --rm -m 512m -v /memload:/memload hub.c.163.com/library/centos:latest
[root@a81686360ba1 /]# 
[root@a81686360ba1 /]# exit
exit

3.2 限制容器對CPU的存取

預設情況下,每個容器對主機 CPU 週期的存取是無限制的。您可以設定各種約束來限制給定容器對主機 CPU 週期的存取。大多數使用者使用和設定 預設的 CFS 排程程式。您還可以設定實時排程程式。

CFS 是用於普通 Linux 程序的 Linux 核心 CPU 排程程式。幾個執行時標誌允許您設定對容器擁有的 CPU 資源的存取量。當您使用這些設定時,Docker 會修改主機上容器的 cgroup 的設定。

常用的引數有

引數 引數解釋
--cpus= 指定容器可以使用多少可用 CPU 資源。例如,如果主機有兩個 CPU,並且您設定--cpus="1.5"了 ,則容器最多可以保證一個半的 CPU。這相當於設定--cpu-period="100000"和--cpu-quota="150000"。
--cpu-period= 指定 CPU CFS 排程程式週期,它與 --cpu-quota. 預設為 100000 微秒(100 毫秒)。大多數使用者不會更改預設設定。對於大多數用例,--cpus是一種更方便的選擇。
--cpu-quota= 對容器施加 CPU CFS 配額。--cpu-period容器在被限制之前被限制的每微秒數。因此充當有效上限。對於大多數用例,--cpus是一種更方便的選擇。
--cpuset-cpus 限制容器可以使用的特定 CPU 或核心。如果您有多個 CPU,則容器可以使用的逗號分隔列表或連字元分隔的 CPU 範圍。第一個 CPU 編號為 0。有效值可能是0-3(使用第一個、第二個、第三個和第四個 CPU)或1,3(使用第二個和第四個 CPU)。
--cpu-shares 將此標誌設定為大於或小於預設值 1024 的值,以增加或減少容器的重量,並允許它存取或多或少比例的主機 CPU 週期。這僅在 CPU 週期受到限制時才會強制執行。當有足夠多的 CPU 週期可用時,所有容器都會根據需要使用盡可能多的 CPU。這樣,這是一個軟限制。--cpu-shares不會阻止容器以 swarm 模式排程。它優先考慮可用 CPU 週期的容器 CPU 資源。它不保證或保留任何特定的 CPU 存取許可權。

對CPU的限制一般是設定CPU的親和性,檢視cpu資訊:兩個CPU:On-line CPU(s) list: 0,1

[root@k8smaster ~]# lscpu 
Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
Byte Order:            Little Endian
CPU(s):                2
On-line CPU(s) list:   0,1
Thread(s) per core:    1
Core(s) per socket:    2
座:                 1
NUMA 節點:         1
廠商 ID:           GenuineIntel
CPU 系列:          6
型號:              142
型號名稱:        Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz
步進:              10
CPU MHz:             1991.381
BogoMIPS:            3984.01
超管理器廠商:  VMware
虛擬化型別:     完全
L1d 快取:          32K
L1i 快取:          32K
L2 快取:           256K
L3 快取:           8192K
NUMA 節點0 CPU:    0,1
Flags:                 fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon nopl xtopology tsc_reliable nonstop_tsc eagerfpu pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch fsgsbase tsc_adjust bmi1 avx2 smep bmi2 invpcid mpx rdseed adx smap clflushopt xsaveopt xsavec arat

使用centos映象建立容器,裡面執行5個cat程序

[root@k8smaster ~]# docker run -it --rm  -v /memload:/memload hub.c.163.com/library/centos:latest
[root@1a4fff793014 /]# 
[root@1a4fff793014 /]# cat /dev/zero > /dev/null &
[1] 15
[root@1a4fff793014 /]# cat /dev/zero > /dev/null &
[2] 16
[root@1a4fff793014 /]# cat /dev/zero > /dev/null &
[3] 17
[root@1a4fff793014 /]# cat /dev/zero > /dev/null &
[4] 18
[root@1a4fff793014 /]# cat /dev/zero > /dev/null &
[5] 19
[root@1a4fff793014 /]# exit 
exit

當在容器執行5個cat程序之後,開啟另外一個Linux終端,檢視每個cat程序執行在哪個CPU上,可以看到cat程序都執行在0號和1號CPU上

[root@k8smaster ~]# ps mo pid,comm,psr `pgrep cat`
   PID COMMAND         PSR
130120 cat               -
     - -                 0
130143 cat               -
     - -                 1
130144 cat               -
     - -                 0
130145 cat               -
     - -                 1
130146 cat               -
     - -                 1

--cpuset-cpus=0 設定容器裡的程序都執行在0號CPU上

[root@k8smaster ~]# docker run -it --rm  --cpuset-cpus=0 -v /memload:/memload hub.c.163.com/library/centos:latest
[root@0c3b37f8e679 /]# cat /dev/zero > /dev/null &
[1] 15
[root@0c3b37f8e679 /]# cat /dev/zero > /dev/null &
[2] 16
[root@0c3b37f8e679 /]# cat /dev/zero > /dev/null &
[3] 17
[root@0c3b37f8e679 /]# cat /dev/zero > /dev/null &
[4] 18
[root@0c3b37f8e679 /]# cat /dev/zero > /dev/null &
[5] 19
[root@0c3b37f8e679 /]# 
[root@0c3b37f8e679 /]# exit
exit

--cpuset-cpus=1 設定容器裡的程序都執行在1號CPU上

[root@k8smaster ~]# docker run -it --rm  --cpuset-cpus=1 -v /memload:/memload hub.c.163.com/library/centos:latest
[root@dac513abce35 /]# 
[root@dac513abce35 /]# cat /dev/zero > /dev/null &
[1] 15
[root@dac513abce35 /]# cat /dev/zero > /dev/null &
[2] 16
[root@dac513abce35 /]# 
[root@dac513abce35 /]# cat /dev/zero > /dev/null &
[3] 17
[root@dac513abce35 /]# cat /dev/zero > /dev/null &
[4] 18
[root@dac513abce35 /]# exit
exit

--cpuset-cpus=0,1 設定容器裡的程序都執行在0,1號CPU上

[root@k8smaster ~]# docker run -it --rm  --cpuset-cpus=0,1 -v /memload:/memload hub.c.163.com/library/centos:latest
[root@244fe7eb8707 /]# cat /dev/zero > /dev/null &
[1] 15
[root@244fe7eb8707 /]# cat /dev/zero > /dev/null &
[2] 16
[root@244fe7eb8707 /]# cat /dev/zero > /dev/null &
[3] 17
[root@244fe7eb8707 /]# cat /dev/zero > /dev/null &
[4] 18
[root@244fe7eb8707 /]# cat /dev/zero > /dev/null &
[5] 19
[root@244fe7eb8707 /]# 
[root@244fe7eb8707 /]# exit
exit

--cpuset-cpus=0-7,14 設定容器裡的程序都執行在0-7,14號CPU上,由於沒有那麼多CPU所以報錯

[root@k8smaster ~]# docker run -it --rm  --cpuset-cpus=0-7,14 -v /memload:/memload hub.c.163.com/library/centos:latest
docker: Error response from daemon: Requested CPUs are not available - requested 0-7,14, available: 0-1.
See 'docker run --help'.

注意:還可以設定容器對NVIDIA GPU 的存取,不過目前暫時沒用到。