摘要

  随着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. biological clock

    '''this application aimed to cauculate people's biological block about emotional(28), energy(23),int ...

  2. LeetCode(150) Evaluate Reverse Polish Notation

    题目 Evaluate the value of an arithmetic expression in Reverse Polish Notation. Valid operators are +, ...

  3. LeetCode(1)Two Sum

    题目: Given an array of integers, find two numbers such that they add up to a specific target number. ...

  4. PAT Basic 1044

    1044 火星数字 火星人是以 13 进制计数的: 地球人的 0 被火星人称为 tret. 地球人数字 1 到 12 的火星文分别为:jan, feb, mar, apr, may, jun, jly ...

  5. express中间件的next()方法

    next()方法出现在express框架中的中间件部分,由于node异步的原因,我们需要提供一种机制,当当前中间件工作完成之后,通知下一个中间件执行,因此一个基本的中间件应该是这种形式 var mid ...

  6. django的rest framework框架——分页、视图、路由、渲染器

    一.rest framework的分页 1.使用rest framework内置类PageNumberPagination实现分类 from django.conf.urls import url f ...

  7. Knockout v3.4.0 中文版教程-4-通过监控数组工作

    2.通过监控数组工作 1. 监控数组 如果你想检测或者响应一个对象的改变,你用observables.如果你想检测和响应一个集合的改变,使用observableArray.这个在很多情况下都非常有用, ...

  8. linux 搭建apache 服务器

    1.查看apache服务器 /etc/init.d/httpd status 若没有,则使用yum  -y install httpd  安装软件 2.设置开机启动 chkconfig httpd o ...

  9. 【02】你是如何理解 HTML 语义化的,有什么好处

    [02]你是如何理解 HTML 语义化的   01,语义化,就是通过HTML标签来表示页面包含的信息. 02,其中有HTML标签的语义化和CSS命名的语义化. 03,HTML标签语义化的的含义是:   ...

  10. luogu3629 [APIO2010]巡逻

    创造一个环出来,可以让环上的边都只访问一次. 对于 \(k=1\),答案就是树的直径两边连起来. 倘若 \(k=2\),那就先按照 \(k=1\) 的求一遍,然后我们发现,如果第二条加的边构成的环和第 ...