资源限制
容器资源限制概述
- 官方文档:https://docs.docker.com/config/containers/resource_constraints/
- 默认情况下,容器没有对资源的使用限制,即在某些情况下,可以将宿主机的资源耗尽
- Docker 提供了控制容器使用资源的方法,可以限制容器对内存、cpu等资源的使用量,可以在运行docker run 命令时配合特定的参数加以限制
前期准备
- 容器中资源限制的很多功能都要求宿主机的内核支持
- 要检查是否支持这些功能,可以使用docker info命令查看是否有警告信息
- 官方文档:https://docs.docker.com/engine/install/linux-postinstall/#your-kernel-does-not-support-cgroup-swap-limit-capabilities
范例:
root@Ubuntu2004:~# docker info
Client:
Context: default
Debug Mode: false
Plugins:
app: Docker App (Docker Inc., v0.9.1-beta3)
buildx: Build with BuildKit (Docker Inc., v0.6.3-docker)
scan: Docker Scan (Docker Inc., v0.17.0)
Server:
Containers: 0
Running: 0
Paused: 0
Stopped: 0
Images: 77
Server Version: 20.10.10
Storage Driver: overlay2
Backing Filesystem: xfs
Supports d_type: true
Native Overlay Diff: true
userxattr: false
Logging Driver: json-file
Cgroup Driver: cgroupfs
Cgroup Version: 1
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: io.containerd.runc.v2 io.containerd.runtime.v1.linux runc
Default Runtime: runc
Init Binary: docker-init
containerd version: 2a1d4dbdb2a1030dc5b01e96fb110a9d9f150ecc
runc version: v1.0.3-0-gf46b6ba
init version: de40ad0
Security Options:
seccomp
Profile: default
Kernel Version: 4.18.0-240.el8.x86_64
Operating System: CentOS Linux 8
OSType: linux
Architecture: x86_64
CPUs: 4
Total Memory: 3.81GiB
Name: docker
ID: RWES:NEXJ:23MD:CYNE:RAHI:45N2:NEJZ:RY42:SHA7:MI4F:XNLL:TUZF
Docker Root Dir: /var/lib/docker
Debug Mode: false
Registry: https://index.docker.io/v1/
Labels:
Experimental: false
Insecure Registries:
10.0.0.100
10.0.0.101
127.0.0.0/8
Registry Mirrors:
https://jqm0rnhf.mirror.aliyuncs.com/
Live Restore Enabled: false
WARNING: No swap limit support #无交换限制支持,这样会影响容器运行的性能解决办法
- 修改内核参数来消除以上警告
root@Ubuntu2004:~# vim /etc/default/grub
...
#添加或编辑该GRUB_CMDLINE_LINUX行以添加 cgroup_enable=memory swapaccount=1 这两个键值对:
GRUB_CMDLINE_LINUX="net.ifnames=0 cgroup_enable=memory swapaccount=1 biosdevname=0;"
...
#更新GRUB
root@Ubuntu2004:~# update-grub
#禁用swap挂载
root@Ubuntu2004:~# vim /etc/fstab
...
#/swap.img none swap sw 0 0
...
#重启使其生效
root@Ubuntu2004:~# reboot
#再次查看,可以看到无WARNING了OOM
- Out Of Memory(内存溢出、内存泄漏、内存异常)
- 对于Linux主机,如果没有足够的内存,则系统则会抛出OOM,从而kill掉内存量使用最大的进程,而内存使用量较大的进程通常都是生产中重要进程,如Java、MySQL等…
- 产生 OOM 异常时,dockerd会尝试通过调整docker守护进程上的OOM优先级来减轻这些风险,以便它比系统上的其他进程更不可能被杀死,但是容器的OOM优先级未调整,这使得单个容器被杀死的可能性比docker守护程序或其他系统进程被杀死的可能性更大
- 不推荐通过在守护进程或容器上手动设置–oom-sorce-adj为极端负数,或通过在容器上设置–oom-kill-disable来绕过这些安全措施
OOM 优先级机制
- linux会为每个进程算一个分数,在内存不足的时候会将分数最高的kill掉
/proc/PID/oom_score_adj
#范围为 -1000 到 1000,值越高越容易被宿主机kill掉,如果将该值设置为 -1000,则进程永远不会被宿主机 kernel kill
/proc/PID/oom_adj
#范围为 -17 到 15 ,取值越高越容易被干掉,如果是-17,则表示不能被kill
#该参数的存在是为了和旧版本的Linux内核兼容
/proc/PID/oom_score
#这个值是系统综合进程的内存消耗量、CPU时间(utime+存活时间(uptime - start time))和 oom_adj 计算出来的进程得分,消耗内存越多得分越高,则越容易被宿主机内核kill掉OOM 优先级范例:
# pidof vim
3310
# pidof dockerd
953
# cat /proc/3310/oom_score_adj
0
# cat /proc/953/oom_score_adj
-500
# cat /proc/3310/oom_adj
0
# cat /proc/953/oom_adj
-8
# cat /proc/3310/oom_score
669
# cat /proc/953/oom_score
366容器的内存限制
- docker内存限制分为两种:
- 硬性内存限制,即只允许容器使用给定的内存大小
- 非硬性内存限制,即容器可以使用尽可能多的内存,除非内核检测到主机上的内存不够用了
内存限制相关选项
- 官方文档:https://docs.docker.com/config/containers/resource_constraints/
- 这些选项中的大多数采用正整数,后跟
b,k,m,g, 后缀来表示字节、千字节、兆字节或千兆字节。 - 常用选项:
| 选项 | 说明 |
|---|---|
| -m 或 –memory= | 容器可以使用的最大内存量。如果设置此选项,则允许的最小值为6m(6 兆字节)。也就是说,您必须将该值设置为至少 6 兆字节。 |
| –oom-kill-disable | 默认情况下,如果发生内存不足 (OOM) 错误,内核会终止容器中的进程。要更改此行为,请使用该--oom-kill-disable选项。仅在您还设置了该-m/--memory选项的容器上禁用 OOM kill。如果-m未设置该标志,主机可能会耗尽内存,内核可能需要终止主机系统的进程以释放内存。 |
| … | … |
范例:
未做限制前
- 显示的是宿主机的内存和使用量
[root@docker ~]# docker run --name test -it --rm ubuntu:20.04
root@1162cadbad75:/# free -h
total used free shared buff/cache available
Mem: 3.8Gi 378Mi 2.9Gi 9.0Mi 512Mi 3.2Gi
Swap: 0B 0B 0B
[root@docker ~]# docker stats --no-stream test
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
d9463c55ffa2 test 0.00% 2.059MiB / 3.81GiB 0.05% 976B / 0B 0B / 0B 1做限制后
- -m 100m,限制使用量为100m
[root@docker ~]# docker run --name test -it --rm -m 100m ubuntu:20.04
[root@docker ~]# docker stats --no-stream test
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
f81449e7ee62 test 0.00% 2.445MiB / 100MiB 2.45% 766B / 0B 0B / 0B 1容器的cpu限制
-
一个核心的CPU可以通过调度(上下文切换)而运行多个进程,但是同一个单位时间内只能有一个进程在CPU上运行。
-
Linux kernel 进程的调度基于CFS(Completely Fair Scheduler)完全公平调度
-
官方文档:https://docs.docker.com/config/containers/resource_constraints/
cpu限制相关选项
-
配置默认的CFS调度程序
-
常用选项:
| 选项 | 描述 |
|---|---|
| –cpus= |
指定容器可以使用多少可用 CPU 资源。例如,如果主机有两个 CPU,并且您设置--cpus="1.5"了 ,则容器最多可以保证一个半的 CPU。这相当于设置--cpu-period="100000"和--cpu-quota="150000"。(假设有4个cpu,并且设置了–cpus=“2”,则表示将利用每个cpu的百分之五十(雨露均沾,而不是盯住两个cpu来进行限制)) |
| –cpuset-cpus | 限制容器可以使用的特定 CPU 或内核。如果您有多个 CPU,则容器可以使用的逗号分隔列表或连字符分隔的 CPU 范围。第一个 CPU 编号为 0。有效值可能是0-3(使用第一个、第二个、第三个和第四个 CPU)或1,3(使用第二个和第四个 CPU)。 |
| … | … |
压力测试工具 stress-ng
官方镜像
docker pull lorel/docker-stress-ng测试cpu限制
相关选项
[root@docker ~]# docker run -it --rm --name test-cpu lorel/docker-stress-ng|grep cpu
-c N, --cpu N start N workers spinning on sqrt(rand())
--cpu-ops N stop when N cpu bogo operations completed
-l P, --cpu-load P load CPU by P %%, 0=sleep, 100=full load (see -c)
--cpu-method m specify stress cpu method m, default is all
Example: stress-ng --cpu 8 --io 4 --vm 2 --vm-bytes 128M --fork 4 --timeout 10s宿主机CPU概况
[root@docker ~]# lscpu |grep CPU
CPU op-mode(s): 32-bit, 64-bit
CPU(s): 4
On-line CPU(s) list: 0-3
CPU family: 23
CPU MHz: 2095.977
NUMA node0 CPU(s): 0-3未做限制前测试
#使用三颗cpu
[root@docker ~]# docker run -it --rm --name test-cpu lorel/docker-stress-ng --cpu 3
stress-ng: info: [1] defaulting to a 86400 second run per stressor
stress-ng: info: [1] dispatching hogs: 3 cpu
#可以看到使用了284.61%的CPU,也就相当于3颗cpu(每颗cpu100%)
[root@docker ~]# docker stats --no-stream test-cpu
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
672fd8f10064 test-cpu 284.61% 14.65MiB / 3.81GiB 0.38% 906B / 0B 0B / 0B 4
#查看容器进程的cpu使用相关文件
[root@docker ~]# cat /sys/fs/cgroup/cpuset/docker/c5888748a888d58834e7d4249c1cf1017b0fad690de256f915baa036e07ffd12/cpuset.cpus
0-3 #可以使用0-3号cpu,也就是4颗cpu
[root@docker ~]# top
top - 00:36:38 up 4:11, 2 users, load average: 2.01, 1.70, 0.81
Tasks: 189 total, 5 running, 184 sleeping, 0 stopped, 0 zombie
%Cpu0 : 93.9 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 6.1 hi, 0.0 si, 0.0 st
%Cpu1 : 93.9 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 6.1 hi, 0.0 si, 0.0 st
%Cpu2 : 95.8 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 4.2 hi, 0.0 si, 0.0 st
%Cpu3 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st做限制后测试
#使用三颗cpu,但限制使用一颗(也支持浮点数,如:--cpus 1.5)
[root@docker ~]# docker run -it --rm --name test-cpu --cpus 1 lorel/docker-stress-ng --cpu 3
stress-ng: info: [1] defaulting to a 86400 second run per stressor
stress-ng: info: [1] dispatching hogs: 3 cpu
[root@docker ~]# docker stats --no-stream test-cpu
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
7e62901a2ad1 test-cpu 115.60% 12.75MiB / 3.81GiB 0.33% 1.12kB / 0B 0B / 0B 4
[root@docker ~]# top
top - 00:42:48 up 4:18, 2 users, load average: 0.06, 1.01, 0.87
Tasks: 186 total, 4 running, 182 sleeping, 0 stopped, 0 zombie
%Cpu0 : 29.8 us, 0.0 sy, 0.0 ni, 67.7 id, 0.0 wa, 2.5 hi, 0.0 si, 0.0 st
%Cpu1 : 29.7 us, 0.3 sy, 0.0 ni, 68.2 id, 0.0 wa, 1.7 hi, 0.0 si, 0.0 st
%Cpu2 : 0.0 us, 0.0 sy, 0.0 ni, 99.7 id, 0.0 wa, 0.3 hi, 0.0 si, 0.0 st
%Cpu3 : 30.0 us, 0.0 sy, 0.0 ni, 68.6 id, 0.0 wa, 1.4 hi, 0.0 si, 0.0 st测试cpu绑定
- 一般不建议将进程绑定在0号cpu上,因为0号cpu通常比较忙
#限制使用1颗cpu,并只绑定在1和3号cpu上
[root@docker ~]# docker run -it --rm --name test-cpu --cpus 1 --cpuset-cpus 1,3 lorel/docker-stress-ng --cpu 3
stress-ng: info: [1] defaulting to a 86400 second run per stressor
stress-ng: info: [1] dispatching hogs: 3 cpu
#查看绑定结果
[root@docker ~]# top
top - 00:52:01 up 4:27, 2 users, load average: 0.92, 0.80, 0.92
Tasks: 182 total, 5 running, 177 sleeping, 0 stopped, 0 zombie
%Cpu0 : 0.0 us, 0.3 sy, 0.0 ni, 99.0 id, 0.0 wa, 0.7 hi, 0.0 si, 0.0 st
%Cpu1 : 50.0 us, 0.0 sy, 0.0 ni, 47.0 id, 0.0 wa, 3.0 hi, 0.0 si, 0.0 st
%Cpu2 : 0.3 us, 0.0 sy, 0.0 ni, 99.3 id, 0.0 wa, 0.3 hi, 0.0 si, 0.0 st
%Cpu3 : 49.8 us, 0.0 sy, 0.0 ni, 46.8 id, 0.0 wa, 3.0 hi, 0.3 si, 0.0 st