资源限制介绍

对于KVM、VMware 等虚拟化技术,用户可以控制分配多少CPU、内存资源给每个虚拟机;在默认的情况下,容器是没有资源限制的,可以使用主机内核调度程序允许的尽可能多的给资源,Docker提供了可以限制容器使用多少内存或者CPU的方法,设置docker run命令的运行时配置标志

其中一些功能要求宿主机的内核支持Linux功能,要检查支持,可以使用docker info命令,如果内核中禁用了某项功能,可能会在输出结尾处看到警告

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

容器内存限制

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

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

内存限制参数

容器可以使用的内存包括两部分:物理内存和Swap

Docker通过下面几个参数来控制容器内存的使用量

硬限制

  • -m 或 --memory:设置内存的使用限额,例如100MB,2GB

    • 如果设置此选项,则允许的最小值为4m
  • --memory-swap:容器可以使用的交换分区和物理内存大小总和,要在设置了物理内存限制的前提才能设置交换分区的限制

    • 如果设置此选项为-1,则容器可以使用主机上swap的最大空间

软限制

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

案例

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

内存硬限制

  • 拉取容器压测工具镜像
  1. [root@server ~]# docker pull lorel/docker-stress-ng
  2. [root@server ~]# docker run -it --rm lorel/docker-stress-ng -help
  • 使用压测工具开启两个工作进程,每个工作进程最大允许使用内存256M,宿主机不限制容器的最大内存
  1. [root@server ~]# docker run -it --rm --name test lorel/docker-stress-ng --vm 2 --vm-bytes 256m
  2. [root@server ~]# docker stats
  3. CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM %
  4. baa6f314a695 test 200.47% 514.3MiB / 1.777GiB 28.26%
  • 限制最大使用内存为256m
  1. [root@server ~]# docker run -it --rm -m 256m --name test lorel/docker-stress-ng --vm 2 --vm-bytes 256m
  2. [root@server ~]# docker stats
  3. CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM %
  4. 1d1641be39bb test 198.85% 255.9MiB / 256MiB 99.98%
  • 这种限制实际上就是修改了cgroup的文件值
  1. [root@server ~]# cat /sys/fs/cgroup/memory/docker/ebd3994ebc7dbed851cc1cad857d5c76dd4b80d48982912574ed3781a10f3490/memory.limit_in_bytes
  2. 268435456

内存软限制

  • 设置软限制为128m,软限制不会真正限制到内存的使用
[root@server ~]# docker run -it --rm -m 256m --memory-reservation 128m --name test lorel/docker-stress-ng --vm 2 --vm-bytes 256m
[root@server ~]# docker stats
CONTAINER ID   NAME    CPU %     MEM USAGE / LIMIT   MEM
5049ed7face5   test    197.64%   255.9MiB / 256MiB   99.96%

交换分区限制

  • 限制物理内存和交换分区总和使用为512m,也就是交换分区内存为256m
[root@server ~]# docker run -it --rm -m 256m --memory-swap 512m --name test lorel/docker-stress-ng --vm 2 --vm-bytes 256m

容器CPU限制

一个宿主机,有几十个核心的CPU,但是宿主机上可以同时运行成百上千个不同的进程用以处理不同的任务,多进程共用一个CPU的核心依赖技术就是为可压缩资源,即一个核心CPU可以通过调度而运行多个进程

默认情况下,所有容器可以平等地使用宿主机的CPU资源并且没有限制

CPU限制参数

  • --cpus:指定容器可以使用多少可用CPU资源

    • 例如,如果主机有两个CPU,并且设置了—cpu=1.5,那么该容器将保证最多可以访问1.5个的CPU;如果是4核CPU,那么还可以是4核心上的每核用一点,但是总计是1.5核心的CPU
  • --cpu-shares:值越高的容器将会得到更多的时间片

    • 假如容器A的cpu share是1024容器B的cpu share是2048,当两个容器都需要CPU资源时,容器B可以得到的CPU资源是容器A的两倍
  • --cpuset-cpus:用于指定容器运行的CPU编号,也就是所谓的绑核

案例

未限制容器CPU

  • 启动4个进程,占用4核CPU,未限制容器会把CPU全部占用完
[root@server ~]# docker run -it --rm --name test lorel/docker-stress-ng --vm 4 --cpu 4
[root@server ~]# docker stats
CONTAINER ID   NAME      CPU %
55ffcad51e02   test      399.60%

限制容器CPU

  • CPU限额为4个CPU核数
[root@server ~]# docker run -it --rm --cpus 2 --name test lorel/docker-stress-ng --vm 4 --cpu 4
[root@server ~]# docker stats
CONTAINER ID   NAME    CPU %
58be7d27d14f   test    201.49%
  • 将容器运行到指定的CPU上
[root@server ~]# docker run -it --rm --cpus 2 --cpuset-cpus 1,3 --name test lorel/docker-stress-ng --vm 4 --cpu 4
[root@server ~]# docker stats
CONTAINER ID   NAME    CPU %
cd8419b513d0   test    201.61%
[root@server ~]# top        # 按1显示每个CPU使用情况
%Cpu0  :  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu1  :100.0 us,  0.0 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu2  :  0.3 us,  0.0 sy,  0.0 ni, 99.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu3  :100.0 us,  0.0 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
  • 基于cpu-shares对CPU进行时间片切分,设置test1时间切片为1000,test2和test3时间切片都为500,即最终的CPU核数分配为 2:1:1
[root@server ~]# docker run -it --rm -d --cpu-shares 1000 --name test1 lorel/docker-stress-ng --vm 4 --cpu 4
[root@server ~]# docker run -it --rm -d --cpu-shares 500 --name test2 lorel/docker-stress-ng --vm 4 --cpu 4
[root@server ~]# docker run -it --rm -d --cpu-shares 500 --name test3 lorel/docker-stress-ng --vm 4 --cpu 4
[root@server ~]# docker stats
CONTAINER ID   NAME     CPU %
61756b578686   test1    194.67%
c18e233fb742   test2    91.87%
11062da5ca72   test3    91.10%