1.环境准备

1.1安装20.04版本的ubuntu并安装docker

上一篇文章中我安装的是ubuntu最新版本21.10,在测试cgroup的时候会报错,没找到合适的解决方案,就换了个低版本的ubuntu。

在下方链接中可以找到

​https://app.vagrantup.com/ubuntu​

mkdir docker&&cd docker

~/Desktop/docker  vagrant init ubuntu/focal64
A `Vagrantfile` has been placed in this directory. You are now
ready to `vagrant up` your first virtual environment! Please read
the comments in the Vagrantfile as well as documentation on
`vagrantup.com` for more information on using Vagrant.

启动虚拟机
~/Desktop/docker  vagrant up
进入虚拟机
~/Desktop/docker  vagrant ssh
安装docker
vagrant@ubuntu-focal:~$ curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun
启动docker
vagrant@ubuntu-focal:~$ sudo service docker start

2.Cgroup介绍与实践

2.1cgroup介绍

Cgroups (Control Groups)是 Linux 下用于对一个或一组进程进行资源控制和监控的机制;

Cgroup可以对诸如 CPU 使用时间、内存、磁盘 I/O 等进程所需的资源进行限制;

2.2cgroup可以对哪些资源进行限制

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

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

cpuacct: 产生 cgroup 任务的 CPU 资源报告

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

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

freezer: 暂停和恢复 cgroup 任务

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

net_cls: 标记每个网络包以供 cgroup 方便使用

ns: 名称空间子系统

pid: 进程标识子系统

ubuntu21.10版本看不到该结果,不知道怎么解决。
root@ubuntu-focal:/sys/fs/cgroup# mount -t cgroup
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,name=systemd)
cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,net_cls,net_prio)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)
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/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)
cgroup on /sys/fs/cgroup/rdma type cgroup (rw,nosuid,nodev,noexec,relatime,rdma)
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)

还可以直接到/sys/fs/cgroup查看
root@ubuntu-focal:/sys/fs/cgroup# ls -l
total 0
dr-xr-xr-x 5 root root 0 Jan 23 01:31 blkio
lrwxrwxrwx 1 root root 11 Jan 23 01:31 cpu -> cpu,cpuacct
dr-xr-xr-x 6 root root 0 Jan 23 01:31 cpu,cpuacct
lrwxrwxrwx 1 root root 11 Jan 23 01:31 cpuacct -> cpu,cpuacct
dr-xr-xr-x 2 root root 0 Jan 23 01:31 cpuset
dr-xr-xr-x 5 root root 0 Jan 23 01:31 devices
dr-xr-xr-x 3 root root 0 Jan 23 01:31 freezer
dr-xr-xr-x 2 root root 0 Jan 23 01:31 hugetlb
dr-xr-xr-x 5 root root 0 Jan 23 01:31 memory
lrwxrwxrwx 1 root root 16 Jan 23 01:31 net_cls -> net_cls,net_prio
dr-xr-xr-x 2 root root 0 Jan 23 01:31 net_cls,net_prio
lrwxrwxrwx 1 root root 16 Jan 23 01:31 net_prio -> net_cls,net_prio
dr-xr-xr-x 2 root root 0 Jan 23 01:31 perf_event
dr-xr-xr-x 5 root root 0 Jan 23 01:31 pids
dr-xr-xr-x 2 root root 0 Jan 23 01:31 rdma
dr-xr-xr-x 5 root root 0 Jan 23 01:31 systemd
dr-xr-xr-x 5 root root 0 Jan 23 01:31 unified

2.3对cpu限制的案例

查看cpu限制下有哪些限制项

cpu.shares: 可出让的能获得 CPU 使用时间的相对值。

cpu.cfs_period_us:cfs_period_us 用来配置时间周期长度,单位为 us(微秒)。

cpu.cfs_quota_us:cfs_quota_us 用来配置当前 Cgroup 在 cfs_period_us 时间内最多能使用的 CPU 时间数,单位为 us(微秒)。

