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/
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
参考链接: