这里主要简介什么是Cgroup,使用场景以及其原理和实践。
一、什么是Cgroup,使用场景?
容器本质上是进程,既然是进程就会消耗掉系统资源,比如:CPU、内存、磁盘、网络带宽等,如果不加以限制,容器在某些情况下就会无限制地吃掉宿主机的系统资源,显然这不是我们期望发生的,另外当我们的环境中运行了很多容器,且系统资源一定的情况下,我们有优先保证主要容器应用的需求,如何既能够解决此问题同时又能够满足我们的需求呢?答案就是:Linux Cgroup(全程Linux Control Group),在前面的文章中,介绍了namespace为容器这类进程提供了隔离,而Cgroup可以为容器这类进程提供资源使用上限,两者黄金搭档,共同为容器应用保驾护航。
二、Cgroup的原理和实践
CPU的周期控制
Cgroup可以为容器进程使用的CPU、内存、磁盘、网络带宽资源进行限制,具体是如何实现的呢?接下来我们一起来实操下,在 Linux 中,Cgroups 给用户暴露出来的操作接口是文件系统,即它以文件和目录的方式组织在操作系统的 /sys/fs/cgroup 这个路径下,我们先去此目录查看下
[root@k8s-master /]# cd sys/fs/cgroup/ [root@k8s-master cgroup]# ls blkio cpuacct cpuset freezer memory net_cls,net_prio perf_event rdma cpu cpu,cpuacct devices hugetlb net_cls net_prio pids systemd
可以看到在cgroup的这个目录下存在很多子目录,这些都是cgroup可以限制地资源种类,我们在进一步进入到CPU的子目录查看下,里面有限制资源种类的详细的限制地指标,比如
1、cpu.cfs_period_us:指定容器对CPU的使用多长时间重新做一次分配
2、cpu.cfs_quota_us:指在cpu.cfs_period_us周期内给分配多少时间给容器
这两个指标需要一起配合使用来实现CPU的周期控制,我们先手动模拟容器创建的时候,如何完成利用cgroup来实现资源限制,以CPU周期控制为例子,先在/sys/fs/cgroup/cpu目录下创建1个container_
test的目录,如下所示我已经创建好(红色字体)。
[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0); “复制代码”)
[root@k8s-master cgroup]# cd cpu [root@k8s-master cpu]# ls cgroup.clone_children cpuacct.usage_all cpu.cfs_period_us docker cgroup.procs cpuacct.usage_percpu cpu.cfs_quota_us kubepods cgroup.sane_behavior cpuacct.usage_percpu_sys cpu.rt_period_us notify_on_release container_test cpuacct.usage_percpu_user cpu.rt_runtime_us release_agent cpuacct.stat cpuacct.usage_sys cpu.shares system.slice cpuacct.usage cpuacct.usage_user cpu.stat tasks
[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0); “复制代码”)
然后进入到此目录下,ls查看下,这里出现了一个神奇的形象,此目录下自动生成了很多CPU子系统控制的指标,这些指标我们并未进行新增,也就是说在/sys/fs/cgroup/cpu目录下会给新建的目默认配置CPU子系统资源限制的指标
[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0); “复制代码”)
[root@k8s-master cpu]# cd container_test/ [root@k8s-master container_test]# ls cgroup.clone_children cpuacct.usage_percpu cpu.cfs_period_us cpu.stat cgroup.procs cpuacct.usage_percpu_sys cpu.cfs_quota_us notify_on_release cpuacct.stat cpuacct.usage_percpu_user cpu.rt_period_us tasks cpuacct.usage cpuacct.usage_sys cpu.rt_runtime_us cpuacct.usage_all cpuacct.usage_user cpu.shares
[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0); “复制代码”)
这些指标如何作用呢?为了体现资源的使用情况,我们先写一个程序来模拟来吃掉系统资源的情况,然后再来查看指标
[root@k8s-master sh]# cat while.sh #!/bin/bash while : ; do : ; done &
[root@k8s-master sh]# sh while.sh
通过如上程序,写了一个while无限循环的shell脚本,默认情况下,这个程序之后的进程会占据掉系统所剩集群的所有资源,可通过top命令查看下
[root@k8s-master sh]# ps -ef |grep while root 14975 1 97 20:29 pts/1 00:02:48 sh while.sh
如上图所示,while循环的进程占据掉了96.3%的CPU资源,在实际的应用中若进程这样无限制的使用资源,将会给操作系统带来很大的负担,那么如何控制进程资源的使用呢?回到我们之前创建在container_test目录下
[root@k8s-master container_test]# cat cpu.cfs_quota_us -1 [root@k8s-master container_test]# cat cpu.cfs_period_us 100000
默认创建的目录下cfs_quota_us 若为-1,则表示还未启用quota,即还未实行资源限制,cfs_period_us默认为100000us=100ms=0.1s(秒),接下来我们向cpu.cfs_quota_us 输入30ms=30000us,cfs_period_us值维持不变还是为100ms,在前面关于这2个概念有介绍,cpu.cfs_quota_us表示的是cfs_period_us的周期内,分配30/100的时间,即30%,接下来验证下
[root@k8s-master container_test]# echo 30000 》 /sys/fs/cgroup/cpu/container_test/cpu.cfs_quota_us
[root@k8s-master container_test]# cat cpu.cfs_quota_us
30000
设置已完成,但是此时还不会立即生效,还需要将进程ID输入到资源限制地task里
[root@k8s-master container_test]# echo 14975 》 /sys/fs/cgroup/cpu/container_test/tasks
接下来我们在通过top查看下资源使用情况,如下图所示,可以看到CPU的资源使用上限由原来的96.3%已经降到29.9%了,表明此while进程的CPU的资源使用上限已经设置成功。
以上整个过程为手动设置模拟容器创建的过程中CPU份额控制的过程,实际上在容器创建的过程中,并不需要上面这般步骤,我们只需要在run容器的时候指定指标参数即可,如下所示
[root@k8s-master container_test]# docker run -it -d --cpu-period=100000 --cpu-quota=30000 nginx /bin/bash
上面的命令是后台守护进程的方式运行了1个nginx的容器,且指定CPU的每隔100000us=100ms做一次分配,且每次分配给容器的时间为30ms,可以看到这个分配和前面手动分配是一致的,值得注意的是这里需要加上-d来创建容器,若不加上的话会进入到终端交互界面,一旦提出终端交互界面后,容器这个进程也将会退出,而我们希望容器进程保持后台运行,因此需要加上-d,容器运行成功后,将会在docker目录下新建一个以容器ID命名的目录,这个目录和前面手动创建的目录以上,系统会默认配置资源限制的参数,我们可以如下看下:
[root@k8s-master container_test]# docker run -it -d --cpu-period=100000 --cpu-quota=30000 nginx /bin/bash 16f51f6780685be9c83b1684515005f30aed91916fdd6573b28eaf56be201e4a
[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0); “复制代码”)
[root@k8s-master docker]# ls 01a0fd62d2110e54b0c3635b2897e7c18e6b78f026fa57b4214d7662dd3b38ba cpuacct.usage_sys 16f51f6780685be9c83b1684515005f30aed91916fdd6573b28eaf56be201e4a cpuacct.usage_user cgroup.clone_children cpu.cfs_period_us cgroup.procs cpu.cfs_quota_us cpuacct.stat cpu.rt_period_us cpuacct.usage cpu.rt_runtime_us cpuacct.usage_all cpu.shares cpuacct.usage_percpu cpu.stat cpuacct.usage_percpu_sys notify_on_release cpuacct.usage_percpu_user tasks
[![复制代码](https://common.cnblogs.com/images/copycode.gif)](javascript:void(0); “复制代码”)
如上红色部分为docker目录下依据容器的名称默认创建的目录,我们进入到这个目录,然后输出下之前我们在创建的时候指定的cpu.cfs_quota_us和cfs_period_us值
[root@k8s-master 16f51f6780685be9c83b1684515005f30aed91916fdd6573b28eaf56be201e4a]# cat cpu.cfs_period_us 100000
[root@k8s-master 16f51f6780685be9c83b1684515005f30aed91916fdd6573b28eaf56be201e4a]# cat cpu.cfs_quota_us 30000
可以看到我们之前设置的值已经生效了,也就是说这个nginx的容器最多可以支持使用到30%左右的CPU带宽。
相类似的我们可以对容器获取CPU的资源的优先级进行设置,通过--cpu-share这个参数,其指定的值并非是给容器具体的份额,其实是个权重,在需要对容器资源进行限制时才会生效,权重大的,可以优先得到CPU的资源;另外还可以对使用的核数进行限制,针对多核的服务器,可以控制容器运行限定使用哪些CPU内核和内存节点,即使用-cpuset-cpus和-cpuset-mens参数,比如:我们可以指定创建的容器只能用0、1、2三核。
三、总结
本文以CPU中周期控制限制某进程的CPU资源使用为例子,介绍了其手动设置参数和容器自动设置参数,每新建1个容器,在/sys/fs/cgroup/cpu/docker目录下都会自动以容器的ID为名字创建1个目录,且在此目录下支持对CPU、内存、网络带宽、磁盘的资源使用进行限制,而其限制地处理与CPU的周期控制是类似的,这里就未做过多介绍