資源限制

預設情況下,容器沒有資源限制,可以使用主機核心排程器允許的任何給定資源。 Docker 提供了控制容器可以使用多少記憶體或 CPU 的方法,設定 docker run 命令的執行階段設定旗標。 本節詳細說明了您應該何時設定此類限制以及設定它們的可能含義。

許多這些功能需要您的核心支援 Linux 功能。 要檢查支援,您可以使用 docker info 命令。 如果您的核心停用了某個功能,您可能會在輸出結尾看到如下警告

WARNING: No swap limit support

請參閱您的作業系統文件以啟用它們。 也請參閱 Docker 引擎疑難排解指南 以取得更多資訊。

記憶體

瞭解記憶體不足的風險

請務必不要允許正在執行的容器占用過多的主機記憶體。 在 Linux 主機上,如果核心偵測到沒有足夠的記憶體來執行重要的系統功能,它會拋出 OOME記憶體不足例外狀況,並開始終止程序以釋放記憶體。任何程序都可能被終止,包括 Docker 和其他重要的應用程式。如果終止了錯誤的程序,則可能會導致整個系統當機。

Docker 會嘗試透過調整 Docker 守護行程式上的 OOM 優先順序來降低這些風險,使其比系統上的其他程序更不可能被終止。 容器上的 OOM 優先順序不會調整。 這使得個別容器比 Docker 守護行程式或其他系統程序更容易被終止。 您不應該嘗試透過在守護行程式或容器上手動將 --oom-score-adj 設定為極端負數,或在容器上設定 --oom-kill-disable 來規避這些防護措施。

有關 Linux 核心 OOM 管理的更多資訊,請參閱 記憶體不足管理服務,並使用服務級別限制和節點標籤來確保應用程式僅在具有足夠記憶體的主機上執行

限制容器的記憶體存取

Docker 可以強制執行硬性或軟性記憶體限制。

  • 硬性限制讓容器使用的記憶體不超過固定數量。
  • 軟性限制允許容器根據需要使用盡可能多的記憶體,除非滿足某些條件,例如當內核偵測到主機記憶體不足或爭用情況。

部分選項在單獨使用或設定多個選項時會有不同的效果。

大多數選項接受一個正整數,後跟一個後綴 `b`、`k`、`m`、`g`,分別表示位元組、KB、MB 或 GB。

選項說明
`-m` 或 `--memory=`容器可以使用的最大記憶體量。如果設定此選項,則允許的最小值為 `6m`(6 MB)。也就是說,您必須將值設定為至少 6 MB。
--memory-swap*允許此容器交換到磁碟的記憶體量。請參閱`--memory-swap` 詳細資訊
--memory-swappiness預設情況下,主機內核可以交換出容器使用的匿名頁面的百分比。您可以將 `--memory-swappiness` 設定為 0 到 100 之間的值,以調整此百分比。請參閱`--memory-swappiness` 詳細資訊
--memory-reservation允許您指定一個小於 `--memory` 的軟性限制,當 Docker 偵測到主機記憶體爭用或不足時會啟用。如果您使用 `--memory-reservation`,則必須將其設定為低於 `--memory` 才能生效。由於它是軟性限制,因此不保證容器不會超過限制。
--kernel-memory容器可以使用的最大核心記憶體量。允許的最小值為 `6m`。由於核心記憶體無法交換出去,因此核心記憶體不足的容器可能會阻塞主機資源,這可能會對主機和其他容器產生副作用。請參閱`--kernel-memory` 詳細資訊
--oom-kill-disable預設情況下,如果發生記憶體不足 (OOM) 錯誤,內核會終止容器中的行程。要更改此行為,請使用 `--oom-kill-disable` 選項。僅在您也設定了 `-m/--memory` 選項的容器上停用 OOM 終止機制。如果未設定 `-m` 旗標,主機可能會耗盡記憶體,內核可能需要終止主機系統的行程以釋放記憶體。

有關 cgroup 和記憶體的更多資訊,請參閱記憶體資源控制器 的說明文件。

--memory-swap 詳細資訊

`--memory-swap` 是一個修飾旗標,僅在也設定了 `--memory` 時才有意義。使用交換空間允許容器在用盡所有可用 RAM 時將超出記憶體需求寫入磁碟。對於經常將記憶體交換到磁碟的應用程式來說,會有一定的效能損失。

