一次搞明白 Docker 容器资源限制

前言

在使用容器时(未被Kubernetes进行管理的情况下),我们单台主机上可能会跑几十个容器,容器虽然都相互隔离,但是用的却是与宿主机相同的内核,CPU、内存、磁盘等硬件资源。注:容器没有内核。默认情况下,容器没有资源限制,可以使用主机内核调度程序允许的尽可能多的给定资源;如果不对容器资源进行限制,容器之间就会相互影响,一些占用硬件资源较高的容器会吞噬掉所有的硬件资源,从而导致其它容器无硬件资源可用,发生停服状态。Docker提供了限制内存,CPU或磁盘IO的方法, 可以对容器所占用的硬件资源大小以及多少进行限制,我们在使用docker create创建一个容器或者docker run运行一个容器的时候就可以来对此容器的硬件资源做限制。

Docker核心

Docker分别使用Namespace和CGroup实现了对容器的资源隔离和资源限制,本文将会讲到怎么使用内核来调用CGroup对容器资源做限制。

OOM介绍

out of memorty
OOM:out of memorty的简称,称之为内存溢出

1.如果内存耗尽,内存将无法给予内存空间,内核检测到没有足够的内存来执行重要的系统功能,它会抛出OOM或Out of Memory异常,内存将会溢出,随之会有选择性的杀死相应的进程。
2.内存属于不可压缩性资源,如果执行这个进程的内存不够使用,这个进程它就会一直申请内存资源,直到内存溢出。
3.CPU属于可压缩性资源,所以CPU并不会出现这种情况,例如一个进程占用了一个核心100%的CPU,那么原本这个进程是需要占用200%的CPU资源,如果其它进程所占用的CPU核心并不需要多高的CPU频率,那么此进程就会占用掉空闲的CPU,如果其它进程也需要他自己核心的CPU频率,那么此进程就只能使用对它自己所使用CPU核心100%,因此叫做可压缩。
4.内存的有选择性:为什么不是杀死占用内存最高的进程呢?举个例子:例如我们运行了一个MySQL和一个Tomcat;这个MySQL原本是需要占用2G的内存资源,但他占用了1.9G;而Tomcat原本是需要占用500M的内存空间,可他占用了1G内存空间,这个时候当内存报异常OOM的时候,就会选择Tomcat进程进行发送kill -9的信号,进行杀死以释放内存。
5.当我们的一个重要的进程占用的内存超标而导致内存OOM的情况下,我们不希望内核来Kill掉我们这个进程,怎么办?我们可以调整内存OOM后kill进程的优先级,优先级越高越优先杀死,则反之 为此,Docker特地调整了docker daemon的OOM优先级,以免它被内核的杀死,但容器的优先级并未被调整
导致内存OOM
1.加载对象过大;
2.相应资源过多,来不及加载;
3.应用运行时间较长未重启,从而一点一点占用内存资源,长期积累导致占用内存空间较多;
4.代码存在内存泄漏bug。
解决OOM办法
1.内存引用上做一些处理,常用的有软引用;
2.内存中加载图片直接在内存中做处理,(如边界压缩);
3.动态回收内存;
4.优化Delivk虚拟机的堆内存分配;
5.自定义堆内存大小;
6.定期重启应用以释放内存。
压测工具stress

下载stress

docker pull lorel/docker-stress-ng:latest
latest:Pullingfrom lorel/docker-stress-ng
c52e3ed763ff:Pull complete
a3ed95caeb02:Pull complete
7f831269c70e:Pull complete
Digest: sha256:c8776b750869e274b340f8e8eb9a7d8fb2472edd5b25ff5b7d55728bca681322
Status:Downloaded newer image for lorel/docker-stress-ng:latest

使用方法

docker run --name stress -it --rm lorel/docker-stress-ng:latest stress --help
–name 指定lorel/docker-stress-ng:latest所启动的测试得容器名称为stress
–it:打开一个伪终端,并提供交互式
–rm:容器停止即删除
lorel/docker-stress-ng:latest:压测stress工具镜像名称
stress:lorel/docker-stress-ng:latest镜像内所内置的命令,必须使用此命令来指定–help支持的选项

stress常用选项

–cpu N:启动几个子进程来做压测,默认一个进程使用一个CPU核心,选项可简写为-c N
docker run --name stress -it --rm lorel/docker-stress-ng:latest stress --help | grep “cpu N”
-c N,–cpu N start N workers spinning on sqrt(rand())

