在kubernetes的controller-manager模块中有一个ResourceQuotaController控制器,通过这个控制器管理所有的资源配额,目前可以管理的资源包括POD、CPU和内存。
下面会介绍ResourceQuotaController控制器是如何进行管理的。首先,我们看一个结构体PodSpec,这个结构体用来存放POD的描述信息,如下图所示:
在这个结构体中有一个变量ActiveDeadlineSeconds,这是一个可选的正整型变量,也就是变量的值需要大于0。对于每个POD,当POD在NODE上启动之后kubernentes就可以获取这个POD运行时间,如果给这个POD对应的PodSpec中设置了数值,那么就意味着如果POD运行时间超过了这个POD对应的ActiveDeadlineSeconds变量值,那么kubelet会把这个POD设置成Failed状态,并重新进行同步,其实kubelet就是操作PodStatus这个结构体的Phase变量,将这个变量设置成Failed状态,下图就是PodStatus结构体:
ResourceQuotaController控制器通过这种方法可以限制特定时间范围内POD的数量,还可以限制这些POD使用的CPU和内存。比如运行时间2天内的POD个数不能超过10个,并且这些POD占用的CPU不能超过2核、内存不能超过2G。
如果不给配置变量ActiveDeadlineSeconds的值,那么就意味着可以对长期运行的POD进行配额控制。比如长时间运行的POD个数不能超过5个,并且这些POD占用的CPU不能超过20核、内存不能超过20G。
ResourceQuotaController控制器对于配额的控制,体现在如下几个结构体上面:
其中配额规格结构体是ResourceQuotaSpec,这个结构体中两个变量分别是Hard和Scopes,第一个变量Hard表示配额要求的资源数量上限,是一个GO语言map类型的数组变量,map类型是一种无序的键值对集合,map类型最重要的一点是通过key来快速检索数据,key类似于索引,指向数据的值,因为Hard是个数组变量,所以可以存放多个map值, map变量中key的取值就是kubernetes所能进行配置管理的资源,可以被管理的资源名称如下:
可以被管理的资源名称 |
pods |
services |
replicationcontrollers |
resourcequotas |
secrets |
configmaps |
persistentvolumeclaims |
services.nodeports |
services.loadbalancers |
requests.cpu |
requests.memory |
limits.cpu |
limits.memory |
cpu |
memory |
storage |
alpha.kubernetes.io/nvidia-gpu |
第二个变量Scopes表示配额作用范围,是一个字符串数值类型的变量,取值包括:
资源配额管理范围 |
Terminating |
NotTerminating |
BestEffort |
NotBestEffort |
当管理范围是“Terminating”的时候,作用范围是PodSpec. ActiveDeadlineSeconds>=0的POD;当管理范围是“NotTerminating”的时候,作用范围是PodSpec.ActiveDeadlineSeconds为空的POD;当管理范围是“BestEffort”的时候,作用范围是这样的POD:这些POD中所有容器都没有设置request和limit,当管理范围是“NotBestEffort”的时候,作用范围同“BestEffort”相反。
其中配额状态结构体是ResourceQuotaStatus,这个结构体中两个变量分别是Hard和Used,第一个变量Hard表示限制资源使用的配额数量上限,第二个变量Used表示资源已经使用的配额数量。ResourceQuotaController控制器会将资源使用情况进行统计,定时更新Used数值。
结构体ResourceQuota包含了ResourceQuotaSpec和ResourceQuotaStatus,结构体ResourceQuotaList存放kubernetes中所有资源配额。
在kubernetes中要想使资源配额管理起作用,那么只需要将ResourceQuota作为admission-control的一个参数:
$ kube-apiserver --admission-control=ResourceQuota
如下为配额管理的一些示例:
1. 创建namespace:
$ kubectl create -f /home/demo/resourcequota/namespace.yaml namespace "quota-example" created $ kubectl get namespaces NAME STATUS AGE default Active 2m kube-system Active 2m quota-example Active 39s2.给这个namespace配置一个ResourceQuota对象:
$ kubectl create -f /home/demo/resourcequota/quota-demo.yaml--namespace=quota-example resourcequota "object-counts"created $ kubectl describe quota quota-demo--namespace=quota-example Name: quota-demo Namespace: quota-example Resource Used Hard -------- ---- ---- limits.cpu 0 2 limits.memory 0 2Gi pods 0 4 requests.cpu 0 1 requests.memory 0 1Gi
这样就给quota-example这个namespace设置了资源配额,这个资源配额限制了quota-example中可以使用的POD个数上限,这个上限是10个,同时还设置了POD中每个容器CPU和内存的request和limit。
3. 创建一个ngix应用,并且给这个应用设置配额
$ kubectl run nginx --image=nginx--replicas=1 --namespace=quota-example deployment "nginx" created $ kubectl get pods--namespace=quota-example
这时候查询不出来数据,也就是说并没有创建出来POD,我们来分析下没有创建POD的原因。
$ kubectl describe deployment nginx--namespace=quota-example Name: nginx Namespace: quota-example CreationTimestamp: Mon, 06 Jun 2016 16:11:37 -0400 Labels: run=nginx Selector: run=nginx Replicas: 0 updated | 1 total | 0available | 1 unavailable StrategyType: RollingUpdate MinReadySeconds: 0 RollingUpdateStrategy: 1 max unavailable, 1 max surge OldReplicaSets: <none> NewReplicaSet: nginx-3137573019 (0/1 replicascreated)
$ kubectl describe rs nginx-3137573019--namespace=quota-example Name: nginx-3137573019 Namespace: quota-example Image(s): nginx Selector: pod-template-hash=3137573019,run=nginx Labels: pod-template-hash=3137573019 run=nginx Replicas: 0 current / 1 desired Pods Status: 0 Running / 0 Waiting / 0 Succeeded/ 0 Failed No volumes. Events:
这里我们主要看Message信息:Error creating:pods "nginx-3137573019-" is forbidden: Failed quota:compute-resources: must specifylimits.cpu,limits.memory,requests.cpu,requests.memory。
因为我们在资源配额中要求设置容器的request和limit,但是这个nginx应用并没有设置,所以POD创建不成功,这就说明资源配额管理在起作用。
我们可以重新启动nignx应用:
$ kubectl run nginx --image=nginx --replicas=1 --requests=cpu=100m,memory=256Mi--limits=cpu=200m,memory=512Mi --namespace=quota-example
$ kubectl get pods --namespace=quota-example NAME READY STATUS RESTARTS AGE nginx-3137573019-fvrig 1/1 Running 0 6m
我们还可以看看现在资源配额的使用情况:
$ kubectl describe quota--namespace=quota-example Name: compute-resources Namespace: quota-example Resource Used Hard -------- ---- ---- limits.cpu 200m 2 limits.memory 512Mi 2Gi pods 1 4 requests.cpu 100m 1 requests.memory 256Mi 1Gi
4. 我们可以根据需要,在不同的作用范围内设置不同的资源配额
4.1. 下面这个资源配额配置文件的作用范围是BestEffort的POD,这些POD不能超过2个。什么是BestEffort的POD?前面已经介绍过了,就是POD中的所有容器都没有设置CPU和内存的request和limit。
$cat quota-best-effort apiVersion:v1 kind:ResourceQuota metadata: name: quota-best-effort spec: hard: pods: "2" scopes: - BestEffort
4.2.下面这个资源配额配置文件的作用范围是Terminating 和NotBestEffort的POD,这些POD不能超过2个,并且这些POD使用计算资源不能超过2核CPU和1G内存。
$ cat quota-terminating apiVersion: v1 kind: ResourceQuota metadata: name: quota-terminating spec: hard: pods: "2" memory.limit: 1Gi cpu.limit: 2 scopes: -Terminating -NotBestEffort
4.3. 下面这个资源配额配置文件的作用范围是NotTerminating和NotBestEffort的POD,这些POD不能超过2个,并且这些POD使用计算资源不能超过4核CPU和4G内存。由于作用范围是NotTerminating,那么就是指PodSpec. ActiveDeadlineSeconds为空,实际上就是不限制POD运行时间,所以就是可以长期运行的POD。
$ cat quota-longrunning apiVersion: v1 kind: ResourceQuota metadata: name: quota-longrunning spec: hard: pods: "2" memory.limit: 4Gi cpu.limit: 4 scopes: -NotTerminating -NotBestEffort
4.4.下面这个资源配额配置文件只是限制自由使用数量,POD不能超过6个,RC不能超过10个。
$ cat quota-longrunning apiVersion: v1 kind: ResourceQuota metadata: name: quota-longrunning spec: hard: pods: "2" memory.limit: 4Gi cpu.limit: 4 scopes: -NotTerminating -NotBestEffort
可以看到,通过资源配额管理,可以帮助我们解决以下问题:
1.控制计算资源使用量
我们在实际生产环境中经常遇到的情况是,用户申请了过多的资源,用户应用的资源使用率太低,造成了资源的浪费。管理员通常会给集群设置超卖系数,来提高整个集群的资源使用率;另外管理员也会给用户设置资源配额上限,来限制用户使用资源的数量。通过上面的介绍我们可以看到,kubernetes的资源配额,我们可以从应用的层次上来进行配额管理,可以设置不同应用的资源配额上限。
2. 控制besteffort类型POD资源使用量
如果POD中的所有容器都没有设置request和limit,那么这些POD的QoS类型是besteffort,这种类型的POD更方便kubernetes进行调度,但是存在的问题是,如果不对这些POD进行资源管理,那么就会导致这个kubernetes集群资源过载,会影响这个集群中的所有应用,所以通过将资源配额管理的作用范围设置成besteffort,kubernetes可以通过限制这些POD的资源,避免整个集群资源过载。
3.控制长期运行的应用和短暂运行的应用资源使用率
在实际使用中,在kubernetes集群中会同时存在两种类型的应用,一种是长期运行的应用,比如网站这种web应用,还有一种就是短暂运行的应用,比如编译网站的这种应用。通过资源配额管理,可以同时对这两种不同类型的应用设置资源使用上限,来控制不同应用的资源使用。