爱她吗 发表于 2018-5-27 10:07:40

Docker Cgroups

cgroup 是如何做到内存,cpu 和 io 速率的隔离?
本文用脚本运行示例进程,来验证 Cgroups 关于 cpu、内存、io 这三部分的隔离效果。
测试机器环境
  查看系统
# cat   /etc/redhat-release  CentOS Linux release 7.2.1511 (Core)

  安装相关软件
# yum-yinstall libcgroup-tools  上传所需要的镜像

# dockerload<   centos7.tar
# dockerload<   stress.ta
# dockerimages  REPOSITORY            TAG               IMAGE ID            CREATED             SIZE

  docker.io/jess/stress   latest            3fd6e5b25290      12 months ago       125.4 MB
  docker.io/centos      latest            50dae1ee8677      13 months ago       196.7 MB
  设置开机自启动并启动 Cgroups
# systemctl enable cgconfig.service  Created symlink from /etc/systemd/system/sysinit.target.wants/cgconfig.service to /usr/lib/systemd/system/cgconfig.service.

# systemctl   startcgconfig.service执行 mount 命令查看 cgroup 的挂载点
# mount  \sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime,seclabel)

  proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
  devtmpfs on /dev type devtmpfs (rw,nosuid,seclabel,size=922976k,nr_inodes=230744,mode=755)
  securityfs on /sys/kernel/security type securityfs (rw,nosuid,nodev,noexec,relatime)
  tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev,seclabel)
  devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,seclabel,gid=5,mode=620,ptmxmode=000)
  tmpfs on /run type tmpfs (rw,nosuid,nodev,seclabel,mode=755)
  tmpfs on /sys/fs/cgroup type tmpfs (ro,nosuid,nodev,noexec,seclabel,mode=755)
  cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd)
  pstore on /sys/fs/pstore type pstore (rw,nosuid,nodev,noexec,relatime)
  cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb)
  cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpuacct,cpu)
  cgroup on /sys/fs/cgroup/net_cls type cgroup (rw,nosuid,nodev,noexec,relatime,net_cls)
  cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
  cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
  cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
  cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
  cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)
  cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
  从上面内容可以看到 cgroup 挂载在/sys/fs/cgroup 目录
  

groups 可以限制 blkio、cpu、cpuacct、cpuset、devices、freezer、memory、net_cls、ns 等系 统的资源,以下是主要子系统的说明:
blkio这个子系统设置限制每个块设备的输入输出控制。例如:磁盘,光盘以及 usb 等等。
cpu这个子系统使用调度程序为 cgroup 任务提供 cpu 的访问。
cpuacct产生 cgroup 任务的 cpu 资源报告。
cpuset如果是多核心的 cpu,这个子系统会为 cgroup 任务分配单独的 cpu 和内存。
devices允许或拒绝 cgroup 任务对设备的访问。
freezer暂停和恢复 cgroup 任务。
memory设置每个 cgroup 的内存限制以及产生内存资源报告。
net_cls 标记每个网络包以供 cgroup 方便使用,它通过使用等级识别符(classid)标记网络数 据包,从而允许 Linux 流量控制程序(TC:Traffic Controller)识别从具体 cgroup 中生成 的数据包。
ns:命名空间子系统

cgroups 管理进程 cpu 资源 我们先看一个限制 cpu 资源的例子: 跑一个耗 cpu 的脚本

运行一个容器,在容器内创建脚本并运行脚本,脚本内容:
# docker   run   -it50dae1ee8677   /bin/bash# vi cpu.sh  #!/bin/bash

  i=0
  while true
  do
   let i++
  done
  

# chmod   +x cpu.sh
# ./cpu.sh  将容器切换到后台运行
  在宿主机上 top 可以看到这个脚本基本占了 90%多的 cpu 资源
# toptop - 10:14:15 up1:01,4 users,load average: 0.72, 0.37, 0.21

Tasks: 403 total,   2 running, 400 sleeping,   1 stopped,   0 zombie
%Cpu(s):0.8 us,0.6 sy,0.0 ni, 98.2 id,0.5 wa,0.0 hi,0.0 si,0.0 st
KiB Mem :1876624 total,   234236 free,   563224 used,1079164 buff/cache
KiB Swap:2097148 total,2097040 free,      108 used.1090296 avail Mem