–vm N:启动几个进程来做匿名页压测,选项可简写为-m N
docker run --name stress -it --rm lorel/docker-stress-ng:latest stress --help | grep “vm N”
-m N,–vm N start N workers spinning on anonymous mmap

–vm-bytes N:为–vm N指定的进程提供内存分配,每个进程可以分配到的内存数量,默认为256M
docker run --name stress -it --rm lorel/docker-stress-ng:latest stress --help | grep “vm-bytes N”
–vm-bytes N allocate N bytes per vm worker (default256MB)

Docker内存限制

限制内存注意事项
1.为需要限制容器内的应用提前做好压测,例如Nginx容器自身所占内存空间,以及预算业务量大小所需占用的内存空间,进行压测后,才能进入生产环境使用;
2.保证宿主机内存资源充足,监控及时上报容器内的内存使用情况,一旦容器所占用的内存不足,立刻对容器内存限制做调整或者打包此容器为镜像到其它内存充足的机器上进行启动;
3.如果物理内存充足,尽量不要使用swap交换内存,swap会导致内存计算复杂。
设置内存选项
注意:可限制的内存单位:b、k、m、g;分别对应bytes、KB、MB、GB

-m or --memory=:容器能使用的最大内存大小,最小值为4M
–memory-swap=:容器能够使用swap内存的大小,使用—memory-swap选项必须要使用—memory选项,否则—memory-swap不生效
–memory-swappiness:默认情况下,主机可以把容器使用的匿名页swap出来,你可以设置一个0-100之间的值,代表swap出来的比例,如果此值设置为0,容器就会先使用物理内存,能不用就不用swap空间,如果设置为100,则反之,能用swap就会用,哪怕有一丝可以用到swap空间的可能性就会使用swap空间
–memory-reservation:预留的一个内存空间,设置一个内存使用soft limit,如果docker发现主机内存不足,会执行OOM操作,这个值必须小于—memory设置的值
–kernel-memory:容器能够使用kernel memory大小,最小值为4M
–oom-kill-disable:是否运行OOM的时候杀死容器,只有设置了-m或者-memory,才可以设置此值,值为flase或者true,设置为false之后当此容器的内存溢出的时候就会对此容器执行kill操作,否则容器会耗尽主机内存,而且导致主机应用被杀死,如果这个容器运行的应用非常重要,就把—oom-kill-disable设置为true,就是禁止被oom杀掉
–memory-swap详解: swap:交换内存 ram:物理内存

图片

查看内存大小:

图片

限制容器内存
使用docker的–memory选项来限制容器能够使用物理内存的大小,使用stress命令的选项–vm指定启动几个占用内存的进程和每个占用内存进程所占用的内存空间大小 我们指定了容器最多使用物理内存512M,启动两个占用内存的进程,每个进程分别占用512M的空间,那么两个进程理论上需要占用1024的空间,我们只给了1024的空间,显然是不够的:

docker run --name stress-memory -it --rm -m 512M lorel/docker-stress-ng:latest stress --vm 2–vm-bytes 512M
stress-ng: info:[1] defaulting to a 86400 second run per stressor
stress-ng: info:[1] dispatching hogs:2 vm

使用docker stats命令来查看容器硬件资源的使用情况 可以看到我们的stress-memory容器的总内存为512M,使用了500多点,但为超过521M,内存占用的百分比为99.3%:

图片

使用htop命令来查看资源情况:

图片

限制容器swap内存
设置oom时是否杀掉进程
Docker CPU限制

查看CPU核心数以及编码:

图片

设置CPU选项
–cpu-shares:共享式CPU资源,是按比例切分CPU资源;比如当前系统上一共运行了两个容器,第一个容器上权重是1024,第二个容器权重是512, 第二个容器启动之后没有运行任何进程,自己身上的512都没有用完,而第一台容器的进程有很多,这个时候它完全可以占用容器二的CPU空闲资源,这就是共享式CPU资源;如果容器二也跑了进程,那么就会把自己的512给要回来,按照正常权重1024:512划分,为自己的进程提供CPU资源。如果容器二不用CPU资源,那容器一就能够给容器二的CPU资源所占用,如果容器二也需要CPU资源,那么就按照比例划分,这就是CPU共享式,也证明了CPU为可压缩性资源。
–cpus:限制容器运行的核数;从docker1.13版本之后,docker提供了–cpus参数可以限定容器能使用的CPU核数。这个功能可以让我们更精确地设置容器CPU使用量,是一种更容易理解也常用的手段。
-cpuset-cpus:限制容器运行在指定的CPU核心;运行容器运行在哪个CPU核心上,例如主机有4个CPU核心,CPU核心标识为0-3,我启动一台容器,只想让这台容器运行在标识0和3的两个CPU核心上,可以使用cpuset来指定。
限制CPU Share
启动stress压测工具,并使用stress命令加–cpu选项来启动四个进程,默认一个进程占用一颗CPU核心:

