标签:aaa cut 手工 detail 控制器 which 进程组 shell cgroup
上一篇文章将到 Docker 容器使用 linux namespace 来隔离其运行环境,使得容器中的进程看起来就像爱一个独立环境中运行一样。但是,光有运行环境隔离还不够,因为这些进程还是可以不受限制地使用系统资源,比如网络、磁盘、CPU以及内存 等。为了让容器中的进程更加可控,Docker 使用 Linux cgroups 来限制容器中的进程允许使用的系统资源。
Linux Cgroup 可???让???您???为???系???统???中???所???运???行???任???务???(进???程???)的???用???户???定???义???组???群???分???配???资???源??? — 比???如??? CPU 时???间???、???系???统???内???存???、???网???络???带???宽???或???者???这???些???资???源???的???组???合???。???您???可???以???监???控???您???配???置???的??? cgroup,拒???绝??? cgroup 访???问???某???些???资???源???,甚???至???在???运???行???的???系???统???中???动???态???配???置???您???的??? cgroup。所以,可以将 controll groups 理解为 controller (system resource) (for) (process)groups,也就是是说它以一组进程为目标进行系统资源分配和控制。
它主要提供了如下功能:
使???用??? cgroup,系???统???管???理???员???可???更???具???体???地???控???制???对???系???统???资???源???的???分???配???、???优???先???顺???序???、???拒???绝???、???管???理???和???监???控???。???可???更???好???地???根???据???任???务???和???用???户???分???配???硬???件???资???源???,提???高???总???体???效???率???。
在实践中,系统管理员一般会利用CGroup做下面这些事(有点像为某个虚拟机分配资源似的):
Linux 系统中,一切皆文件。Linux 也将 cgroups 实现成了文件系统,方便用户使用。在我的 Ubuntu 14.04 测试环境中:
root@devstack:/home/sammy# mount -t cgroup cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,relatime,cpuset) cgroup on /sys/fs/cgroup/cpu type cgroup (rw,relatime,cpu) systemd on /sys/fs/cgroup/systemd type cgroup (rw,noexec,nosuid,nodev,none,name=systemd)
root@devstack:/home/sammy# lssubsys -m cpuset /sys/fs/cgroup/cpuset cpu /sys/fs/cgroup/cpu cpuacct /sys/fs/cgroup/cpuacct memory /sys/fs/cgroup/memory devices /sys/fs/cgroup/devices freezer /sys/fs/cgroup/freezer blkio /sys/fs/cgroup/blkio perf_event /sys/fs/cgroup/perf_event hugetlb /sys/fs/cgroup/hugetlb
root@devstack:/home/sammy# ls /sys/fs/cgroup/ -l total 0 drwxr-xr-x 3 root root 0 Sep 18 21:46 blkio drwxr-xr-x 3 root root 0 Sep 18 21:46 cpu drwxr-xr-x 3 root root 0 Sep 18 21:46 cpuacct drwxr-xr-x 3 root root 0 Sep 18 21:46 cpuset drwxr-xr-x 3 root root 0 Sep 18 21:46 devices drwxr-xr-x 3 root root 0 Sep 18 21:46 freezer drwxr-xr-x 3 root root 0 Sep 18 21:46 hugetlb drwxr-xr-x 3 root root 0 Sep 18 21:46 memory drwxr-xr-x 3 root root 0 Sep 18 21:46 perf_event drwxr-xr-x 3 root root 0 Sep 18 21:46 systemd
我们看到 /sys/fs/cgroup 目录中有若干个子目录,我们可以认为这些都是受 cgroups 控制的资源以及这些资源的信息。
默认的话,在 Ubuntu 系统中,你可能看不到 net_cls 和 net_prio 目录,它们需要你手工做 mount:
root@devstack:/sys/fs/cgroup# modprobe cls_cgroup root@devstack:/sys/fs/cgroup# mkdir net_cls root@devstack:/sys/fs/cgroup# mount -t cgroup -o net_cls none net_cls root@devstack:/sys/fs/cgroup# modprobe netprio_cgroup root@devstack:/sys/fs/cgroup# mkdir net_prio root@devstack:/sys/fs/cgroup# mount -t cgroup -o net_prio none net_prio root@devstack:/sys/fs/cgroup# ls net_prio/cgroup.clone_children cgroup.procs net_prio.ifpriomap notify_on_release tasks cgroup.event_control cgroup.sane_behavior net_prio.prioidx release_agent root@devstack:/sys/fs/cgroup# ls net_cls/ cgroup.clone_children cgroup.event_control cgroup.procs cgroup.sane_behavior net_cls.classid notify_on_release release_agent tasks
写一段最简单的 C 程序:
int main(void) { int i = 0; for(;;) i++; return 0; }
编译,运行,发现它占用的 CPU 几乎到了 100%:
top - 22:43:02 up 1:14, 3 users, load average: 0.24, 0.06, 0.06 PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 2304 root 20 0 4188 356 276 R 99.6 0.0 0:11.77 hello
接下来我们做如下操作:
root@devstack:/home/sammy/c# mkdir /sys/fs/cgroup/cpu/hello root@devstack:/home/sammy/c# cd /sys/fs/cgroup/cpu/hello root@devstack:/sys/fs/cgroup/cpu/hello# ls cgroup.clone_children cgroup.procs cpu.cfs_quota_us cpu.stat tasks cgroup.event_control cpu.cfs_period_us cpu.shares notify_on_release root@devstack:/sys/fs/cgroup/cpu/hello# cat cpu.cfs_quota_us -1 root@devstack:/sys/fs/cgroup/cpu/hello# echo 20000 > cpu.cfs_quota_us root@devstack:/sys/fs/cgroup/cpu/hello# cat cpu.cfs_quota_us 20000 root@devstack:/sys/fs/cgroup/cpu/hello# echo 2428 > tasks
然后再来看看这个进程的 CPU 占用情况:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 2428 root 20 0 4188 356 276 R 19.9 0.0 0:46.03 hello
它占用的 CPU 几乎就是 20%,也就是我们预设的阈值。这说明我们通过上面的步骤,成功地将这个进程运行所占用的 CPU 资源限制在某个阈值之内了。
如果此时再启动另一个 hello 进程并将其 id 加入 tasks 文件,则两个进程会共享设定的 CPU 限制:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 2428 root 20 0 4188 356 276 R 10.0 0.0 285:39.54 hello 12526 root 20 0 4188 356 276 R 10.0 0.0 0:25.09 hello
同样地,我们针对它占用的内存做如下操作:
root@devstack:/sys/fs/cgroup/memory# mkdir hello root@devstack:/sys/fs/cgroup/memory# cd hello/ root@devstack:/sys/fs/cgroup/memory/hello# cat memory.limit_in_bytes 18446744073709551615 root@devstack:/sys/fs/cgroup/memory/hello# echo 64k > memory.limit_in_bytes root@devstack:/sys/fs/cgroup/memory/hello# echo 2428 > tasks root@devstack:/sys/fs/cgroup/memory/hello#
上面的步骤会把进程 2428 说占用的内存阈值设置为 64K。超过的话,它会被杀掉。
运行命令:
sudo dd if=/dev/sda1 of=/dev/null
通过 iotop 命令看 IO (此时磁盘在快速转动),此时其写速度为 242M/s:
TID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND 2555 be/4 root 242.60 M/s 0.00 B/s 0.00 % 61.66 % dd if=/dev/sda1 of=/dev/null
接着做下面的操作:
root@devstack:/home/sammy# mkdir /sys/fs/cgroup/blkio/io root@devstack:/home/sammy# cd /sys/fs/cgroup/blkio/io root@devstack:/sys/fs/cgroup/blkio/io# ls -l /dev/sda1 brw-rw---- 1 root disk 8, 1 Sep 18 21:46 /dev/sda1 root@devstack:/sys/fs/cgroup/blkio/io# echo ‘8:0 1048576‘ > /sys/fs/cgroup/blkio/io/blkio.throttle.read_bps_device root@devstack:/sys/fs/cgroup/blkio/io# echo 2725 > /sys/fs/cgroup/blkio/io/tasks
结果,这个进程的IO 速度就被限制在 1Mb/s 之内了:
TID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND 2555 be/4 root 990.44 K/s 0.00 B/s 0.00 % 96.29 % dd if=/dev/sda1 of=/dev/null
cgroups 的术语包括:
默认情况下,Docker 启动一个容器后,会在 /sys/fs/cgroup 目录下的各个资源目录下生成以容器 ID 为名字的目录(group),比如:
/sys/fs/cgroup/cpu/docker/03dd196f415276375f754d51ce29b418b170bd92d88c5e420d6901c32f93dc14
此时 cpu.cfs_quota_us 的内容为 -1,表示默认情况下并没有限制容器的 CPU 使用。在容器被 stopped 后,该目录被删除。
运行命令 docker run -d --name web41 --cpu-quota 25000 --cpu-period 100 --cpu-shares 30 training/webapp python app.py 启动一个新的容器,结果:
root@devstack:/sys/fs/cgroup/cpu/docker/06bd180cd340f8288c18e8f0e01ade66d066058dd053ef46161eb682ab69ec24# cat cpu.cfs_quota_us 25000 root@devstack:/sys/fs/cgroup/cpu/docker/06bd180cd340f8288c18e8f0e01ade66d066058dd053ef46161eb682ab69ec24# cat tasks 3704 root@devstack:/sys/fs/cgroup/cpu/docker/06bd180cd340f8288c18e8f0e01ade66d066058dd053ef46161eb682ab69ec24# cat cpu.cfs_period_us 2000
Docker 会将容器中的进程的 ID 加入到各个资源对应的 tasks 文件中。表示 Docker 也是以上面的机制来使用 cgroups 对容器的 CPU 使用进行限制。
相似地,可以通过 docker run 中 mem 相关的参数对容器的内存使用进行限制:
--cpuset-mems string MEMs in which to allow execution (0-3, 0,1) --kernel-memory string Kernel memory limit -m, --memory string Memory limit --memory-reservation string Memory soft limit --memory-swap string Swap limit equal to memory plus swap: ‘-1‘ to enable unlimited swap --memory-swappiness int Tune container memory swappiness (0 to 100) (default -1)
比如 docker run -d --name web42 --blkio-weight 100 --memory 10M --cpu-quota 25000 --cpu-period 2000 --cpu-shares 30 training/webapp python app.py:
root@devstack:/sys/fs/cgroup/memory/docker/ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410# cat memory.limit_in_bytes 10485760
root@devstack:/sys/fs/cgroup/blkio/docker/ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410# cat blkio.weight
100
目前 docker 已经几乎支持了所有的 cgroups 资源,可以限制容器对包括 network,device,cpu 和 memory 在内的资源的使用,比如:
root@devstack:/sys/fs/cgroup# find -iname ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410 ./net_prio/docker/ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410 ./net_cls/docker/ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410 ./systemd/docker/ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410 ./hugetlb/docker/ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410 ./perf_event/docker/ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410 ./blkio/docker/ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410 ./freezer/docker/ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410 ./devices/docker/ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410 ./memory/docker/ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410 ./cpuacct/docker/ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410 ./cpu/docker/ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410 ./cpuset/docker/ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410
net_cls 和 tc 一起使用可用于限制进程发出的网络包所使用的网络带宽。当使用 cgroups network controll net_cls 后,指定进程发出的所有网络包都会被加一个 tag,然后就可以使用其他工具比如 iptables 或者 traffic controller (TC)来根据网络包上的 tag 进行流量控制。关于 TC 的文档,网上很多,这里不再赘述,只是用一个简单的例子来加以说明。
关于 classid,它的格式是 0xAAAABBBB,其中,AAAA 是十六进制的主ID(major number),BBBB 是十六进制的次ID(minor number)。因此,0X10001 表示 10:1,而 0x00010001 表示 1:!。
(1)首先在host 的网卡 eth0 上做如下设置:
tc qdisc del dev eth0 root #删除已有的规则
tc qdisc add dev eth0 root handle 10: htb default 12
tc class add dev eth0 parent 10: classid 10:1 htb rate 1500kbit ceil 1500kbit burst 10k #限速
tc filter add dev eth0 protocol ip parent 10:0 prio 1 u32 match ip protocol 1 0xff flowid 10:1 #只处理 ping 参数的网络包
其结果是:
(2)启动容器
容器启动后,其 init 进程在host 上的 PID 就被加入到 tasks 文件中了:
root@devstack:/sys/fs/cgroup/net_cls/docker/ff8d9715b7e11a5a69446ff1e3fde3770078e32a7d8f7c1cb35d51c75768fe33# ps -ef | grep 10047 231072 10047 10013 1 07:08 ? 00:00:00 python app.py
设置 net_cls classid:
echo 0x100001 > net_cls.classid
再在容器启动一个 ping 进程,其 ID 也被加入到 tasks 文件中了。
(3)查看tc 情况: tc -s -d class show dev eth0
Every 2.0s: tc -s class ls dev eth0 Wed Sep 21 04:07:56 2016
class htb 10:1 root prio 0 rate 1500Kbit ceil 1500Kbit burst 10Kb cburst 1599b
Sent 17836 bytes 182 pkt (dropped 0, overlimits 0 requeues 0)
rate 0bit 0pps backlog 0b 0p requeues 0
lended: 182 borrowed: 0 giants: 0
tokens: 845161 ctokens: 125161
我们可以看到 tc 已经在处理 ping 进程产生的数据包了。再来看一下 net_cls 和 ts 合作的限速效果:
10488 bytes from 192.168.1.1: icmp_seq=35 ttl=63 time=12.7 ms 10488 bytes from 192.168.1.1: icmp_seq=36 ttl=63 time=15.2 ms 10488 bytes from 192.168.1.1: icmp_seq=37 ttl=63 time=4805 ms 10488 bytes from 192.168.1.1: icmp_seq=38 ttl=63 time=9543 ms
其中:
block IO: --blkio-weight value Block IO (relative weight), between 10 and 1000 --blkio-weight-device value Block IO weight (relative device weight) (default []) --cgroup-parent string Optional parent cgroup for the container CPU: --cpu-percent int CPU percent (Windows only) --cpu-period int Limit CPU CFS (Completely Fair Scheduler) period --cpu-quota int Limit CPU CFS (Completely Fair Scheduler) quota -c, --cpu-shares int CPU shares (relative weight) --cpuset-cpus string CPUs in which to allow execution (0-3, 0,1) --cpuset-mems string MEMs in which to allow execution (0-3, 0,1) Device: --device value Add a host device to the container (default []) --device-read-bps value Limit read rate (bytes per second) from a device (default []) --device-read-iops value Limit read rate (IO per second) from a device (default []) --device-write-bps value Limit write rate (bytes per second) to a device (default []) --device-write-iops value Limit write rate (IO per second) to a device (default []) Memory: --kernel-memory string Kernel memory limit -m, --memory string Memory limit --memory-reservation string Memory soft limit --memory-swap string Swap limit equal to memory plus swap: ‘-1‘ to enable unlimited swap --memory-swappiness int Tune container memory swappiness (0 to 100) (default -1)
参考链接:
上一篇文章将到 Docker 容器使用 linux namespace 来隔离其运行环境,使得容器中的进程看起来就像爱一个独立环境中运行一样。但是,光有运行环境隔离还不够,因为这些进程还是可以不受限制地使用系统资源,比如网络、磁盘、CPU以及内存 等。为了让容器中的进程更加可控,Docker 使用 Linux cgroups 来限制容器中的进程允许使用的系统资源。
Linux Cgroup 可???让???您???为???系???统???中???所???运???行???任???务???(进???程???)的???用???户???定???义???组???群???分???配???资???源??? — 比???如??? CPU 时???间???、???系???统???内???存???、???网???络???带???宽???或???者???这???些???资???源???的???组???合???。???您???可???以???监???控???您???配???置???的??? cgroup,拒???绝??? cgroup 访???问???某???些???资???源???,甚???至???在???运???行???的???系???统???中???动???态???配???置???您???的??? cgroup。所以,可以将 controll groups 理解为 controller (system resource) (for) (process)groups,也就是是说它以一组进程为目标进行系统资源分配和控制。
它主要提供了如下功能:
使???用??? cgroup,系???统???管???理???员???可???更???具???体???地???控???制???对???系???统???资???源???的???分???配???、???优???先???顺???序???、???拒???绝???、???管???理???和???监???控???。???可???更???好???地???根???据???任???务???和???用???户???分???配???硬???件???资???源???,提???高???总???体???效???率???。
在实践中,系统管理员一般会利用CGroup做下面这些事(有点像为某个虚拟机分配资源似的):
Linux 系统中,一切皆文件。Linux 也将 cgroups 实现成了文件系统,方便用户使用。在我的 Ubuntu 14.04 测试环境中:
root@devstack:/home/sammy# mount -t cgroup cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,relatime,cpuset) cgroup on /sys/fs/cgroup/cpu type cgroup (rw,relatime,cpu) systemd on /sys/fs/cgroup/systemd type cgroup (rw,noexec,nosuid,nodev,none,name=systemd)
root@devstack:/home/sammy# lssubsys -m cpuset /sys/fs/cgroup/cpuset cpu /sys/fs/cgroup/cpu cpuacct /sys/fs/cgroup/cpuacct memory /sys/fs/cgroup/memory devices /sys/fs/cgroup/devices freezer /sys/fs/cgroup/freezer blkio /sys/fs/cgroup/blkio perf_event /sys/fs/cgroup/perf_event hugetlb /sys/fs/cgroup/hugetlb
root@devstack:/home/sammy# ls /sys/fs/cgroup/ -l total 0 drwxr-xr-x 3 root root 0 Sep 18 21:46 blkio drwxr-xr-x 3 root root 0 Sep 18 21:46 cpu drwxr-xr-x 3 root root 0 Sep 18 21:46 cpuacct drwxr-xr-x 3 root root 0 Sep 18 21:46 cpuset drwxr-xr-x 3 root root 0 Sep 18 21:46 devices drwxr-xr-x 3 root root 0 Sep 18 21:46 freezer drwxr-xr-x 3 root root 0 Sep 18 21:46 hugetlb drwxr-xr-x 3 root root 0 Sep 18 21:46 memory drwxr-xr-x 3 root root 0 Sep 18 21:46 perf_event drwxr-xr-x 3 root root 0 Sep 18 21:46 systemd
我们看到 /sys/fs/cgroup 目录中有若干个子目录,我们可以认为这些都是受 cgroups 控制的资源以及这些资源的信息。
默认的话,在 Ubuntu 系统中,你可能看不到 net_cls 和 net_prio 目录,它们需要你手工做 mount:
root@devstack:/sys/fs/cgroup# modprobe cls_cgroup root@devstack:/sys/fs/cgroup# mkdir net_cls root@devstack:/sys/fs/cgroup# mount -t cgroup -o net_cls none net_cls root@devstack:/sys/fs/cgroup# modprobe netprio_cgroup root@devstack:/sys/fs/cgroup# mkdir net_prio root@devstack:/sys/fs/cgroup# mount -t cgroup -o net_prio none net_prio root@devstack:/sys/fs/cgroup# ls net_prio/cgroup.clone_children cgroup.procs net_prio.ifpriomap notify_on_release tasks cgroup.event_control cgroup.sane_behavior net_prio.prioidx release_agent root@devstack:/sys/fs/cgroup# ls net_cls/ cgroup.clone_children cgroup.event_control cgroup.procs cgroup.sane_behavior net_cls.classid notify_on_release release_agent tasks
写一段最简单的 C 程序:
int main(void) { int i = 0; for(;;) i++; return 0; }
编译,运行,发现它占用的 CPU 几乎到了 100%:
top - 22:43:02 up 1:14, 3 users, load average: 0.24, 0.06, 0.06 PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 2304 root 20 0 4188 356 276 R 99.6 0.0 0:11.77 hello
接下来我们做如下操作:
root@devstack:/home/sammy/c# mkdir /sys/fs/cgroup/cpu/hello root@devstack:/home/sammy/c# cd /sys/fs/cgroup/cpu/hello root@devstack:/sys/fs/cgroup/cpu/hello# ls cgroup.clone_children cgroup.procs cpu.cfs_quota_us cpu.stat tasks cgroup.event_control cpu.cfs_period_us cpu.shares notify_on_release root@devstack:/sys/fs/cgroup/cpu/hello# cat cpu.cfs_quota_us -1 root@devstack:/sys/fs/cgroup/cpu/hello# echo 20000 > cpu.cfs_quota_us root@devstack:/sys/fs/cgroup/cpu/hello# cat cpu.cfs_quota_us 20000 root@devstack:/sys/fs/cgroup/cpu/hello# echo 2428 > tasks
然后再来看看这个进程的 CPU 占用情况:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 2428 root 20 0 4188 356 276 R 19.9 0.0 0:46.03 hello
它占用的 CPU 几乎就是 20%,也就是我们预设的阈值。这说明我们通过上面的步骤,成功地将这个进程运行所占用的 CPU 资源限制在某个阈值之内了。
如果此时再启动另一个 hello 进程并将其 id 加入 tasks 文件,则两个进程会共享设定的 CPU 限制:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 2428 root 20 0 4188 356 276 R 10.0 0.0 285:39.54 hello 12526 root 20 0 4188 356 276 R 10.0 0.0 0:25.09 hello
同样地,我们针对它占用的内存做如下操作:
root@devstack:/sys/fs/cgroup/memory# mkdir hello root@devstack:/sys/fs/cgroup/memory# cd hello/ root@devstack:/sys/fs/cgroup/memory/hello# cat memory.limit_in_bytes 18446744073709551615 root@devstack:/sys/fs/cgroup/memory/hello# echo 64k > memory.limit_in_bytes root@devstack:/sys/fs/cgroup/memory/hello# echo 2428 > tasks root@devstack:/sys/fs/cgroup/memory/hello#
上面的步骤会把进程 2428 说占用的内存阈值设置为 64K。超过的话,它会被杀掉。
运行命令:
sudo dd if=/dev/sda1 of=/dev/null
通过 iotop 命令看 IO (此时磁盘在快速转动),此时其写速度为 242M/s:
TID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND 2555 be/4 root 242.60 M/s 0.00 B/s 0.00 % 61.66 % dd if=/dev/sda1 of=/dev/null
接着做下面的操作:
root@devstack:/home/sammy# mkdir /sys/fs/cgroup/blkio/io root@devstack:/home/sammy# cd /sys/fs/cgroup/blkio/io root@devstack:/sys/fs/cgroup/blkio/io# ls -l /dev/sda1 brw-rw---- 1 root disk 8, 1 Sep 18 21:46 /dev/sda1 root@devstack:/sys/fs/cgroup/blkio/io# echo ‘8:0 1048576‘ > /sys/fs/cgroup/blkio/io/blkio.throttle.read_bps_device root@devstack:/sys/fs/cgroup/blkio/io# echo 2725 > /sys/fs/cgroup/blkio/io/tasks
结果,这个进程的IO 速度就被限制在 1Mb/s 之内了:
TID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND 2555 be/4 root 990.44 K/s 0.00 B/s 0.00 % 96.29 % dd if=/dev/sda1 of=/dev/null
cgroups 的术语包括:
默认情况下,Docker 启动一个容器后,会在 /sys/fs/cgroup 目录下的各个资源目录下生成以容器 ID 为名字的目录(group),比如:
/sys/fs/cgroup/cpu/docker/03dd196f415276375f754d51ce29b418b170bd92d88c5e420d6901c32f93dc14
此时 cpu.cfs_quota_us 的内容为 -1,表示默认情况下并没有限制容器的 CPU 使用。在容器被 stopped 后,该目录被删除。
运行命令 docker run -d --name web41 --cpu-quota 25000 --cpu-period 100 --cpu-shares 30 training/webapp python app.py 启动一个新的容器,结果:
root@devstack:/sys/fs/cgroup/cpu/docker/06bd180cd340f8288c18e8f0e01ade66d066058dd053ef46161eb682ab69ec24# cat cpu.cfs_quota_us 25000 root@devstack:/sys/fs/cgroup/cpu/docker/06bd180cd340f8288c18e8f0e01ade66d066058dd053ef46161eb682ab69ec24# cat tasks 3704 root@devstack:/sys/fs/cgroup/cpu/docker/06bd180cd340f8288c18e8f0e01ade66d066058dd053ef46161eb682ab69ec24# cat cpu.cfs_period_us 2000
Docker 会将容器中的进程的 ID 加入到各个资源对应的 tasks 文件中。表示 Docker 也是以上面的机制来使用 cgroups 对容器的 CPU 使用进行限制。
相似地,可以通过 docker run 中 mem 相关的参数对容器的内存使用进行限制:
--cpuset-mems string MEMs in which to allow execution (0-3, 0,1) --kernel-memory string Kernel memory limit -m, --memory string Memory limit --memory-reservation string Memory soft limit --memory-swap string Swap limit equal to memory plus swap: ‘-1‘ to enable unlimited swap --memory-swappiness int Tune container memory swappiness (0 to 100) (default -1)
比如 docker run -d --name web42 --blkio-weight 100 --memory 10M --cpu-quota 25000 --cpu-period 2000 --cpu-shares 30 training/webapp python app.py:
root@devstack:/sys/fs/cgroup/memory/docker/ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410# cat memory.limit_in_bytes 10485760
root@devstack:/sys/fs/cgroup/blkio/docker/ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410# cat blkio.weight
100
目前 docker 已经几乎支持了所有的 cgroups 资源,可以限制容器对包括 network,device,cpu 和 memory 在内的资源的使用,比如:
root@devstack:/sys/fs/cgroup# find -iname ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410 ./net_prio/docker/ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410 ./net_cls/docker/ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410 ./systemd/docker/ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410 ./hugetlb/docker/ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410 ./perf_event/docker/ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410 ./blkio/docker/ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410 ./freezer/docker/ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410 ./devices/docker/ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410 ./memory/docker/ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410 ./cpuacct/docker/ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410 ./cpu/docker/ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410 ./cpuset/docker/ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410
net_cls 和 tc 一起使用可用于限制进程发出的网络包所使用的网络带宽。当使用 cgroups network controll net_cls 后,指定进程发出的所有网络包都会被加一个 tag,然后就可以使用其他工具比如 iptables 或者 traffic controller (TC)来根据网络包上的 tag 进行流量控制。关于 TC 的文档,网上很多,这里不再赘述,只是用一个简单的例子来加以说明。
关于 classid,它的格式是 0xAAAABBBB,其中,AAAA 是十六进制的主ID(major number),BBBB 是十六进制的次ID(minor number)。因此,0X10001 表示 10:1,而 0x00010001 表示 1:!。
(1)首先在host 的网卡 eth0 上做如下设置:
tc qdisc del dev eth0 root #删除已有的规则
tc qdisc add dev eth0 root handle 10: htb default 12
tc class add dev eth0 parent 10: classid 10:1 htb rate 1500kbit ceil 1500kbit burst 10k #限速
tc filter add dev eth0 protocol ip parent 10:0 prio 1 u32 match ip protocol 1 0xff flowid 10:1 #只处理 ping 参数的网络包
其结果是:
(2)启动容器
容器启动后,其 init 进程在host 上的 PID 就被加入到 tasks 文件中了:
root@devstack:/sys/fs/cgroup/net_cls/docker/ff8d9715b7e11a5a69446ff1e3fde3770078e32a7d8f7c1cb35d51c75768fe33# ps -ef | grep 10047 231072 10047 10013 1 07:08 ? 00:00:00 python app.py
设置 net_cls classid:
echo 0x100001 > net_cls.classid
再在容器启动一个 ping 进程,其 ID 也被加入到 tasks 文件中了。
(3)查看tc 情况: tc -s -d class show dev eth0
Every 2.0s: tc -s class ls dev eth0 Wed Sep 21 04:07:56 2016
class htb 10:1 root prio 0 rate 1500Kbit ceil 1500Kbit burst 10Kb cburst 1599b
Sent 17836 bytes 182 pkt (dropped 0, overlimits 0 requeues 0)
rate 0bit 0pps backlog 0b 0p requeues 0
lended: 182 borrowed: 0 giants: 0
tokens: 845161 ctokens: 125161
我们可以看到 tc 已经在处理 ping 进程产生的数据包了。再来看一下 net_cls 和 ts 合作的限速效果:
10488 bytes from 192.168.1.1: icmp_seq=35 ttl=63 time=12.7 ms 10488 bytes from 192.168.1.1: icmp_seq=36 ttl=63 time=15.2 ms 10488 bytes from 192.168.1.1: icmp_seq=37 ttl=63 time=4805 ms 10488 bytes from 192.168.1.1: icmp_seq=38 ttl=63 time=9543 ms
其中:
block IO: --blkio-weight value Block IO (relative weight), between 10 and 1000 --blkio-weight-device value Block IO weight (relative device weight) (default []) --cgroup-parent string Optional parent cgroup for the container CPU: --cpu-percent int CPU percent (Windows only) --cpu-period int Limit CPU CFS (Completely Fair Scheduler) period --cpu-quota int Limit CPU CFS (Completely Fair Scheduler) quota -c, --cpu-shares int CPU shares (relative weight) --cpuset-cpus string CPUs in which to allow execution (0-3, 0,1) --cpuset-mems string MEMs in which to allow execution (0-3, 0,1) Device: --device value Add a host device to the container (default []) --device-read-bps value Limit read rate (bytes per second) from a device (default []) --device-read-iops value Limit read rate (IO per second) from a device (default []) --device-write-bps value Limit write rate (bytes per second) to a device (default []) --device-write-iops value Limit write rate (IO per second) to a device (default []) Memory: --kernel-memory string Kernel memory limit -m, --memory string Memory limit --memory-reservation string Memory soft limit --memory-swap string Swap limit equal to memory plus swap: ‘-1‘ to enable unlimited swap --memory-swappiness int Tune container memory swappiness (0 to 100) (default -1)
参考链接:
理解Docker(4):Docker 容器使用 cgroups 限制资源使用
标签:aaa cut 手工 detail 控制器 which 进程组 shell cgroup
原文地址:http://www.cnblogs.com/mfc-itblog/p/6680632.html