PID USER      PRNI    VIRT    RES    SHR S%CPU %MEM   TIME+ COMMAND                                                                     
4982 root      20   0   11636   1104    924 R 100.00.1   1:41.89 cpu.sh                                                                     
5051 root      20   0146416   2108   1368 R   6.20.1   0:00.02 top                                                                        
    1 root      20   0126020   6256   3504 S   0.00.3   0:08.91 systemd                                                                     
    2 root      20   0       0      0      0 S   0.00.0   0:00.11 kthreadd                                                                     
    3 root      20   0       0      0      0 S   0.00.0   0:01.42 ksoftirqd/0
下面用 cgroups 控制这个进程的 cpu 资源
对于 centos7 来说,通过 systemd-cgls 来查看系统 cgroups tree:
# systemd-cgls查看主要内容

─system.slice
├─systemd-machined.service
│ └─4909 /usr/lib/systemd/systemd-machined
├─docker-06e008e6ecec4f5c138e568c6b5b1659387a003b1cfb037c07006679db976d63.scope
│ ├─4889 /bin/bash
│ └─4982 /bin/bash ./cpu.sh

注:4982 就是我们所运行的容器 pid
# cd/sys/fs/cgroup/cpu/system.slice/docker-06e008e6ecec4f5c138e568c6b5b1659387a003b1cfb037c07006679db976d63.scope/
# echo50000 > cpu.cfs_quota_us
# cat cpu.cfs_quota_us50000
将 cpu.cfs_quota_us 设为 50000,相对于 cpu.cfs_period_us 的 100000 是 50%
# cat cpu.cfs_period_us100000


进入容器,再次执行脚本,打开宿主机的另一个终端执行 top 命令
然后 top 的实时统计数据如下,cpu 占用率将近 50%,看来 cgroups 关于 cpu 的控制起了效果

# top  top - 10:22:06 up1:09,5 users,load average: 0.81, 0.81, 0.50

  Tasks: 405 total,   2 running, 401 sleeping,   2 stopped,   0 zombie
  %Cpu(s):5.4 us,0.5 sy,0.0 ni, 94.1 id,0.0 wa,0.0 hi,0.0 si,0.0 st
  KiB Mem :1876624 total,   234944 free,   559720 used,1081960 buff/cache
  KiB Swap:2097148 total,2097040 free,      108 used.1093452 avail Mem
  
  PID USER      PRNI    VIRT    RES    SHR S%CPU %MEM   TIME+ COMMAND                                                                     
   4982 root      20   0   11636   1104    924 R50.20.1   8:04.80 cpu.sh                                                                     
   5243 root      20   0146388   2284   1424 R   0.70.1   0:00.08 top                                                                        
   3184 root      20   03751081775614116 S   0.30.9   0:13.06 vmtoolsd                                                                     
      1 root      20   0126020   6256   3504 S   0.00.3   0:09.07 systemd                                                                     
    2 root      20   0       0      0      0 S   0.00.0   0:00.12 kthreadd   
CPU 资源控制
CPU 资源的控制也有两种策略,一种是完全公平调度 (CFS:Completely Fair Scheduler) 策略,提供了限额和按比例分配两种方式进行资源控制;另一种是实时调度(Real-Time Scheduler)策略,针对实时进程按周期分配固定的运行时间。配置时间都以微秒(μs)为 单位,文件名中用 us 表示。
CFS 调度策略下的配置 按权重比例设定 CPU 的分配
docker 提供了–cpu-shares 参数,在创建容器时指定容器所使用的 CPU 份额值。例如: 使用命令 docker run -tid –cpu-shares 100镜像,创建容器,则最终生成的 cgroup 的 cpu 份额
  

配置可以下面的文件中找到:
# cat /sys/fs/cgroup/cpu/system.slice/docker-<容器的完整长 ID>/cpu.shares
# dockerrun   -dit--cpu-shares100 docker.io/centos:latest5a5d2c1a2cea9b665ba7a8b9374e436f8b566b1e7b33fb541e6d26150c0d2748

# cat/sys/fs/cgroup/cpu/system.slice/docker-5a5d2c1a2cea9b665ba7a8b9374e436f8b566b1e7b33fb541e6d26150c0d2748.scope/cpu.shares100

cpu-shares 的值不能保证可以获得 1 个 vcpu 或者多少 GHz 的 CPU 资源,仅仅只是一个加权 值。
该加权值是一个整数(必须大于等于 2)表示相对权重,最后除以权重总和算出相对比例, 按比例分配 CPU 时间。
默认情况下,每个 docker 容器的 cpu 份额都是 1024。单独一个容器的份额是没有意义的, 只有在同时运行多个容器时,容器的 cpu 加权的效果才能体现出来。例如,两个容器 A、B 的 cpu 份额分别为 1000 和 500,在 cpu 进行时间片分配的时候,容器 A 比容器 B 多一倍的 机会获得 CPU 的时间片。如果容器 A 的进程一直是空闲的,那么容器 B 是可以获取比容器 A 更多的 CPU 时间片的。极端情况下,比如说主机上只运行了一个容器,即使它的 cpu 份额 只有 50,它也可以独占整个主机的 cpu 资源。
cgroups 只在容器分配的资源紧缺时,也就是说在需要对容器使用的资源进行限制时,才会 生效。因此,无法单纯根据某个容器的 cpu 份额来确定有多少 cpu 资源分配给它,资源分配 结果取决于同时运行的其他容器的 cpu 分配和容器中进程运行情况。
cpu-shares 演示案例:
先删除 docker 主机上运行的容器
# dockerstop   $(dockerps -aq)5a5d2c1a2cea

06e008e6ecec
# dockerrm $(docker ps -aq)5a5d2c1a2cea
06e008e6ecec
  Docker通过--cpu-shares指定CPU份额 运行一个容器指定cpu份额为1024
# docker run -it --rm --cpu-shares1024 --cpuset-cpus 0 --name   nmgkj docker.io/jess/stress--cpu 2  stress: info: dispatching hogs: 2 cpu, 0 io, 0 vm, 0 hdd

注:
--cpu-shares 指定 CPU 份额,默认就是 1024
--cpuset-cpus可以绑定 CPU。例如,指定容器在--cpuset-cpus    0,1或--cpuset-cpus0-3
--cpu 是 stress 命令的选项表示产生 n 个进程 每个进程都反复不停的计算随机数的平方根
stress 命令是 linux 下的一个压力测试工具。
在 docker 宿主机上打开一个 terminal 执行 top
# toptop - 10:33:26 up1:21,4 users,load average: 1.67, 0.73, 0.49

Tasks: 406 total,   4 running, 402 sleeping,   0 stopped,   0 zombie
%Cpu(s):3.0 us,0.1 sy,0.0 ni, 96.9 id,0.0 wa,0.0 hi,0.0 si,0.0 st
KiB Mem :1876624 total,    77540 free,   588504 used,1210580 buff/cache
KiB Swap:2097148 total,2096948 free,      200 used.1007420 avail Mem

PID USER      PRNI    VIRT    RES    SHR S%CPU %MEM   TIME+ COMMAND
42397 root      20   0    7164   92      0 R50.30.0   0:44.72 stress
42396 root      20   0    7164   92      0 R50.00.0   0:44.71 stress
914 root      20   0317548   6280   4844 S   0.30.3   0:15.77 vmtoolsd
4489 root      20   08845443280813240 S   0.31.7   0:13.12 dockerd-current
42449 root      20   0146388   2284   1420 R   0.30.1   0:00.08 top

然后再启动一个容器, --cpu-shares 为 512。

# docker run -it --rm--cpu-shares 512 --cpuset-cpus0 --name nmgkj1 docker.io/jess/stress --cpu 2stress: info: dispatching hogs: 2 cpu, 0 io, 0 vm, 0 hdd

  查看 top 的现实结果

# toptop - 10:41:01 up1:28,5 users,load average: 3.90, 2.35, 1.30

Tasks: 419 total,   6 running, 412 sleeping,   1 stopped,   0 zombie
%Cpu(s):4.1 us,0.1 sy,0.0 ni, 95.8 id,0.0 wa,0.0 hi,0.0 si,0.0 st
KiB Mem :1876624 total,    75512 free,   605852 used,1195260 buff/cache
KiB Swap:2097148 total,2096908 free,      240 used.   988448 avail Mem

PID USER      PRNI    VIRT    RES    SHR S%CPU %MEM   TIME+ COMMAND                                                                     
42396 root      20   0    7164   92      0 R33.40.0   4:16.42 stress                                                                     
42397 root      20   0    7164   92      0 R33.10.0   4:16.42 stress                                                                     
42862 root      20   0    7164   88      0 R16.90.0   0:15.80 stress                                                                     
42863 root      20   0    7164   88      0 R16.60.0   0:15.79 stress                                                                     
3070 root      20   0 1683956 17818843700 S   0.79.5   0:13.86 gnome-shell      

可以看到nmgkj的 CPU占比为 1024/(1024+512)=2/3,nmgkj1的 CPU    占比为
512/(1024+512)=1/3
将nmgkj的 cpu.shares 改为 512
# echo "512" > /sys/fs/cgroup/cpu/system.slice/docker-e15d89c61db31632458441e20efc3d0633d6f015681c6a0624f6bd2a1f9e3e17.scope/cpu.shares
# toptop - 10:51:20 up1:39,6 users,load average: 4.02, 3.81, 2.62

  Tasks: 421 total,   6 running, 413 sleeping,   2 stopped,   0 zombie
  %Cpu(s): 25.1 us,0.3 sy,0.0 ni, 74.5 id,0.0 wa,0.0 hi,0.0 si,0.0 st
  KiB Mem :1876624 total,    70484 free,   610852 used,1195288 buff/cache
  KiB Swap:2097148 total,2096908 free,      240 used.   983260 avail Mem
  
  PID USER      PRNI    VIRT    RES    SHR S%CPU %MEM   TIME+ COMMAND                                                                              
  42396 root      20   0    7164   92      0 R25.20.0   7:39.42 stress                                                                              
  42397 root      20   0    7164   92      0 R25.20.0   7:39.43 stress                                                                              
  42862 root      20   0    7164   88      0 R24.80.0   2:02.77 stress                                                                              
  42863 root      20   0    7164   88      0 R24.80.0   2:02.77 stress                                                                              
4489 root      20   08845443227213228 S   2.01.7   0:14.18 dockerd-current      
可以看到两个容器的 CPU 占比趋于平均 设定 CPU 使用周期使用时间上限
cgroups 里,可以用 cpu.cfs_period_us 和 cpu.cfs_quota_us 来限制该组中的所有进程在单 位时间里可以使用的 cpu 时间。cpu.cfs_period_us 就是时间周期,默认为 100000,即百毫 秒。cpu.cfs_quota_us就是在这期间内可使用的 cpu时间,默认 -1,即无限制。

cpu.cfs_period_us:设定时间周期(单位为微秒(μs)),必须与 cfs_quota_us 配合使用。 cpu.cfs_quota_us :设定周期内最多可使用的时间(单位为微秒(μs))。这里的配置指 task 对单个 cpu 的使用上限。

举个例子,如果容器进程需要每 1 秒使用单个 CPU 的 0.2 秒时间,可以将 cpu-period 设置为
1000000(即 1 秒),cpu-quota 设置为 200000(0.2 秒)。
当然,在多核情况下,若 cfs_quota_us 是 cfs_period_us 的两倍,就表示在两个核上 完全使用 CPU,例如如果允许容器进程需要完全占用两个 CPU,则可以将 cpu-period 设置为 100000(即 0.1 秒),cpu-quota 设置为 200000(0.2 秒)。
使用示例:
使用命令 docker run 创建容器
# docker run --rm --cpu-period100000 --cpu-quota200000 --cpuset-cpus0,1 docker.io/jess/stress --cpu 2在宿主机上执行 top

# top  top - 10:58:34 up1:46,4 users,load average: 1.17, 1.61, 2.05

  Tasks: 403 total,   3 running, 400 sleeping,   0 stopped,   0 zombie
  %Cpu(s): 30.7 us,0.0 sy,0.0 ni, 69.3 id,0.0 wa,0.0 hi,0.0 si,0.0 st
  KiB Mem :1876624 total,    97528 free,   592712 used,1186384 buff/cache
  KiB Swap:2097148 total,2096908 free,      240 used.1002848 avail Mem
  
  PID USER      PRNI    VIRT    RES    SHR S%CPU %MEM   TIME+ COMMAND                                                                              
  43979 root      20   0    7164   92      0 R99.70.0   0:48.43 stress                                                                              
  43978 root      20   0    7164   92      0 R99.30.0   0:48.87 stress                                                                              
  44021 root      20   0146388   2288   1424 R   0.30.1   0:00.20 top                                                                                 
      1 root      20   0191556   6268   3504 S   0.00.3   0:09.83 systemd                                                                              
      2 root      20   0       0      0      0 S   0.00.0   0:00.12 kthreadd         
