cgroups简介
Docker 通过 Cgroup 来控制容器使用的资源配额,包括 CPU、内存、磁盘三大方面, 基本覆盖了常见的资源配额和使用量控制。
Cgroup 是 ControlGroups 的缩写,是 Linux 内核提供的一种可以限制、记录、隔离进程组所使用的物理资源(如 CPU、内存、磁盘 IO 等等) 的机制,被 LXC、docker 等很多项目用于实现进程资源控制。Cgroup 本身是提供将进程进行分组化管理的功能和接口的基础结构,I/O 或内存的分配控制等具体的资源管理是通过该功能来实现的。
cgroups有四大功能
- 资源限制:可以对任务使用的资源总额进行限制
- 优先级分配:通过分配的cpu时间片数量以及磁盘IO带宽大小,实际上相当于控制了任务运行优先级。
- 资源统计:可以统计系统的资源使用量,如cpu时长,内存用量等
- 任务控制: cgroup可以对任务 执行挂起、恢复等操作
cpu时间切片
时间片即CPU分配给各个程序的时间,每个线程被分配一个时间段,称作它的时间片,即该进程允许运行的时间,使各个程序从表面上看是同时进行的。如果在时间片结束时进程还在运行,则CPU将被剥夺并分配给另一个进程。如果进程在时间片结束前阻塞或结束,则CPU当即进行切换。而不会造成CPU资源浪费
在宏观上:我们可以同时打开多个应用程序,每个程序并行不悖,同时运行。但在微观上:由于只有一个CPU,一次只能处理程序要求的一部分,如何处理公平,一种方法就是引入时间片,每个程序轮流执行
cpu资源控制
1)设置cpu使用率上限 Linux通过CFS(Completely Fair Scheduler,完全公平调度器)来调度各个进程对CPU的使用。CFS默认的调度周期是100ms。 我们可以设置每个容器进程的调度周期,以及在这个周期内各个容器最多能使用多少 CPU 时间。
使用 --cpu-period 即可设置调度周期,使用 --cpu-quota 即可设置在每个周期内容器能使用的CPU时间。两者可以配合使用。
CFS 周期的有效范围是 1ms1s,对应的 --cpu-period 的数值范围是 10001000000。
而容器的 CPU 配额必须不小于 1ms,即 --cpu-quota 的值必须 >= 1000。
1)查看容器的默认CPU使用限制
#创建并启动容器
docker run -itd --name test5 centos:7 /bin/bash
#查看容器状态
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3ed82355f811 centos:7 "/bin/bash" 5 days ago Up 6 hours test5
#切换到cgroup下针对容器的相关配置目录
cd /sys/fs/cgroup/cpu/docker/3ed82355f81151c4568aaa6e7bc60ba6984201c119125360924bf7dfd6eaa42b/
cat cpu.cfs_quota_us
-1
cat cpu.cfs_period_us
100000
#cpu.cfs_period_us:cpu分配的周期(微秒,所以文件名中用 us 表示),默认为100000。
#cpu.cfs_quota_us:表示该cgroups限制占用的时间(微秒),默认为-1,表示不限制。 如果设为50000,表示占用50000/100000=50%的CPU。
2)进行压力测试
docker exec -it test1 /bin/bash
vim /cpu.sh
#!/bin/bash
i=0
while true
do
let i++
done
chmod +x /cpu.sh
./cpu.sh
top
#可以看到这个脚本占了很多的cpu资源
3)设置50%的比例分配CPU使用时间上限
docker run -itd --name test6 --cpu-quota 50000 centos:7 /bin/bash
#可以重新创建一个容器并设置限额
或者
cd /sys/fs/cgroup/cpu/docker/3ed82355f81151c4568aaa6e7bc60ba6984201c119125360924bf7dfd6eaa42b/
echo 50000 > cpu.cfs_quota_us
#进入容器test2,写一个死循环脚本并运行
docker exec -it 3ed82355f811 /bin/bash
vi /cpu.sh
#!/bin/bash
i=0
while true
do
let i++
done
chmod +x cpu.sh
./cpu.sh
top
#可以看到cpu占用率接近50%,cgroups对cpu的控制起了效果
4)对已存在的容器进行CPU限制
直接修改/sys/fs/cgroup/cpu/docker/容器id/cpu.cfs_quota_us文件即可
cd /sys/fs/cgroup/cpu/docker/
ls
5544961646e2c58c895c64893cb49035f29c2952593c97e25b7fdfb6ad4f6187
55e08e9f0a0947701148c7b054143d428fbe717456743b558d0295a5367f0f82
......
cd 5544961646e2c58c895c64893cb49035f29c2952593c97e25b7fdfb6ad4f6187/
[root@localhost 5544961646e2c58c895c64893cb49035f29c2952593c97e25b7fdfb6ad4f6187]#echo "40000" > cpu.cfs_quota_us
[root@localhost 5544961646e2c58c895c64893cb49035f29c2952593c97e25b7fdfb6ad4f6187]#cd ~
docker exec -it test1 bash
[root@5544961646e2 /]# ./cpu.sh
^C
[root@5544961646e2 /]# exit
exit
top
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
4635 root 20 0 11688 1096 916 R 39.9 0.1 1:27.62 cpu.sh
5)设置CPU资源占用比(设置多个容器时才有效)
docker rm $(docker ps -aq) -f
#删除所有容器
Docker 通过 --cpu-shares 指定 CPU 份额,默认值为1024,值为1024的倍数。
#创建两个容器为 c1 和 c2,若只有这两个容器,设置容器的权重,使得c1和c2的CPU资源占比为1/3和2/3。
docker run -itd --name c1 --cpu-shares 512 centos:7
docker run -itd --name c2 --cpu-shares 1024 centos:7
docker ps -a
5.1)分别进入容器进行压力测试
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
sysctl -p
net.ipv4.ip_forward = 1
#宿主机开启路由转发功能,使容器能够连通外网
docekr exec -it c1 bash
与
docker exec -it c2 bash
#分别进入容器,进行压力测试
yum install -y epel-release
yum install -y stress
stress -c 4
#产生四个进程,每个进程都反复不停的计算随机数的平方根
c1:
c2:
5.2)查看容器运行状态,观察CPU使用占比
#再打开一个终端,查看容器运行状态(动态更新)
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
d0d385e3b519 c2 279.70% 204.6MiB / 3.686GiB 5.42% 35.5MB / 672kB 0B / 49.8MB 7
3ba090d35e34 c1 119.64% 204.5MiB / 3.686GiB 5.42% 35.5MB / 661kB 0B / 49.9MB 7
#因为宿主机有4核,所以CPU总百分比是400%。
#c1:c2 = 133.03%:266.52% ≈ 1:2
6)设置容器绑定指定CPU(梆核)
注意:CPU编号是从0开始的,编号1、3是代表第二个核和第四个核
#先分配虚拟机4个CPU核数
docker run -itd --name test7 --cpuset-cpus 1,3 centos:7 /bin/bash
#进入容器,进行压力测试
yum install -y epel-release
yum install stress -y
stress -c 4
#退出容器,执行 top 命令再按 1 查看CPU使用情况。
7)对内存使用的限制
-m (或--memory=)选项用于限制容器可以使用的最大内存
docker run -itd --name test8 -m 512m centos:7 /bin/bash
docker stats
//限制可用的 swap 大小, --memory-swap
强调一下,--memory-swap 是必须要与 --memory 一起使用的。
正常情况下,--memory-swap 的值包含容器可用内存和可用 swap。
所以 -m 300m --memory-swap=1g 的含义为:容器可以使用 300M 的物理内存,并且可以使用 700M(1G - 300)的 swap。
如果 --memory-swap 设置为 0 或者 不设置,则容器可以使用的 swap 大小为 -m 值的两倍。
如果 --memory-swap 的值和 -m 值相同,则容器不能使用 swap。
如果 --memory-swap 值为 -1,它表示容器程序使用的内存受限,而可以使用的 swap 空间使用不受限制(宿主机有多少 swap 容器就可以使用多少)。
8)限制容器可用的swap大小
#限制可用的swap 大小,--memory-swap
●强调一下, --memory-swap是必须要与 --memory(或-m)一起使用的。
●正常情况下, --memory-swap 的值包含容器可用内存和可用swap 。
●所以 -m 300m --memory-swap=1g 的含义为:容器可以使用300M 的物理内存,并且可以使用700M (1G - 300M)的swap。
设置为0或者不设置,则容器可以使用的 swap 大小为 -m 值的两倍。
如果 --memory-swap 的值和 -m 值相同,则容器不能使用swap。
如果 --memory-swap 值为 -1,它表示容器程序使用的内存受限,而可以使用的swap空间使用不受限制(宿主机有多少swap 容器就可以使用多少)。
#--memory-swap 的值包含容器可用内存和可用swap,减去-m的值才是可用swap的值。
#表示容器可以使用512M的物理内存,并且可以使用512M的swap。因为1g减去512m的物理内存,剩余值才是可用swap。
docker run -itd --name yy01 -m 512m --memory-swap=1g centos:7 bash
#--memoryswap值和 -m 的值相同,表示容器无法使用swap
docker run -itd --name yy02 -m 512m --memory-swap=512m centos:7 bash
# --memory-swap 的值设置为0或者不设置,则容器可以使用的 swap 大小为 -m 值的两倍。
docker run -itd --name yy03 -m 512m centos:7 bash
# --memory-swap 值为 -1,它表示容器程序使用的内存受限,但可以使用的swap空间使用不受限制(宿主机有多少swap 容器就可以使用多少)。
docker run -itd --name yy04 -m 512m --memory-swap=-1 centos:7 bash
9)对磁盘IO的配置控制(blkio)的限制
--device-read-bps:限制某个设备上的读速度bps ( 数据量),单位可以是kb、mb (M)或者gb。
--device-write-bps : 限制某个设备上的写速度bps ( 数据量),单位可以是kb、mb (M)或者gb。
--device-read-iops :限制读某个设备的iops (次数)
--device-write-iops :限制写入某个设备的iops ( 次数)
--device-read-bps:限制某个设备上的读速度bps ( 数据量),单位可以是kb、mb (M)或者gb。
例: docker run -itd --name test9 --device-read-bps /dev/sda:1M centos:7 /bin/bash
#表示该容器每秒只能读取1M的数据量
--device-write-bps : 限制某个设备上的写速度bps ( 数据量),单位可以是kb、mb (M)或者gb。
例: docker run -itd --name test10 --device-write-bps /dev/sda:1mb centos:7 /bin/bash
#表示该容器每秒只能写入1M的数据量
--device-read-iops :限制读某个设备的iops (次数)
--device-write-iops :限制写入某个设备的iops ( 次数)
9.1创建容器,不限制写的速度
#创建容器tt01,不限制写入速度
docker run -it --name tt01 centos:7 /bin/bash
#通过dd来验证写速度,拷贝50M的数据
dd if=/dev/zero of=/opt/test.out bs=10M count=5 oflag=direct #添加oflag参数以规避掉文件系统cache
#创建容器tt01,不限制写入速度
docker run -it --name test01 centos:7 /bin/bash
#通过dd来验证写速度,拷贝50M的数据到容器中
dd if=/dev/zero of=/opt/test.out bs=10M count=5 oflag=direct #添加oflag参数以规避掉文件系统cache
5+0 records in
5+0 records out
52428800 bytes (52 MB) copied, 0.0948474 s, 553 MB/s
#没有限制写速度的情况下,写入很快,0.09秒的时间内已写入50M的数据,写入速度为553M/s。
#创建容器,并限制写入速度为1MB/s,即每秒只能写入1MB的数据量。
docker run -it --name test02 --device-write-bps /dev/sda:1mb centos:7 bash
#通过dd来验证写速度,拷贝50M的数据到容器中
dd if=/dev/zero of=/opt/test.out bs=10M count=5 oflag=direct #添加oflag参数以规避掉文件系统cache
5+0 records in
5+0 records out
52428800 bytes (52 MB) copied, 50.0048 s, 1.0 MB/s
#写入50M的数据,需要50s左右,因为限制了容器的写速度是 1.0 MB/s。
清除docker占用的磁盘空间
docker system prune -a 可用于清理磁盘,删除关闭的容器、无用的数据卷和网络
docker system prune -a