去启动虚拟机的时候都会要求虚拟机多少资源,之前的namespace对用户的进程进行隔离了,放在了不同的namespace,互相不可见了,但是事实上都是主机fork出来的,运行在同一个操作系统里面的进程,如果不加以管控一定会出现一些问题。
会出现什么问题呢?比如写了一个应用里面有个bug是死循环,这样可能吃掉很多cpu,这样主机可能会变慢了。其他的应用就会受到影响了。还有或者应用内存泄露,那么吃掉了宿主机上面的很多内存,这样主机就整个都不能访问了,因为可能没有内存了。还有磁盘空间也是类似。
除了给容器提供封闭的环境之外,还要做一件事情就是资源管控,比如cpu和内存。
cgroup也分不同的子系统,这些不同的子系统会控制不同的资源,这些资源在cgroup里面叫做subsystem,就是不同的子系统。
cgroup如何去管理进程的,因为进程是树状结构,一个进程会fork出很多的其他进程,cgroup也用了类似的层级结构,也就是(Hierarchy)的方式来组织管理,
cgroup有不同的子系统,cpu是一个子系统,如果要管控cpu那么是使用cpu的子系统。如果要管控进程的内存,它是用内存子系统去管控的。
Cgroup是怎么管理的?以树状结构去管理的。
同样task_struct里面也有css_set这个结构体,这个结构体是用来描述,这个进程所在从group的一个状态的情况。(cgroup也是task_struct里面一个重要的属性)
最下面是系统的硬件,在此之上是操作系统内核,它包含了cgroup。内核和用户空间是通过系统调用来调用的。任何操作系统都会有一个初始化的进程,如systemd,对于任何的容器进程都是由systemd fork出来的子进程再fork出来的。
cgroups 实现了对资源的配额和度量。
cpu share和cpu qutoa区别:cpu share定义的是相对值,相对值意味着有人竞争的时候,大家就按照这个百分比去划分,如果没有人竞争就可以一直使用,B group里面的进程虽然使用了2/3的时间片,但是里面什么都没有跑,没有耗费任何cpu,那么A就可以将所有cpu吃掉。
但是绝对时间,给你设置了0.1的cpu,你就不可能超过它。
可以看到不同的子系统
[root@docker ~]# cd /sys/fs/cgroup/
[root@docker cgroup]# ls
blkio cpu cpuacct cpu,cpuacct cpuset devices freezer hugetlb memory net_cls net_cls,net_prio net_prio perf_event pids rdma systemd
cpu子系统当中的配置,这些配置是用来配置目录下面的进程能够使用多少cpu的
[root@docker cgroup]# cd cpu
[root@docker cpu]# ls
cgroup.clone_children cpuacct.stat cpuacct.usage_percpu cpuacct.usage_sys cpu.cfs_quota_us cpu.shares notify_on_release tasks
cgroup.procs cpuacct.usage cpuacct.usage_percpu_sys cpuacct.usage_user cpu.rt_period_us cpu.stat release_agent user.slice
cgroup.sane_behavior cpuacct.usage_all cpuacct.usage_percpu_user cpu.cfs_period_us cpu.rt_runtime_us docker system.slice
cpu.shares是一个相对值,约定一个cpu的相对值。假设有两个不同的文件目录,这个不同的文件目录里面都有cpu.shares。这个cpu.shares就是约定一个相对值,两个cgroup能够使用的cpu是几比几的,也就是比例。
[root@docker cpu]# cat cpu.shares
1024
cpu.cfs_quota_us cpu.cfs_period_us 这两个文件是用来控制一个进程使用cpu的绝对值。
cpu.cfs_period_us:可以简单理解为cpu的时间片
cpu.cfs_quota_us:是指在这么多时间片下面,我能够使用多少cpu
[root@master cpu]# cat cpu.cfs_quota_us cpu.cfs_period_us
-1
100000
在cpu子系统下面创建一个demo。之前所说的文件都会被创建出来。
这里有个程序,里面就是跑着死循环,吃cpu资源,现在运行这个程序。
可以看到占用了200%的cpu,如果有这种的应用就会将内存白白吃光了,这是非常危险的,因为没有独立的操作系统。
有什么办法来控制呢?这个进程的PID是62261,要通过cgroup去控制这个进程,怎么控制呢?
将这个进程cgroup.procs写入到这个文件告诉cgroup要控制的进程是哪个。
现在要控制cpu了,控制cpu的参数有两个,cpu.cfs_period_us cpu.cfs_quota_us ,死循环进程现在占用了两个cpu,-1代表不做任何的资源限制。现在设置为100000,也就是使用一个cpu。
可以看到cpu降下去了,只使用了一个cpu。设置为10000的意思呢?
现在cpu.cfs_period_us cpu.cfs_quota_us是相等的,意味着在100000个cpu时间片里面,被控制的进程能够拿到100000个cpu时间片,也就是能够拿到1个cpu。
通过这种方式,控制了这个进程使用的cpu。
cpu这种资源叫做可压缩资源,本来程序是消耗两个cpu的,但是给你一个cpu你也可以跑,但是这样程序一定会慢下来,所以在做容器化的时候,本来应用进程跑的好好的,突然部署到某一个地方发现慢了,发一个request就timeout了,这就得看看进程的cpu是不是给少了。
还有一种是不可压缩资源,比如内存。
可不可以在容器当中看cpu资源的使用率呢,进入到容器里面按top是不行的,看到的是主机的top,所以你要在容器里面通过top,通过cpuinfo,memifo来看资源利用率是不行的。
如果要看cpu怎么看呢? 通过cgroup cpu子系统的cpuacct去查看,这里面会告诉你cpu的使用情况。
[root@docker cpu]# cat cpuacct.usage
5666263771
[root@docker cpu]# cat cpuacct.stat
user 191
system 340
用于统计 Cgroup 及其子 Cgroup 下进程的 CPU 的使用情况。
memory.usage_in_bytes
memory.max_usage_in_bytes
memory.limit_in_bytes
memory.oom_Control
操作系统的资源像cpu这种资源,是可压缩资源,虽然我这个进程很忙,可能需要两个cpu,但是给他0.1个cpu也是ok的,只不过进程会变慢,但是内存不一样,内存给其限制了,那么超出的内存在做内存申请的时候就申请不出来,导致OOM。
上面可以看到cgroup是通过一系列的文件来管控所有的资源分配的,包括创建了一个cgroup,同时将一个cgroup和这个进程进行关联,也就是将进程号echo到那个procs文件里面,同时修改cpu的quota来限制其使用的资源,这一整套都是cgroup的文件系统,cgroup本身可以有不同的driver。
当操作系统使用systemd作为init system时,初始化进程生成一个根cgroup目录结构并作为cgroup管理器。
systemd与cgroup紧密结合,并且为每个systemd unit分配cgroup。
docker默认用cgroupfs作为cgroup驱动。
存在问题∶
因此kubelet会默认--cgroup-driver=systemd,若运行时cgroup不一致时,kubelet会报错
所以在搭建kubrnetes集群的时候,你往往需要去修改docker本身的cgroup driver,那么kubelet才能够启动起来。
实现了在主机上面启动的进程,但是通过cgroup控制使用多少资源,就算你程序有bug也是不能多使用资源。