参考:https://infoq.cn/article/docker-kernel-knowledge-cgroups-resource-isolation
一、cgroups是什么?
cgroups 是 Linux 内核提供的一种机制,这种机制可以根据特定的行为,把一系列系统任务及其子任务整合(或分隔)到按资源划分等级的不同组内,从而为系统资源管理提供一个统一的框架。
通俗的来说,cgroups 可以限制、记录、隔离进程组所使用的物理资源(包括:CPU、memory、IO 等),为容器实现虚拟化提供了基本保证,是构建 Docker 等一系列虚拟化管理工具的基石。
二、 cgroups 的作用
实现 cgroups 的主要目的是为不同用户层面的资源管理,提供一个统一化的接口。从单个进程的资源控制到操作系统层面的虚拟化。Cgroups 提供了以下四大功能:
- 资源限制(Resource Limitation):cgroups 可以对进程组使用的资源总额进行限制。如设定应用运行时使用内存的上限,一旦超过这个配额就发出 OOM(Out of Memory)。
- 优先级分配(Prioritization):通过分配的 CPU 时间片数量及硬盘 IO 带宽大小,实际上就相当于控制了进程运行的优先级。
- 资源统计(Accounting): cgroups 可以统计系统的资源使用量,如 CPU 使用时长、内存用量等等,这个功能非常适用于计费。
- 进程控制(Control):cgroups 可以对进程组执行挂起、恢复等操作。
三、 术语表
- task(任务):cgroups 的术语中,task 就表示系统的一个进程。
- cgroup(控制组):cgroups 中的资源控制都以 cgroup 为单位实现。cgroup 表示按某种资源控制标准划分而成的任务组,包含一个或多个子系统。一个任务可以加入某个 cgroup,也可以从某个 cgroup 迁移到另外一个 cgroup。
- subsystem(子系统):cgroups 中的 subsystem 就是一个资源调度控制器(Resource Controller)。比如 CPU 子系统可以控制 CPU 时间分配,内存子系统可以限制 cgroup 内存使用量。
- hierarchy(层级树):hierarchy 由一系列 cgroup 以一个树状结构排列而成,每个 hierarchy 通过绑定对应的 subsystem 进行资源调度。hierarchy 中的 cgroup 节点可以包含零或多个子节点,子节点继承父节点的属性。整个系统可以有多个 hierarchy。
mount -t cgroup 可以用于查询系统中已经mount 的cgroup的文件系统,这里的t表示type
接下来做个小测试:
1.cd /sys/fs/cgroup/memory
2.mkdir x1
3.cd x1,可以发现,x1目录下自动生成了一系列文件,
4.echo 209715200 > memory.limit_in_bytes 209715200表示200MB
上图并没有使用memory限制。
上图使用了x1目录的memory,所以当超过200MB时,超过的部分会占用swap分区。
如果想要实现超过200MB时,进程直接被杀死,可以采用如下操作:
然后,我们可以在启动容器的时候限制内存和swap分区
如上图所示,当限制memory启动容器后,会在cgroup的memory的目录下生成了docker目录
进入docker目录,可以发现里有一长串字符的目录,这一长串目录就是刚才创建的容器ID,进入这个ID目录,查看memory的限制文件,可以发现,里面数值是209715200,表示200MB。
其次,swap限制文件的数值也跟创建容器时的数值相同,并且容器进程号也可以在tasks文件下查看到。
通过cgroup限制cpu
两个文件:
/sys/fs/cgroup/cpu/cpu.cfs_quota_us 配额,表示该cgroup限制占用的时间,默认为-1,表示不限制,如果设为50000,表示占用50000/100000=50%的CPU。
/sys/fs/cgroup/cpu/cpu.cfs_period_us CPU分配的周期,默认为100000
测试:
1.在/sys/fs/cgroup/cpu/下创建一个目录,mkdir xupt,进入这个目录后,会发现里面自动生成了一系列文件,也包括以上两个文件
2.将cpu.cfs_quota_us里面的内容改为20000,表示20%的CPU, echo 20000 > cpu.cfs_quota_us
3.dd if=/dev/zero of=/dev/null & 这时一个填满CPU的操作,这时,查看cpu占有率,使用top命令,可以看到cpu占有率为100%
4.接下来将这个CPU占有率达到100%的PID加入到/sys/fs/cgroup/cpu/xupt/tasks中,echo xxxx > tasks
5.再次查看cpu占有率,top ,可以发现,cpu占有率从100%降到了20%
容器就是一个进程,因此限制容器CPU的方法与以上操作相同,只不过都简化为了docker命令,例如,开启一个容器,限制其cpu占有率为20%:
docker run -it --name vm1 --cpu-quota=20000 ubuntu
限制写入磁盘速度
1.docker run -it --rm --device-write-bps /dev/sda:30MB ubuntu
--device-write-bps 限制写入磁盘速度的参数, /dev/sda 限制的设备, 30MB表示限制的具体数值
2.在docker命令交互界面:dd if=/dev/zero of=file bs=1M count=300 oflag=direct
oflag=direct 不经过缓存,内存,直接写入磁盘中
使用软件控制cgroup和proc
由于 Docker 自身的原因,在容器内执行诸如 free 、top等命令时,看到的却是宿主机的相关状态信息,给监控带来了困扰.
通过在宿主机安装 lxcfs 组件,增强 Docker 容器的隔离性,执行 free 命令时真正显示 -m 参数所设置的内存值
1.下载lxcfs的rpm包 lxcfs-2.0.5-3.el7.centos.x86_64.rpm
2.安装此rpm包时需要fuse-libs依赖包,因此用yum安装
yum install -y lxcfs-2.0.5-3.el7.centos.x86_64.rpm
3.安装完成后需要用
lxcfs /var/lib/lxcfs &
命令在/var/lib/lxcfs下生成proc和cgroup目录
4.测试:限制生成的容器内存为200MB,swap分区为200MB
docker run -it --name vm1 -m 200m -v /var/lib/lxcfs/proc/cpuinfo:/proc/cpuinfo \
-v /var/lib/lxcfs/proc/diskstats:/proc/diskstats \
-v /var/lib/lxcfs/proc/meminfo:/proc/meminfo \
-v /var/lib/lxcfs/proc/stat:/proc/stat \
-v /var/lib/lxcfs/proc/swaps:/proc/swaps \
-v /var/lib/lxcfs/proc/uptime:/proc/uptime \
ubuntu
进入容器的交互界面后运行free -m命令查看内存。