Runtime options with Memory, CPUs, and GPUs

预计阅读时间:16分钟

默认情况下,容器没有资源限制,并且可以使用主机内核调度程序允许的尽可能多的给定资源. Docker 提供了控制容器可以使用多少内存或 CPU 的方法,设置docker run命令的运行时配置标志. 本节提供有关何时应设置此类限制以及设置这些限制的可能影响的详细信息.

其中许多功能需要您的内核支持 Linux 功能. 要检查支持,您可以使用docker info命令. 如果您的内核中禁用了一项功能,您可能会在输出末尾看到如下警告:

WARNING: No swap limit support

请查阅您的操作系统文档以启用它们. 了解更多.

Memory

Understand the risks of running out of memory

重要的是不要让正在运行的容器消耗过多的主机内存. 在 Linux 主机上,如果内核检测到没有足够的内存来执行重要的系统功能,它会抛出OOMEOut Of Memory Exception ,并开始杀死进程以释放内存. 任何进程都会被杀死,包括 Docker 和其他重要的应用程序. 如果错误的进程被杀死,这可以有效地关闭整个系统.

Docker 尝试通过调整 Docker 守护进程的 OOM 优先级来降低这些风险,使其比系统上的其他进程更不可能被杀死. 容器的OOM优先级没有调整. 这使得单个容器被杀死的可能性比 Docker 守护进程或其他系统进程被杀死的可能性更大. 您不应尝试通过在守护进程或容器上手动将--oom-score-adj设置为极端负数,或通过在容器上设置--oom-kill-disable来规避这些保护措施.

For more information about the Linux kernel’s OOM management, see 内存不足管理.

您可以通过以下方式降低 OOME 导致的系统不稳定风险:

  • 在将应用程序投入生产之前执行测试以了解应用程序的内存要求.
  • 确保您的应用程序仅在具有足够资源的主机上运行.
  • 限制容器可以使用的内存量,如下所述.
  • 在 Docker 主机上配置交换时请注意. 交换比内存更慢且性能更低,但可以提供缓冲以防止系统内存耗尽.
  • 考虑将您的容器转换为服务,并使用服务级别约束和节点标签来确保应用程序仅在具有足够内存的主机上运行

Limit a container’s access to memory

Docker 可以强制执行硬内存限制,允许容器使用不超过给定数量的用户或系统内存,或软限制,允许容器根据需要使用尽可能多的内存,除非满足某些条件,例如何时内核检测到主机内存不足或争用. 其中一些选项在单独使用或设置多个选项时具有不同的效果.

这些选项中的大多数采用正整数,后跟bkmg后缀,表示字节、千字节、兆字节或千兆字节.

Option Description
-m or --memory= 容器可以使用的最大内存量. 如果设置此选项,则允许的最小值为6m (6 兆字节). 也就是说,您必须将该值设置为至少 6 兆字节.
--memory-swap* 允许此容器交换到磁盘的内存量. 请参阅--memory-swap详细信息.
--memory-swappiness 默认情况下,主机内核可以换出容器使用的一定百分比的匿名页面. 您可以将--memory-swappiness设置为 0 到 100 之间的值,以调整此百分比. 请参阅--memory-swappiness详细信息.
--memory-reservation 允许您指定小于--memory的软限制,当 Docker 检测到主机上的争用或内存不足时激活该软限制. 如果您使用--memory-reservation ,则必须将其设置为低于--memory才能优先. 因为是软限制,所以不保证容器不超过限制.
--kernel-memory 容器可以使用的最大内核内存量. 允许的最小值为4m . 因为内核内存不能被换出,内核内存不足的容器可能会阻塞主机资源,这会对主机和其他容器产生副作用. 请参阅--kernel-memory详细信息.
--oom-kill-disable 默认情况下,如果发生内存不足 (OOM) 错误,内核会终止容器中的进程. 要更改此行为,请使用--oom-kill-disable选项. 仅在您还设置了-m/--memory选项的容器上禁用 OOM 杀手. 如果未设置-m标志,主机可能会耗尽内存,内核可能需要终止主机系统的进程以释放内存.

有关 cgroups 和一般内存的更多信息,请参阅Memory Resource Controller的文档.

--memory-swap details

--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设置为正整数,则容器无权访问 swap . 请参阅防止容器使用交换.

  • 如果--memory-swap未设置,而--memory已设置,则容器可以使用与--memory设置一样多的交换,如果主机容器配置了交换内存. 例如,如果--memory="300m"--memory-swap没有设置,容器总共可以使用 600m 的内存和交换空间.

  • 如果--memory-swap显式设置为-1 ,则允许容器使用无限交换,最多为主机系统上可用的数量.

  • 在容器内部,诸如free之类的工具会报告主机的可用交换,而不是容器内部的可用交换. 不要依赖free或类似工具的输出来确定是否存在交换.

Prevent a container from using swap

如果--memory--memory-swap设置为相同的值,这会阻止容器使用任何交换. 这是因为--memory-swap是可以使用的组合内存和交换量,而--memory只是可以使用的物理内存量.

--memory-swappiness details

  • 值 0 关闭匿名页面交换.
  • 值 100 将所有匿名页面设置为可交换.
  • 默认情况下,如果您不设置--memory-swappiness ,则该值是从主机继承的.

--kernel-memory details

