Linux-docker资源限制

资源限制:

默认情况下,容器没有资源限制,可以使用主机讷河调度程序允许的尽可能多的给定资源,Docker提供了控制容器可以限制容器使用多少内存或CPU的方法,设置docker run命令的运行时配置标志。

其中许多功能都要求宿主机的内核支持Linux功能,要检查支持,可以使用docker info命令,如果内核中禁用了某项功能,可能会在输出结尾处看到警告:WRANING:No swap limit support

对于Linux主机,如果没有足够的内容来执行其他重要的系统任务,将会抛出OOM(Out of Memory Exception,内存溢出、内存泄漏、内存异常),随后系统会开始杀死京城以释放内存,凡是运行在宿柱苣的进程都有可能被kill,包括docked和其他的应用程序,如果重要的系统进程被kill,会导致和该进程相关的服务全部宕机。

 

 产生OOM异常时,dockerd尝试通过调整docker守护程序上的OMM 优先级来减轻这些风险,以便它比系统上的其他京城更不可能被杀死,但是容器的OMM优先级未调整,这使得单个容器被杀死的可能性比Docker守护程序或其他系统进程被杀死的可能性更大,不推荐通过在守护程序或容器上手动设置--oom-score-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+stime)、存活时间(uptime-start time)和oom_adj计算出的进程得分,消耗内存越多得分越高,越容易被宿主机kernel强制杀死。

 

容器的内存限制:

Docker可以强制执行硬性内存限制,即只允许容器使用给定的内存大小。

Docker也可以执行非硬性内存限制,即容器可以使用尽可能多的内存,除非内核检测到主机上的内存不够用了。

Most of these options take a positive integer,followed by a suffix of b,k,m,g,to indicate bytes,kilobytes,megabytes,or gigabytes.
大部分的选项取正整数,跟着一个后缀b,k,m,g,表示字节,千字节,兆字节,或千兆字节。

--oom-score-adj:#宿主机kernel对进程使用的内存进行评分,评分最高的将被宿主机内核kill掉(越低越不同意被kill),可以指定一个容器的评分为较低的负数,但是不推荐手动指定。
--oom-kill-disable:#对某个容器关闭oom机制。

内存限制参数:
-m or --memory:#容器可以使用的最大内存量,如果设置此选项,则允许的最小存值为4m(4兆字节)。

--memory-swap:#容器可以使用的交换分区大小,必须要在设置了物理内存限制的前提才能设置交换分区的限制。

--memory-swappiness:#设置容器使用交换分区的倾向性,值越高越倾向于使用swap分区,范围为0-100,0为能不用就不用,100为能用就用。

--kernel-memory:#容器可以使用的最大内核内存量,最小为4m,由于内核内存与用户空间内存隔离,因此无法与用户空间内存直接交换,因此内核内存不足的容器可能会阻塞宿主主机资源,这会对主机和其他容器或者其他服务进程产生影响,因此不要设置内核内存大小。

--memory-reservation:#允许指定小于--memory的软限制,当daocker检测到主机上的争用或内存不足时会被激活该限制,如果使用--memory-reservation,则必须将其设置为低于--memory才能使其优先。因为它时软限制,所以不饿能保证容器不超过限制。

--omm-kill-disable:#默认情况下,发生OOM时,kernel会杀死容器内进程,但是可以使用--oom-kill-disable参数,可以禁止oom发生在指定的容器上,即仅在已设置-m/ --memory选项的容器上禁用OOM,如果-m参数未配置,产生OOM时,主机为了释放内存还会杀死系统进程。

swap限制:

--memory-swap:#只有在设置了 --memory后才会有意义。使用swap,可以让容器将超出限制部分的内存置换到磁盘上,WARNING:经常将内存交换到磁盘的应用程序会降低性能。

不同的--memory-swap设置会产生不同的效果:
--memory-swap:#值为正数,那么--memory和--memory-swap都必须要设置,--memory-swap表示你能使用的内存和swap分区大小的总和,例如:--memory=300m,--memory-swap=1g,那么该容器能够使用300m内存和700 swap,即--memory 是实际物理内存大小值不变,而swap的实际大小计算方式为(--memory-swap)-(--memory)=容器可用swap。

--memory-swap:#如果设置为0,则忽略该设置,并将该值视为未设置,即未设置交换分区。

