社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  docker

Docker----Cgroup原理描述及应用实例操练

小爱人 • 5 年前 • 576 次点击  


前言

CGroup 是 Control Groups 的缩写,是 Linux 内核提供的一种可以限制、记录、隔离进程组 (process
groups) 所使用的物力资源 (如 cpu memory i/o 等等) 的机制。2007 年进入 Linux 2.6.24
内核,CGroups 不是全新创造的,它将进程管理从 cpuset 中剥离出来,作者是 Google 的 Paul
Menage。CGroups 也是 LXC 为实现虚拟化所使用的资源管理手段。

一:CGroup描述

1.1:CGroup 支持的文件种类

文件名 R/W 用途
Release_agent RW 删除分组时执行的命令,这个文件只存在于根分组
Notify_on_release RW 设置是否执行 release_agent。为 1 时执行
Tasks RW 属于分组的线程 TID 列表
Cgroup.procs R 属于分组的进程 PID 列表。仅包括多线程进程的线程 leader 的 TID,这点与 tasks 不同
Cgroup.event_control RW 监视状态变化和分组删除事件的配置文件

12:CGroup 层级图

mark

如图所示的 CGroup 层级关系显示,CPU 和 Memory 两个子系统有自己独立的层级系统,而又通过 Task Group 取得关联关系。

1.3:CGroup 特点

在 cgroups 中,任务就是系统的一个进程。

控制族群(control group)。控制族群就是一组按照某种标准划分的进程。Cgroups
中的资源控制都是以控制族群为单位实现。一个进程可以加入到某个控制族群,也从一个进程组迁移到另一个控制族群。一个进程组的进程可以使用
cgroups 以控制族群为单位分配的资源,同时受到 cgroups 以控制族群为单位设定的限制。

层级(hierarchy)。控制族群可以组织成 hierarchical
的形式,既一颗控制族群树。控制族群树上的子节点控制族群是父节点控制族群的孩子,继承父控制族群的特定的属性。

子系统(subsytem)。一个子系统就是一个资源控制器,比如 cpu 子系统就是控制 cpu
时间分配的一个控制器。子系统必须附加(attach)到一个层级上才能起作用,一个子系统附加到某个层级以后,这个层级上的所有控制族群都受到这个子系统的控制。

1.4:子系统的介绍

  • 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上的线程。:

1.5:CGroup 典型应用架构图

mark

二:使用stress工具压测CPU和内存

  • 使用Dockerfile来创建一个基于Centos的stress工具镜像
[root@localhost ~]# iptables -F
[root@localhost ~]# setenforce 0
[root@localhost ~]# mkdir /opt/stress

[root@localhost ~]# vim /opt/stress/Dockerfile

FROM centos:7
MAINTAINER shuai "shuai.@tom.com"
RUN yum install -y wget
RUN wget -O /etc/yum.repos.d/epel.


    
repo http://mirrors.aliyun.com/repo/epel-7.repo
RUN yum install -y stress
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 新建镜像
[root@localhost ~]# cd /opt/stress/

[root@localhost stress]# docker build -t centos:stress .
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3
  • 查看镜像