cpu.stat : Cgroup 内的进程使用的 CPU 时间统计。

nr_periods : 经过 cpu.cfs_period_us 的时间周期数量。

nr_throttled : 在经过的周期内,有多少次因为进程在指定的时间周期内用光了配额时间而受到限制。

throttled_time : Cgroup 中的进程被限制使用 CPU 的总用时,单位是 ns(纳秒)。

root@ubuntu-focal:/sys/fs/cgroup/cpu# pwd
/sys/fs/cgroup/cpu
root@ubuntu-focal:/sys/fs/cgroup/cpu# ls -l
total 0
-rw-r--r-- 1 root root 0 Jan 23 01:48 cgroup.clone_children
-rw-r--r-- 1 root root 0 Jan 23 01:48 cgroup.procs
-r--r--r-- 1 root root 0 Jan 23 01:48 cgroup.sane_behavior
drwxr-xr-x 2 root root 0 Jan 23 01:55 container
-rw-r--r-- 1 root root 0 Jan 23 01:48 cpu.cfs_period_us
-rw-r--r-- 1 root root 0 Jan 23 01:48 cpu.cfs_quota_us
-rw-r--r-- 1 root root 0 Jan 23 01:48 cpu.shares
-r--r--r-- 1 root root 0 Jan 23 01:48 cpu.stat
-r--r--r-- 1 root root 0 Jan 23 01:48 cpuacct.stat
-rw-r--r-- 1 root root 0 Jan 23 01:48 cpuacct.usage
-r--r--r-- 1 root root 0 Jan 23 01:48 cpuacct.usage_all
-r--r--r-- 1 root root 0 Jan 23 01:48 cpuacct.usage_percpu
-r--r--r-- 1 root root 0 Jan 23 01:48 cpuacct.usage_percpu_sys
-r--r--r-- 1 root root 0 Jan 23 01:48 cpuacct.usage_percpu_user
-r--r--r-- 1 root root 0 Jan 23 01:48 cpuacct.usage_sys
-r--r--r-- 1 root root 0 Jan 23 01:48 cpuacct.usage_user
drwxr-xr-x 2 root root 0 Jan 23 01:48 init.scope
-rw-r--r-- 1 root root 0 Jan 23 01:48 notify_on_release
-rw-r--r-- 1 root root 0 Jan 23 01:48 release_agent
drwxr-xr-x 91 root root 0 Jan 23 01:46 system.slice
-rw-r--r-- 1 root root 0 Jan 23 01:48 tasks
drwxr-xr-x 2 root root 0 Jan 23 01:48 user.slice

下面结合cpu.cfs_period_us 和 cpu.cfs_quota_us做一次实验。

这两个参数需要组合使用,可以用来限制进程在长度为 cfs_period 的一段时间内,只能被分配到总量为 cfs_quota 的 CPU 时间

2.3.1在cpu子系统下新建一个目录

会自动在该目录下生成一些文件