其設定可能會產生複雜的影響

  • 如果 `--memory-swap` 設定為正整數,則必須同時設定 `--memory` 和 `--memory-swap`。`--memory-swap` 表示可以使用的記憶體和交換空間的總量,而 `--memory` 控制非交換記憶體使用的量。因此,如果 `--memory="300m"` 且 `--memory-swap="1g"`,則容器可以使用 300m 的記憶體和 700m(`1g - 300m`)的交換空間。

  • 如果 `--memory-swap` 設定為 `0`,則忽略該設定,並將該值視為未設定。

  • 如果 `--memory-swap` 設定為與 `--memory` 相同的值,並且 `--memory` 設定為正整數,則**容器無法使用交換空間**。請參閱防止容器使用交換空間

  • 如果未設定 `--memory-swap`,但設定了 `--memory`,則如果主機容器已設定交換記憶體,則容器可以使用與 `--memory` 設定一樣多的交換空間。例如,如果 `--memory="300m"` 且未設定 `--memory-swap`,則容器總共可以使用 600m 的記憶體和交換空間。

  • 如果 `--memory-swap` 顯式設定為 `-1`,則容器可以使用無限的交換空間,最高可達主機系統上的可用量。

  • 在容器內,諸如 `free` 之類的工具會報告主機的可用交換空間,而不是容器內可用的交換空間。不要依賴 `free` 或類似工具的輸出判斷交換空間是否存在。

防止容器使用交換空間

如果 `--memory` 和 `--memory-swap` 設定為相同的值,則可以防止容器使用任何交換空間。這是因為 `--memory-swap` 是可以使用的記憶體和交換空間的總量,而 `--memory` 只是可以使用的實體記憶體量。

--memory-swappiness 詳細資訊

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

--kernel-memory 詳細資訊

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

  • **無限記憶體,無限核心記憶體**:這是預設行為。
  • **無限記憶體,有限核心記憶體**:當所有 cgroup 所需的記憶體量大於主機上實際存在的記憶體量時,此設定適用。您可以將核心記憶體設定為永遠不會超過主機上的可用記憶體,需要更多記憶體的容器需要等待。
  • **有限記憶體,無限核心記憶體**:總記憶體有限,但核心記憶體無限。
  • **有限記憶體,有限核心記憶體**:限制使用者和核心記憶體對於除錯記憶體相關問題很有用。如果容器使用了超出預期的任何一種記憶體,它會在不影響其他容器或主機的情況下耗盡記憶體。在此設定中,如果核心記憶體限制低於使用者記憶體限制,則核心記憶體不足會導致容器發生 OOM 錯誤。如果核心記憶體限制高於使用者記憶體限制,則核心限制不會導致容器發生 OOM。

當您啟用核心記憶體限制時,主機會以每個行程為基礎追蹤「高水位標記」統計資訊,以便您可以追蹤哪些行程(在本例中為容器)正在使用過多的記憶體。可以透過在主機上檢視 `/proc/<PID>/status` 來查看每個行程的資訊。

CPU

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

設定預設的 CFS 排程器

CFS 是適用於一般 Linux 行程的 Linux 內核 CPU 排程器。您可以使用多個執行時期旗標來設定容器對 CPU 資源的存取量。當您使用這些設定時,Docker 會修改主機上容器 cgroup 的設定。

選項說明
--cpus=<value>指定容器可以使用多少可用的 CPU 資源。例如,如果主機有兩個 CPU,並且您設定 `--cpus="1.5"`,則容器最多可以保證使用一個半 CPU。這相當於設定 `--cpu-period="100000"` 和 `--cpu-quota="150000"`。
--cpu-period=<value>指定 CPU CFS 排程器週期,與 `--cpu-quota` 一起使用。預設值為 100000 微秒(100 毫秒)。大多數使用者不會更改此預設值。對於大多數使用案例,`--cpus` 是一個更方便的替代方案。
--cpu-quota=<value>對容器施加 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 存取權。

如果您有 1 個 CPU,則以下每個命令都保證容器每秒最多使用 50% 的 CPU。

$ docker run -it --cpus=".5" ubuntu /bin/bash

這相當於手動指定 `--cpu-period` 和 `--cpu-quota`;

$ docker run -it --cpu-period=100000 --cpu-quota=50000 ubuntu /bin/bash

設定即時排程器

您可以將容器設定為使用即時排程器,適用於無法使用 CFS 排程器的任務。您需要確保主機的內核已正確設定,然後才能設定 Docker 精靈設定個別容器

**警告**

CPU 排程和優先順序設定是進階的核心層級功能。大多數使用者不需要更改這些預設值。錯誤地設定這些值可能會導致您的主機系統變得不穩定或無法使用。

設定主機的內核

