Docker容器限制

对于Docker等大多数Linux容器来说,Cgroups技术是用来制造约束的主要手段。

Linux Cgroups

Linux Cgroups(Linux control groups)是Linux内核中用来进程设置资源限制的一个重要功能,其最主要的作用是限制一个进程组所能使用的资源上限,包括CPU、内存、磁盘、网络带宽等等。此外Cgroups还能对进程进行优先级设置、审计,以及将进程挂起和恢复等操作。

在Linux中,Cgroups向用户暴露出来的操作接口是文件系统,即它以文件和目录的方式组织在操作系统的/sys/fs/cgroup路径下。可以使用mount命令查看:

1
2
3
4
5
6
7
8
9
10
11
12
$ mount -t cgroup
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd)
cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,net_prio,net_cls)
cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,pids)
cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,hugetlb)
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,freezer)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,cpuacct,cpu)
cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,blkio)
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,perf_event)
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,memory)
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,cpuset)
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,seclabel,devices)

限制cpu资源的示例

可以看到在/sys/fs/cgroup下面有很多如cpuset、cpu、memory这样的子目录,也叫子系统,都是当前机器可以被限制的资源种类。在子系统对应的资源种类下,可以看到这类资源具体被限制的方法,以cpu为例:

1
2
3
$ ls /sys/fs/cgroup/cpu
cgroup.clone_children cgroup.procs cpuacct.stat cpuacct.usage_percpu cpu.cfs_quota_us cpu.rt_runtime_us cpu.stat release_agent tasks
cgroup.event_control cgroup.sane_behavior cpuacct.usage cpu.cfs_period_us cpu.rt_period_us cpu.shares notify_on_release system.slice user.slice

这些配置文件的使用方法是:需要在对应的子系统下面创建一个目录,比如:

1
2
3
4
5
$ cd /sys/fs/cgroup/cpu
$ mkdir container
$ ls container/
cgroup.clone_children cgroup.procs cpuacct.usage cpu.cfs_period_us cpu.rt_period_us cpu.shares notify_on_release
cgroup.event_control cpuacct.stat cpuacct.usage_percpu cpu.cfs_quota_us cpu.rt_runtime_us cpu.stat tasks

操作系统会在新创建的container目录下自动生成该子系统对应的资源限制文件,这个目录称为一个”控制组“。

通过后台执行一个死循环脚本为例,来演示如何对cpu资源进行限制:

1
2
$ while : ; do : ; done &
[1] 15525

使用top命令确认CPU资源是否被占满:

1
2
3
$ top
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
15525 root 20 0 115544 600 168 R 100.0 0.0 2:32.06 bash

接下来向container组里的cfs_quota文件写入20ms(20000us),意味着在每100ms的时间里,被该控制组限制的进程只能使用20ms的CPU时间,即该进程只能使用20%的CPU带宽,并把被限制的进程的PID写入container组里的tasks文件,以上配置就会生效:

1
2
3
4
5
$ echo 20000 > /sys/fs/cgroup/cpu/container/cpu.cfs_quota_us
$ echo 15525 > /sys/fs/cgroup/cpu/container/tasks
$ top
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
15525 root 20 0 115544 600 168 R 19.9 0.0 7:14.85 bash

可以看到CPU的使用率立刻降到了20%。

总结

除CPU子系统外,Cgroups的每一项子系统都有其独有的资源限制能力,比如blkio(为块设备设定I/O限制,一般用于磁盘等设备)、cpuset(为进程分配单独的CPU核和对应的内存节点)、memory(为进程设定内存使用限制)等。

Linux Cgroups简单而言就是一个子系统目录上加上一组资源限制文件的组合。对于Docker等Linux容器项目来说,它们只需要在每个子系统下面为每个容器创建一个控制组(即创建一个新目录),然后在启动容器进程之后,把这个进程的PID填写到对应的控制组的tasks文件中即可。至于在这些控制组下面的资源文件中填写什么值,就靠用户执行docker run时的参数指定:

1
2
3
4
5
$ docker run -it --cpu-period=100000 --cpu-quota=20000 ubuntu /bin/bash
$ cat /sys/fs/cgroup/cpu/docker/5d5c9f67d/cpu.cfs_period_us
100000
$ cat /sys/fs/cgroup/cpu/docker/5d5c9f67d/cpu.cfs_quota_us
20000
作者

chengzhy

发布于

2023-10-06

更新于

2023-10-06

许可协议

评论

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×