docker run --name stress-share -it --rm --cpu-shares 512 lorel/docker-stress-ng:latest stress -c 2
stress-ng: info:[1] defaulting to a 86400 second run per stressor
stress-ng: info:[1] dispatching hogs:2 cpu

压测工具会吃掉俩个核心的所有CPU资源 再次打开一个窗口,使用htop命令来查看硬件资源损耗情况 我们一共开了两个进程,默认会占用两个cpu核心,每个核心的资源为100%,两个也就是为200%,由于没有指定限制在某个CPU核心上,所以它是动态的跑在四核CPU核心数,但是stress占用CPU的资源不会超出200%:

图片

再次打开一个窗口,使用docker top container也可以查看到两个进程一共消耗了多少cpu资源:

图片

限制CPU核数
我们使用docker的–cpus选项来限制cpu运行的核心数,使用stress命令的选项–cpu来限制启动的进程数 显示cpu只运行两个核心数,也就是只能运行200%CPU资源,启动4个进程,也就是讲这4个进程只能跑在200%的cpu资源上:

docker run --name stress-cpus -it --rm --cpus 2 lorel/docker-stress-ng:latest stress -c 4
stress-ng: info:[1] defaulting to a 86400 second run per stressor
stress-ng: info:[1] dispatching hogs:4 cpu

使用htop命令查看cpu占用资源 可以看到四个进程,但是跑在了四颗cpu上面,但是每颗cpu只运行了50%左右的资源,4*50也就是200%左右的cpu资源:

图片

使用docker top container也可以查看到四个进程一共消耗了多少cpu资源:

图片

限制容器运行在指定核心
我们使用docker的–cpuset-cpus选项来指定cpu运行在哪个核心上,使用stress的选项–cpu来指定启动的进程数 我们指定4个进程运行在编号为0和2的cpu上:

docker run --name stress-cpuset -it --rm --cpuset-cpus=0,2 lorel/docker-stress-ng:latest stress -c 4
stress-ng: info:[1] defaulting to a 86400 second run per stressor
stress-ng: info:[1] dispatching hogs:4 cpu

使用htop查看系统硬件占用资源 可以看到和预期一样,占用了第一颗和第三颗cpu,每个进程占用cpu资源为50%,总资源为200%,两颗cpu的量:

图片

作者:Wayne
来源:https://zhuanlan.zhihu.com/p/162699218

全部评论

相关推荐

