docker资源配额
- Kubernetes
- 2024-04-30
- 646热度
- 0评论
docker资源配额
Docker 通过 cgroup 来控制容器使用的资源限制,可以对 docker 限制的资源包括 CPU、内存和磁盘。
指定docker容器可以使用的cpu份额
CPU shares (relative weight) 在创建容器时指定容器所使用的 CPU 份额值。cpu-shares 的值不能保证可以获得 1 个 vcpu 或者多少 GHz 的 CPU 资源,仅仅只是一个弹性的加权值。
默认每个docker容器的cpu份额都是1024。在同一个CPU核心上,同时运行多个容器时,容器的cpu加权的效果才能体现出来。
例如:两个容器 A、B 的 cpu 份额分别为 1000 和 500,结果会怎么样?
情况 1:A 和 B 正常运行,占用同一个 CPU,在 cpu 进行时间片分配的时候,容器 A 比容器 B 多一倍的机会获得 CPU 的时间片。
情况 2:分配的结果取决于当时其他容器的运行状态。比如容器 A 的进程一直是空闲的,那么容器 B是可以获取比容器 A 更多的 CPU 时间片的; 比如主机上只运行了一个容器,即使它的 cpu 份额只有50,它也可以独占整个主机的 cpu 资源。
cgroups 只在多个容器同时争抢同一个 cpu 资源时,cpu 配额才会生效。因此,无法单纯根据某个容器的 cpu 份额来确定有多少 cpu 资源分配给它,资源分配结果取决于同时运行的其他容器的 cpu 分配和容器中进程运行情况。
例如:给容器实例分配512权重的cpu使用份额
[root@docker-master ~]# docker run -it --cpu-shares 512 centos bash
[root@31c17fd9c5d0 /]# cat /sys/fs/cgroup/cpu/cpu.shares
512
注意:单独一个容器,看不出来使用的 cpu 的比例。 因没有 docker 实例同此 docker 实例竞争。测试需要启动多个容器,测试一下是不是只能使用 512 份额的 cpu 资源。
通过-c 设置的 cpu share 并不是 CPU 资源的绝对数量,而是一个相对的权重值。某个容器最终能分配到的 CPU 资源取决于它的 cpu share 占所有容器 cpu share 总和的比例。通过 cpu share可以设置容器使用 CPU 的优先级。
docker CPU core控制
对多核 CPU 的服务器,docker 还可以控制容器运行限定使用哪些 cpu 内核和内存节点,即使用--cpuset-cpus 和--cpuset-mems 参数。对具有 NUMA 拓扑(具有多 CPU、多内存节点)的服务器尤其有用,可以对需要高性能计算的容器进行性能最优的配置。如果服务器只有一个内存节点,则--cpuset-mems 的配置基本上不会有明显效果。
服务器架构一般分为SMP、NUMA、MPP 体系结构,这三个体系结构都是用于并行计算的,但它们在硬件组织和工作方式上有所不同。
-
SMP(Symmetric Multiprocessing):
- SMP 是一种对称多处理体系结构,它在单个系统内部有多个处理器(CPU),并且每个处理器都可以访问相同的物理内存和 I/O 设备。
- 所有处理器之间共享相同的系统总线和内存总线。每个处理器可以访问系统中的所有内存区域,这使得 SMP 系统中的任何处理器都可以运行任何任务。
- SMP 系统通常由几个 CPU 芯片组成,每个 CPU 有自己的缓存,但所有 CPU 共享同一组内存。
- SMP 系统通常用于普通服务器和工作站,以及一般用途的多处理器计算机。
-
NUMA(Non-Uniform Memory Access):
- NUMA 是一种非一致性内存访问体系结构,它在一个系统中有多个处理器和多个内存节点,但每个处理器只能访问其本地节点的内存(本地内存)较快,而访问远程节点的内存则较慢。
- NUMA 系统通常由多个处理器组成,每个处理器都与本地内存节点相连。每个内存节点与一组处理器连接,并且有自己的内存。
- NUMA 系统中的处理器和内存被分割成多个 NUMA 区域,每个区域内的处理器可以访问相同的内存节点。
- NUMA 系统通常用于高性能计算(HPC)、大型数据库和虚拟化环境等需要大量内存和高吞吐量的场景。
-
MPP(Massively Parallel Processing):
- MPP 是一种大规模并行处理体系结构,它由大量的处理器和存储节点组成,这些节点通过高速网络连接在一起。
- 每个节点通常包含处理器、内存和存储,并且在节点之间共享数据和处理任务。
- MPP 系统的设计旨在处理大规模数据并行任务,每个节点负责处理数据的一个子集,然后将结果汇总或合并。
- MPP 系统通常用于大型数据仓库、数据分析、科学计算等需要高度并行处理的场景。
总的来说,SMP 适用于中等规模的多处理器系统,每个处理器可以访问相同的内存和 I/O;NUMA 适用于需要大量内存和高性能的系统,但内存访问速度可能不同;而 MPP 适用于大规模的数据并行处理任务,需要大量的处理器和存储节点。
docker cpu配额控制参数的混合使用
cpu-shares 控制只发生在容器竞争同一个 cpu 的时间片时有效。
如果通过 cpuset-cpus 指定容器 A 使用 cpu 0,容器 B 只是用 cpu1,在主机上只有这两个容器使用对应内核的情况,它们各自占用全部的内核资源,cpu-shares 没有明显效果。但是容器 A 和容器 B 配置上 cpuset-cpus 值都绑定到同一个 cpu 上,然后同时抢占 cpu 资源,就可以观察到控制效果。
拓展:stress命令
安装压力测试软件stress
[root@docker-master ~]# yum -y install eple-release
[root@docker-master ~]# yum -y install stress
stress常用参数及解释如下表所示
参数 | 解释 |
---|---|
-c | 产生 n 个进程,每个进程都反复不停的计算随机数的平方根,测试 cpu |
-i | 产生 n 个进程,每个进程反复调用 sync(),sync()用于将内存上的内容写到硬盘上,测试磁盘 io |
-m | 产生 n 个进程,每个进程不断调用内存分配 malloc()和内存释放 free()函数 ,测试内存 |
--vm-bytes | 指定 malloc 时内存的字节数 (默认 256MB) |
--vm-hang | 指定在 free 栈的秒数 |
-v | 显示版本信息 |
-n | 显示已完成的指令信息 |
-t | 指定运行 N 秒后停止 |
--backoff | 等待指定微秒数后开始运行 |
产生2个cpu进程,2个io进程,20秒后停止
[root@docker-master ~]# stress -c 2 -i 2 -t 20s
stress: info: [119123] dispatching hogs: 2 cpu, 2 io, 0 vm, 0 hdd
在程序运行的过程中,使用top命令,查看cpu的负载情况
top - 04:11:27 up 6 days, 24 min, 3 users, load average: 0.61, 0.30, 0.15
Tasks: 152 total, 5 running, 142 sleeping, 5 stopped, 0 zombie
%Cpu0 : 59.3 us, 40.7 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
#%Cpu1 : 62.9 us, 36.8 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.3 si, 0.0 st
KiB Mem : 1863032 total, 146140 free, 411696 used, 1305196 buff/cache
KiB Swap: 2097148 total, 2091772 free, 5376 used. 1166572 avail Mem
# PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
#119124 root 20 0 7312 96 0 R 50.0 0.0 0:04.12 stress
119126 root 20 0 7312 96 0 R 50.0 0.0 0:04.13 stress
119125 root 20 0 7312 96 0 R 40.1 0.0 0:03.26 stress
119127 root 20 0 7312 96 0 D 40.1 0.0 0:03.30 stress ...省略部分输出...
对#号的行进行参数的解析
参数 | 解释 |
---|---|
%Cpu1 | 第二个CPU |
us | 用户空间,表示 CPU 用于执行用户进程的时间百分比,100.0表示 CPU 的所有时间都花在了用户进程上 |
sy | 系统内核,表示 CPU 用于执行内核进程的时间百分比 |
ni | nice值,表示 CPU 用于执行用户进程,但是这些进程的优先级被调整了 |
id | 空闲,表示 CPU 处于空闲状态的时间百分比,0表示 CPU 没有空闲时间 |
wa | I/O等待, CPU 等待 I/O 操作完成的时间百分比 |
hi | 硬中断,表示 CPU 处理硬中断的时间百分比 |
si | 软中断,表示 CPU 处理软中断的时间百分比 |
st | 虚拟机偷窃,表示被虚拟化环境偷窃的时间百分比 |
参数 | 解释 |
---|---|
PID | 进程 ID,用于唯一标识每个进程 |
USER | 启动进程的用户 |
PR | 进程的优先级 |
NI | 进程的 nice 值,表示进程的优先级调整 |
VIRT | 进程占用的虚拟内存大小(以 KB 为单位) |
RES | 进程当前使用的物理内存大小(以 KB 为单位) |
SHR | 进程使用的共享内存大小(以 KB 为单位) |
S | 进程状态(R表示运行,D表示不可中断的睡眠,S表示睡眠,Z表示僵尸进程等) |
%CPU | 进程占用 CPU 的百分比 |
%MEN | 进程占用内存的百分比 |
TIME+ | 进程已经运行的时间 |
COMMAND | 启动进程的命令 |
根据第三行的#号条目,可以得出
1、进程 ID 为 119124 的进程是一个名为stress的进程,它在进行 CPU 压力测试(R状态,表示正在运行)。
2、该进程占用了 50.0% 的 CPU 资源。
3、它占用了较少的虚拟内存(VIRT)和物理内存(RES)。
4、这个进程启动时使用的命令是stress。
例如:测试 cpu-shares 和 cpuset-cpus 混合使用运行效果,创建两个容器实例:docker10 和 docker20,容器只允许在cpu0上运行,并为两个容器设置不同的份额,观察实验效果。
创建docker10实例,只允许在cpu0上运行,使用份额为512
[root@docker-master ~]# docker run -itd --name docker10 --cpuset-cpus 0 --cpu-shares 512 centos-repo /bin/bash
a6a71f6b3f50ec8829424c69db625e8bf30221b9e5cf1df4b8eaaa5363c8376f
创建docker20实例,只允许在cpu0上运行,使用份额为1024
[root@docker-master ~]# docker run -itd --name docker20 --cpuset-cpus 0 --cpu-shares 1024 centos-repo /bin/bash
a4f99b3c1c3cfea29d6b760ad30860fd0b9963acdc2c4c30f5c89e9a822381fe
在docker10容器内安装stress命令,进行压测
[root@1fff2ce6c839 /]# yum -y install eple-release
[root@1fff2ce6c839 /]# yum -y install stress
[root@1fff2ce6c839 /]# stress -c 2 -t 10m
stress: info: [101] dispatching hogs: 2 cpu, 0 io, 0 vm, 0 hdd
在docker20容器内安装stress命令,进行压测
[root@0de66602e400 /]# yum -y install eple-release
[root@0de66602e400 /]# yum -y install stress
[root@0de66602e400 /]# stress -c 2 -t 10m
stress: info: [101] dispatching hogs: 2 cpu, 0 io, 0 vm, 0 hdd
新建终端,使用top命令,查看cpu负载情况。两个容器只在 cpu0 上运行,说明 cpu 绑定限制成功。而 docker20 是 docker10 使用 cpu 的 2倍。说明--cpu-shares 限制资源成功。
top - 04:50:40 up 6 days, 1:03, 4 users, load average: 2.53, 0.98, 0.46
Tasks: 162 total, 5 running, 152 sleeping, 5 stopped, 0 zombie
%Cpu0 :100.0 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu1 : 0.3 us, 0.3 sy, 0.0 ni, 97.4 id, 0.0 wa, 0.0 hi, 2.0 si, 0.0 st
KiB Mem : 1863032 total, 192844 free, 443132 used, 1227056 buff/cache
KiB Swap: 2097148 total, 2090172 free, 6976 used. 1136848 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
120597 root 20 0 7960 92 0 R 33.6 0.0 0:07.67 stress
120598 root 20 0 7960 92 0 R 33.2 0.0 0:07.66 stress
120507 root 20 0 7960 96 0 R 16.6 0.0 0:24.55 stress
120508 root 20 0 7960 96 0 R 16.6 0.0 0:24.55 stress
...省略部分输出...
docker容器控制内存
docker使用-m参数对内存使用量进行控制
例如:允许容器使用的内存上限为128M
[root@docker-master ~]# docker run -it -m 128m centos
[root@161bfae868fe /]# cat /sys/fs/cgroup/memory/memory.limit_in_bytes
134217728
docker容器控制IO
docker使用--device-write-bps value参数控制容器对宿主机IO设备的读写速度
例如:限制容器实例对硬盘的最高写入速度为2MB/s
生成容器,限制容器对IO写入的速度为2MB/s
[root@docker-master ~]# docker run -it --rm --device-write-bps /dev/sda:2MB centos
[root@28e417935901 /]#
docker inspect命令查看限制写入的参数是否生效
[root@28e417935901 /]# docker inspect 28e417935901
...省略部分输出...
"BlkioWeight": 0,
"BlkioWeightDevice": [],
"BlkioDeviceReadBps": null,
"BlkioDeviceWriteBps": [
{
"Path": "/dev/sda",
"Rate": 2097152
}
],
"BlkioDeviceReadIOps": null,
"BlkioDeviceWriteIOps": null,
...省略部分输出...
使用time和dd命令生成测试文件,观察到当前读写速度为669MB/s
[root@28e417935901 /]# time dd if=/dev/zero of=test bs=2M count=10
10+0 records in
10+0 records out
20971520 bytes (21 MB, 20 MiB) copied, 0.0313692 s, 669 MB/s
real 0m0.035s
user 0m0.000s
sys 0m0.035s
添加direct和nonblock参数,再次测试,发现写入速度降低,证明容器读写IO限制成功
[root@28e417935901 /]# time dd if=/dev/zero of=test bs=2M count=10 oflag=direct,nonblock
10+0 records in
10+0 records out
20971520 bytes (21 MB, 20 MiB) copied, 10.0226 s, 2.1 MB/s
real 0m10.025s
user 0m0.006s
sys 0m0.000s
参数 | 解释 |
---|---|
direct | 读写数据采用直接 IO 方式,不走缓存。直接从内存写硬盘上 |
nonblock | 读写数据采用非阻塞 IO 方式,优先写 dd 命令的数据 |
docker容器运行结束后自动释放资源
自动释放资源的使用场景适用于许多情况,特别是在以下情况下:
- 开发和测试环境:在开发和测试过程中,经常需要运行各种容器化的应用程序。当这些应用程序不再需要时,自动释放资源可以确保不浪费资源,并使得开发和测试环境更加高效。
- CI/CD 流水线:在持续集成和持续交付(CI/CD)流水线中,会频繁地启动容器来运行测试、构建和部署任务。一旦任务完成,这些容器就可以自动释放资源,从而避免在无用的容器堆积中浪费资源。
- 临时性工作负载:有些工作负载只需要暂时运行,比如数据处理任务、临时服务等。在这种情况下,自动释放资源可以确保资源在不再需要时被回收,节省成本和资源。
- 资源密集型任务:某些任务可能需要大量的计算资源,但是只需要在特定时间段内运行。通过自动释放资源,可以确保在任务完成后立即释放这些资源,以便其他任务或服务可以使用它们。
- 负载均衡和伸缩:在负载均衡和自动伸缩的环境中,自动释放资源可以确保在负载下降时释放不再需要的容器,从而减少资源浪费。
docker使用rm参数使容器命令运行结束后,自动删除容器,自动释放资源。
例如:
运行一个名为 "rm" 的容器,基于 CentOS 镜像,并在容器内执行 sleep 6命令,意味着容器将休眠 6 秒钟,指定rm参数,容器命令运行完成后删除容器。
[root@docker-master ~]# docker run -itd --rm --name rm centos sleep 6
7a5b62e21e8e3747fab61546531556cf405c611b8d9f8a8800ffe6425c6ada2e
在宿主机上查看容器运行状态,等待6秒后,再次查看容器状态,由于命令已经被执行,所以容器已经被删除
[root@docker-master ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7a5b62e21e8e centos "sleep 6" 3 seconds ago Up 2 seconds rm
[root@docker-master ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@docker-master ~]# docker ps -a | grep rm
[root@docker-master ~]#