1. 程式人生 > 實用技巧 >8. Docker資源管理

8. Docker資源管理

Docker 資源限制

限制容器的資源

預設情況下, 容器沒有資源限制 ,可以使用主機核心排程程式允許的儘可能多的給定資源。 Docker 提供了控制容器可以 使用多少記憶體或 CPU 的方法 ,設定 docker run 命令的執行時配置標誌。其實 docker 真正能控制的資源是CPU 和 記憶體。CPU 是可壓縮型資源,記憶體是非可壓縮型資源。

其中許多功能都要求您的 核心支援 Linux 功能 。要檢查支援,可以使用該 docker info 命令。如果核心中禁用了某項功能,您可能會在輸出結尾處看到一條警告,如下所示: WARNING: No swap limit support ,請參閱作業系統的文件以啟用它們

[root@docker ~]#docker info 
Client:
 Debug Mode: false

Server:
 Containers: 0
  Running: 0
  Paused: 0
  Stopped: 0
 Images: 103
 Server Version: 19.03.13
 Storage Driver: overlay2
  Backing Filesystem: xfs
  Supports d_type: true
  Native Overlay Diff: true
 Logging Driver: json-file
 Cgroup Driver: cgroupfs
 Plugins:
  Volume: local
  Network: bridge host ipvlan macvlan null overlay
  Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
 Swarm: inactive
 Runtimes: runc
 Default Runtime: runc
 Init Binary: docker-init
 containerd version: 8fba4e9a7d01810a393d5d25a3621dc101981175
 runc version: dc9208a3303feef5b3839f4323d9beb36df0a9dd
 init version: fec3683
 Security Options:
  seccomp
   Profile: default
 Kernel Version: 3.10.0-1062.el7.x86_64
 Operating System: CentOS Linux 7 (Core)
 OSType: linux
 Architecture: x86_64
 CPUs: 4
 Total Memory: 7.638GiB
 Name: docker.super.com
 ID: LNH2:NQNF:THDU:IPDP:DXRX:FWH6:MSNG:6P3V:E4HC:YU3M:WZ27:ML47
 Docker Root Dir: /var/lib/docker
 Debug Mode: false
 Registry: https://index.docker.io/v1/
 Labels:
 Experimental: false
 Insecure Registries:
  192.168.118.46:80
  127.0.0.0/8
 Registry Mirrors:
  http://hub-mirror.c.163.com/
 Live Restore Enabled: false
  • OOME(Out Of Memory Exception)

    在Linux主機上,如果核心探測到當前宿主機已經沒有足夠的記憶體可用於實現某些重要的系統功能,那麼就會丟擲OOME,或者開始啟動 kill 某些程序以釋放記憶體。

    一旦發生 OOME,任何程序都有可能被殺死,包括 docker daemon 在內

    為此,Docker特地調整了 docker daemon 的OOM優先順序,以免它被核心“正法”,但容器的優先順序並未被調整。

memory

記憶體不足的風險

重要的是不要讓正在執行的容器佔用太多的主機記憶體。在 Linux 主機上,如果核心檢測到沒有足夠的記憶體來執行重要的系統功能,它會丟擲一個 OOME

或者 Out Of Memory Exception ,並 開始查殺程序以釋放記憶體任何程序都會被殺死 ,包括 Docker 和其他重要的應用程式。如果錯誤的程序被殺死,這可以有效地降低整個系統。

Docker 嘗試通過調整 Docker 守護程式上的 OOM 優先順序 來降低這些風險, 以便它比系統上的其他程序更不可能被殺死 。容器上的 OOM 優先順序未調整。這使得單個容器被殺死的可能性比 Docker 守護程式或其他系統程序被殺死的可能性更大。您不應試圖通過 --oom-score-adj 在守護程式或容器上手動設定為極端負數或通過設定容器來繞過這些安全措施 --oom-kill-disable

您可以通過以下方式降低 OOME 導致系統不穩定的風險:

  • 在將應用程式投入生產之前,請執行 測試 以瞭解應用程式的記憶體要求。
  • 確保您的應用程式 僅在具有足夠資源 的主機上執行。
  • 限制容器可以使用的記憶體量 ,如下所述。
  • 在 Docker 主機上配置交換時要小心。交換比記憶體更慢且效能更低,但可以 提供緩衝 以防止系統記憶體耗盡。
  • 考慮將容器轉換為 服務 ,並使用服務級別約束和節點標籤來確保應用程式僅在具有足夠記憶體的主機上執行

限制容器對記憶體設有的設定

Docker 可以 強制執行硬記憶體限制 ,允許容器使用不超過給定數量的使用者或系統記憶體或軟限制,這允許容器使用盡可能多的記憶體,除非滿足某些條件,例如核心檢測到主機上的低記憶體或爭用。當單獨使用或設定了多個選項時,其中一些選項會產生不同的效果。

大部分的選項取正整數,跟著一個字尾 b , k , m , g ,,表示位元組,千位元組,兆位元組或千兆位元組。