从上面可以看到基本占了 100%的 cpu 资源
则最终生成的 cgroup 的 cpu 周期配置可以下面的目录中找到:
/sys/fs/cgroup/cpu/system.slice/docker-<容器的完整长 ID>/
# cat /sys/fs/cgroup/cpu/system.slice/docker-968e072047c474480100ab1770a7310bfa1c58e81a43616888c4a9e1937fcd66.scope/cpu.cfs_period_us100000

# cat /sys/fs/cgroup/cpu/system.slice/docker-968e072047c474480100ab1770a7310bfa1c58e81a43616888c4a9e1937fcd66.scope/cpu.cfs_quota_us200000

修改容器的 cpu.cfs_period_us和 cpu.cfs_quota_us 值
# echo "1000000" > /sys/fs/cgroup/cpu/system.slice/docker-968e072047c474480100ab1770a7310bfa1c58e81a43616888c4a9e1937fcd66.scope/cpu.cfs_period_us
# echo "500000" > /sys/fs/cgroup/cpu/system.slice/docker-968e072047c474480100ab1770a7310bfa1c58e81a43616888c4a9e1937fcd66.scope/cpu.cfs_quota_us  

执行 top 查看 cpu 资源
  # top
  top - 11:10:01 up1:57,6 users,load average: 0.18, 1.18, 1.73
  Tasks: 410 total,   3 running, 403 sleeping,   4 stopped,   0 zombie
  %Cpu(s):6.0 us,0.2 sy,0.0 ni, 93.8 id,0.0 wa,0.0 hi,0.0 si,0.0 st
  KiB Mem :1876624 total,    88956 free,   599888 used,1187780 buff/cache
  KiB Swap:2097148 total,2096908 free,      240 used.   994772 avail Mem
  
  PID USER      PRNI    VIRT    RES    SHR S%CPU %MEM   TIME+ COMMAND                                                                              
  43978 root      20   0    7164   92      0 R24.80.0   9:54.96 stress                                                                              
  43979 root      20   0    7164   92      0 R24.50.0   9:49.97 stress                                                                              
  44435 root      20   0146392   2292   1424 R   0.70.1   0:00.07 top                                                                                 
   3070 root      20   0 1683956 17821643700 S   0.39.5   0:14.81 gnome-shell                                                                        
44052 root      20   0146388   2296   1432 S   0.30.1   0:03.87 top   
从上图可以看到基本占了 50%的 cpu 资源


RT 调度策略下的配置 实时调度策略与公平调度策略中的按周期分配时间的方法类似,也是 在周期内分配一个固定的运行时间。
cpu.rt_period_us :设定周期时间。
cpu.rt_runtime_us:设定周期中的运行时间。
# ls/sys/fs/cgroup/cpu/system.slice/docker-968e072047c474480100ab1770a7310bfa1c58e81a43616888c4a9e1937fcd66.scope/cgroup.clone_childrencgroup.procscpuacct.usagecpu.cfs_period_uscpu.rt_period_us   cpu.sharesnotify_on_release cgroup.event_control   cpuacct.statcpuacct.usage_percpucpu.cfs_quota_us cpu.rt_runtime_uscpu.stat    tasks



