cgroup 如何做到内存,cpu io 速率的隔离?

本文用脚本运行示例进程,来验证 Cgroups 关于 cpu、内存、io 这三部分的隔离效果。

测试机器环境

查看系统

 [root@localhost ~]# cat   /etc/redhat-release

CentOS Linux release 7.2.1511 (Core)

安装相关软件

[root@localhost ~]# yum  -y  install libcgroup-tools

上传所需要的镜像

[root@localhost src]# docker  load  <   centos7.tar  
[root@localhost src]# docker  load  <     stress.ta
[root@localhost src]# docker  p_w_picpaths

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

[root@localhost ~]# systemctl enable cgconfig.service

Created symlink from /etc/systemd/system/sysinit.target.wants/cgconfig.service to /usr/lib/systemd/system/cgconfig.service.

[root@localhost ~]# systemctl   start  cgconfig.service

执行 mount 命令查看 cgroup 的挂载点

[root@localhost ~]# 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 可以限制 blkiocpucpuacctcpusetdevicesfreezermemorynet_clsns 等系 统的资源,以下是主要子系统的说明:

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

cpu  这个子系统使用调度程序为 cgroup 任务提供 cpu 的访问。

cpuacct  产生 cgroup 任务的 cpu 资源报告。

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

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

freezer  暂停和恢复 cgroup 任务。

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

net_cls 标记每个网络包以供 cgroup 方便使用,它通过使用等级识别符(classid)标记网络数 据包,从而允许 Linux 流量控制程序(TCTraffic Controller)识别从具体 cgroup 中生成 的数据包。

ns:命名空间子系统

 

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

 

运行一个容器,在容器内创建脚本并运行脚本,脚本内容:

[root@localhost ~]# docker   run   -it  50dae1ee8677     /bin/bash
[root@06e008e6ecec /]# vi cpu.sh

#!/bin/bash

i=0

while true

do

 let i++

done


[root@06e008e6ecec /]# chmod   +x cpu.sh 
[root@06e008e6ecec /]# ./cpu.sh

将容器切换到后台运行

在宿主机上 top 可以看到这个脚本基本占了 90%多的 cpu 资源

[root@localhost ~]# top

top - 10:14:15 up  1: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      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                                                                      

  4982 root      20   0   11636   1104    924 R 100.0  0.1   1:41.89 cpu.sh                                                                       

 5051 root      20   0  146416   2108   1368 R   6.2  0.1   0:00.02 top                                                                          

    1 root      20   0  126020   6256   3504 S   0.0  0.3   0:08.91 systemd                                                                      

    2 root      20   0       0      0      0 S   0.0  0.0   0:00.11 kthreadd                                                                     

    3 root      20   0       0      0      0 S   0.0  0.0   0:01.42 ksoftirqd/0

下面用 cgroups 控制这个进程的 cpu 资源

对于 centos7 来说,通过 systemd-cgls 来查看系统 cgroups tree

[root@localhost ~]# 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

[root@localhost ~]# cd  /sys/fs/cgroup/cpu/system.slice/docker-06e008e6ecec4f5c138e568c6b5b1659387a003b1cfb037c07006679db976d63.scope/
[root@localhost docker-06e008e6ecec4f5c138e568c6b5b1659387a003b1cfb037c07006679db976d63.scope]# echo  50000 > cpu.cfs_quota_us 
[root@localhost docker-06e008e6ecec4f5c138e568c6b5b1659387a003b1cfb037c07006679db976d63.scope]# cat cpu.cfs_quota_us

50000

cpu.cfs_quota_us 设为 50000,相对于 cpu.cfs_period_us 的 100000 是 50%

[root@localhost docker-06e008e6ecec4f5c138e568c6b5b1659387a003b1cfb037c07006679db976d63.scope]# cat cpu.cfs_period_us

100000

 

进入容器,再次执行脚本,打开宿主机的另一个终端执行 top 命令

然后 top 的实时统计数据如下,cpu 占用率将近 50%,看来 cgroups 关于 cpu 的控制起了效果

 

[root@localhost ~]# top

top - 10:22:06 up  1: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      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                                                                      

 4982 root      20   0   11636   1104    924 R  50.2  0.1   8:04.80 cpu.sh                                                                       

 5243 root      20   0  146388   2284   1424 R   0.7  0.1   0:00.08 top                                                                          

 3184 root      20   0  375108  17756  14116 S   0.3  0.9   0:13.06 vmtoolsd                                                                     

    1 root      20   0  126020   6256   3504 S   0.0  0.3   0:09.07 systemd                                                                      

    2 root      20   0       0      0      0 S   0.0  0.0   0:00.12 kthreadd    