--memory-swap:#如果等于--memory的值,并且--memory设置为正整数,容器无权访问swap即也没有设置交换分区。

--memory-swap:#如果设置为unset,如果宿主即开启了swap,则实际容器的swap值为2x(--memory),即两倍于物理内存大小,单数并不准确(在容器中使用free命令所看到的swap空间并不精确,毕竟每个容器都可以看到具体大小,但是宿主机的swap是有上线而且不是所有容器看到的累计大小)。

--memory-swap:#如果设置为-1,如果宿主机开启了swap,则容器可以使用主机上swap的最大空间。

 

内存限制验证:

假如一个容器未做内存使用限制,则该容器可以利用到系统内存最大空间,默认创建的容器没有做内存资源限制。

#docker pull lorel/docker-stress-ng    #测试镜像

#docker run -it --rm   lorel/docker-stress-ng -help #查看帮助信息

内存大小硬限制:

启动两个工作进程,每个工作进程最大允许使用内存256M,且宿主机不限制当前容器最大内存

[14:08:12 root@ubuntu-lyj ~]#docker run -it --rm --name web1 lorel/docker-stress-ng --vm 2 --vm-bytes 256M 

docker stats

CONTAINER ID   NAME                CPU %     MEM USAGE / LIMIT     MEM %     NET I/O           BLOCK I/O         PIDS
2984d9095fef   web1                198.13%   526.7MiB / 1.924GiB   26.73%    1.17kB / 0B       0B / 0B           5

宿主机限制容器最大内存使用:

[14:13:27 root@ubuntu-lyj ~]#docker run -it --rm -m256m --name web1 lorel/docker-stress-ng --vm 2 --vm-bytes 256M

docker stats

CONTAINER ID   NAME                CPU %     MEM USAGE / LIMIT     MEM %     NET I/O           BLOCK I/O         PIDS
5ec5e0faec8c   web1                45.91%    256MiB / 256MiB       100.00%   766B / 0B         1.33GB / 1.66GB   5

宿主机cgroup验证:

#cat /sys/fs/cgroup/memory/docker/容器ID/memory.limit_in_bytes

268435456     #宿主机基于cgroup对容器进行内存资源的大小限制

注*:通过echo命令可以更改限制的值,但是可以在原基础之上增大内存限制,缩小内存限制会报错 write error:Device or resource busy

 内存大小软限制

[15:11:35 root@ubuntu-lyj ~]#docker run -it --rm -m256m --memory-reservation 128m --name web1 lorel/docker-stress-ng --vm 2 --vm-bytes 256M
[15:13:24 root@ubuntu-lyj ~]#cat /sys/fs/cgroup/memory/docker/0a095c22dc8c97093ff2a8b63201f53e844431c0d278489aa54b0a35874f68b9/memory.soft_limit_in_bytes 
9223372036854771712

 

关闭OOM机制:

[15:17:12 root@ubuntu-lyj ~]#docker run -it --rm -m 256m --oom-kill-disable --name web1 lorel/docker-stress-ng --vm 2 --vm-bytes 256M 
[15:17:35 root@ubuntu-lyj ~]#cat /sys/fs/cgroup/memory/docker/87acd096b98b6eb6717eaf3ba92e2b3243f9716ba7d726db5f62e785591dbda4/memory.oom_control 
oom_kill_disable 1
under_oom 0
oom_kill 0

 

交换分区限制:

[15:19:10 root@ubuntu-lyj ~]#docker run -it --rm -m 256m --memory-swap 512m --name web1 centos bash
[15:23:21 root@ubuntu-lyj ~]#cat /sys/fs/cgroup/memory/docker/05a7cc790d500d78f6d37ab4876c4acb6bd001e6e6d1ceab1dda9b99be6fa84a/memory.kmem.limit_in_bytes 
9223372036854771712

 

容器的CPU限制