透過執行 `zcat /proc/config.gz | grep CONFIG_RT_GROUP_SCHED` 或檢查檔案 `/sys/fs/cgroup/cpu.rt_runtime_us` 是否存在,驗證 Linux 內核中是否啟用了 `CONFIG_RT_GROUP_SCHED`。有關設定核心即時排程器的指南,請參閱您的作業系統說明文件。

設定 Docker 精靈

若要使用即時排程器執行容器,請使用 --cpu-rt-runtime 旗標執行 Docker Daemon,並將其設定為每個執行期間保留給即時任務的最大微秒數。例如,在預設週期為 1000000 微秒(1 秒)的情況下,設定 --cpu-rt-runtime=950000 可確保使用即時排程器的容器在每個 1000000 微秒的週期內可以運行 950000 微秒,為非即時任務留下至少 50000 微秒的可用時間。要在使用 systemd 的系統上永久設定此配置,請為 docker 服務建立一個 systemd 單元檔案。範例請參閱說明如何使用 systemd 單元檔案 設定 Daemon 使用代理伺服器的指示。

設定個別容器

當您使用 docker run 啟動容器時,可以傳遞多個旗標來控制容器的 CPU 優先順序。有關適當值的資訊,請參閱您的作業系統文件或 ulimit 命令。

選項說明
--cap-add=sys_nice授予容器 CAP_SYS_NICE 權限,允許容器提高行程 nice 值、設定即時排程策略、設定 CPU 親和性以及其他操作。
--cpu-rt-runtime=<值>容器在 Docker Daemon 的即時排程器週期內可以以即時優先順序執行的最大微秒數。您還需要 --cap-add=sys_nice 旗標。
--ulimit rtprio=<值>容器允許的最大即時優先順序。您還需要 --cap-add=sys_nice 旗標。

以下範例命令在 debian:jessie 容器上設定這三個旗標。

$ docker run -it \
    --cpu-rt-runtime=950000 \
    --ulimit rtprio=99 \
    --cap-add=sys_nice \
    debian:jessie

如果核心或 Docker Daemon 設定不正確,則會發生錯誤。

GPU

存取 NVIDIA GPU

先決條件

請造訪官方 NVIDIA 驅動程式頁面以下載並安裝正確的驅動程式。安裝完成後,請重新啟動系統。

驗證您的 GPU 是否正在運行且可供存取。

安裝 nvidia-container-toolkit

請遵循 NVIDIA Container Toolkit 的官方 安裝說明

公開 GPU 以供使用

啟動容器時,請加入 --gpus 旗標以存取 GPU 資源。指定要使用的 GPU 數量。例如:

$ docker run -it --rm --gpus all ubuntu nvidia-smi

公開所有可用的 GPU,並返回類似以下的結果:

+-------------------------------------------------------------------------------+
| NVIDIA-SMI 384.130            	Driver Version: 384.130               	|
|-------------------------------+----------------------+------------------------+
| GPU  Name 	   Persistence-M| Bus-Id    	Disp.A | Volatile Uncorr. ECC   |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M.   |
|===============================+======================+========================|
|   0  GRID K520       	Off  | 00000000:00:03.0 Off |                  N/A      |
| N/A   36C	P0    39W / 125W |  	0MiB /  4036MiB |      0%  	Default |
+-------------------------------+----------------------+------------------------+
+-------------------------------------------------------------------------------+
| Processes:                                                       GPU Memory   |
|  GPU   	PID   Type   Process name                         	Usage  	|
|===============================================================================|
|  No running processes found                                                   |
+-------------------------------------------------------------------------------+

使用 device 選項指定 GPU。例如:

$ docker run -it --rm --gpus device=GPU-3a23c669-1f69-c64e-cf85-44e9b07e7a2a ubuntu nvidia-smi

公開指定的 GPU。

$ docker run -it --rm --gpus '"device=0,2"' ubuntu nvidia-smi

公開第一個和第三個 GPU。

...注意事項

NVIDIA GPU 只能由運行單一引擎的系統存取。

設定 NVIDIA 功能

您可以手動設定功能。例如,在 Ubuntu 上,您可以執行以下操作:

$ docker run --gpus 'all,capabilities=utility' --rm ubuntu nvidia-smi

這將啟用 utility 驅動程式功能,該功能會將 nvidia-smi 工具新增到容器中。

可以透過環境變數在映像檔中設定功能以及其他配置。您可以在 nvidia-container-toolkit... 文件中找到有關有效變數的更多資訊。這些變數可以在 Dockerfile 中設定。

您也可以使用會自動設定這些變數的 CUDA 映像檔。請參閱 NGC 官方 CUDA 映像檔...目錄頁面。