CPU 资源控制

CPU 资源的控制也有两种策略,一种是完全公平调度 CFSCompletely 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

[root@localhost ~]# docker  run   -dit  --cpu-shares  100 docker.io/centos:latest

5a5d2c1a2cea9b665ba7a8b9374e436f8b566b1e7b33fb541e6d26150c0d2748

[root@localhost ~]# cat  /sys/fs/cgroup/cpu/system.slice/docker-5a5d2c1a2cea9b665ba7a8b9374e436f8b566b1e7b33fb541e6d26150c0d2748.scope/cpu.shares

100

cpu-shares 的值不能保证可以获得 1  vcpu 或者多少 GHz  CPU 资源,仅仅只是一个加权 值。

该加权值是一个整数(必须大于等于 2)表示相对权重,最后除以权重总和算出相对比例, 按比例分配 CPU 时间。

默认情况下,每个 docker 容器的 cpu 份额都是 1024。单独一个容器的份额是没有意义的, 只有在同时运行多个容器时,容器的 cpu 加权的效果才能体现出来。例如,两个容器 AB  cpu 份额分别为 1000  500,在 cpu 进行时间片分配的时候,容器 A 比容器 B 多一倍的 机会获得 CPU 的时间片。如果容器 A 的进程一直是空闲的,那么容器 B 是可以获取比容器 A 更多的 CPU 时间片的。极端情况下,比如说主机上只运行了一个容器,即使它的 cpu 份额 只有 50,它也可以独占整个主机的 cpu 资源。

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

cpu-shares 演示案例:

先删除 docker 主机上运行的容器

[root@localhost ~]# docker  stop   $(docker  ps -aq)

5a5d2c1a2cea

06e008e6ecec

[root@localhost ~]# docker  rm $(docker ps -aq)

5a5d2c1a2cea

06e008e6ecec

Docker通过--cpu-shares指定CPU份额 运行一个容器指定cpu份额为1024

[root@localhost ~]# docker run -it --rm --cpu-shares  1024 --cpuset-cpus 0 --name   nmgkj docker.io/jess/stress  --cpu 2

stress: info: [1] dispatching hogs: 2 cpu, 0 io, 0 vm, 0 hdd

注:

--cpu-shares 指定 CPU 份额,默认就是 1024

--cpuset-cpus  可以绑定 CPU。例如,指定容器在--cpuset-cpus    0,1  --cpuset-cpus  0-3

--cpu  stress 命令的选项表示产生 n 个进程 每个进程都反复不停的计算随机数的平方根

stress 命令是 linux 下的一个压力测试工具。

 docker 宿主机上打开一个 terminal 执行 top

[root@localhost ~]# top

top - 10:33:26 up  1: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      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND

42397 root      20   0    7164     92      0 R  50.3  0.0   0:44.72 stress

42396 root      20   0    7164     92      0 R  50.0  0.0   0:44.71 stress

914 root      20   0  317548   6280   4844 S   0.3  0.3   0:15.77 vmtoolsd

4489 root      20   0  884544  32808  13240 S   0.3  1.7   0:13.12 dockerd-current

42449 root      20   0  146388   2284   1420 R   0.3  0.1   0:00.08 top

 

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

 

[root@localhost ~]# docker run -it --rm  --cpu-shares 512 --cpuset-cpus  0 --name nmgkj1 docker.io/jess/stress --cpu 2

stress: info: [1] dispatching hogs: 2 cpu, 0 io, 0 vm, 0 hdd

查看 top 的现实结果

[root@localhost ~]# top

top - 10:41:01 up  1: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      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                                                                      

42396 root      20   0    7164     92      0 R  33.4  0.0   4:16.42 stress                                                                       

42397 root      20   0    7164     92      0 R  33.1  0.0   4:16.42 stress                                                                       

42862 root      20   0    7164     88      0 R  16.9  0.0   0:15.80 stress                                                                       

42863 root      20   0    7164     88      0 R  16.6  0.0   0:15.79 stress                                                                       

 3070 root      20   0 1683956 178188  43700 S   0.7  9.5   0:13.86 gnome-shell        

 

可以看到nmgkj   CPU  占比为 1024/(1024+512)=2/3nmgkj1   CPU    占比为

512/(1024+512)=1/3

nmgkj cpu.shares 改为 512

[root@localhost ~]# echo "512" > /sys/fs/cgroup/cpu/system.slice/docker-e15d89c61db31632458441e20efc3d0633d6f015681c6a0624f6bd2a1f9e3e17.scope/cpu.shares
[root@localhost ~]# top