cpuset - CPU 绑定
对多核 CPU 的服务器,docker 还可以控制容器运行限定使用哪些 cpu 内核和内存节点,即 使用–cpuset-cpus 和–cpuset-mems 参数。对具有 NUMA 拓扑(具有多 CPU、多内存节点)的 服务器尤其有用,可以对需要高性能计算的容器进行性能最优的配置。如果服务器只有一个 内存节点,则–cpuset-mems 的配置基本上不会有明显效果
注:
现在的机器上都是有多个 CPU 和多个内存块的。以前我们都是将内存块看成是一大块内存, 所有 CPU 到这个共享内存的访问消息是一样的。但是随着处理器的增加,共享内存可能会 导致内存访问冲突越来越厉害,且如果内存访问达到瓶颈的时候,性能就不能随之增加。 NUMA(Non-Uniform Memory Access)就是这样的环境下引入的一个模型。比如一台机 器是有 2 个处理器,有 4 个内存块。我们将 1 个处理器和两个内存块合起来,称为一个 NUMA
  

node,这样这个机器就会有两个 NUMA node。在物理分布上,NUMA node 的处理器和内 存块的物理距离更小,因此访问也更快。比如这台机器会分左右两个处理器(cpu1, cpu2), 在每个处理器两边放两个内存块(memory1.1, memory1.2, memory2.1,memory2.2),这样 NUMA node1 的 cpu1 访问 memory1.1 和 memory1.2 就比访问 memory2.1 和 memory2.2 更快。所以使用 NUMA 的模式如果能尽量保证本 node 内的 CPU 只访问本 node 内的内存 块,那这样的效率就是最高的。

使用示例:
# dockerrun-dit --nametest1 --cpuset-cpus0-2docker.io/centos:latestc653ee715b2f8b4f774023f6e50abe702db8c18bdcc90d17907bf9857c737526

# dockerps

CONTAINER ID      IMAGE                     COMMAND             CREATED             STATUS            PORTS               NAMES
c653ee715b2f      docker.io/centos:latest   "/bin/bash"         6 seconds ago       Up 5 seconds                            test1

表示创建的容器只能用 0、1、2 这三个内核。最终生成的 cgroup 的 cpu 内核配置如下:
# cat /sys/fs/cgroup/cpuset/system.slice/docker-c653ee715b2f8b4f774023f6e50abe702db8c18bdcc90d17907bf9857c737526.scope/cpuset.cpus  0-2

cpuset.cpus:在这个文件中填写 cgroup 可使用的 CPU 编号,如 0-2,16 代表 0、1、2 和 16这 4 个 CPU。
cpuset.mems:与 CPU 类似,表示 cgroup 可使用的 memory node,格式同上
通过 docker exec <容器 ID> taskset -c -p 1(容器内部第一个进程编号一般为 1),可以看到容器 中进程与 CPU 内核的绑定关系,可以认为达到了绑定 CPU 内核的目的。
总结:
CPU 配额控制参数的混合使用
当上面这些参数中时,cpu-shares 控制只发生在容器竞争同一个内核的时间片时,如果通过 cpuset-cpus 指定容器 A 使用内核 0,容器 B 只是用内核 1,在主机上只有这两个容器使用对 应内核的情况,它们各自占用全部的内核资源,cpu-shares 没有明显效果。
cpu-period、cpu-quota 这两个参数一般联合使用,在单核情况或者通过 cpuset-cpus 强制容 器使用一个 cpu 内核的情况下,即使 cpu-quota 超过 cpu-period,也不会使容器使用更多的 CPU 资源。
cpuset-cpus、cpuset-mems 只在多核、多内存节点上的服务器上有效,并且必须与实际的物 理配置匹配,否则也无法达到资源控制的目的。
在系统具有多个 CPU 内核的情况下,需要通过 cpuset-cpus 为容器 CPU 内核才能比较方便地 进行测试。

内存配额控制
和 CPU 控制一样,docker 也提供了若干参数来控制容器的内存使用配额,可以控制容器的
swap 大小、可用内存大小等各种内存方面的控制。主要有以下参数:
Docker 提供参数-m, --memory=""限制容器的内存使用量,如果不设置-m,则默认容器内存 是不设限的,容器可以使用主机上的所有空闲内存
内存配额控制使用示例 设置容器的内存上限,参考命令如下所示
#docker    run    -dit    --memory    128m   镜像
默认情况下,除了–memory 指定的内存大小以外,docker 还为容器分配了同样大小的 swap
分区,也就是说,上面的命令创建出的容器实际上最多可以使用 256MB 内存,而不是 128MB
  

内存。如果需要自定义 swap 分区大小,则可以通过联合使用–memory–swap 参数来实现控 制。
# docker run-dit --nameceshi1 --memory 128m docker.io/jess/stress--vm 1 --vm-bytes   256M--vm-hang 0