内核内存限制以分配给容器的总内存表示. 考虑以下场景:

  • 无限内存,无限内核内存:这是默认行为.
  • 无限内存,有限内核内存:当所有 cgroup 所需的内存量大于主机上实际存在的内存量时,这是合适的. 您可以将内核内存配置为永远不会超过主机上可用的内存,并且需要更多内存的容器需要等待它.
  • 有限内存,无限内核内存:整体内存是有限的,但内核内存不是.
  • 有限的内存,有限的内核内存:限制用户和内核内存对于调试与内存相关的问题很有用. 如果容器使用的任一类型内存的数量超出预期,它就会耗尽内存,而不会影响其他容器或主机. 在此设置中,如果内核内存限制低于用户内存限制,则内核内存不足会导致容器出现 OOM 错误. 如果内核内存限制高于用户内存限制,则内核限制不会导致容器出现 OOM.

当您打开任何内核内存限制时,主机会基于每个进程跟踪"高水位线"统计信息,因此您可以跟踪哪些进程(在本例中为容器)正在使用过多的内存. 这可以通过查看主机上的/proc/<PID>/status来查看每个进程.

CPU

默认情况下,每个容器对主机 CPU 周期的访问是无限制的. 您可以设置各种约束来限制给定容器对主机 CPU 周期的访问. 大多数用户使用和配置默认的 CFS 调度程序. 您还可以配置实时调度程序.

Configure the default CFS scheduler

CFS 是用于普通 Linux 进程的 Linux 内核 CPU 调度程序. 几个运行时标志允许您配置对容器拥有的 CPU 资源的访问量. 当您使用这些设置时,Docker 会修改主机上容器的 cgroup 的设置.

Option Description
--cpus=<value> 指定容器可以使用多少可用 CPU 资源. 例如,如果主机有两个 CPU,而您设置--cpus="1.5" ,则容器最多可以保证一个半的 CPU. 这相当于设置--cpu-period="100000"--cpu-quota="150000" .
--cpu-period=<value> 指定与--cpu-quota一起使用的 CPU CFS 调度程序周期. 默认为 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

Configure the realtime scheduler

对于无法使用 CFS 调度程序的任务,您可以将容器配置为使用实时调度程序. 在配置 Docker 守护进程配置单个容器之前,您需要确保主机的内核配置正确.

Warning

CPU 调度和优先级是高级内核级功能. 大多数用户不需要更改这些默认值. 错误地设置这些值会导致您的主机系统变得不稳定或无法使用.

Configure the host machine’s kernel

通过运行zcat /proc/config.gz | grep CONFIG_RT_GROUP_SCHED验证 Linux 内核中是否启用了CONFIG_RT_GROUP_SCHED | zcat /proc/config.gz | grep CONFIG_RT_GROUP_SCHED或通过检查文件/sys/fs/cgroup/cpu.rt_runtime_us的存在. 有关配置内核实时调度程序的指导,请参阅您的操作系统的文档.

Configure the Docker daemon

要使用实时调度程序运行容器,请运行 Docker 守护程序,并将--cpu-rt-runtime标志设置为每个运行时期间为实时任务保留的最大微秒数. 例如,在默认周期为 1000000 微秒(1 秒)的情况下,设置--cpu-rt-runtime=950000可确保使用实时调度程序的容器每 1000000 微秒周期可以运行 950000 微秒,留下至少 50000 微秒可用对于非实时任务. 要使此配置在使用 systemd 的系统上永久生效,请参阅使用systemd控制和配置 Docker .

Configure individual containers

当您使用docker run启动容器时,您可以传递多个标志来控制容器的 CPU 优先级. 有关适当值的信息,请参阅操作系统的文档或ulimit命令.

Option Description
--cap-add=sys_nice 授予容器CAP_SYS_NICE能力,允许容器提升进程nice值、设置实时调度策略、设置 CPU 亲和性和其他操作.
--cpu-rt-runtime=<value> The maximum number of microseconds the container can run at realtime priority within the Docker daemon’s realtime scheduler period. You also need the --cap-add=sys_nice flag.
--ulimit rtprio=<value> 容器允许的最大实时优先级. 您还需要--cap-add=sys_nice标志.

以下示例命令在debian:jessie容器上设置这三个标志中的每一个.

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

如果未正确配置内核或 Docker 守护程序,则会发生错误.

GPU

Access an NVIDIA GPU

Prerequisites

访问官方NVIDIA 驱动程序页面以下载并安装正确的驱动程序. 完成后重新启动系统.

验证您的 GPU 是否正在运行且可访问.

Install 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 守护程序.

Expose GPUs for use

启动容器以访问 GPU 资源时包括--gpus标志. 指定要使用的 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.

Note

NVIDIA GPU 只能由运行单个引擎的系统访问.

Set NVIDIA capabilities

您可以手动设置功能. 例如,在 Ubuntu 上,您可以运行以下命令:

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

这启用了将nvidia-smi工具添加到容器的utility驱动程序功能.

可以通过环境变量在图像中设置功能以及其他配置. 有关有效变量的更多信息,请参见nvidia-container-runtime GitHub 页面. 这些变量可以在 Dockerfile 中设置.

您还可以使用自动设置这些变量的 CUDA 图像. 有关更多信息,请参阅CUDA 图像GitHub 页面.

docker, daemon, configuration, runtime

by  icopy.site