摘要

  随着Docker技术被越来越多的个人、企业所接受,其用途也越来越广泛。Docker资源管理包含对CPU、内存、IO等资源的限制,但大部分Docker使用者在使用资源管理接口时往往还比较模糊。
  本文将尝试介绍Docker资源管理背后的Cgroups机制,并且列举主要的资源管理接口对应的Cgroups接口,让Docker使用者对资源管理更加清晰。

一、Docker资源管理接口概览

格式

描述

-m, --memory=" <数字>[<单位>]" 内存使用限制。 数字需要使用整数,对应的单位是b, k, m, g中的一个。最小取值是4M。
--memory-swap="<数字>[<单位>]" 总内存使用限制 (物理内存 + 交换分区,数字需要使用整数,对应的单位是b, k, m, g中的一个。
--memory-reservation="<数字>[<单位>]" 内存软限制。 数字需要使用正整数,对应的单位是b, k, m, g中的一个。
--kernel-memory="<数字>[<单位>]" 内核内存限制。 数字需要使用正整数,对应的单位是b, k, m, g中的一个。最小取值是4M。
--oom-kill-disable=false 内存耗尽时是否杀掉容器
--memory-swappiness="" 调节容器内存使用交换分区的选项,取值为0和100之间的整数(含0和100)。
-c, --cpu-shares=0 CPU份额 (相对权重)
--cpu-period=0 完全公平算法中的period值
--cpu-quota=0 完全公平算法中的quota值
--cpuset-cpus="<数字>" 限制容器使用的cpu核(0-3, 0,1)
--cpuset-mems="" 限制容器使用的内存节点,该限制仅仅在NUMA系统中生效。
--blkio-weight=0 块设备IO相对权重,取值在10值1000之间的整数(包含10和1000)
--blkio-weight-device="设备名称:权重值" 指定的块设备的IO相对权重
--device-read-bps="<设备路径>:<数字>[<单位>]" 限制对某个设备的读取速率 ,数字需要使用正整数,单位是kb, mb, or gb中的一个。
--device-write-bps="<设备路径>:<数字>[<单位>]" 限制对某个设备的写速率 ,数字需要使用正整数,单位是kb, mb, or gb中的一个。
--device-read-iops="<设备路径>:<数字>" 限制对某个设备每秒IO的读取速率,数字需要使用正整数。
--device-write-iops="<设备路径>:<数字>" 限制对某个设备每秒IO的写速率,数字需要使用正整数。

二、Docker资源管理原理——Cgroups子系统介绍

  Cgroups是control groups的缩写,最初由google的工程师提出,后来被整合进Linux内核。Cgroups是Linux内核提供的一种可以限制、记录、隔离进程组(process groups)所使用的物理资源(如:CPU、内存、IO等)的机制。Cgroups由7个子系统组成:分别是cpuset、cpu、cpuacct、blkio、devices、freezer、memory。不同类型资源的分配和管理是由各个cgroup子系统负责完成的。

  在 /sys/fs/cgroup/子系统名称/docker 目录中为每个容器创建一个 cgroup 目录,并且以容器长ID命名,如下 cpu 资源系统,目录中包含所有与 cpu 相关的 cgroup 配置:

[vagrant@localhost docker]$ pwd
/sys/fs/cgroup/cpu/docker
[vagrant@localhost docker]$ ll
total 0
drwxr-xr-x. 2 root root 0 Feb 27 02:37 02c8442f5e65909bc1f7ecfc1596f1474d7d9d1dcd3e2cd34d059cabc578d2c5

[vagrant@localhost docker]$ cd 02c8442f5e65909bc1f7ecfc1596f1474d7d9d1dcd3e2cd34d059cabc578d2c5/
[vagrant@localhost 02c8442f5e65909bc1f7ecfc1596f1474d7d9d1dcd3e2cd34d059cabc578d2c5]$ ll
total 0
-rw-r--r--. 1 root root 0 Feb 27 02:37 cgroup.clone_children
--w--w--w-. 1 root root 0 Feb 27 02:37 cgroup.event_control
-rw-r--r--. 1 root root 0 Feb 27 02:37 cgroup.procs
-r--r--r--. 1 root root 0 Feb 27 02:37 cpuacct.stat
-rw-r--r--. 1 root root 0 Feb 27 02:37 cpuacct.usage
-r--r--r--. 1 root root 0 Feb 27 02:37 cpuacct.usage_percpu
-rw-r--r--. 1 root root 0 Feb 27 02:37 cpu.cfs_period_us
-rw-r--r--. 1 root root 0 Feb 27 02:37 cpu.cfs_quota_us
-rw-r--r--. 1 root root 0 Feb 27 02:37 cpu.rt_period_us
-rw-r--r--. 1 root root 0 Feb 27 02:37 cpu.rt_runtime_us
-rw-r--r--. 1 root root 0 Feb 27 02:37 cpu.shares
-r--r--r--. 1 root root 0 Feb 27 02:37 cpu.stat
-rw-r--r--. 1 root root 0 Feb 27 02:37 notify_on_release
-rw-r--r--. 1 root root 0 Feb 27 02:37 tasks

  1. memory -- 用来限制cgroup中的任务所能使用的内存上限。

子系统常用cgroups接口

描述

对应的docker接口

cgroup/memory/memory.limit_in_bytes

设定内存上限,单位是字节,也可以使用k/K、m/M或者g/G表示要设置数值的单位。 -m, --memory=""
cgroup/memory/memory.memsw.limit_in_bytes

设定内存加上交换分区的使用总量。通过设置这个值,可以防止进程把交换分区用光。 --memory-swap=""
cgroup/memory/memory.soft_limit_in_bytes

设定内存限制,但这个限制并不会阻止进程使用超过限额的内存,只是在系统内存不足时,会优先回收超过限额的进程占用的内存,使之向限定值靠拢。 --memory-reservation=""
cgroup/memory/memory.kmem.limit_in_bytes

设定内核内存上限。 --kernel-memory=""
cgroup/memory/memory.oom_control

如果设置为0,那么在内存使用量超过上限时,系统不会杀死进程,而是阻塞进程直到有内存被释放可供使用时,另一方面,系统会向用户态发送事件通知,用户态的监控程序可以根据该事件来做相应的处理,例如提高内存上限等。 --oom-kill-disable=""
cgroup/memory/memory.swappiness

控制内核使用交换分区的倾向。取值范围是0至100之间的整数(包含0和100)。值越小,越倾向使用物理内存。 --memory-swappiness=
    • 读取内存对应的cgroups文件

      [vagrant@localhost cgroup]$ docker run -ti --rm -m 200M centos bash -c "cat /sys/fs/cgroup/memory/memory.limit_in_bytes"
      209715200

      当内存限制在200M时,cgoups的文件数值为 209715200,单位为字节,刚好等于200M。其中,--rm 表示退出之后删除创建的容器。

    • 读取交换内存对应的cgroups文件
      [vagrant@localhost cgroup]$ docker run -ti --rm -m 200M --memory-swap=300M centos bash -c "cat /sys/fs/cgroup/memory/memory.memsw.limit_in_bytes"
      314572800

      当内存限制在300M时,cgoups的文件数值为 314572800,单位为字节,刚好等于300M。

    其余的,以此类推。

  2. 使用stress镜像学习如何为容器分配内存    

     centos-stress-source:1.0.2镜像已在上一篇中创建完成,这边直接使用,链接

    • 分配的内存比指定的内存和交换内存小时,执行正常,不断释放与分配

      [vagrant@localhost cgroup]$  docker run -ti --rm -m 200M --memory-swap=300M centos-stress-source:1.0.2 --vm 1 --vm-bytes 280M
      stress: info: [1] dispatching hogs: 0 cpu, 0 io, 1 vm, 0 hdd
      stress: dbug: [1] using backoff sleep of 3000us
      stress: dbug: [1] --> hogvm worker 1 [5] forked
      stress: dbug: [5] allocating 293601280 bytes ...
      stress: dbug: [5] touching bytes in strides of 4096 bytes ...
      stress: dbug: [5] freed 293601280 bytes
      stress: dbug: [5] allocating 293601280 bytes ...
      stress: dbug: [5] touching bytes in strides of 4096 bytes ...
    • 分配的内存比指定的内存和交换内存大时

      [vagrant@localhost cgroup]$  docker run -ti --rm -m 200M --memory-swap=300M centos-stress-source:1.0.2 --vm 1 --vm-bytes 310M
      stress: info: [1] dispatching hogs: 0 cpu, 0 io, 1 vm, 0 hdd
      stress: dbug: [1] using backoff sleep of 3000us
      stress: dbug: [1] --> hogvm worker 1 [5] forked
      stress: dbug: [5] allocating 325058560 bytes ...
      stress: dbug: [5] touching bytes in strides of 4096 bytes ...
      stress: FAIL: [1] (415) <-- worker 5 got signal 9
      stress: WARN: [1] (417) now reaping child worker processes
      stress: FAIL: [1] (421) kill error: No such process
      stress: FAIL: [1] (451) failed run completed in 1s

      分配的内存试图超过300M时,stress线程报错,容器强行退出。

    • 不指定swap-memory时,默认swap的值确认

      1、指定 -m 内存值为100M

      [vagrant@localhost tmp]$ docker run -ti --rm -m 100M centos bash -c "cat /sys/fs/cgroup/memory/memory.limit_in_bytes && cat /sys/fs/cgroup/memory/memory.memsw.limit_in_bytes"
      104857600
      209715200

      可以看到上述情况,在不指定 memory-swap 大小的情况下,默认取memory的两倍值, 即 200M。

      2、当一方的指定值为-1时,表示无限大

      [vagrant@localhost tmp]$docker run -ti --rm -m 100M --memory-swap -1 centos bash -c "cat /sys/fs/cgroup/memory/memory.limit_in_bytes && cat /sys/fs/cgroup/memory/memory.memsw.limit_in_bytes"
      104857600
      9223372036854771712

      可以看到,memory-swap为 无限大。


      3、memory 和 memory-swap的关系

      memory-swap = memory + swap

      所以,当memory-swap值小于memory设定值的时候,会报错如下

      [vagrant@localhost tmp]$ docker run -ti --rm -m 200M --memory-swap 100M centos bash -c "cat /sys/fs/cgroup/memory/memory.limit_in_bytes && cat /sys/fs/cgroup/memory/memory.memsw.limit_in_bytes"
      docker: Error response from daemon: Minimum memoryswap limit should be larger than memory limit, see usage.
      See 'docker run --help'.

  3. cpu子系统

子系统常用cgroups接口

描述

对应的docker接口

cgroup/cpu/cpu.shares

负责CPU比重分配的接口。假设我们在cgroupfs的根目录下创建了两个cgroup(C1和C2),并且将cpu.shares分别配置为512和1024,那么当C1和C2争用CPU时,C2将会比C1得到多一倍的CPU占用率。要注意的是,只有当它们争用CPU时CPU share才会起作用,如果C2是空闲的,那么C1可以得到全部的CPU资源。 -c, --cpu-shares=""
cgroup/cpu/cpu.cfs_period_us

负责CPU带宽限制,需要与cpu.cfs_quota_us搭配使用。我们可以将period设置为1秒,将quota设置为0.5秒,那么cgroup中的进程在1秒内最多只能运行0.5秒,然后就会被强制睡眠,直到下一个1秒才能继续运行。 --cpu-period=""
cgroup/cpu/cpu.cfs_quota_us

负责CPU带宽限制,需要与cpu.cfs_period_us搭配使用。 --cpu-quota=""
    • 设置cpu权重,容器竞争cpu资源时是才起作用,但容器情况下可以使用到全部的容器资源
      启动容器 container_a,设置 cpu share = 1024

      [vagrant@localhost tmp]$ docker run --rm --name container_a -it -c 1024 centos-stress-source:1.0.2  --cpu 1
      stress: info: [1] dispatching hogs: 1 cpu, 0 io, 0 vm, 0 hdd
      stress: dbug: [1] using backoff sleep of 3000us
      stress: dbug: [1] --> hogcpu worker 1 [5] forked

      启动容器 container_b,设置 cpu share = 512

      [vagrant@localhost ~]$ docker run --rm --name container_b -it -c 512 centos-stress-source:1.0.2  --cpu 1
      stress: info: [1] dispatching hogs: 1 cpu, 0 io, 0 vm, 0 hdd
      stress: dbug: [1] using backoff sleep of 3000us
      stress: dbug: [1] --> hogcpu worker 1 [5] forked

      在host中执行 top 查看 cpu 的使用情况

      [vagrant@localhost ~]$ top
      top - 12:09:26 up 10:39, 3 users, load average: 2.07, 0.82, 0.40
      Tasks: 101 total, 3 running, 98 sleeping, 0 stopped, 0 zombie
      %Cpu(s): 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 : 500108 total, 160592 free, 107168 used, 232348 buff/cache
      KiB Swap: 1572860 total, 1370868 free, 201992 used. 337508 avail Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
      7996 root 20 0 7264 96 0 R 66.3 0.0 2:37.42 stress
      8142 root 20 0 7264 96 0 R 33.3 0.0 0:20.98 stress

      以上,可以看到 container_a 占用的 cpu 资源是 container_b 的两倍。
      暂停container_a 可以发现数据如下

      [vagrant@localhost ~]$ docker pause container_a
      container_a
      [vagrant@localhost ~]$ top
      top - 12:11:08 up 10:41, 3 users, load average: 2.02, 1.18, 0.58
      Tasks: 101 total, 2 running, 99 sleeping, 0 stopped, 0 zombie
      %Cpu(s):100.0 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
      KiB Mem : 500108 total, 160468 free, 107288 used, 232352 buff/cache
      KiB Swap: 1572860 total, 1370868 free, 201992 used. 337384 avail Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
      8142 root 20 0 7264 96 0 R 99.3 0.0 1:01.57 stress
      3276 root 20 0 644028 28028 9832 S 0.3 5.6 1:41.57 dockerd

      可以看到,当 在container_a空闲的时候,container_b 能够用满整个 cpu。

    • PS. 需要退出当前测试时,需要直接ctrl+c,或者 直接执行 docker stop <container name>,执行过 docker pause <container name>的,只能执行stop退出。

  • 4. Block IO

    子系统常用cgroups接口

    描述

    对应的docker接口

    cgroup/blkio/blkio.weight

    设置权重值,取值范围是10至1000之间的整数(包含10和1000)。这跟cpu.shares类似,是比重分配,而不是绝对带宽的限制,因此只有当不同的cgroup在争用同一个块设备的带宽时,才会起作用。 --blkio-weight=""
    cgroup/blkio/blkio.weight_device

    对具体的设备设置权重值,这个值会覆盖上述的blkio.weight。 --blkio-weight-device=""
    cgroup/blkio/blkio.throttle.read_bps_device

    对具体的设备,设置每秒读块设备的带宽上限。 --device-read-bps=""
    cgroup/blkio/blkio.throttle.write_bps_device

    设置每秒写块设备的带宽上限。同样需要指定设备。 --device-write-bps=""
    cgroup/blkio/blkio.throttle.read_iops_device

    设置每秒读块设备的IO次数的上限。同样需要指定设备。 --device-read-iops=""
    cgroup/blkio/blkio.throttle.write_iops_device

    设置每秒写块设备的IO次数的上限。同样需要指定设备。 --device-write-iops=""
    • 磁盘的读写权重

      docker 可通过设置权重、限制 bps (每秒读写的数据量)和 iops(每秒 IO 的次数) 的方式控制容器读写磁盘的带宽。

      1、限制读写 IO 为50M/s,则最终的读写速度会在50M左右。

      [vagrant@localhost tmp]$ docker  run -it --rm --device-write-bps /dev/sda:50M centos               [root@540f9b91405e /]# time dd if=/dev/zero of=test.out bs=1M count=800 oflag=direct
      800+0 records in
      800+0 records out
      838860800 bytes (839 MB) copied, 15.9115 s, 52.7 MB/s real 0m15.913s
      user 0m0.002s
      sys 0m0.321s

      2、不限制 IO

      [vagrant@localhost tmp]$ docker  run -it --rm centos
      [root@77f63fec8b34 /]# time dd if=/dev/zero of=test.out bs=1M count=800 oflag=direct
      800+0 records in
      800+0 records out
      838860800 bytes (839 MB) copied, 1.6477 s, 509 MB/s real 0m1.649s
      user 0m0.000s
      sys 0m0.302s

      PS.注意oflag=direct,需要指定IO方式,目前BLKIO限额只对direct(不使用文件缓存)生效。因为容器的文件系统在 host /dev/sda 上,所以在容器中写文件,相当于对 host /dev/sda 进行写操作

    • BLKIO限额具有竞争资源的情况,与 cpu 配额一样

      1、是 container_b 的BLKIO 优先级是 container_a 的两倍

      设置 container_a 的 --blkio-weight 300

      [vagrant@localhost tmp]$ docker  run -it --rm --name container_a --blkio-weight 300 centos
      [root@7cd7ff76edb4 /]# time dd if=/dev/zero of=test.out bs=1M count=800 oflag=direct
      800+0 records in
      800+0 records out
      838860800 bytes (839 MB) copied, 3.12988 s, 268 MB/s real 0m3.131s
      user 0m0.001s
      sys 0m0.335s

      设置 container_b 的 --blkio-weight 600

      [vagrant@localhost ~]$ docker  run -it --rm --name container_b --blkio-weight 600 centos
      [root@89aa5264b9d1 /]# time dd if=/dev/zero of=test.out bs=1M count=800 oflag=direct
      800+0 records in
      800+0 records out
      838860800 bytes (839 MB) copied, 2.10906 s, 398 MB/s real 0m2.111s
      user 0m0.001s
      sys 0m0.296s

      ps. 由于收到执行命令没有办法做到同时IO,所以读写速度上的比例并没有严格的1:2。

      引用
        [1] Docker资源管理探秘:Docker背后的内核Cgroups机制   [2] 《每天5分钟玩转Docker容器技术》

Docker资源限制实现——cgroup的更多相关文章

  1. Docker资源限制与Cgroups

    一.Linux control groups 简介     Linux CGroup全称Linux Control Group, 是Linux内核的一个功能,用来限制,控制与分离一个进程组群的资源(如 ...

  2. Docker资源网站收藏

    Docker资源 Docker官方英文资源: docker官网:http://www.docker.com Docker windows入门:https://docs.docker.com/windo ...

  3. 你可能不知道的Docker资源限制

    What is 资源限制? 默认情况下,容器是没有资源限制的,它会尽可能地使用宿主机能够分配给它的资源.Docker提供了一种控制分配多少量的内存.CPU或阻塞I/O给一个容器的方式,即通过在dock ...

  4. Docker 资源 | 官方文件

    Docker资源 Docker官方英文资源: docker官网:http://www.docker.com Docker windows入门:https://docs.docker.com/windo ...

  5. Docker 资源汇总

    Docker 资源汇总 Docker官方英文资源 Docker官网:http://www.docker.com Docker Windows 入门:https://docs.docker.com/do ...

  6. docker资源隔离实现方式

    默认情况下,一个容器没有资源限制,几乎可以使用宿主主机的所有资源.docker提供了控制内存.cpu.block io.但是实际上主要是namespace和cgroup控制资源的隔离. Docker的 ...

  7. 如何快速清理 docker 资源

    如果经常使用 docker,你会发现 docker 占用的资源膨胀很快,其中最明显也最容易被察觉的应该是对磁盘空间的占用.本文将介绍如何快速的清理 docker 占用的系统资源,具体点说就是删除那些无 ...

  8. Docker资源限制

    我们在容器中运行docker镜像的时候,可以指定一些设置容器cpu和内存的相关参数来进行限制,这样子尽量把容器资源做的相对稳定一些.这些参数是在docker run/create命令使用,比如: -- ...

  9. docker 资源限制

    docker run 时使用-m指定可以使用的内存大小, 记录在cgroup配置文件中 cat /sys/fs/cgroup/memory/memory.limit_in_bytes jvm内存会超过 ...

随机推荐

  1. VUE +element el-table运用sortable 拖拽table排序,实现行排序,列排序

    Sortable.js是一款轻量级的拖放排序列表的js插件(虽然体积小,但是功能很强大) 项目需求是要求能对element中 的table进行拖拽行排序 这里用到了sorttable Sortable ...

  2. Vnc自动登录器(VncManager)v1.3-多国语言绿色版-Release1-20190215

    Vnc自动登录器 v1.3 (20190215) By: ybmj@vip.163.com , https://www.cnblogs.com/ybmj/ 下载地址:http://bbs.wuyou. ...

  3. bzoj5368 [Pkusc2018]真实排名

    题目描述: bz luogu 题解: 组合数计数问题. 首先注意排名指的是成绩不小于他的选手的数量(包括他自己). 考虑怎么增大才能改变排名. 小学生都知道,对于成绩为$x$的人,让他自己不动并让$\ ...

  4. PHP 把字符转换为 HTML 实体 - htmlentities() 函数

    定义和用法 htmlentities() 函数把字符转换为 HTML 实体. 语法 htmlentities(string,quotestyle,character-set) 参数 描述 string ...

  5. Python的第二堂课(1)

    一.编程语言的分类 机器语言:直接使用二进制命令去编写程序. 优点:执行效率高 缺点:开发效率低 汇编语言:用英文标签代替二进制命令去编写程序 优点:开发效率高于机器语言 缺点:执行效率低于机器语言 ...

  6. HDU 2476 区间DP String painter

    题解 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm ...

  7. 45个有用的JavaScript技巧

    众所周知,JavaScript是世界上最流行的变成语言,不管是web网页,手机APP(例如PhoneGap或Appcelerator),还是服务器端(例如NodeJS或Wakanda)还有许多其他的实 ...

  8. Objective-c 实例变量的访问级别

    在C#和JAVA中无论是method还是variable都有严格的访问级别控制,那么在object-c中对访问级别的使用非常稀少,原因可能是因为在method上没有访问级别的语法,单单控制变量没有什么 ...

  9. ssh执行远程服务器脚本 提示php: command not found

    ssh执行远程服务器脚本 提示php: command not found 设置环境变量 一台机器作为管理机,来管理其他服务器,并通过key认证,免密码登陆的. 在管理机上通过ssh登陆到其他服务器来 ...

  10. Centos6.5搭建git远程仓库

    远程仓库搭建 step1:安装git ```yum -y install git``` step2:创建用户git,用来运行git服务 useradd git passwd git //修改git用户 ...