容器系列之docker系统资源限制及验证
Docker的系统资源限制
分析:docker可以实现主要依赖于namespace,control group,默认情况下,一个容器中没有资源限制的,所以它可以几乎消耗完docker主机上所分配的所有资源,在此基础上,docker提供了可控制memory,CPU,内存是非可压缩性资源,CPU是可压缩性资源,当一个容器内的进程消耗完它的内存后,可能会因为OOM被kill掉,而CPU则不影响,kernel可以压缩它不受影响
资源限制
内存:OOME
linux主机上kernel探测到主机内存不足使用,就会发出一个异常,并且开始杀死一些进程一旦发生OOME,任何进程都有可能被杀死,包括docker daemon在内为此,Docker特地的调整了docker daemon的OOM优先级,以免它被内核"正法”,但容器的优先级并未被调整
工作逻辑:在宿主机上,运行了很多的容器中,包括系统级有很多的进程,也包括docker daemon自身的进程,如果内核要执行一些系统管理级的操作,发现内存没有了,启动评估,那个进程是memory hogs(消耗内存最多的进程),一般认为那个比较消耗内存,就会把那个的进程kill,比较快释放内存,但是不一样应该被杀,如A可以消耗内存10G,B可消耗内存1G,A只消耗10分之一,B已经消耗完了,不一定要Kill, 如果没有标准,就以那个进程消耗多,就杀那个进程。
内核会对进程排优先级,自从到下逆序,一个个的杀掉,直接内存足够使用为止。
每个进程可以分配OOM obj,每个进程计算好后可以有一个OOM score,得分越高就应该被杀掉的,得分是对它的申请和占用的空间使用一系列复杂的计算来做的,如果计算出后,某个进程是最高的,但是不应该被杀掉,如docker daemon这个进程可以调整优先级处理。每个进程有一个oom adj,也就是权重,优先级越低,得分就变得越少,可以把docker daemon的优先级调低,得分就少,就不会被杀。
如果一个容器在生产提供重要的服务,它却被杀掉,就很严重,应该开启就要调整它的优先级。而且也可以定义容器的策略,一旦被kill掉,可以restart,
限制容器的访问内存
注:ram是物理内存,swap是交换内存
-m 限制容器的物理内存空间,如4m
--memory-swap * 限制交换内存空间使用,要让它生效,必须先设定-m选项的使用,没有设置物理内存,就不能设置交换分区的
--memory-swappiness 使用memory的倾向性
--memory-reservation 预留的内存空间
--oom-kill-disable 禁止OOM被KILL掉,如容器很消耗内存,又很重要
CPU
默认情况下,每个容器是不限制使用宿主机上CPU资源,可以自行限制,不过大多数用户使用默认的CFS调度,CPU的核心数量是小于进程数的,一个系统上可能运行很多进程,需要运行进程数量大于核心数量时,那个应该优先运行?所以需要调度器来操作,因此内核中进程管理最重要的一个组件是进程调度器,调度进程运行在本地CPU核心上的,那个进程应该被优先运行,非实时的优先级是100-139,实时是0-99,使用nice值来调整[-20,19]非实时的,使用CFS(完全公平调度器),是分配每个进程使用的CPU的,进程还分为两类批处理的和交互式的,交互式的优先级比较高,用户点击mouse就要执行,不然就感觉很慢,但是交互界面使用的CPU的时间都比较短的,但是批处理进程比较消耗CPU,但是通常不需要立刻做出响应,优先级比较低。
CPU密集型表示对资源占用很大,I/O密集型的是对于I/O资源占用比较大的,对于CPU资源应该尽可能调低它的优先级,因为给它它就会尽可能的使用,内核有算法对这些进程做计算和惩罚,动态调低调高。
选项:
--cpu-shares CPU资源共享,按比例切分系统上所有可用的CPU资源,如当前系统上一共运行了两个容器,权重比是1024:512的值,假设两个容器不需要尽可能多的使用CPU,CPU资源假设有100份,两个容器的比例是2:1,如果第二个容器一启动几乎都不需要CPU资源,这时第一个容器可以占用所有的CPU资源,就是需要就按比例分,不需要就给要用的。CPU是可压缩资源,随时按比例运行。
还有一个特点:假设有四个核心,有四个容器,各自占用一个,如果其他的三个都不使用,其中一个可以占用四个核心来使用,就是400%的CPU使用率,但是可以限制它们所使用的量
但是限制可以灵活限制,如可以强行运行在那个核心上,或者使用多少的比例(不强制在那颗核心上,总数达到就可以)
--cpus=<value> 一个容器可以使用几核心,可以使用小数,如1.5核(限制数量)
--cpuset-cpus 进程只能运行在那个核心上(限制范围)
[root@node1 ~]# lscpu Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Byte Order: Little Endian CPU(s): 2 On-line CPU(s) list: 0,1 下载压力测试docker https://hub.docker.com/r/lorel/docker-stress-ng/ [root@node1 ~]# docker pull lorel/docker-stress-ng 测试内存 [root@node1 ~]# docker run --name stress -it --rm -m 256m lorel/docker-stress-ng:latest stress --vm 2 #-m指定可使用的内存大小,--vm启动的子进程,每个进程默认是256MB,所以两个进程是512M,会超出 [root@node1 ~]# docker top stress UID PID PPID C STIME TTY TIME CMD root 62910 62884 0 19:30 pts/0 00:00:00 /usr/bin/stress-ng stress --vm 2 root 62942 62910 0 19:30 pts/0 00:00:00 /usr/bin/stress-ng stress --vm 2 root 62943 62910 0 19:30 pts/0 00:00:00 /usr/bin/stress-ng stress --vm 2 root 62965 62942 0 19:30 pts/0 00:00:00 /usr/bin/stress-ng stress --vm 2 [root@node1 ~]# docker stats CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS 2dc8f3c34779 stress 28.08% 256MiB / 256MiB 100.01% 648B / 0B 465MB / 16.5GB 5 测试CPU [root@node1 ~]# docker run --name stress -it --rm --cpus 1 lorel/docker-stress-ng:latest stress --cpu 4 #限制使用1颗核心,启动4个进程来操作 [root@node1 ~]# docker stats CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS 5a006d928b2c stress 99.97% 7.938MiB / 3.686GiB 0.21% 508B / 0B 0B / 0B 5 不限制,它会使用完,因为是两核心,差不多200% CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS abb5cf0e98f9 stress 199.06% 7.934MiB / 3.686GiB 0.21% 578B / 0B 0B / 0B 5 指定使用那个核心 [root@node1 ~]# docker run --name stress -it --rm --cpuset-cpus 1 lorel/docker-stress-ng:latest stress --cpu 4 尽可能使用 [root@node1 ~]# docker run --name stress -it --rm --cpu-shares 1024 lorel/docker-stress-ng:latest stress --cpu 4