2025-11-26 11:21
已编辑
武汉理工大学 Java
个人bg: 211本,一段京东实习,一段xhs实习,一段小厂实习。互联网只有美团一个带薪意向。转正失败情况:京东实习了四个月,感觉收获比较少,做的事情偏基础,第三个月底答辩,离职后两个月被告知转正失败。对此我只能说,零售卡硕。xhs实习两个月,反而感觉收获更多,被安排了有挑战的事情,大模型在业务场景中的运用,最后一个星期通知有转正机会,边做需求边匆忙准备,答辩采取一票否决制,四个领导三过一否,也失败。(早知道xhs今年开这么高我就熬夜赶材料了)不过在这个过程中,也push自己了解了一定rag mcp 大模型的相关知识,对于后续面阿里和美团很有帮助。个人基础情况:hot100能默写。去年12底学完jvm juc。2月入职京东前小林coding guide就差不多看完了。后面实习的时候也有继续补面筋,场景题。秋招情况:8月初就投了,也不晚。滴滴: 笔试a了没面,可能投的岗位太小众了?(抱着拿了也不去 用于a价的想法)一直卡着。携程: 不发笔。发官方邮件也不回。京东:笔试挂了。嗯,很耻辱,那天在外面玩但确实很久没复习笔试考试范围了,全忘光了。腾讯:从来没约过,可能暑期面了十几次面太多了。阿里控股:一面挂。阿里国际:hr面后一个月挂。字节:国际电商三面挂->星图一面挂(面的时候已经有很多候选人了)-> 安全风控二面挂(业务不是很好,面试过程说漏嘴说业务会影响我选择,场景题没答好)-> 中台一面后无消息快手:二面挂。xhs:hr面后无消息,排序应该很靠后。虾皮:hr面两个月无消息,应该还在泡池子。百度:一面挂。pdd:笔试a3后笔试挂。难绷。个人反思总结:for 后来者。1. 笔试一定要把握好,虽然面试中都是hot100,有些甚至不考面试题,但是大厂笔试题是有acm难度的,挂了就是挂了,很多没有第二次机会,约面也没机会了。建议时间充裕情况下,还是要把灵神的题单多刷点。顺序可以参考:代码随想录视频+题 -> 灵神视频+题 ->hot100 ->灵神题单(可以每个part挑难度低的前几道写)2. 一段深入长的实习经历一定是大于两段短的,不过现在再让我选到底是继续在jd还是去xhs我还是选不出来。在面试的过程中,有些面试官也会认为我实习的太浅,没有做什么有深度的事情,对多种方案的调研不全面。如果实习做的事情比较有挑战最好,如果没有,也要尽量往多种方案调研最后选择了哪个方案,达到了当初定的业务指标/技术指标方面包装。3. 还是得早投。身边除了bg特别好的朋友,投的晚的无一例外秋招情况会差很多。8月前投能赶上提前批。最晚不要8月中旬过了还没投完。有投的早的没有实习的朋友秋招结果也可以。没有面试的同学一定要尝试官网,boss直聘多种途径投。4. 对于有实习的同学,基础没有那么重要了,更多还是专注于对实习的考察,可以以金字塔的形式进行论述,避免在最开始的时候就展开大量细节。如果实在没有实习,bg够硬,投的够早也会有面,只需要一个比较深入的项目应该就没问题,把项目当作自己在实习要投入生产的心态去调研包装。5. 有的时候真的看运气。即使是同一个部门甚至是同一个组的同学,做的事情也会有差异,这主要看导师被分配到什么样的活。for me:大二的时候绩点排名前10%,但还是决定放弃保研,开始学java,这一路走来,经历迷茫踏实的反复,也想和自己说句幸苦了,谁想得到当初给自己定的目标是有份工作不饿死就行。可能差点运气,可能在关键节点上做的还是不够,对于实习的包装,对于面试表现还是差点。会后悔自己没读研吗?其实我也有考雅思,申请了港大计算机,但估计大概率还是工作(实则也没港大offer)。人不能既要又要还要,我不能既要早点工作赚钱,实现我财富自由支配,带不舍得花钱的家人去旅游的想法,又要长期来看高学历晋升的优势,还要在大环境变差一届比一届卷我也能找到差强人意的工作。所以,至少现在,我不后悔。如果我更倾向于国企而不是互联网,比起技术挑战更偏爱稳定的生活我大概率会读研。如果我本科没有211,我还想进大厂,我也大概率会读研。会后悔自己没选其他的方向吗?java确实相对卷一点,但也只是相对的,因为其他方向的人也很多,并不是换方向就一定会更好。计算机这一行本就短命,能干到35就算成功,大家都是为了赚钱,基于此,在背景没那么硬时,选择一个相对人少的方向进大厂是对的。看自己怎么理解了。最好的还是参考直系学长学姐的选择,一定要多沟通交流。一些安慰自己的话,秋招是人生的起点,不一定是高费阵容才能吃鸡,低费阵容早点发育也有吃鸡的上限。(随便乱说的)。最后还想再写一段话给学妹们,程序员这一行,女生确实会相对少一点,但比起传统工科非常直接的偏向男生,计算机这一行认为菜是原罪,性别的因素会少很多,更多看个人技术和水平。在京东实习的时候,我的小组长在我进去第一天就和我说,我们部门女生虽然少,但是水平都至少是中上的,都很能吃苦很能干。无论是我们组干活巨快的A姐,还是总能很快解答我问题的B姐,又或者是其他总能给我提供建议的其他姐姐们,都使我对这一点坚信不疑,她们高学历,专业,细心,耐心。如果你也热爱技术,虽然有时会被bug折磨,但喜欢学到知识时候的踏实,喜欢bug fix的爽感,你就是适合这一行的。我的秋招结束了,但我大概率不会甘心,还是会想试试春招,但我也真的觉得到现在这一步已经很棒了。欢迎同校学妹学弟们找我沟通交流~
疲倦的牛马还在上班:再冲一次,春招不留遗憾吧!
我的秋招日记
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务