Docker核心技术-cgroup资源使用限制
cgroup(linux control group)
在了解了通过namespace可以实现在linux上对于资源隔离的管控,那么还有一个问题就是,我们即使通过namespace将不同进程隔离开,那么加入其中一个进程耗尽了主机的所有CPU和内存资源,那么其他进程即使通过ns进行了隔离,但因为主机没有可用的CPU和内存,那么也是无法工作的,另外我们也知道docker可以控制容器所使用的CPU和内存等资源,那么是怎么做到的呢?带着这些问题我们来看看linux是怎么通过cgroup来实现资源的控制和限制的。
cgroup示例
在linux中一切皆是文件,那么cgroup对于资源的限制肯定也是通过文件来实现的,我们可以在/sys/fs/cgroup目录中看到限制的对象。
[root@i-l7l18s0l cgroup]# pwd
/sys/fs/cgroup
[root@i-l7l18s0l cgroup]# ls cpu
cgroup.clone_children cgroup.procs cpuacct.stat cpuacct.usage_percpu cpu.cfs_quota_us cpu.rt_runtime_us cpu.stat notify_on_release system.slice user.slice
cgroup.event_control cgroup.sane_behavior cpuacct.usage cpu.cfs_period_us cpu.rt_period_us cpu.shares docker release_agent tasks
[root@i-l7l18s0l cgroup]#
查看cpu下的文件可以看到cfs_period_us和cfs_quota_us,通过组合使用这两个参数可以实现,限制进程在cfs_period_us的一段时间,只能被分配到总量为cfs_quota_us的CPU,下面我们通过一个示例来演示如何限制。
在/sys/fs/cgroup/cpu下新建一个new-cpu-limit目录, 同时查看目录可以看到对应的限制文件也会自动进行创建。
[root@i-l7l18s0l cpu]# mkdir new_cpu_limit
[root@i-l7l18s0l cpu]# ls
cgroup.clone_children cgroup.procs cpuacct.stat cpuacct.usage_percpu cpu.cfs_quota_us cpu.rt_runtime_us cpu.stat new_cpu_limit release_agent tasks
cgroup.event_control cgroup.sane_behavior cpuacct.usage cpu.cfs_period_us cpu.rt_period_us cpu.shares docker notify_on_release system.slice user.slice
[root@i-l7l18s0l cpu]#
[root@i-l7l18s0l cpu]# ls new_cpu_limit/
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
[root@i-l7l18s0l cpu]#
写一个死循环占满CPU
[root@docker cpu]# while : ; do : ; done &
[1] 9240
[root@docker cpu]# top
查看进程CPU使用率
查看new_cpu_limit目录下cfs_quota_us和cfs_period_us默认值
[root@docker cpu]# cd new_cpu_limit/
[root@docker new_cpu_limit]# cat cpu.cfs_quota_us
-1
[root@docker new_cpu_limit]# cat cpu.cfs_period_us
100000
[root@docker new_cpu_limit]#
cpu.cfs_quota_us值为-1代表没有任何限制,cpu.cfs_period_us则是默认的100ms(100000us),接下来将new_cpu_limit控制组的cpu.cfs_quota_us文件写入50ms(50000),这表示在100ms周期内,cpu最多使用50%,同时将该进程的pid=9240写入对应的tasks文件,表示对pid=9240进程限制:
[root@docker new_cpu_limit]# echo 50000 > cpu.cfs_quota_us
[root@docker new_cpu_limit]# echo 9240 > tasks
再次查看CPU使用率,检查是否cgroup控制生效,通过下面截图可以看到进程的cpu使用率降到了50%,也就是说我们的配置生效了
通过以上例子可以知道linux是怎么限制进程的资源使用情况的。
docker容器资源限制
上面的示例讲解了linux对于资源的限制,那么我们接下来看下docker对于容器资源的限制是怎么做的。
通过命令docker inspect $containerId --format {{}}
[root@docker ~]# docker inspect 583d44c9ac18
[root@docker ~]# docker inspect 583d44c9ac18
[
{
"Id": "583d44c9ac18f0134be6529b448539196c895b137db2aa77b54317a22e3f9f51",
"Created": "2022-01-29T07:53:17.061823755Z",
"Path": "./go-gin",
"Args": [],
"State": {
...
},
"Image": ...,
"LogPath": "",
"Name": "/relaxed_meninsky",
"RestartCount": 0,
"Driver": "overlay2",
"MountLabel": "",
"ProcessLabel": "",
"AppArmorProfile": "",
"ExecIDs": [
"96e6e59418b86d5241733d6cb66e9f3872ad72ae30c1da0aa6789fab8ecce61b"
],
"HostConfig": {
"Binds": null,
"ContainerIDFile": "",
"LogConfig": {
"Type": "journald",
"Config": {}
},
"NetworkMode": "default",
"PortBindings": {},
"RestartPolicy": {
"Name": "no",
"MaximumRetryCount": 0
},
"AutoRemove": false,
"VolumeDriver": "",
"VolumesFrom": null,
"CapAdd": null,
"CapDrop": null,
"Dns": ...,
"ShmSize": 67108864,
"Runtime": "docker-runc",
"ConsoleSize": [
0,
0
],
"Isolation": "",
"CpuShares": 0,
"Memory": 0,
"NanoCpus": 0,
"CgroupParent": "",
"BlkioWeight": 0,
"BlkioWeightDevice": null,
"BlkioDeviceReadBps": null,
"BlkioDeviceWriteBps": null,
"BlkioDeviceReadIOps": null,
"BlkioDeviceWriteIOps": null,
"CpuPeriod": 0,
"CpuQuota": 0,
"CpuRealtimePeriod": 0,
"CpuRealtimeRuntime": 0,
"CpusetCpus": "",
"CpusetMems": "",
"Devices": [],
"DiskQuota": 0,
"KernelMemory": 0,
"MemoryReservation": 0,
"MemorySwap": 0,
"MemorySwappiness": -1,
"OomKillDisable": false,
"PidsLimit": 0,
"Ulimits": null,
"CpuCount": 0,
"CpuPercent": 0,
"IOMaximumIOps": 0,
"IOMaximumBandwidth": 0
},
"GraphDriver": {
"Name": "overlay2",
"Data": ...
}
},
"Mounts": [],
"Config": {
"Hostname": "583d44c9ac18",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"ExposedPorts": {
"8888/tcp": {}
},
"Tty": true,
"OpenStdin": true,
"StdinOnce": false,
"Env": ...,
"Cmd": null,
"ArgsEscaped": true,
"Image": "13227829078/gogin:v1.0",
"Volumes": null,
"WorkingDir": "/app",
"Entrypoint": [
"./go-gin"
],
"OnBuild": null,
"Labels": {}
},
"NetworkSettings": {
"Bridge": "",,
"MacAddress": "02:42:ac:11:00:02",
"Networks": {
"bridge": {
...
}
}
}
}
]
在{{.HosConfig}}中可以看到对于容器资源的限制,如图显示默认没有配置资源的限制,这是时候我们查看下对应的cgroup下文件是不是这样的。
[root@docker cpu]# pwd
/sys/fs/cgroup/cpu
[root@docker cpu]# ls
aegis cgroup.clone_children cgroup.procs cpuacct.stat cpuacct.usage_percpu cpu.cfs_quota_us cpu.rt_runtime_us cpu.stat notify_on_release system.slice user.slice
assist cgroup.event_control cgroup.sane_behavior cpuacct.usage cpu.cfs_period_us cpu.rt_period_us cpu.shares new_cpu_limit release_agent tasks
[root@docker cgroup]# cat cpu/system.slice/docker-583d44c9ac18f0134be6529b448539196c895b137db2aa77b54317a22e3f9f51.scope/cpu.cfs_period_us
100000
[root@docker cgroup]# cat cpu/system.slice/docker-583d44c9ac18f0134be6529b448539196c895b137db2aa77b54317a22e3f9f51.scope/cpu.cfs_quota_us
-1
可以看到在目录重新启动一个容器cpu/system.slice/docker-583d44c9ac18f0134be6529b448539196c895b137db2aa77b54317a22e3f9f51.scope下,确实有对应的限制文件,也是cgroup的默认参数。那么我们在重新启动一个容器,添加上对于cpu的限制再次查看
[root@docker cpu]# docker run -it -d --cpu-quota=50000 --cpu-period=120000 --name gogin 13227829078/gogin:v1.0
23cd79c0b5d73a395c2c6bfd2358c120523680ce047f447a867b8e51698ec31c
[root@docker cpu]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
23cd79c0b5d7 13227829078/gogin:v1.0 "./go-gin" 2 seconds ago Up 2 seconds 8888/tcp gogin
583d44c9ac18 13227829078/gogin:v1.0 "./go-gin" 2 hours ago Up 2 hours 8888/tcp relaxed_meninsky
[root@docker cpu]# ls
aegis cgroup.clone_children cgroup.procs cpuacct.stat cpuacct.usage_percpu cpu.cfs_quota_us cpu.rt_runtime_us cpu.stat notify_on_release system.slice user.slice
assist cgroup.event_control cgroup.sane_behavior cpuacct.usage cpu.cfs_period_us cpu.rt_period_us cpu.shares new_cpu_limit release_agent tasks
[root@docker cpu]# docker inspect 23cd79c0b5d7
可以看到添加的限制已经被使用
查看对应的cpu限制文件内容也是我们设置的值
[root@docker cgroup]# cat cpu/system.slice/docker-23cd79c0b5d73a395c2c6bfd2358c120523680ce047f447a867b8e51698ec31c.scope/cpu.cfs_quota_us
50000
[root@docker cgroup]# cat cpu/system.slice/docker-23cd79c0b5d73a395c2c6bfd2358c120523680ce047f447a867b8e51698ec31c.scope/cpu.cfs_period_us
120000
到这里我们也清楚了docker通过cgroup可以实现对于资源用量的限制,关于更多的docker资源限制的设置可以通过docker run --help
来进行查看。