一个宿主机,有几十个核心的CPU,但是宿主机可以同时运行成千上百个不同的进程用以处理不同的任务,多进程功用一个CPU的核心依赖技术就是为可压缩资源,即一个核心的CPU可以通过调度而运行多个进程,但是同一个单位时间内只能有一个进程在CPU上运行,那么这么多的进程怎么在CPU上执行和调度

  • 实时优先级:0-99
  • 非实时优先级(nice):-20-19,对应100-139的京城优先级
  • Linux kernel 进程的调度基于 CFS(Completely Fair Scheduler),完全公平调度
  • CPU密集型的场景:优先级越低越好,计算密集型任务的特点是要进行大量的计算,消耗CPU资源,比如计算圆周率,数据处理、对视屏进行高清解码等等,全靠CPU的运算能力。
  • IO密集型的场景:优先级值高点,涉及到网络、磁盘IO的任务都是IO密集型任务,这类任务的特点是CPU消耗很少,任务的大部分时间都在等待IO操作完成(因为IO的速度远远低于CPU和内存的速度),比如web应用,高并发,数据量大的动态网站来说,数据库因该为IO密集型。

 

#磁盘的调度算法

[15:36:29 root@ubuntu-lyj ~]#cat /sys/block/sda/queue/scheduler 
noop deadline [cfq] 

默认情况下,每个容器对主机CPU周期的访问权限是不受限制的,但是我们可以设置各种约束给定容器访问主机的CPU周期,大多数用户使用的是默认的CFS调度,在docker 1.13及更高版本中,还可以配置实时优先级。

参数:

--cpus #指定容器可以使用多少可用CPU资源,例如,如果主机有两个CPU,并且设置了--cpus="1.5",那么该容器将保证最多可以访问1.5个的CPU(如果是4核CPU,那么还可以是4核上每核用一点,但是总计是1.5核心的CPU),这相当于设置--cpu-period="100000"(cpu调度周期)和--cpu-quota="150000"(cpu调度限制),--cpus主要在docker1.13和更高版本中使用,目的是替代--cpu-period和--cpu-quota两个参数,从而使配置更简单,但是最大不饿能超出宿主机的cpu总核心数(在操作系统看到cpu超线程后的数值)。

[15:49:12 root@ubuntu-lyj ~]#docker run -it --rm --cpus 3 centos bash
docker: Error response from daemon: Range of CPUs is from 0.01 to 2.00, as there are only 2 CPUs available.
See 'docker run --help'. #分配给容器的CPU超出了宿主机CPU总数

--cpu-period:#(cpu调度周期)设置cpu的CFS调度周期,必须于--cpu-quota一起使用,默认周期为100微妙(1Secaond=1000Millisecond=1000000Microsecond)。

--cpu-quota:#在容器上添加CPU CFS配额,计算方式为cpu-quota/cpu-period的结果值,早期的docker(1.12及之前)使用此方式设置对容器的cpu限制值,新版本docker(1.13及以上版本)通常使用--cpus色湖之此值。

--cpuset-cpus:#用于指定容器运行cpu编号,也就是我们所谓的绑核。

--cpuset-mem:#设置使用哪个cpu的内存,仅对非同一内存访问(NUMA)架构有效。

--cpu-shares:#用于设置cfs中调度的相对最大比例权重,cpu-share的值越高的容器,将会分得更多的时间片(宿主机多核CPU总数为100%,假如容器A为1024,容器B为2048,那么容器B将最大是容器A的可用CPU的两倍),默认的时间片1024,最大262144.

 

测试CPU限制

未限制容器cpu:

对于一台两核测试服务器,如果不做限制,容器会把宿主机的cpu全部占完:

[15:49:15 root@ubuntu-lyj ~]#docker run -it --rm --name web1 lorel/docker-stress-ng --cpu 2 --vm 2
#分配2核cpu并启动2个线程

docker stats:容器运行状态

CONTAINER ID   NAME                CPU %     MEM USAGE / LIMIT     MEM %     NET I/O           BLOCK I/O         PIDS
6afa9599d130   web1                190.27%   529MiB / 1.924GiB     26.85%    766B / 0B         0B / 0B           

在宿主机查看cpu限制参数

[16:09:48 root@ubuntu-lyj ~]#cat /sys/fs/cgroup/cpuset/docker/e87738dc831e827b3258550592d67f1ee7df22bb5651c85ca3fc5a908f4414eb/cpuset.cpus
0-1

 

限制容器CPU:

只给容器分配最多两核宿主机cpu利用率

