• Docker中的Cgroup资源配置方法


    摘要

    Docker通过Cgroup来控制容器使用的资源配额,包括CPU、内存、磁盘三大方面,基本覆盖了常见的资源配额和使用量控制。

    一、Cgroup简介

    Cgroup是Control Groups的缩写,是Linux内核提供的一种可以限制、记录、隔离进程组所使用的物理资源(如CPU、内存、磁盘IO等待)的机制,被LXC、docker等很多项目用于实现进程资源控制。Cgroup本身是提供将进程进行分组化管理的功能和接口的基础结构,I/O或内存的分配控制等具体的资源管理是通过该功能来实现的。这些具体的资源管理功能称为Cgroup子系统,有以下几大子系统实现:

    blkio:设置限制每个块设备的输入输出控制。例如:磁盘,光盘以及usb等等

    CPU:使用调度程序为cgroup任务提供CPU的访问

    cpuacct:产生cgroup任务的CPU资源报告

    cpuset:如果是多核心的CPU,这个子系统会为cgroup任务分配单独的CPU和内存

    devices:允许或拒绝cgroup任务对设备的访问

    freezer:暂停和恢复cgroup任务

    memory:设置每个cgroup的内存限制以及产生内存资源报告

    net_cls:标记每个网络包以供cgroup方便使用

    ns:命名空间子系统

    perf_event:增加了对每个group的监测跟踪的能力,可以监测属于某个特定的group的所有线程以及运行在特定CPU上的线程

    下面开始使用stress压力测试工具来测试CPU和内存使用状况

    二、安装stress工具

     1 创建stress目录
     2 [root@server1 ~]# mkdir /opt/stress
     3 [root@server1 ~]# cd /opt/stress/
     4 
     5 编写Dockerfile文件
     6 [root@server1 stress]# vim DockerfileFROM centos:7
     7 MAINTAINER xu
     8 RUN yum -y install wget
     9 RUN wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/rep
    10 o/epel-7.repo
    11 RUN yum -y install stress
    12 
    13 构建镜像
    14 [root@server1 stress]# docker build -t centos:stress .
    15 
    16 查看镜像
    17 [root@server1 stress]# docker images
    18 REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
    19 centos              stress              821b4e4b3972        5 seconds ago       417MB

    三、CPU资源分配

    默认情况下,每个Docker容器的CPU份额都是1024。单独一个容器的份额是没有意义的。只有在同时运行多个容器时,容器的CPU加权的效果才能体现出来。例如,两个容器A、B的CPU份额分别为1000和500,在CPU进行时间片分配的时候,容器A比容器B多一倍的机会获得CPU的时间片。但分配的结果取决于当时主机和其他容器的运行状态,实际上也无法保证容器A一定能获得CPU时间片。比如容器A的进程一直时空闲的,那么容器B是可以获取比容器A更多的CPU时间片的,极端情况下,例如主机上只运行了一个容器,即使它的CPU份额只有50,它也可以独占整个主机的CPU资源

    Cgroup只在容器分配的资源紧缺时,即在需要对容器使用的资源进行限制时,才会生效。因此,无法单纯根据某个容器的CPU份额来确定有多少CPU资源分配给它,资源分配结果取决于同时运行的其他容器的CPU分配和容器中进程运行情况。

    可以通过cpu share可以设置容器使用CPU的优先级,比如,启动了两个容器及运行查看CPU使用百分比

    3.1、运行两个容器

    1 [root@server1 stress]# docker run -dit --name cpu500 --cpu-shares 500 centos:stress stress -c 10
    2 c0083744c59f24ca4ff008b2e5fa25dbd7e3363c7b81362d5f4f87c0ac486c7b
    3 [root@server1 stress]# docker run -dit --name cpu1000 --cpu-shares 1000 centos:stress stress -c 10
    4 b84cc76469bc7264b26a3c9db846b2e07918a25e425b1bf62bc9688e501dc82f

    3.2、查看内存使用情况

     1 进入cpu1000容器
     2 [root@server1 stress]# docker exec -it b84cc76469bc /bin/bash
     3 
     4 查看cpu使用情况
     5 [root@b84cc76469bc /]# top
     6 
     7 进入cpu500容器
     8 [root@server1 stress]# docker exec -it c0083744c59f /bin/bash
     9 
    10 查看cpu使用情况
    11 [root@c0083744c59f /]# top

    容器1000cpu使用情况如下

     容器500cpu使用情况如下

    对比后可以得出cpu1000的容器cpu使用率大概是另一个的两倍

    四、CPU周期限制

    Docker提供了--cpu-period、--cpu-quota两个参数控制容器可以分配到的CPU时钟周期。

    • --cpu-period是用来指定容器对CPU的使用要在多长时间内做一次重新分配。
    • --cpu-quota是用来指定在这个周期内,最多可以有多少时间用来跑这个容器。
    • 与--cpu-shares不同的是,这种配置是指定一个绝对值,容器对CPU资源的使用绝对不会超过配置的值
    • cpu-period和cpu-quota的单位为微秒(μs)。cpu-period的最小值为1000微秒,最大值为1秒(10^6 μs),默认值为 0.1 秒(100000 μs)。
    • cpu-quota的值默认为-1,表示不做控制。cpu-period和cpu-quota参数一般联合使用

    例如:容器进程需要每1秒使用单个CPU的0.2秒时间,可以将cpu-period设置为1000000(即1秒),cpu-quota 设置为 200000(0.2 秒)。当然,在多核情况下,如果允许容器进程完全占用两个CPU,则可以将cpu-period设置为100000(即0.1秒),cpu-quota设置为200000(0.2秒)。

     1 运行容器并设置周期
     2 [root@server1 stress]# docker run -dit --cpu-period 100000 --cpu-quota 200000 centos:stress 
     3 9449396fc3b0b8a99b1fb8fb211998032bc91933df831b5c3341e435a64beda5
     4 [root@server1 stress]# docker ps -a
     5 CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                        PORTS               NAMES
     6 9449396fc3b0        centos:stress       "/bin/bash"         5 seconds ago       Up 4 seconds                                      goofy_mclean
     7 
     8 进入容器
     9 [root@server1 stress]# docker exec -it 9449396fc3b0 /bin/bash
    10 
    11 查看周期
    12 [root@9449396fc3b0 /]# cat /sys/fs/cgroup/cpu/cpu.cfs_period_us 
    13 100000
    14 [root@9449396fc3b0 /]# cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us 
    15 200000

    五、CPU Core控制

    对多核 CPU 的服务器,Docker 还可以控制容器运行使用哪些 CPU 内核,即使用--cpuset-cpus 参数。这对具有多 CPU 的服务器尤其有用,可以对需要高性能计算的容器进行性能最优的配置。

    5.1、进行CPU Core控制配置

     1 表示创建的容器只能用 0、1两个内核
     2 [root@server1 ~]# docker run -dit --name cpu1 --cpuset-cpus 0-1 centos:stress 
     3 3266be3c50ebfe8e4e34bc3c202e7ad419314aedccdea1b09c941baf029569d1
     4 
     5 查看容器运行状态
     6 [root@server1 ~]# docker ps -a
     7 CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
     8 3266be3c50eb        centos:stress       "/bin/bash"         6 seconds ago       Up 5 seconds                            cpu1
     9 
    10 进入容器
    11 [root@server1 ~]# docker exec -it 3266be3c50eb /bin/bash
    12 
    13 生成 的 cgroup 的 CPU 内核配置如下
    14 [root@3266be3c50eb /]# cat /sys/fs/cgroup/cpuset/cpuset.cpus
    15 0-1

    5.2、CPU内核绑定

    通过下面指令可以看到容器中进程与 CPU 内核的绑定关系,达到绑定 CPU 内核的目的

    1 [root@server1 ~]# docker exec 3266be3c50eb taskset -c -p 1
    2 pid 1's current affinity list: 0,1

    5.3、压力测试

    六、CPU配额参数的混合使用

    通过 cpuset-cpus 参数指定容器 A 使用 CPU 内核 1,容器 B 只是用 CPU 内核 3。在主机上只有这两个容器使用对应 CPU 内核的情况,它们各自占用全部的内核资源,cpu-shares 没有明显效果。

    cpuset-cpus、cpuset-mems 参数只在多核、多内存节点上的服务器上有效,并且必须与实际的物理配置匹配,否则也无法达到资源控制的目的。

    在系统具有多个 CPU 内核的情况下,需要通过 cpuset-cpus 参数为设置容器 CPU 内核才能方便地进行测试

     1 CPU配置
     2 [root@server1 ~]# docker run -dit --name cpu3 --cpuset-cpus 1 --cpu-shares 500 centos:stress stress -c 1
     3 275bc9803463abd9098c632d836f605d76bab74467cff2cd57f956762f6fed24
     4 [root@server1 ~]# docker run -dit --name cpu4 --cpuset-cpus 3 --cpu-shares 1000 centos:stress stress -c 1
     5 be61e954017eb398701c9c17440cdf3c72450e4ebb1b76fb2022afeadee277fd
     6 
     7 查看容器运行情况
     8 [root@server1 ~]# docker ps -a 
     9 CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS              PORTS               NAMES
    10 be61e954017e        centos:stress       "stress -c 1"       48 seconds ago       Up 48 seconds                           cpu4
    11 275bc9803463        centos:stress       "stress -c 1"       About a minute ago   Up About a minute                       cpu3
    12 
    13 分别进入两个容器
    14 [root@server1 ~]# docker exec -it 275bc9803463 /bin/bash
    15 [root@server1 ~]# docker exec -it be61e954017e /bin/bash
    16 
    17 分别查看CPU使用情况
    18 [root@be61e954017e /]# top        #记住按1查看每个核心的占用

    cpu3容器cpu使用情况

    cpu4容器cpu使用情况

    总结:上面的 centos:stress 镜像安装了 stress 工具,用来测试 CPU 和内存的负载。通过 在两个容器上分别执行 stress -c 1 命令,将会给系统一个随机负载,产生 1 个进程。这 个进程都反复不停的计算由 rand() 产生随机数的平方根,直到资源耗尽。观察到宿主机上的 CPU 使用率,第三个内核的使用率接近 100%, 并且一批进程的 CPU 使用率明显存在 2:1 的使用比例的对比。

    七、内存限额

    与操作系统类似,容器可使用的内存包括两部分:物理内存和Swap,Docker通过下面两组参数来控制容器内存的使用量

    • -m或--memory:设置内存的使用限额,例如100M、1024M。
    • --memory-swap:设置内存+swap的使用限额

    执行如下命令允许该容器最多使用200M的内存和300M的内存+swap

     1 内存限额配置
     2 [root@server1 ~]# docker run -it -m 200M --memory-swap=300M progrium/stress --vm 1 --vm-bytes 280M
     3 stress: dbug: [1] using backoff sleep of 3000us
     4 stress: dbug: [1] --> hogvm worker 1 [6] forked
     5 stress: dbug: [6] allocating 293601280 bytes ...
     6 stress: dbug: [6] touching bytes in strides of 4096 bytes ...
     7 会一直运行
     8 
     9 --vm 1:启动 1 个内存工作线程。 
    10 --vm-bytes 280M:每个线程分配 280M 内存。 
    11 默认情况下,容器可以使用主机上的所有空闲内存。
    12 
    13 如果让工作线程分配的内存超过300M,分配的内存超过限额,stress线程报错,容器退出
    14 [root@server1 ~]# docker run -it -m 200M --memory-swap=300M progrium/stress --vm 1 --vm-bytes 310M
    15 stress: info: [1] dispatching hogs: 0 cpu, 0 io, 1 vm, 0 hdd
    16 stress: dbug: [1] using backoff sleep of 3000us
    17 stress: dbug: [1] --> hogvm worker 1 [6] forked
    18 stress: dbug: [6] allocating 325058560 bytes ...
    19 stress: dbug: [6] touching bytes in strides of 4096 bytes ...
    20 stress: FAIL: [1] (416) <-- worker 6 got signal 9
    21 stress: WARN: [1] (418) now reaping child worker processes
    22 stress: FAIL: [1] (422) kill error: No such process         #没有进程退出
    23 stress: FAIL: [1] (452) failed run completed in 1s

    八、Block IO的限制

    默认情况下,所有容器能平等地读写磁盘,可以通过设置--blkio-weight参数来改变容器block IO的优先级。--blkio-weight与--cpu-shares类似,设置的是相对权重值,默认为500。

    在下面的例子中,容器A读写磁盘的带宽是容器B的两倍

     1 Block IO 的限制配置
     2 [root@server1 ~]# docker run -dit --name container_A --blkio-weight 400 centos:stress 
     3 6cfcf6a595b729cf77267ad939e70a1e30f973b3197d4aec2903ec3429a78b3b
     4 [root@server1 ~]# docker run -dit --name container_B --blkio-weight 200 centos:stress 
     5 e680d986196c36c4910c7e91fe798c2389e0d298c0c4e5bc7b76d99e288fdf82
     6 
     7 查看容器运行情况
     8 [root@server1 ~]# docker ps -a 
     9 CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS                      PORTS               NAMES
    10 e680d986196c        centos:stress       "/bin/bash"              46 seconds ago       Up 46 seconds                                   container_B
    11 6cfcf6a595b7        centos:stress       "/bin/bash"              About a minute ago   Up About a minute                               container_A
    12 
    13 进入容器分别查看
    14 [root@server1 ~]# docker exec -it 6cfcf6a595b7 /bin/bash
    15 [root@6cfcf6a595b7 /]# cat /sys/fs/cgroup/blkio/blkio.weight
    16 400
    17 
    18 [root@server1 ~]# docker exec -it e680d986196c /bin/bash
    19 [root@e680d986196c /]# cat /sys/fs/cgroup/blkio/blkio.weight
    20 200

    九、bps和iops的限制

    bps是byte per second,每秒读写的数据量

    iops是io per second,每秒IO的次数

    可通过以下参数控制容器的bps和iops:

    • --device-read-bps,限制读某个设备的bps
    • --device-write-bps,限制写某个设备的bps
    • --device-read-iops,限制读某个设备的iops
    • --device-write-iops,限制写某个设备的iops 

    下面的示例是限制容器写/dev/sda的速率为5MB/s

     1 bps 和 iops 的限制配置
     2 [root@server1 ~]# docker run -dit --device-write-bps /dev/sda:5MB centos:stress 
     3 88fa4e4ca86fa3f17ed829d91a597d7b7f6645ca0c11d23af3441406203291f2
     4 
     5 查看容器运行情况
     6 [root@server1 ~]# docker ps -a
     7 CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
     8 88fa4e4ca86f        centos:stress       "/bin/bash"         5 seconds ago       Up 4 seconds                            interesting_mclaren
     9 
    10 进入容器
    11 [root@server1 ~]# docker exec -it 88fa4e4ca86f /bin/bash
    12 
    13 进行测试
    14 [root@88fa4e4ca86f /]# dd if=/dev/zero of=text bs=1M count=1024 oflag=direct      #
    15 可以按ctrl+c中断查看
    16 ^C14+0 records in
    17 14+0 records out
    18 14680064 bytes (15 MB) copied, 2.80506 s, 5.2 MB/s #限速5MB/s

    通过dd命令测试在容器中写磁盘的速度。因为容器的文件系统是在host /dev/sda上的,在容器中写文件相当于对host /dev/sda进行写操作。另外,oflag=direct指定用direct IO方式写文件,这样 --device-write-bps才能生效

    结果表明限速5MB/s左右。作为对比测试,如果不限速,结果如下:

    1 运行另一个容器
    2 [root@server1 ~]# docker run -it centos:stress 
    3 
    4 [root@ffd2062aa3a4 /]# dd if=/dev/zero of=text bs=1M count=1024 oflag=direct
    5 1024+0 records in
    6 1024+0 records out
    7 1073741824 bytes (1.1 GB) copied, 0.465947 s, 2.3 GB/s  #不限速,2.3GB/s
  • 相关阅读:
    js jquery 获取服务器控件的三种方法
    jquery.autocomplete.js用法及示例,小白进
    devexpress 经验笔记
    Powerdesigner逆向工程从sql server数据库生成pdm (转载)
    SQLServer的数据类型
    显示隐藏磁盘,显示联想一键恢复的隐藏磁盘分区
    做mapx、ArcEngine的二次开发出现“没有注册类别 (异常来自 HRESULT:0x80040154 (REGDB_E_CLASSNOTREG)”
    我们无法创建新的分区 也找不到现有的分
    Windows无法安装到GPT分区形式磁盘,怎么办?
    oracle 空间数据库说明
  • 原文地址:https://www.cnblogs.com/xuhao0705/p/14073525.html
Copyright © 2020-2023  润新知