[root@localhost stress]# docker images
[root@localhost ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
centos              stress              0cc400af48ae        23 hours ago        426MB
centos              7                   7e6257c9f8d8        6 weeks ago         203MB
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5
  • 使用如下命令创建容器

命令中的–cpu–shares参数值不能保证可以获得个vcpu或者多少GHz的CPU资源,它仅是一个弹性的加权值

[root@localhost stress]# docker run -itd --cpu-shares 100 centos:stress

[root@localhost stress]# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
84fff47241b6        centos:stress       "/bin/bash"         38 seconds ago      Up 37 seconds                           compassionate_brahmagupta
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

默认情况下,Docker容器的CPU份额都是1024.单独一个容器的份额是没有意义的,只有在同时运行多个容器时,容器的CPU加权才能能体现出来。

例如:两个容器A、B的CPU权重份额分别是1000和500,在CPU进行时间分片分配的时候,容器A比B多一倍的机会获得CPU的时间片.

单分配的结果取决于当时主机和其他容器的运行状态,实际上也无法保证容器A一定能获得cpu时间片。比如容器A的进程一直是空闲的,那么容器B是可以获取比容器A更多的CPU时间片的,极端情况下,列如主机上只运行了一个容器,即使它的CPU份额只有50,它也独占整个主机的CPU资源。

比如,启动了两个容器及运行查看 CPU 使用百分比

[root@localhost stress]# docker run -itd --name cpu512 --cpu-shares 512 centos:stress stress -c 10      '//容器产生的十个函数子进程'

#进入容器使用top查看CPU使用情况
[root@localhost stress]# docker exec -it 23bbe8182b5c bash
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

如图所示
mark

2.再开一个容器做比较

[root@localhost ~]# docker run -tid --name cpu1024 --cpu-shares 1024 centos:stress stress -c 10

[root@localhost ~]# docker ps -a
[root@localhost ~]# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
605fc2d70557        centos:stress       "stress -c 10"      3 seconds ago       Up 2 seconds                            cpu1024
23bbe8182b5c        centos:stress       "stress -c 10"      5 minutes ago       Up 5 minutes                            cpu512

#进入容器查看top    1查看核心的负载
[root@localhost ~]# docker exec -it 605fc2d70557 bash   #入容器使用top对比两个容器的%CPU,比例是1:2
[root@605fc2d70557 /]# top   '//查看进程'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

如图
mark

三:CPU周期限制

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

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

例如:

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

[root@localhost stress]# docker run -itd --name cpushuai --cpu-period 100000 --cpu-quota 200000 centos:stress


[root@localhost stress]# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                            PORTS               NAMES
5faae11dd9d1        centos:stress       "/bin/bash"         5 seconds ago       Up 4 seconds                                          cpushuai
605fc2d70557        centos:stress       "stress -c 10"      51 minutes ago      Exited (137) About a minute ago                       cpu1024
23bbe8182b5c        centos:stress       


    
"stress -c 10"      56 minutes ago      Exited (137) About a minute ago     cpu512

#进入容器
[root@localhost stress]# docker exec -it 5faae11dd9d1 bash

[root@5faae11dd9d1 /]# cat /sys/fs/cgroup/cpu/cpu.cfs_period_us 
100000
[root@5faae11dd9d1 /]# cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us  
200000

#查看CPU
[root@5faae11dd9d1 cpu]# top
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

在这里插入图片描述

四:CPU Core 控制:

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

#创建容器
[root@localhost stress]# docker run -itd --name cpu02 --cpuset-cpus=0-2 centos:stress
//执行该命令(需要宿主机为四核),表示创建的容器只能使用012 三个内核。 不会影响其他核心来抢占资源

#查看容器列表
[root@localhost stress]# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                        PORTS               NAMES
8b65ddbb9c85        centos:stress       "/bin/bash"         52 seconds ago      Up 51 seconds                                     cpu02

#进入容器
[root@localhost stress]# docker exec -it 8b65ddbb9c85 bash

#查看核心
[root@8b65ddbb9c85 /]# cat /sys/fs/cgroup/cpuset/cpuset.cpus
0-2


    

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

如图
mark

  • 通过下面指令可以看到容器中进程与CPU内核的绑定关系,达到绑定CPU内核的目的
#容器内部的第一个进程号pid为1被绑定到指定CPU运行
[root@localhost stress]# docker exec 8b65ddbb9c85 taskset -c -p 1
pid 1's current affinity list: 0-2
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

如图
mark

  • 我们用stress进行压测
[root@localhost stress]# docker exec -it 8b65ddbb9c85 bash
[root@8b65ddbb9c85 /]# stress -c 10
stress: info: [47] dispatching hogs: 10 cpu, 0 io, 0 vm, 0 hdd
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3
  • 另外开一个终端查看top
    mark

五:CPU 配额控制参数的混合使用:

通过 cpuset-cpus 参数指定容器 A 使用 CPU 内核 0,容器B 只是用 CPU 内核1;在主机上只有这两个容器使用对应
CPU 内核的情况,它们各自占有全部的内核资源,cpu-shares 没有明显效果。cpuset-cpus、cpuset-mems
参数只在多核、多内存节点上的服务器上有效,并且必须与实际的物理配置匹配,否则也无法达到资源控制的目的。在系统具有多个 CPU
内核的情况下,需要通过 cpuset-cpus 参数为设置容器 CPU 内核才能方便地进行测试。

#新建容器cpu3 只使用cpu 1 权重为512
[root@localhost stress]# docker run -itd --name cpu3 --cpuset-cpus 1 --cpu-shares 512 centos:stress stress -c 1
25cffab0395c791d7467ac20433bb6c75b6e56ca6bf1df4c3e943e4eb3d63ef5

#查看容器列表
[root@localhost stress]# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                        PORTS               NAMES
25cffab0395c        centos:stress       "stress -c 1"       7 seconds ago       Up 6 seconds                                      cpu3

#进入容器
[root@localhost stress]# docker exec -it 25cffab0395c bash
[root


    
@25cffab0395c /]# top        '//查看进程 按1可以看到每个核心的占用情况'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

如图
mark

我们在创建一个容器做比较

#这次的权重为1024
[root@localhost ~]# docker run -itd --name cpu4 --cpuset-cpus 3 --cpu-shares 1024 centos:stress stress -c 1

[root@localhost ~]# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                        PORTS               NAMES
2259964f13bb        centos:stress       "stress -c 1"       6 seconds ago       Up 5 seconds                                      cpu4
25cffab0395c        centos:stress       "stress -c 1"       9 minutes ago       Up 9 minutes     

#进入容器查看进程
[root@localhost ~]# docker exec -it 2259964f13bb bash
[root@2259964f13bb /]# top
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

如图
mark

六:内存限额:

与操作系统类似,容器可使用的内存包括两部分:物理内存 和 Swap;

docker 通过下面两组参数来控制容器内存的使用量:

-m 或 --memory:设置内存的使用限额,例如 100M、1024M; –memory-swap:设置内存 +swap 的使用限额。 例如:执行如下命令允许该容器最多使用 200M的内存,300M 的swap:

[root@localhost stress]# docker run -it -m 200M --memory-swap=300M progrium/stress --vm 1 --vm-bytes 280M
Unable to find image 'progrium/stress:latest' locally

# --vm 1:启动1个内存工作线程;
   --vm-bytes 280M :每个线程分配280M内存;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

如果让工作线程分配的内存超过 300M,分配的内存超过限额,stress线程报错,容器退出:




    
[root@localhost stress]# docker run -it -m 200M --memory-swap=300M progrium/stress --vm 1 --vm-bytes 310M
  • 1
  • 1

如图
mark

七:Block IO 的限制:

默认情况下,所有容器能平等地读写磁盘,可以通过设置 --blkio-weight 参数来改变容器 block IO 的优先级。

–blkio-weight 与 --cpu-shares 类似,设置的是相对权重值,默认为500 在下面的例子中,容器 A
读写磁盘的带宽是容器 B 的两倍:

[root@localhost stress]# docker run -it --name container_A --blkio-weight 600 centos:stress
[root@9cae2ee0165a /]#  cat /sys/fs/cgroup/blkio/blkio.weight
600

[root@localhost stress]# docker run -it --name container_B --blkio-weight 300 centos:stress
[root@6ed938c0086b /]# cat /sys/fs/cgroup/blkio/blkio.weight
300
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

八:bps 和 iops 的限制:

(1)bps :是 byte per second,每秒读写的数据量;

(2)iops :是 io per second,每秒 IO 的次数;

(3)可以通过以下的参数来控制 bps 和 iops:

–device-read-bps:限制读某个设备的 bps; device-write-bps:限制写某个设备的 bps;
device-read-iops:限制读某个设备的 iops; device-write-iops:限制写某个设备的 iops。 例如:

  • 限制容器 写 /dev/sda 磁盘的速率为 5MB/s:
[root@localhost stress]# docker run -it --device-write-bps /dev/sda:5MB centos:stress 

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

[root@11993eca702e /]# dd if=/dev/zero of=test bs=1M count=1024 oflag=direct
                                     #ctrl+c中断
                                   
167+0 records out
175112192 bytes (175 MB) copied, 33.4011 s, 5.2 MB/


    
s

[root@11993eca702e /]# exit
exit
#结果表明限速为5M/s左右。

#为了对比,我们不限速测试,如下
[root@localhost stress]# docker run -it centos:stress
[root@7e98a3cbc23e /]# dd if=/dev/zero of=test bs=1M count=1024 oflag=direct
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 1.01742 s, 1.1 GB/s

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

如图
mark
是不是每天更加努力一点呢?

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/73789