Docker Cgroup资源配置

一.简介

  • CGroup 是 Control Groups 的缩写,是 Linux 内核提供的一种可以限制、记录、隔离进程组 (process groups) 所使用的物力资源 (如 cpu memory i/o 等等) 的机制。2007 年进入 Linux 2.6.24 内核,CGroups 不是全新创造的,它将进程管理从 cpuset 中剥离出来,作者是 Google 的 Paul Menage。CGroups 也是 LXC 为实现虚拟化所使用的资源管理手段。
  • Cgroups最初的目标是为资源管理提供的一个统一的框架,既整合现有的cpuset等子系统,也为未来开发新的子系统提供接口。现在的cgroups适用于多种应用场景,从单个进程的资源控制,到实现操作系统层次的虚拟化(OS Level Virtualization)。

二.Cgroup 功能及组成

  • CGroup 是将任意进程进行分组化管理的 Linux 内核功能。CGroup 本身是提供将进程进行分组化管理的功能和接口的基础结构,I/O 或内存的分配控制等具体的资源管理功能是通过这个功能来实现的。这些具体的资源管理功能称为 CGroup 子系统或控制器。CGroup 子系统有控制内存的 Memory 控制器、控制进程调度的 CPU 控制器等。运行中的内核可以使用的 Cgroup 子系统由/proc/cgroup 来确认。

  • CGroup 提供了一个 CGroup 虚拟文件系统,作为进行分组管理和各子系统设置的用户接口。要使用 CGroup,必须挂载 CGroup 文件系统。这时通过挂载选项指定使用哪个子系统。

提供的功能 作用
限制进程组可以使用的资源数量(Resource limiting ) 如:memory子系统可以为进程组设定一个memory使用上限,一旦进程组使用的内存达到限额再申请内存,就会出发OOM(out of memory)。
进程组的优先级控制(Prioritization ) 如:可以使用cpu子系统为某个进程组分配特定cpu share。
记录进程组使用的资源数量(Accounting ) 如:可以使用cpuacct子系统记录某个进程组使用的cpu时间
进程组隔离(Isolation) 如:使用ns子系统可以使不同的进程组使用不同的namespace,以达到隔离的目的,不同的进程组有各自的进程、网络、文件系统挂载空间。
进程组控制(Control) 如:使用freezer子系统可以将进程组挂起和恢复。

三.Cgroup子系统介绍

子系统 介绍
blkio 是块设备设定输入/输出限制,比如物理设备(磁盘,固态硬盘,USB 等等)
cpu 使用调度程序提供对 CPU 的 cgroup
cpuacct 自动生成 cgroup 中任务所使用的 CPU 报告。
cpuset 为 cgroup 中的任务分配独立 CPU(在多核系统)和内存节点。
devices 可允许或者拒绝 cgroup 中的任务访问设备。
freezer 挂起或者恢复 cgroup 中的任务。
memory 设定 cgroup 中任务使用的内存限制,并自动生成由那些任务使用的内存资源报告。
net_cls 使用等级识别符(classid)标记网络数据包,可允许 Linux 流量控制程序(tc)识别从具体 cgroup 中生成的数据包。
ns 名称空间子系统。

四.Cgroup相关概念及其关系

1.相关概念

  • 1.任务(task)。在cgroups中,任务就是系统的一个进程。
  • 2.控制族群(control group)。控制族群就是一组按照某种标准划分的进程。Cgroups中的资源控制都是以控制族群为单位实现。一个进程可以加入到某个控制族群,也从一个进程组迁移到另一个控制族群。一个进程组的进程可以使用cgroups以控制族群为单位分配的资源,同时受到cgroups以控制族群为单位设定的限制。
  • 3.层级(hierarchy)。控制族群可以组织成hierarchical的形式,既一颗控制族群树。控制族群树上的子节点控制族群是父节点控制族群的孩子,继承父控制族群的特定的属性。
  • 4.子系统(subsytem)。一个子系统就是一个资源控制器,比如cpu子系统就是控制cpu时间分配的一个控制器。子系统必须附加(attach)到一个层级上才能起作用,一个子系统附加到某个层级以后,这个层级上的所有控制族群都受到这个子系统的控制。

2.相互关系

  • 1.每次在系统中创建新层级时,该系统中的所有任务都是那个层级的默认 cgroup(我们称之为 root cgroup ,此cgroup在创建层级时自动创建,后面在该层级中创建的cgroup都是此cgroup的后代)的初始成员。
  • 2.一个子系统最多只能附加到一个层级。
  • 3.一个层级可以附加多个子系统
  • 4.一个任务可以是多个cgroup的成员,但是这些cgroup必须在不同的层级。
  • 5.系统中的进程(任务)创建子进程(任务)时,该子任务自动成为其父进程所在 cgroup 的成员。然后可根据需要将该子任务移动到不同的 cgroup 中,但开始时它总是继承其父任务的cgroup。

五.实验搭建

1.stress工具测试CPU和内存

使用dockerfile 创建一个基于Centos的stress工具镜像

cd /opt                                              #进入opt目录
mkdir stress                                         #创建stress目录
cd stress                                            #进入stress目录

vim Dockerfile                                       #创建Dockerfile文件
FROM centos:7                                        #基础镜像
MAINTAINER lmx                                       #描述信息,自定义
RUN yum install -y wget                              #下载wget工具(wget作用是支持网页端的下载)
RUN wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo  #通过wget从阿里云下载yum仓库的配置文件,一些扩展性的软件包可以使用了
RUN yum install -y stress                            #下载stress软件包,作用是可以指定多个线程去不停的做循环语句