50a7a6194e0f2b11dfebd5dec8bf7ba041c947fcacdd3416be2f59b2e1be7953
# docker psCONTAINER ID      IMAGE               COMMAND             CREATED             STATUS            PORTS               NAMES

可以发现,使用 256MB 进行压力测试时,由于超过了内存上限(128MB 内存+128MB swap), 进程被 OOM(out of memory)杀死。
使用 250MB 进行压力测试时,进程可以正常运行。
# dockerrun-dit --name ceshi2 --memory 128mdocker.io/jess/stress --vm 1 --vm-bytes 250M --vm-hang 0

2736a2870784307959e6d1304b66b06906f6692fbcd7f876203f1cab466e3526
# docker psCONTAINER ID      IMAGE                   COMMAND                  CREATED            STATUS            PORTS               NAMES

2736a2870784      docker.io/jess/stress   "stress --vm 1 --vm-b"   About a minute ago   Up About a minute                     ceshi2
通过 docker stats 可以查看到容器的内存已经满负载了。
#docker    stats   ceshi2
# dockerstatsceshi2  

   CONTAINER         CPU %               MEM USAGE / LIMIT   MEM %               NET I/O             BLOCK I/O             PIDS
      ceshi2            0.00%                  134 MiB / 134.2 MiB 99.85%            648 B / 648 B       6.526 MB / 371.7 MB   0
对上面的命令创建的容器,可以查看到在 cgroups 的配置文件中,查看到容器的内存大小为 128MB (128×1024×1024=134217728B), 内 存 和 swap 加 起 来 大 小 为 256MB (256×1024×1024=268435456B)。
#cat /sys/fs/cgroup/memory/system.slice/docker-<容器的完整 ID>/memory.limit_in_bytes
#cat/sys/fs/cgroup/memory/system.slice/docker-<          容    器    的    完   整
ID>/memory.memsw.limit_in_bytes
# cat /sys/fs/cgroup/memory/system.slice/docker-2736a2870784307959e6d1304b66b06906f6692fbcd7f876203f1cab466e3526.scope/memory.limit_in_bytes  134217728

# cat /sys/fs/cgroup/memory/system.slice/docker-2736a2870784307959e6d1304b66b06906f6692fbcd7f876203f1cab466e3526.scope/memory.memsw.limit_in_bytes  268435456


磁盘 IO 配额控制 主要包括以下参数:
--device-read-bps:限制此设备上的读速度(bytes per second),单位可以是 kb、mb 或者 gb。
--device-read-iops:通过每秒读 IO 次数来限制指定设备的读速度。
--device-write-bps :限制此设备上的写速度(bytes per second),单位可以是 kb、mb 或者 gb。
--device-write-iops:通过每秒写 IO 次数来限制指定设备的写速度。
--blkio-weight:容器默认磁盘 IO 的加权值,有效值范围为 10-1000。
--blkio-weight-device: 针对特定设备的 IO 加权控制。其格式为 DEVICE_NAME:WEIGHT

磁盘 IO 配额控制示例
blkio-weight
使用下面的命令创建两个–blkio-weight 值不同的容器: 在容器中同时执行下面的 dd 命令,进行测试
# dockerrun   -it --rm--name duyuheng --blkio-weight 100 docker.io/centos:latest
# time dd if=/dev/zeroof=test.out bs=1M count=1024 oflag=direct  1024+0 records in

  1024+0 records out
  1073741824 bytes (1.1 GB) copied, 23.1152 s, 46.5 MB/s
  
  real0m23.148s
  user0m0.008s
  sys0m0.484s

# dockerrun-it --rm--rm --name duyuheng1 --blkio-weight 1000 docker.io/centos:latest
# time dd if=/dev/zeroof=test.out bs=1M count=1024 oflag=direct1024+0 records in

1024+0 records out
1073741824 bytes (1.1 GB) copied, 10.8772 s, 98.7 MB/s

real0m11.437s
user0m0.000s
sys0m1.074s
注:oflag=direct 规避掉文件系统的 cache,把写请求直接封装成 io 指令发到硬盘
  
页: [1]
查看完整版本: Docker Cgroups