選項 描述
-m or --memory 容器可以使用的最大記憶體量。如果設定此選項,則允許的最小值為 4m
--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 殺手。如果 -m 未設定該標誌,則主機可能會耗盡記憶體,並且核心可能需要終止主機系統的程序才能釋放記憶體。

--memory-swap 設定

(1)介紹

--memory-swap 是一個修飾符標誌,只有在 --memory 設定時才有意義。使用 swap允許容器在容器耗盡可用的所有 RAM 時將多餘的記憶體需求寫入磁碟。對於經常將記憶體交換到磁碟的應用程式,效能會受到影響。

(2)它的設定會產生複雜的效果:

  • 如果 - -memory-swap 設定為正整數 ,那麼這兩個 --memory 和 --memory-swap必須設定。 --memory-swap 表示可以使用的 memory and swap ,並 --memory控制非交換記憶體 ( 實體記憶體 ) 使用的量。所以如果 --memory="300m" 和 --memory-swap="1g" ,容器可以使用 300 米的記憶體和 700 米( 1g - 300m ) swap 。
  • 如果 --memory-swap 設定為 0 ,則 忽略該設定 ,並將該值視為未設定。
  • 如果 --memory-swap 設定為與值相同的值 --memory ,並且 --memory 設定為正整數 ,則 容器無權訪問 swap 。請參考下面阻止容器使用交換。
  • 如果 --memory-swap 未設定--memory 設定 ,則容器可以 使用兩倍於 --memory 設定 的 swap ,主機容器需要配置有 swap 。例如,如果設定 --memory="300m" 和 --memory-swap 未設定,容器可以使用 300 米的記憶體和 600 米的 swap。
  • 如果 --memory-swap 明確設定為 -1 ,則允許 容器使用無限制 swap ,最多可達宿主機系統上可用的數量
  • 在容器內部,工具如 free 報告主機的 swap ,而不是容器內真正可用的記憶體。 不要依賴 free 或類似工具來確定是否存在 swap 。

(3)防止容器使用交換

如果 --memory --memory-swap 設定為相同的值 ,則 可以防止容器使用 swap。這是因為 --memory-swap 可以使用的 memory and swap ,而 --memory 只是可以使用的實體記憶體量。

--memory-swappiness 設定

  • 值為 0 將關閉匿名頁面交換。
  • 值 100 將所有匿名頁面設定為可交換。
  • 預設情況下,如果未設定 --memory-swappiness ,則值將從主機繼承。

--kernel-memory 設定

(1)介紹

核心記憶體限制以分配給容器的總記憶體表示。請考慮以下方案:

  • 無限記憶體,無限核心記憶體 :這是預設設定。
  • 無限記憶體,有限的核心記憶體 :當所有 cgroup 所需的記憶體量大於主機上實際存在的記憶體量時,這是合適的。您可以將核心記憶體配置為永遠不會覆蓋主機上可用的內容,而需要更多記憶體的容器需要等待它。
  • 有限的記憶體,無限的核心記憶體 :整體記憶體有限,但核心記憶體不受限制。
  • 有限的記憶體,有限的核心記憶體 :限制使用者和核心記憶體對於除錯與記憶體相關的問題非常有用。如果容器使用意外數量的任一型別的記憶體,則記憶體不足而不會影響其他容器或主機。在此設定中,如果核心記憶體限制低於使用者記憶體限制,則核心記憶體不足會導致容器遇到 OOM 錯誤。如果核心記憶體限制高於使用者記憶體限制,則核心限制不會導致容器遇到 OOM 。

當您開啟任何核心記憶體限制時,主機會根據每個程序跟蹤 “ 高水位線 ” 統計資訊,因此您可以跟蹤哪些程序(在本例中為容器)正在使用多餘的記憶體。通過 /proc//status 在主機上檢視,可以在每個過程中看到這一點。

CPU

  • 預設情況下,每個容器對主機 CPU 週期的訪問許可權是 不受限制的
  • 您可以設定各種約束來限制給定容器訪問主機的 CPU 週期。
  • 大多數使用者使用和配置 預設 CFS 排程程式。
  • 在 Docker 1.13 及更高版本中,您還可以配置 實時排程程式。

配置預設 CFS 排程程式

CFS 是用於普通 Linux 程序的 Linux 核心 CPU 排程程式。多個執行時標誌允許您配置容器具有的 CPU 資源訪問量。使用這些設定時, Docker 會修改主機上容器的 cgroup 的設定。

