Docker 009 容器的資源限制
默認情況下,容器是沒有資源限制的,可以使用宿主機上所有可分配的資源,簡單來說就是,容器可以耗盡宿主機資源。Docker 提供了一個可以控制內存、CPU的方法。
資源限制特性需要 Linux 內核支持 capabilities。可以使用 docker info 命令查看是否支持,如果 capability 被關閉,會看到如下信息:
WARNING: No swap limit support
內存 Memory
不允許正在運行的容器占用過多的主機內存,在 Linux 主機上,如果內核檢測到沒有足夠的內存來運行重要的系統功能,則會拋出 OOME(Out Of Memory Exception),並殺掉進程來釋放內存,包括 docker 或者其他重要進程在內,任何一個進程都可能被會 kill 掉,這個異常甚至可能會導致系統宕機。
Docker 嘗試通過吊證守護進程的 OOM 優先級來降低這些風行,使其比其他進程容易被 kill。容器的 OOM 優先級未作調整,這使得單個容器更容易被殺死(相比 docker 守護進程或其他系統進程),一般不建議手動將守護進程或容器的--oom-score-adj設置為一個極端的負數,或者在容器上設置 --oom-kill-disable 來規避這些安全措施。
你可以通過下面的方法來降低 OOM 帶來的風險:
- 投入生產前,執行測試以便了解程序的內存要求
- 確保程序運行在有充足資源的主機上
- 限制容器的內存使用量
- 留意配置的 swap,swap 性能比內存低,但可以提供一個緩沖
- 考慮將容器轉換為服務(swaem service),使用服務級別的約束和節點標簽,以確保應用程序僅在有足夠內存的主機上運行
限制容器的內存用量
Docker 可強制執行硬性的內存限制,即允許容器使用不超過給定數量的用戶或系統的內存;或軟性限制,除非滿足某些條件,否則允許容器根據需要使用盡可能多的內存,例如當內核檢測到內存不足或爭用時。
下面的選項中,當單獨使用或設置多個選項時,其中一些選項會產生不同的效果。這些選項大多使用正整數,單位是 b(bytes), k(kilobytes), m(megabytes), g(gigabytes)。
| 選項 | 描述 |
|---|---|
| -m 或 --memory= | 容器可以使用的最大內存量。如果設置此選項,則最小允許值為4m(4兆字節)。 |
| --memory-swap* | 允許此容器使用的swap的用量,僅在還設置了--memory時才有意義 |
| --memory-swappiness | 默認情況下,主機內核可以換出一定比例的容器使用的匿名頁面,可將該選項的值設置為0-100間,來指定這個比例 |
| --memory-reservation | 允許指定一個比--memory更小的軟限制,當 docker 檢測到主機內存不存或爭用時,會激活該軟限制。如果使用該選項,則必須將其設置為低於--memory的值才會有優先權,因其是軟限制,所以不能保證容器不超過限制, |
| --kernel-memory | 容器可以使用的最大內核內存量。最小允許值為4m。由於無法交換內核內存,因此內核內存不足的容器可能會阻塞主機資源,這可能會對主機和其他容器產生副作用。 |
| --oom-kill-disable | 默認情況下,如果發生內存不足(OOM)錯誤,則內核將終止容器中的進程。若要更改此行為,可使用--oom-kill-disable選項。在設置了-m /-memory選項的容器上禁用OOM 殺手。如果未設置-m標志,則主機可能會耗盡內存,內核可能需要終止主機系統的進程以釋放內存。 |
CPU
默認情況下,每個容器 都可以無限制的使用 CPU,你可以設置各種約束來限制容器對 CPU 的訪問,大多數用戶使用配置的是默認的CFS調度器。
配置默認的 CFS 調度器
CFS 是用於常規Linux 進程的內核 CPU 調度器。有幾個 runtime 標志可以讓你去配置容器可使用的 CPU 資源量。當你配置之后,Docker 會修改主機上容器的cgroup 的設置。
| 選項 | 描述 |
|---|---|
| --cpus= | 指定一個容器可以使用多少有效的 CPU資源。例如,如果宿主機有 2 個 CPU,而你設置了--cpus="1.5",那么容器最多使用一個半的 CPU 可使用。這等價於設置了 --cpu-period =“ 100000” 和 --cpu-quota =“ 150000” |
| --cpu-period= | 指定CPU CFS調度器的周期,默認為100微秒,和--cpu-quota 一起使用。大多數用不會修改此默認設置,Docker1.13 及之后的版本使用 --cpus 替代。 |
| --cpu-quota= | 在容器上設置 CPU CFS 的配額。容器在每個--cpu-period中被限制使用的微秒數。Docker1.13 及之后的版本使用 --cpus 替代。 |
| --cpuset-cpus | 限制容器使用指定的 CPU 或內核,如果有多個 CPU,可使用逗號或者連接符進行分隔。第一個 CPU 序號是 0。 設置的值可能是0-3(使用第一,第二,第三和第四CPU)或1,3(使用第二和第四CPU) |
| --cpu-shares | 默認值為 1024,設置大於或小於默認值,可增加或減少容器的權重,使容器可可以使用更多或更少的 CPU周期。只有在限制 CPU 周期的時候才會執行此操作。當有足夠的 CPU周期可用時,所有的容器都會使用盡可能多的 CPU。--cpu-shares不會影響 swarm 模式的調度。他為有效的CPU周期確定容器 CPU資源的使用優先級。它不保證或保留任何特定的 CPU 訪問權限。 |
--cpu-period 和--cpu-quota兩個參數控制容器可以分配到的CPU時鍾周期。–cpu-period是用來指定容器對CPU的使用要在多長時間內做一次重新分配,而–cpu-quota是用來指定在這個周期內,最多可以有多少時間用來跑這個容器。跟–cpu-shares不同的是這種配置是指定一個絕對值,而且沒有彈性在里面,容器對CPU資源的使用絕對不會超過配置的值。
# 如果有1 個 CPU,下面的命保證容器每秒最多占用 50%的 CPU。
# Docker 1.13 and higher:
$ docker run -it --cpus=".5" ubuntu /bin/bash
# Docker 1.12 and lower:
$ docker run -it --cpu-period=100000 --cpu-quota=50000 ubuntu /bin/bash
配置實時調度器
Docker 1.13 及以后的版本,你可以配置容器使用實時調度器,來執行無法使用 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 守護程序。例如,在默認1000000微秒(1 秒)的時段內,設置--cpu-rt-runtime=950000可以確保使用實時調度器的容器可以在每1000000微秒內與進行950000微秒,這樣就至少有50000微秒可以運行非實時任務。要使配置永久生效需要配置daemon 文件——/etc/docker/daemon.json。
配置單獨的容器
在使用 docker run 啟動容器時,可以指定多個參數來控制容器的優先級,
| 選項 | 描述 |
|---|---|
| --cap-add=sys_nice | 授權給容器 CAP_SYS_NICE功能,這樣可以允許容器提高 nice 值,設置實時調度策略、CPU 親和力和其他操作。 |
| --cpu-rt-runtime= | 在 docker守護程序的實時調度周期內,容器按運行實時優先級運行的最大微秒數,,同時需要設置 --cap-add=sys_nice |
| --ulimit rtprio= | 允許容器使用的最大優先級,同時需要設置--cap-add=sys_nice |
# 下面的命令在容器 debian:jessie 上設置了三個參數,如果內核或 docker daemon 未正確配置,會報錯。
$ docker run -it --cpu-rt-runtime=950000 \
--ulimit rtprio=99 \
--cap-add=sys_nice \
debian:jessie
GPU
使用 NVIDIA GPU
前提條件
訪問官方NVIDIA 驅動頁面,下載並安裝對應的驅動,完成后需要重啟系統。
驗證 GPU 正常運行且可以訪問。
安裝 NVIDIA-CONTAINER-RUNTIME
按照https://nvidia.github.io/nvidia-container-runtime/上的說明操作,並執行如下命令:
$ apt-get install nvidia-container-runtime
# 確保可以通過 $PATH 找到 nvidia-container-runtime-hook
$ which nvidia-container-runtime-hook
重啟docker daemon。
公布並使用GPUS
$ docker run -it --rm --gpus all ubuntu nvidia-smi
啟動容器時,使用 --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 nvidia-smi
設置 NVIDIA功能
你可以手動設置 NVIDIA 功能,例如,在 Ubuntu 上你可以執行如下命令:
$ docker run --gpus 'all,capabilities=utility' --rm ubuntu nvidia-smi
這會啟用 utility 驅動功能,從而將 nvidia-smi 工具添加到容器中。
通過環境變量可以在容器中設置功能和其他的配置,更多信息可以查看GitHub 上的nvidia-container-runtime,這些半兩可以在 Dockerfile 中使用。