[16:16:07 root@ubuntu-lyj ~]#docker run -it --rm --name web1 --cpus 2  lorel/docker-stress-ng --cpu 2 --vm 2
[16:18:46 root@ubuntu-lyj ~]#cat /sys/fs/cgroup/cpu,cpuacct/docker/9bc0c2b6e4651ea5f5f105766828add3a9d1ca9d5564e71209d015c9a3eacd7e/cpu.cfs_quota_us 
200000 #每核心CPU会按照1000为单位转换成百分比进行资源划分,2个核心的CPU就是200000/1000=200%,4个核心400000/100=400%,以此类推。

当前容器状态

CONTAINER ID   NAME                CPU %     MEM USAGE / LIMIT     MEM %     NET I/O           BLOCK I/O         PIDS
9bc0c2b6e465   web1                197.29%   534.5MiB / 1.924GiB   27.13%    1.05kB / 0B       0B / 0B           

注*:cpu资源限制是将分配给容器的2核心分配到了宿主机每一核心cpu上,也就是容器的总cpu值是在宿主机的每一个核心cpu分配部分比例。

 

将容器运行到指定的cpu上:

#cat /sys/fs/cgroup/cpuset/docker/容器ID/cpuset.cpus  #查看容器cpu核数

[16:27:21 root@ubuntu-lyj ~]#docker run -it --rm --name web1 --cpus 1 --cpuset-cpus 1  lorel/docker-stress-ng --cpu 1 --vm 1

容器运行状态

CONTAINER ID   NAME                CPU %     MEM USAGE / LIMIT     MEM %     NET I/O           BLOCK I/O         PIDS
16421bafc99d   web1                98.12%    270.1MiB / 1.924GiB   13.71%    976B / 0B         0B / 0B           

宿主机cpu利用率

top - 16:31:48 up  2:26,  2 users,  load average: 1.10, 1.84, 2.19
Tasks: 205 total,   4 running, 119 sleeping,   0 stopped,   0 zombie
%Cpu0  :  3.1 us,  2.2 sy,  0.0 ni, 86.8 id,  1.3 wa,  0.0 hi,  6.6 si,  0.0 st
%Cpu1  : 99.7 us,  0.3 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  2017496 total,   484540 free,   700296 used,   832660 buff/cache
KiB Swap:  1951740 total,  1951408 free,      332 used.  1110664 avail Mem 

基于cpu-shares对cpu进行切分

  启动两个容器,web-c1的 --cpu-shares值为1000,web-c2的--cpu-shares为500,观察最终效果,--cpu-shares值为1000的web-c1的cpu利用率基本是--cpu-shares为500的web-c2的两倍

[16:50:04 root@ubuntu-lyj ~]#docker run -it --rm --name web-c1  --cpu-shares 1000  lorel/docker-stress-ng --cpu 4 --vm 4

[16:50:01 root@ubuntu-lyj ~]#docker run -it --rm --name web-c2  --cpu-shares 500  lorel/docker-stress-ng --cpu 4 --vm 4

docker stats

CONTAINER ID   NAME                CPU %     MEM USAGE / LIMIT     MEM %     NET I/O           BLOCK I/O         PIDS
2191238e828f   web-c2              121.05%   448.1MiB / 1.924GiB   22.74%    866B / 0B         14.3GB / 128MB    13
db5996a0ae8f   web-c1              245.41%   1.039GiB / 1.924GiB   54.00%    1.38kB / 0B       64.9MB / 3.34MB   

宿主机CPU利用率

top - 16:51:56 up 2 min,  3 users,  load average: 24.11, 7.07, 2.45
Tasks: 277 total,  14 running, 141 sleeping,   0 stopped,   0 zombie
%Cpu0  : 92.8 us,  6.9 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.3 si,  0.0 st
%Cpu1  : 78.5 us, 16.5 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  5.0 si,  0.0 st
%Cpu2  : 93.7 us,  4.6 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  1.7 si,  0.0 st
%Cpu3  : 79.5 us, 13.2 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  7.3 si,  0.0 st
KiB Mem :  2017496 total,    73752 free,  1872944 used,    70800 buff/cache
KiB Swap:  1951740 total,  1240828 free,   710912 used.    31552 avail Mem 

动态修改cpu shares值:

--cpu-shares 的值可以在宿主机cgroup动态修改,修改完成后立即生效,其值可以调大也可以调小。

#echo 2000 > /sys/fs/cgroup/cpu,cpuacct/docker/容器ID/cpu.shares

 

posted @ 2022-08-11 16:58  goodbay说拜拜  阅读(627)  评论(0编辑  收藏  举报