選項 描述
--cpus= 指定容器 可以使用的可用 CPU 資源量 。例如,如果主機有兩個 CPU 並且你已設定 --cpus="1.5" ,則容器最多保證一個半 CPU 。這相當於設定 --cpu-period="100000"和 --cpu-quota="150000" 。可在 Docker 1.13 及更高版本中使用。
--cpu-period= 指定 CPU CFS 排程程式週期,它與並用 --cpu-quota。預設為 100 微秒。大多數使用者不會更改預設設定。如果您使用 Docker 1.13 或更高版本,請 --cpus 使用。
--cpu-quota= 對容器施加 CPU CFS 配額。 --cpu-period 限制前容器限制為每秒的微秒數。作為有效上限。如果您使用 Docker 1.13 或更高版本,請 --cpus 改用。
--cpuset-cpus 限制容器可以 使用的特定 CPU 或核心 。如果您有多個CPU ,則容器可以使用逗號分隔列表或連字元分隔的 CPU 範圍。第一個 CPU 編號為 0. 有效值可能是 0-3 (使用第一個,第二個,第三個和第四個 CPU )或 1,3 (使用第二個和第四個 CPU )。
--cpu-shares 將此標誌設定為大於或小於預設值 1024 的值,以增加或減少容器的重量,並使其可以訪問主機的 CPU 週期的較大或較小比例。僅在 CPU 週期受限時才會強制執行此操作。當有足夠的 CPU 週期時,所有容器都會根據需要使用盡可能多的 CPU 。這樣,這是一個軟限制。 --cpu-shares 不會阻止容器以群集模式進行排程。它為可用的 CPU 週期優先考慮容器 CPU 資源。它不保證或保留任何特定的 CPU 訪問許可權。

操作演示

準備工作

(1)先查詢宿主機的資源:

[root@docker ~]#lscpu 
Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
Byte Order:            Little Endian
CPU(s):                4
On-line CPU(s) list:   0-3
Thread(s) per core:    1
Core(s) per socket:    1
Socket(s):             4
NUMA node(s):          1
Vendor ID:             GenuineIntel
CPU family:            6
Model:                 60
Model name:            Intel Core Processor (Haswell)
Stepping:              1
CPU MHz:               2397.220
BogoMIPS:              4794.44
Virtualization:        VT-x
Hypervisor vendor:     KVM
Virtualization type:   full
L1d cache:             32K
L1i cache:             32K
L2 cache:              4096K
NUMA node0 CPU(s):     0-3

(2)在 dockerhub 下載一個用於壓測的映象

[root@docker ~]#docker pull polinux/stress-ng:latest

(3)該壓測映象的使用方法

[root@docker ~]#docker run --name stress --rm polinux/stress-ng:latest stress --help

使用 --help 可以查詢此壓測映象的用法

例:

stress-ng --cpu 8 --io 4 --vm 2 --vm-bytes 128M --fork 4 --timeout 10s

語法:

  • -c N, --cpu N 啟動 N 個子程序( cpu )
  • --vm N 啟動 N 個程序對記憶體進行壓測
  • --vm-bytes 128M 每個子程序使用多少記憶體(預設 256M )

測試記憶體限制

(1)限制最大使用記憶體啟動容器

[root@docker ~]#docker run --name stress --rm -m 256m polinux/stress-ng:latest stress --vm 2
stress-ng: info:  [1] defaulting to a 86400 second run per stressor
stress-ng: info:  [1] dispatching hogs: 2 vm
stress-ng: info:  [1] cache allocate: default cache size: 4096K


[root@docker ~]#docker stats stress
CONTAINER ID        NAME                CPU %               MEM USAGE / LIMIT   MEM %               NET I/O             BLOCK I/O           PIDS
0cd0f5cd4b3e        stress              108.82%             352KiB / 256MiB     0.13%               656B / 0B           639MB / 2.63GB      5

註釋:

  • -m 256m 限制此容器最大隻能使用 256m 記憶體;
  • --vm 2 啟動壓測容器,使用 256x2=512m 的記憶體;
  • docker stats 結果查詢,容器實際使用記憶體不能超過 256m

測試 CPU 限制

(1)限制最大使用 2 核 CPU

[root@docker ~]#docker run --name stress --rm --cpus 2 polinux/stress-ng:latest stress --cpu 8
stress-ng: info:  [1] defaulting to a 86400 second run per stressor
stress-ng: info:  [1] dispatching hogs: 8 cpu
stress-ng: info:  [1] cache allocate: default cache size: 4096K


[root@docker ~]#docker stats stress
CONTAINER ID        NAME                CPU %               MEM USAGE / LIMIT     MEM %               NET I/O             BLOCK I/O           PIDS
d85b6ba5bb9f        stress              206.12%             38.66MiB / 7.638GiB   0.49%               656B / 0B           0B / 0B             9

(2)不限制使用 CPU 核數

[root@docker ~]#docker run --name stress --rm  polinux/stress-ng:latest stress --cpu 8
stress-ng: info:  [1] defaulting to a 86400 second run per stressor
stress-ng: info:  [1] dispatching hogs: 8 cpu
stress-ng: info:  [1] cache allocate: default cache size: 4096K


[root@docker ~]#docker stats stress
CONTAINER ID        NAME                CPU %               MEM USAGE / LIMIT     MEM %               NET I/O             BLOCK I/O           PIDS
e3223e6c67ea        stress              419.95%             37.03MiB / 7.638GiB   0.47%               656B / 0B           0B / 0B             9

參考連結:

https://zhuanlan.zhihu.com/p/55070876