默认情况下,容器没有资源限制,可以使用主机内核调度程序允许的尽可能多的给定资源。
Memory
内存风险
不允许容器消耗宿主机太多的内存是非常重要的。在 Linux 主机上,如果内核检测到没有足够的内存来执行重要的系统功能,它会抛出 OOME
或 Out of Memory
异常,并开始终止进程以释放内存。任何进程都会被杀死,包括 Docker 和其他重要的应用程序。如果杀错进程,可能导致整个系统瘫痪。
Docker 通过调整 Docker daemon 上的 OOM 优先级来降低这些风险,以便它比系统上的其他进程更不可能被杀死。容器上的 OOM 优先级未调整,这使得单个容器被杀死的可能性比 Docker daemon 或其他系统进程被杀死的可能性更大。你不应试图通过在 daemon 或容器上手动设置 --oom-score-adj
到极端负数,或通过在容器上设置 --oom-kill-disable
来绕过这些安全措施。
有关Linux内核的OOM管理的更多信息,查看 Out of Memory Management
可以通过以下方式降低 OOME 导致系统不稳定的风险:
- 在应用程序发布到生产之前,执行相关测试以便了解应用程序的内存要求;
- 确保应用程序仅在具有足够资源的主机上运行;
- 限制容器可以使用的内存,如下所述;
- 在 Docker 主机上配置 Swap 时要小心,Swap 比内存更慢且性能更低,但可以提供缓冲以防止系统内存耗尽;
- 考虑将 Container 转换部署为 Service,并使用服务级别约束和节点标签来确保应用程序仅在具有足够内存的主机上运行。
限制容器内存
下述选项中的大多数采用正整数,后跟 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 killer,如果未设置 -m 标志,则主机可能会耗尽内存,内核可能需要终止主机系统的进程才能释放内存 |
有关 cgroup 和内存的更多信息,查看 Memory Resource Controller
关于 --memory-swap
--memory-swap
是一个修饰符标志,只有在设置了 --memory
时才有意义。使用 swap 允许容器在容器耗尽所有可用的 RAM 时,将多余的内存需求写入磁盘。对于经常将内存交换到磁盘的应用程序,性能会受到影响。
它的设置会产生复杂的影响:
- 如果
--memory-swap
设置为正整数,则必须设置--memory
和--memory-swap
。--memory-swap
表示可以使用的 memory 和 swap 总量,--memory
控制 no-swap 的用量。 所以,如果设置--memory="300m"
和--memory-swap="1g"
, 容器可以使用 300m memory 和 700m (1g - 300m
) swap。 - 如果
--memory-swap
设置为0
, 该设置被忽略,该值被视为未设置。 - 如果
--memory-swap
的值等于--memory
的值, 并且--memory
设置为正整数, 则容器无权访问 swap。这是因为--memory-swap
是可以使用组合的 Memory 和 Swap,而--memory
只是可以使用的 Memory。 - 如果
--memory-swap
不设置, 并且--memory
设置了值, 容器可以使用--memory
两倍的 Swap(如果主机容器配置了 Swap)。示例: 设置--memory="300m"
并且不设置--memory-swap
,容器可以使用 300m memory 和 600m swap。 - 如果
--memory-swap
设置为-1
,允许容器无限制使用 Swap。 - 在容器内部,像
free
等工具报告的是主机的可用 Swap,而不是容器内可用的。不要依赖于free
或类似工具的输出来确定是否存在 Swap。
关于 --memory-swappiness
- 值为 0 时,关闭匿名页交换。
- 值为 100 时,将所有匿名页设置为可交换。
- 默认情况下,如果不设置
--memory-swappiness
, 该值从主机继承。
关于 --kernel-memory
内核内存限制是就分配给容器的总内存而言的,考虑一下方案:
- 无限内存,无限内核内存:这是默认行为。
- 无限内存,有限内核内存:当所有 cgroup 所需的内存量大于主机上实际存在的内存量时,它是合适的。可以将内核内存配置为永远不会超过主机上可用的内存,而需求更多内存的容器需要等待它。
- 有限内存,无限内核内存:整体内存有限,但内核内存不是。
- 有限内存,有限内核内存:限制用户和内核内存对于调试与内存相关的问题非常有用,如果容器使用意外数量的任意类型的内存,则内存不足不会影响其他容器或主机。在此设置中,如果内核内存限制低于用户内存限制,则内核内存不足会导致容器遇到 OOM 错误。如果内核内存限制高于用户内存限制,则内核限制不会导致容器遇到 OOM。
当你打开任何内核内存限制时,主机会根据每个进程跟踪 “高水位线” 统计信息,因此您可以跟踪哪些进程(在本例中为容器)正在使用多余的内存。通过查看主机上的 /proc/
,可以在每个进程中看到这一点。
CPU
默认情况下,每个容器对主机 CPU 周期的访问权限是不受限制的,您可以设置各种约束来限制给定容器访问主机的 CPU 周期。大多数用户使用和配置 默认 CFS 调度程序。在 Docker 1.13 及更高版本中,还可以配置实时调度程序。
配置默认 CFS 调度程序
CFS 是用于普通 Linux 进程的 Linux 内核 CPU 调度程序。通过以下设置,可以控制容器的 CPU 资源访问量,使用这些设置时,Docker 会修改主机上容器的 cgroup 的设置。
选项 | 描述 |
---|---|
--cpus= |
指定容器可以使用的 CPU 资源量。例如,如果主机有两个CPU并且,设置 --cpus="1.5" ,则容器最多可以使用 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 个 CPU,则以下每个命令都会保证容器每秒最多占 CPU 的 50%。
Docker 1.13 或更高版本:
docker run -it --cpus=".5" ubuntu /bin/bash
Docker 1.12 或更低版本:
docker run -it --cpu-period=100000 --cpu-quota=50000 ubuntu /bin/bash
配置实时调度程序
In Docker 1.13 and higher, you can configure your container to use the realtime scheduler,
在 Docker 1.13 或更高版本,你可以配置容器使用实时调度程序。在配置 Docker daemon 或配置容器之前,需要确保正确配置主机的内核。
警告:CPU 调度和优先级是高级内核级功能,大多数用户不需要从默认值更改这些值,错误地设置这些值可能会导致主机系统变得不稳定或无法使用。
配置主机机器的内核
通过运行 zcat /proc/config.gz | grep CONFIG_RT_GROUP_SCHED
验证是否在 Linux 内核中启用了 CONFIG_RT_GROUP_SCHED
,或者检查是否存在文件 /sys/fs/cgroup/cpu.rt_runtime_us
。有关配置内核实时调度程序的教程,请参阅操作系统的文档。
配置DOCKER DAEMON
要使用实时调度程序运行容器,请运行 Docker daemon,并将 --cpu-rt-runtime
设置为每个运行时间段为实时任务保留的最大微秒数。例如,默认周期为 1000000 微秒(1秒),设置 --cpu-rt-runtime=950000
可确保使用实时调度程序的容器每 1000000 微秒可运行 950000 微秒,并保留至少 50000 微秒用于非实时任务。要在使用 systemd 的系统上永久保留此配置,请参阅 Control and configure Docker with systemd。
配置个别容器
使用 docker run
启动容器时,可以传递多个参数来控制容器的 CPU 优先级。有关适当值的信息,请参阅操作系统的文档或 ulimit
命令。
选项 | 描述 |
---|---|
--cap-add=sys_nice | 授予容器 CAP_SYS_NICE 功能,该功能允许容器引发进程良好值,设置实时调度策略,设置 CPU 亲和性以及其他操作。 |
--cpu-rt-runtime= |
容器可以在 Docker 守护程序的实时调度程序周期内以实时优先级运行的最大微秒数,需要设置 --cap-add=sys_nice 。 |
--ulimit rtprio= |
容器允许的最大实时优先级,需要 --cap-add=sys_nice 标志。 |
示例:
docker run --it --cpu-rt-runtime=950000 \
--ulimit rtprio=99 \
--cap-add=sys_nice \
debian:jessie
如果未正确配置内核或 Docker Daemon,则会发生错误。
相关文章
- Limit a container's resources
- Linux 使用 free 查看系统内存信息
- CentOS 查看系统 CPU 信息