root@ubuntu-focal:/sys/fs/cgroup/cpu#mkdir container
root@ubuntu-focal:/sys/fs/cgroup/cpu# cd container/
root@ubuntu-focal:/sys/fs/cgroup/cpu/container# ls -l
total 0
-rw-r--r-- 1 root root 0 Jan 23 01:55 cgroup.clone_children
-rw-r--r-- 1 root root 0 Jan 23 01:55 cgroup.procs
-rw-r--r-- 1 root root 0 Jan 23 01:55 cpu.cfs_period_us
-rw-r--r-- 1 root root 0 Jan 23 01:55 cpu.cfs_quota_us
-rw-r--r-- 1 root root 0 Jan 23 01:55 cpu.shares
-r--r--r-- 1 root root 0 Jan 23 01:55 cpu.stat
-rw-r--r-- 1 root root 0 Jan 23 01:55 cpu.uclamp.max
-rw-r--r-- 1 root root 0 Jan 23 01:55 cpu.uclamp.min
-r--r--r-- 1 root root 0 Jan 23 01:55 cpuacct.stat
-rw-r--r-- 1 root root 0 Jan 23 01:55 cpuacct.usage
-r--r--r-- 1 root root 0 Jan 23 01:55 cpuacct.usage_all
-r--r--r-- 1 root root 0 Jan 23 01:55 cpuacct.usage_percpu
-r--r--r-- 1 root root 0 Jan 23 01:55 cpuacct.usage_percpu_sys
-r--r--r-- 1 root root 0 Jan 23 01:55 cpuacct.usage_percpu_user
-r--r--r-- 1 root root 0 Jan 23 01:55 cpuacct.usage_sys
-r--r--r-- 1 root root 0 Jan 23 01:55 cpuacct.usage_user
-rw-r--r-- 1 root root 0 Jan 23 01:55 notify_on_release
-rw-r--r-- 1 root root 0 Jan 23 01:55 tasks
root@ubuntu-focal:/sys/fs/cgroup/cpu/container#

查看默认配额

默认是100毫秒
root@ubuntu-focal:/sys/fs/cgroup/cpu/container# cat cpu.cfs_period_us
100000
默认cpu使用没有限制
root@ubuntu-focal:/sys/fs/cgroup/cpu/container# cat cpu.cfs_quota_us
-1

2.3.2在后台运行一个占用cpu较高的脚本

root@ubuntu-focal:/sys/fs/cgroup/cpu/container#  while : ; do : ; done &
[1] 8979

top查看cpu使用率

由于我的虚拟机有两个cpu,这里看到cpu1使用率为100%

docker-cgroup资源限制_docker

2.3.3对上面进行进行限制

把上面进程ID写入task文件中

root@ubuntu-focal:/sys/fs/cgroup/cpu/container# cat tasks
root@ubuntu-focal:/sys/fs/cgroup/cpu/container# echo 8979 > /sys/fs/cgroup/cpu/container/tasks
root@ubuntu-focal:/sys/fs/cgroup/cpu/container# cat tasks
8979

向 container 组里的 cfs_quota 文件写入 20 ms(20000 us)

root@ubuntu-focal:/sys/fs/cgroup/cpu/container# echo 20000 > /sys/fs/cgroup/cpu/container/cpu.cfs_quota_us
root@ubuntu-focal:/sys/fs/cgroup/cpu/container# cat cpu.cfs_quota_us
20000

2.3.4查看当前cpu使用率

为20/100 = 20%

docker-cgroup资源限制_ubuntu_02

进城杀死后,进程就不在tasks文件中了

root@ubuntu-focal:/sys/fs/cgroup/cpu/container# kill 8979
root@ubuntu-focal:/sys/fs/cgroup/cpu/container# cat tasks
root@ubuntu-focal:/sys/fs/cgroup/cpu/container#

2.3.5运行一个资源限制的容器

创建一个容器

root@ubuntu-focal:/sys/fs/cgroup/cpu/container# docker run -it --cpu-period=100000 --cpu-quota=20000 ubuntu /bin/bash
Unable to find image 'ubuntu:latest' locally
latest: Pulling from library/ubuntu
ea362f368469: Pull complete
Digest: sha256:b5a61709a9a44284d88fb12e5c48db0409cfad5b69d4ff8224077c57302df9cf
Status: Downloaded newer image for ubuntu:latest
root@ca16aac7f741:/#

另一个终端查看容器ID

root@ubuntu-focal:~# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ca16aac7f741 ubuntu "/bin/bash" 47 seconds ago Up 45 seconds interesting_bardeen

查看容器的cgroup cpu配置