top - 10:51:20 up  1: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      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                                                                              

42396 root      20   0    7164     92      0 R  25.2  0.0   7:39.42 stress                                                                               

42397 root      20   0    7164     92      0 R  25.2  0.0   7:39.43 stress                                                                               

42862 root      20   0    7164     88      0 R  24.8  0.0   2:02.77 stress                                                                               

42863 root      20   0    7164     88      0 R  24.8  0.0   2:02.77 stress                                                                               

 4489 root      20   0  884544  32272  13228 S   2.0  1.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 设置为 2000000.2 )。

当然,在多核情况下,若 cfs_quota_us  cfs_period_us 的两倍,就表示在两个核上 完全使用 CPU,例如如果允许容器进程需要完全占用两个 CPU,则可以将 cpu-period 设置为 100000 0.1 cpu-quota 设置为 2000000.2 )。

使用示例:

使用命令 docker run 创建容器

[root@localhost ~]# docker run --rm --cpu-period  100000 --cpu-quota  200000 --cpuset-cpus  0,1 docker.io/jess/stress --cpu 2

在宿主机上执行 top

[root@localhost ~]# top

top - 10:58:34 up  1: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      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                                                                              

43979 root      20   0    7164     92      0 R  99.7  0.0   0:48.43 stress                                                                               

43978 root      20   0    7164     92      0 R  99.3  0.0   0:48.87 stress                                                                               

44021 root      20   0  146388   2288   1424 R   0.3  0.1   0:00.20 top                                                                                  

    1 root      20   0  191556   6268   3504 S   0.0  0.3   0:09.83 systemd                                                                              

    2 root      20   0       0      0      0 S   0.0  0.0   0:00.12 kthreadd          

从上面可以看到基本占了 100% cpu 资源

则最终生成的 cgroup  cpu 周期配置可以下面的目录中找到:

/sys/fs/cgroup/cpu/system.slice/docker-<容器的完整长 ID>/

[root@localhost ~]# cat /sys/fs/cgroup/cpu/system.slice/docker-968e072047c474480100ab1770a7310bfa1c58e81a43616888c4a9e1937fcd66.scope/cpu.cfs_period_us

100000

[root@localhost ~]# cat /sys/fs/cgroup/cpu/system.slice/docker-968e072047c474480100ab1770a7310bfa1c58e81a43616888c4a9e1937fcd66.scope/cpu.cfs_quota_us

200000

修改容器的 cpu.cfs_period_us   cpu.cfs_quota_us

[root@localhost ~]# echo "1000000" > /sys/fs/cgroup/cpu/system.slice/docker-968e072047c474480100ab1770a7310bfa1c58e81a43616888c4a9e1937fcd66.scope/cpu.cfs_period_us 
[root@localhost ~]# echo "500000" > /sys/fs/cgroup/cpu/system.slice/docker-968e072047c474480100ab1770a7310bfa1c58e81a43616888c4a9e1937fcd66.scope/cpu.cfs_quota_us


执行 top 查看 cpu 资源

[root@localhost ~]# top

top - 11:10:01 up  1: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      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                                                                              

43978 root      20   0    7164     92      0 R  24.8  0.0   9:54.96 stress                                                                               

43979 root      20   0    7164     92      0 R  24.5  0.0   9:49.97 stress                                                                               

44435 root      20   0  146392   2292   1424 R   0.7  0.1   0:00.07 top                                                                                  

 3070 root      20   0 1683956 178216  43700 S   0.3  9.5   0:14.81 gnome-shell                                                                          

44052 root      20   0  146388   2296   1432 S   0.3  0.1   0:03.87 top   

从上图可以看到基本占了 50%的 cpu 资源


RT 调度策略下的配置 实时调度策略与公平调度策略中的按周期分配时间的方法类似,也是 在周期内分配一个固定的运行时间。

cpu.rt_period_us :设定周期时间。

cpu.rt_runtime_us:设定周期中的运行时间。

[root@localhost ~]# ls  /sys/fs/cgroup/cpu/system.slice/docker-968e072047c474480100ab1770a7310bfa1c58e81a43616888c4a9e1937fcd66.scope/

cgroup.clone_children  cgroup.procs  cpuacct.usage  cpu.cfs_period_us  cpu.rt_period_us   cpu.shares  notify_on_release cgroup.event_control   cpuacct.stat  cpuacct.usage_percpu  cpu.cfs_quota_us cpu.rt_runtime_us  cpu.stat    tasks


cpuset - CPU 绑定