docker build -t centos:stress                        #生成镜像
docker run -itd --cpu-shares 100 centos:stress       #创建容器,命令中的--cpu-shares参数值不能保证可以获得1个vcpu或者多个GHz的CPU资源,它仅是一个弹性的加权值。               

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

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

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

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

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

docker run -tid --name cpu512 --cpu-shares 512 centos:stress stress -c 10   #容器产生10个子函数进程

docker exec -it  64bca244b4fb bash                                          #进入容器使用top查看cpu使用情况

#再开启一个容器做比较
docker run -tid --name cpu1024 --cpu-shares 1024 centos:stress stress -c 10

docker exec -it 6c75bfc905e0 bash                                           #进容器使用top对比两个容器的%CPU,比例是1:2

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.CPU周期限制

  • Docker 提供了–cpu-period、–cpu-quota两个参数控制容器可以分配到的CPU时钟周期
  • –cpu-quota是用来指定在周期内,最大可以有多少时间用来跑这个容器。与–cpu-shares不同的是,这种配置是指定一个绝对值,容器对CPU资源的使用绝对不会超过配置的值。
  • cpu-period和cpu-quota的单位为微妙。cpu-period的最小值为1000微秒,最大值为1秒,默认值为0.1秒。
  • 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秒)。
docker run -tid --cpu-period 100000 --cpu-quota 200000 centos:stress   #创建容器,period是0.1秒,quota为0.2秒
docker exec -it a1e74331431e bash                                      #进入容器

cat /sys/fs/cgroup/cpu/cpu.cfs_period_us                               #查看period文件,为0.1秒
100000

cat /sys/fs/cgroup/cpu/cpu.cfs_quota_us                                #查看quota文件,为0.2秒
200000

在这里插入图片描述
在这里插入图片描述

3.CPU Core控制

  • 对多核CPU的服务器,Docker还可以控制容器运行使用哪些CPU内核,即使用–cpuset-cpus参数。
  • 这对具有多CPU的服务器尤其有用,可以对需要高性能计算的容器进行性能最优的配置。
docker run -tid --name cpu1 --cpuset-cpus 0-1 centos:stress   #执行此命令需要宿主机为双核,表示创建的容器只能用0、1两个内核。

最终生成的cgroup的CPU内核配置如下:
docker exec -it d708eb4f6f03 bash                             #进入容器

cat /sys/fs/cgroup/cpuset/cpuset.cpus
0-1

docker exec d708eb4f6f03 taskset -c -p 1                      #容器内部第一个进程号pid为1被绑定到指定CPU上运行

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.CPU配额控制参数的混合使用

  • 通过cpuset-cpus参数指定容器A使用CPU内核0,容器B只使用CPU内核1。

  • 在主机上只有这两个容器使用对应CPU内核的情况,它们各自占用全部的内核资源,cpu-shares没有明显效果。

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

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

##提前将宿主系统修改为4核心CPU##
docker run -tid --name cpu3 --cpuset-cpus 1 --cpu-shares 512 centos:stress stress -c 1   #创建容器
docker exec -it 8799a625c89c bash    #进入容器


docker run -tid --name cpu4 --cpuset-cpus 3 --cpu-shares 1024 centos:stress stress -c 1   #创建容器
top                                  #按1查看每个核心的占用
docker exec -it 75985e7e13d5 bash

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

在这里插入图片描述

5.内存限额

  • 与操作系统类似,容器可使用的内存包括两部分::物理内存和Swap。
  • Docker通过下面两组参数来控制容器内存的使用量。
docker run -it -m 200M --memory-swap=300M progrium/stress --vm 1 --vm-bytes 280M   #允许该容器最多使用200M的内存和300M的swap。

--vm 1: 启动1个内存工作线程。
--vm-bytes 280M: 每个线程分配280M内存。
-m或--memory: 设置内存的使用限额(软限额)
--memory-swap: 设置内存+swap的使用限额(硬限额)
默认情况下,容器可以使用主机上的所有空闲内存。与CPU的cgroups配置类似,Docker会自动为容器在目录/sys/fs/cgroup/memory/docker/<容器的完整长ID>中创建相应cgroup配置文件
如果让工作线程分配的内存超过300M,分配的内存超过限额,stress线程报错,容器退出。

docker run -it -m 200M --memory-swap=300M progrium/stress --vm 1 --vm-bytes 310M

在这里插入图片描述
在这里插入图片描述

6.Block IO 的限制

  • 默认情况下,所有容器能平等地读写磁盘,可以通过设置–blkio-weight参数来改变容器block IO的优先级。
  • –blkio-weight与–cpu-shares类似,设置的是相对权重值,默认为500。
docker run -it --name container_A --blkio-weight 600 centos:stress
cat /sys/fs/cgroup/blkio/blkio.weight

docker run -it --name container_B --blkio-weight 300 centos:stress
cat /sys/fs/cgroup/blkio/blkio.weight          

在这里插入图片描述
在这里插入图片描述

7.bps和iops的限制

  • bps 是byte per second, 每秒读写的数据量。
  • iops 是io per second, 每秒 IO 的次数。
参数 作用
–device-read-bps 限制读某个设备的bps
–device-write-bps 限制写某个设备的bps
–device-read-iops 限制读某个设备的iops
–device-write-iops 限制写某个设备的iops
docker run -it --device-write-bps /dev/sda:8MB centos:stress
dd if=/dev/zero of=test bs=1M count=1024 oflag=direct   #查看,可以按ctrI+c中断查看

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

在这里插入图片描述

docker run -it centos:stress
dd if=/dev/zero of=test bs=1M count=1024 oflag=direct

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/LI_MINGXUAN/article/details/115323915