root@ubuntu-focal:~# cd /sys/fs/cgroup/cpu/docker/ca16aac7f741a105cfb63f5e226e7261c4b4247d481be743badbb9a3964bbdf0/
root@ubuntu-focal:/sys/fs/cgroup/cpu/docker/ca16aac7f741a105cfb63f5e226e7261c4b4247d481be743badbb9a3964bbdf0# ls -l
total 0
-rw-r--r-- 1 root root 0 Jan 23 03:17 cgroup.clone_children
-rw-r--r-- 1 root root 0 Jan 23 03:15 cgroup.procs
-rw-r--r-- 1 root root 0 Jan 23 03:17 cpu.cfs_period_us
-rw-r--r-- 1 root root 0 Jan 23 03:17 cpu.cfs_quota_us
-rw-r--r-- 1 root root 0 Jan 23 03:17 cpu.shares
-r--r--r-- 1 root root 0 Jan 23 03:17 cpu.stat
-rw-r--r-- 1 root root 0 Jan 23 03:17 cpu.uclamp.max
-rw-r--r-- 1 root root 0 Jan 23 03:17 cpu.uclamp.min
-r--r--r-- 1 root root 0 Jan 23 03:17 cpuacct.stat
-rw-r--r-- 1 root root 0 Jan 23 03:17 cpuacct.usage
-r--r--r-- 1 root root 0 Jan 23 03:17 cpuacct.usage_all
-r--r--r-- 1 root root 0 Jan 23 03:17 cpuacct.usage_percpu
-r--r--r-- 1 root root 0 Jan 23 03:17 cpuacct.usage_percpu_sys
-r--r--r-- 1 root root 0 Jan 23 03:17 cpuacct.usage_percpu_user
-r--r--r-- 1 root root 0 Jan 23 03:17 cpuacct.usage_sys
-r--r--r-- 1 root root 0 Jan 23 03:17 cpuacct.usage_user
-rw-r--r-- 1 root root 0 Jan 23 03:17 notify_on_release
-rw-r--r-- 1 root root 0 Jan 23 03:17 tasks
查看进程
root@ubuntu-focal:/sys/fs/cgroup/cpu/docker/ca16aac7f741a105cfb63f5e226e7261c4b4247d481be743badbb9a3964bbdf0# cat tasks
9972
root@ubuntu-focal:/sys/fs/cgroup/cpu/docker/ca16aac7f741a105cfb63f5e226e7261c4b4247d481be743badbb9a3964bbdf0# docker inspect ca16aac7f741 --format "{{ .State.Pid }}"
9972

20/100 = 20%
这就意味着这个 Docker 容器,只能使用到 20% 的 CPU 带宽
root@ubuntu-focal:/sys/fs/cgroup/cpu/docker/ca16aac7f741a105cfb63f5e226e7261c4b4247d481be743badbb9a3964bbdf0# cat cpu.cfs_period_us
100000
root@ubuntu-focal:/sys/fs/cgroup/cpu/docker/ca16aac7f741a105cfb63f5e226e7261c4b4247d481be743badbb9a3964bbdf0# cat cpu.cfs_quota_us
20000

3.cgroup限制存在的问题

在容器中执行top命令就会发现,它显示的信息和宿主机的信息一样。

​造成这个问题的原因是:/proc文件系统并不知道用户通过cgroup为容器做了什么资源限制,即:/proc文件系统不了解cgroup限制的存在。

容器中执行top

docker-cgroup资源限制_lxcfs_03

宿主机上执行top

docker-cgroup资源限制_lxcfs_04

3.1带来的问题

如果我们pod中的java程序不设置正确的jvm参数,那么就会导致OOM

但是对于一些app,它往往会自动检测当前环境的最大资源数量,然后根据这个数据来合理分配资源。问题就出在这上面,当我们给容器限制之后,它在容器内能检测到的依然是host相关的资源信息。

例如host有16G内存,限制一个容器最多使用2G,在容器里面通过/proc/meminfo看依然是16G内存。这就导致往往app会分配超过2G的内存从而被cgroup杀掉。

LXCFS的出现就是为了解决这个问题,让容器正确的意识到自己被限制的资源。

3.2lxcfs的介绍可以看下面的文章

​https://zhuanlan.zhihu.com/p/101059102​