对多核 CPU 的服务器,docker 还可以控制容器运行限定使用哪些 cpu 内核和内存节点,即 使用–cpuset-cpus –cpuset-mems 参数。对具有 NUMA 拓扑(具有多 CPU、多内存节点)的 服务器尤其有用,可以对需要高性能计算的容器进行性能最优的配置。如果服务器只有一个 内存节点,则–cpuset-mems 的配置基本上不会有明显效果

注:

现在有多 CPU 前我是一存, 所有 CPU 到这个共享内存的访问消息是一样的。但是随着处理器的增加,共享内存可能会 导致内存访问冲突越来越厉害,且如果内存访问达到瓶颈的时候,性能就不能随之增加。 NUMANon-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 内的内存 块,那这样的效率就是最高的。

 

使用示例:

[root@localhost ~]# docker  run  -dit --name  test1 --cpuset-cpus  0-2  docker.io/centos:latest

c653ee715b2f8b4f774023f6e50abe702db8c18bdcc90d17907bf9857c737526

[root@localhost ~]# docker  ps


CONTAINER ID        IMAGE                     COMMAND             CREATED             STATUS              PORTS               NAMES

c653ee715b2f        docker.io/centos:latest   "/bin/bash"         6 seconds ago       Up 5 seconds                            test1

 

表示创建的容器只能用 012 这三个内核。最终生成的 cgroup  cpu 内核配置如下:

[root@localhost ~]# cat /sys/fs/cgroup/cpuset/system.slice/docker-c653ee715b2f8b4f774023f6e50abe702db8c18bdcc90d17907bf9857c737526.scope/cpuset.cpus

0-2

cpuset.cpus:在这个文件中填写 cgroup 可使用的 CPU 编号,如 0-2,16 代表 012 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-periodcpu-quota 这两个参数一般联合使用,在单核情况或者通过 cpuset-cpus 强制容 器使用一个 cpu 内核的情况下,即使 cpu-quota 超过 cpu-period,也不会使容器使用更多的 CPU 资源。

cpuset-cpuscpuset-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 参数来实现控 制。

[root@localhost ~]# docker run  -dit --name  ceshi1 --memory 128m docker.io/jess/stress  --vm 1 --vm-bytes   256M  --vm-hang 0


50a7a6194e0f2b11dfebd5dec8bf7ba041c947fcacdd3416be2f59b2e1be7953

[root@localhost ~]# docker ps

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

可以发现使 256MB 行压试时内存128MB +128MB swap), 进程被 OOM(out of memory)杀死。

使用 250MB 进行压力测试时,进程可以正常运行。

[root@localhost ~]# docker  run  -dit --name ceshi2 --memory 128m  docker.io/jess/stress --vm 1 --vm-bytes 250M --vm-hang 0


2736a2870784307959e6d1304b66b06906f6692fbcd7f876203f1cab466e3526

[root@localhost ~]# docker ps

CONTAINER 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

[root@localhost ~]# docker  stats  ceshi2


 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

[root@localhost ~]# cat /sys/fs/cgroup/memory/system.slice/docker-2736a2870784307959e6d1304b66b06906f6692fbcd7f876203f1cab466e3526.scope/memory.limit_in_bytes

134217728

[root@localhost ~]# cat /sys/fs/cgroup/memory/system.slice/docker-2736a2870784307959e6d1304b66b06906f6692fbcd7f876203f1cab466e3526.scope/memory.memsw.limit_in_bytes

268435456

 

磁盘 IO 配额控制 主要包括以下参数:

--device-read-bps设备bytes per second可以 kbmb 或者 gb

--device-read-iops:通过每秒读 IO 次数来限制指定设备的读速度。

--device-write-bps 设备bytes per second以是 kbmb 或者 gb

--device-write-iops:通过每秒写 IO 次数来限制指定设备的写速度。

--blkio-weight:容器默认磁盘 IO 的加权值,有效值范围为 10-1000

--blkio-weight-device 针对特定设备的 IO 加权控制。其格式为 DEVICE_NAME:WEIGHT

 

磁盘 IO 配额控制示例

blkio-weight

使用下面的命令创建两个–blkio-weight 值不同的容器: 在容器中同时执行下面的 dd 命令,进行测试

[root@localhost ~]# docker  run   -it --rm  --name duyuheng --blkio-weight 100 docker.io/centos:latest
[root@46925d4a8778 /]# time dd if=/dev/zero  of=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

 

[root@localhost ~]# docker  run  -it --rm  --rm --name duyuheng1 --blkio-weight 1000 docker.io/centos:latest
[root@761aadd7e27a /]# time dd if=/dev/zero  of=test.out bs=1M count=1024 oflag=direct

1024+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 指令发到硬盘