当多个用户或者开发团队共享一个有固定节点的的kubernetes集群时,一个团队或者一个用户使用的资源超过他应当使用的资源是需要关注的问题,资源配额是管理员用来解决这个问题的一个工具.
资源配额,通过ResourceQuota
定义,提供了对某一名称空间使用资源的总体约束.它即可以限制这个名称空间下有多少个对象可以被创建,也可以限制对计算机资源使用量的限制(前面说到过,计算机资源包括cpu,内存,磁盘空间等资源)
资源配额通过以下类似方式工作:
不同的团队在不同的名称空间下工作.当前kubernetes并没有强制这样做,完全是自愿的,但是kubernetes团队计划通过acl授权来达到强制这样做.
管理员对每一个名称空间创建一个
ResourceQuota(资源配额)
用户在一个名称空间下创建资源(例如pod,service等),配额系统跟踪资源使用量来保证资源的使用不超过
ResourceQuota
定义的量.如果对一个资源的创建或者更新违反了资源配额约束,则请求会返回失败,失败的http状态码是
403 FORBIDDEN
并且有一条消息来解释哪个约束被违反.如果一个名称空间下的计算机资源配额,比如CPU和内存被启用,则用户必须指定相应的资源申请或者限制的值,否则配额系统可能会阻止pod的创建.
资源配额在某一名称空间下创建策略示例:
在一个有32G内存,16核cpu的集群,让团队A使用20G内存和10核cpu,让团队B使用10G内存和4核cpu,剩余的2G内存和2核cup预留以备进一步分配
限制
测试
名称空间使用1核1G,让生产
名称空间使用剩下的全部资源
当集群的容量小于所有名称空间下配额总和时,将会出现资源竞争,这种情况下kubernetes将会基于先到先分配的原则进行处理
不论是资源竞争或者是资源配额的修改都不会影响已经创建的资源
启用资源配额
很多kubernetes的发行版中资源配额支持默认是开启的,当ResourceQuota
作为apiserver的--enable-admission-plugins=
的其中一个值时,资源配额被开启.
当某一名称空间包含ResourceQuota
对象时资源配额在这个名称空间下生效.
计算机资源配额
你可以限制一个名称空间下可以被申请的计算机资源的总和
kubernetes支持以下资源类型:
Resource Name | Description |
---|---|
cpu | Across all pods in a non-terminal state, the sum of CPU requests cannot exceed this value. |
limits.cpu | Across all pods in a non-terminal state, the sum of CPU limits cannot exceed this value. |
limits.memory | Across all pods in a non-terminal state, the sum of memory limits cannot exceed this value. |
memory | Across all pods in a non-terminal state, the sum of memory requests cannot exceed this value. |
requests.cpu | Across all pods in a non-terminal state, the sum of CPU requests cannot exceed this value. |
requests.memory | Across all pods in a non-terminal state, the sum of memory requests cannot exceed this value. |
扩展资源的资源配额
除了上面提到的,在kubernetes 1.10里,添加了对扩展资源的配额支持
存储资源配额
你可以限制某一名称空间下的存储空间总量的申请
此外,你也可以你也可以根据关联的storage-class
来限制存储空间资源的使用
Resource Name | Description |
---|---|
requests.storage | Across all persistent volume claims, the sum of storage requests cannot exceed this value. |
persistentvolumeclaims | The total number of persistent volume claims that can exist in the namespace. |
.storageclass.storage.k8s.io/requests.storage | Across all persistent volume claims associated with the storage-class-name, the sum of storage requests cannot exceed this value. |
.storageclass.storage.k8s.io/persistentvolumeclaims | Across all persistent volume claims associated with the storage-class-name, the total number of persistent volume claims that can exist in the namespace. |
例如,一个operator
想要想要使黄金和青铜单独申请存储空间,那么这个operator
可以像如下一样申请配额:
gold.storageclass.storage.k8s.io/requests.storage: 500Gi
bronze.storageclass.storage.k8s.io/requests.storage: 100Gi
在1.8版本里,对local ephemeral storage
配额的的支持被添加到alpha特征里.
Resource Name | Description |
---|---|
requests.ephemeral-storage | Across all pods in the namespace, the sum of local ephemeral storage requests cannot exceed this value. |
limits.ephemeral-storage | Across all pods in the namespace, the sum of local ephemeral storage limits cannot exceed this value. |
对象数量配额
1.9版本通过以下语法加入了对所有标准名称空间资源类型的配额支持
count/<resource>.<group>
以下是用户可能想要设置对象数量配额的例子:
count/persistentvolumeclaims
count/services
count/secrets
count/configmaps
count/replicationcontrollers
count/deployments.apps
count/replicasets.apps
count/statefulsets.apps
count/jobs.batch
count/cronjobs.batch
count/deployments.extensions
当使用count/*
类型资源配额,服务器上存在的资源对象将都被控制.这将有助于防止服务器存储资源被耗尽.比如,如果存储在服务器上的secrets
资源对象过大,你可能会想要限制它的数量.过多的secrets
可能会导致服务器无法启动!你也可能会限制job
的数量以防一些设计拙劣的定时任务会创建过多的job以导致服务被拒绝
以下资源类型的限额是支持的
Resource Name | Description |
---|---|
configmaps | The total number of config maps that can exist in the namespace. |
persistentvolumeclaims | The total number of persistent volume claims that can exist in the namespace. |
pods | The total number of pods in a non-terminal state that can exist in the namespace. A pod is in a terminal state if .status.phase in (Failed, Succeeded) is true. |
replicationcontrollers | The total number of replication controllers that can exist in the namespace. |
resourcequotas | The total number of resource quotas that can exist in the namespace. |
services | The total number of services that can exist in the namespace. |
services.loadbalancers | The total number of services of type load balancer that can exist in the namespace. |
services.nodeports | The total number of services of type node port that can exist in the namespace. |
secrets | The total number of secrets that can exist in the namespace. |
例如,pod配额限制了一个名称空间下非terminal
状态的pod总数量.这样可以防止一个用户创建太多小的pod以至于耗尽集群分配给pod的所有IP
配额范围
每一个配额都可以包含一系列相关的范围.配额只会在匹配列举出的范围的交集时才计算资源的使用.
当一个范围被添加到配额里,它将限制它支持的,属于范围的资源.指定的资源不在支持的集合里时,将会导致验证错误
Scope | Description |
---|---|
Terminating | Match pods where .spec.activeDeadlineSeconds >= 0 |
NotTerminating | Match pods where .spec.activeDeadlineSeconds is nil |
BestEffort | Match pods that have best effort quality of service. |
NotBestEffort | Match pods that do not have best effort quality of service. |
BestEffort
范围限制配额只追踪pods
资源
Terminating
,NotTerminating
和NotBestEffort
范围限制配额追踪以下资源:
cpu
limits.cpu
limits.memory
memory
pods
requests.cpu
requests.memory
每一个PriorityClass的资源配额
此特征在1.12片本中为beta
pod可以以指定的优先级创建.你可以通过pod的优先级来控制pod对系统资源的使用,它是通过配额的spec下的scopeSelector
字段产生效果的.
只有当配额spec的scopeSelector
选择了一个pod,配额才会被匹配和消费
你在使用PriorityClass的配额的之前,需要启用
ResourceQuotaScopeSelectors
以下示例创建一个配额对象,并且一定优先级的pod会匹配它.
集群中的pod有以下三个优先级类之一:
low
,medium
,high
每个优先级类都创建了一个资源配额
apiVersion: v1
kind: List
items:
- apiVersion: v1
kind: ResourceQuota
metadata:
name: pods-high
spec:
hard:
cpu: "1000"
memory: 200Gi
pods: "10"
scopeSelector:
matchExpressions:
- operator : In
scopeName: PriorityClass
values: ["high"]
- apiVersion: v1
kind: ResourceQuota
metadata:
name: pods-medium
spec:
hard:
cpu: "10"
memory: 20Gi
pods: "10"
scopeSelector:
matchExpressions:
- operator : In
scopeName: PriorityClass
values: ["medium"]
- apiVersion: v1
kind: ResourceQuota
metadata:
name: pods-low
spec:
hard:
cpu: "5"
memory: 10Gi
pods: "10"
scopeSelector:
matchExpressions:
- operator : In
scopeName: PriorityClass
values: ["low"]
使用kubectl create
来用户以上yml文件
kubectl create -f ./quota.yml
resourcequota/pods-high created
resourcequota/pods-medium created
resourcequota/pods-low created
使用kubectl describe quota
来查看
kubectl describe quota
Name: pods-high
Namespace: default
Resource Used Hard
-------- ---- ----
cpu 0 1k
memory 0 200Gi
pods 0 10
Name: pods-low
Namespace: default
Resource Used Hard
-------- ---- ----
cpu 0 5
memory 0 10Gi
pods 0 10
Name: pods-medium
Namespace: default
Resource Used Hard
-------- ---- ----
cpu 0 10
memory 0 20Gi
pods 0 10
创建一个具有high
优先级的pod,把以下内容保存在high-priority-pod.yml
里
apiVersion: v1
kind: Pod
metadata:
name: high-priority
spec:
containers:
- name: high-priority
image: ubuntu
command: ["/bin/sh"]
args: ["-c", "while true; do echo hello; sleep 10;done"]
resources:
requests:
memory: "10Gi"
cpu: "500m"
limits:
memory: "10Gi"
cpu: "500m"
priorityClassName: high
使用kubectl create
来应用
kubectl create -f ./high-priority-pod.yml
这时候再用kubectl describe quota
来查看
Name: pods-high
Namespace: default
Resource Used Hard
-------- ---- ----
cpu 500m 1k
memory 10Gi 200Gi
pods 1 10
Name: pods-low
Namespace: default
Resource Used Hard
-------- ---- ----
cpu 0 5
memory 0 10Gi
pods 0 10
Name: pods-medium
Namespace: default
Resource Used Hard
-------- ---- ----
cpu 0 10
memory 0 20Gi
pods 0 10
scopeSelector
支持operator
字段的以下值:
In
NotIn
Exist
DoesNotExist
配额资源的申请与限制
当分配计算机资源时,每一个容器可能会指定对cpu或者内存的申请或限制.配额可以配置为它们中的一个值
这里是说配额只能是申请或者限制,而不能同时出现
如果配额指定了requests.cpu
或requests.memory
那么它需要匹配的容器必须显式指定申请这些资源.如果配额指定了limits.cpu
或limits.memory
,那么它需要匹配的容器必须显式指定限制这些资源
查看和设置配额
kubectl支持创建,更新和查看配额
kubectl create namespace myspace
cat <<EOF > compute-resources.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-resources
spec:
hard:
pods: "4"
requests.cpu: "1"
requests.memory: 1Gi
limits.cpu: "2"
limits.memory: 2Gi
requests.nvidia.com/gpu: 4
EOF
kubectl create -f ./compute-resources.yaml --namespace=myspace
cat <<EOF > object-counts.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: object-counts
spec:
hard:
configmaps: "10"
persistentvolumeclaims: "4"
replicationcontrollers: "20"
secrets: "10"
services: "10"
services.loadbalancers: "2"
EOF
kubectl create -f ./object-counts.yaml --namespace=myspace
kubectl get quota --namespace=myspace
NAME AGE
compute-resources 30s
object-counts 32s
kubectl describe quota compute-resources --namespace=myspace
Name: compute-resources
Namespace: myspace
Resource Used Hard
-------- ---- ----
limits.cpu 0 2
limits.memory 0 2Gi
pods 0 4
requests.cpu 0 1
requests.memory 0 1Gi
requests.nvidia.com/gpu 0 4
kubectl describe quota object-counts --namespace=myspace
Name: object-counts
Namespace: myspace
Resource Used Hard
-------- ---- ----
configmaps 0 10
persistentvolumeclaims 0 4
replicationcontrollers 0 20
secrets 1 10
services 0 10
services.loadbalancers 0 2
kubectl通过count/<resource>.<group>
语法形式支持标准名称空间对象数量配额
kubectl create namespace myspace
kubectl create quota test --hard=count/deployments.extensions=2,count/replicasets.extensions=4,count/pods=3,count/secrets=4 --namespace=myspace
kubectl run nginx --image=nginx --replicas=2 --namespace=myspace
kubectl describe quota --namespace=myspace
Name: test
Namespace: myspace
Resource Used Hard
-------- ---- ----
count/deployments.extensions 1 2
count/pods 2 3
count/replicasets.extensions 1 4
count/secrets 1 4
配额和集群容量
ResourceQuotas
独立于集群的容量,它们通过绝对的单位表示.因此,如果你向集群添加了节点,这并不会给集群中的每个名称空间赋予消费更多资源的能力.
有时候需要更为复杂的策略,比如:
把集群中所有的资源按照比例分配给不同团队
允许每个租户根据需求增加资源使用,但是有一个总体的限制以防资源被耗尽
检测名称空间的需求,添加节点,增加配额
这些策略可以通过实现ResourceQuotas
来写一个controller
用于监视配额的使用,并且通过其它信号来调整每个名称空间的配额
默认限制优先类消费
有时候我们可能希望一定优先级别的pod,例如cluster-services
应当被允许在一个名称空间里,当且仅当匹配的配额存在.
通过这种机制,operators可以限制一些高优先级的类只能用于有限数量的名称空间里,并且不是所有的名称空间都可以默认消费它们.
为了使以上生效,kube-apiserver标签--admission-control-config-file
应当传入以下配置文件的路径
apiVersion: apiserver.k8s.io/v1alpha1
kind: AdmissionConfiguration
plugins:
- name: "ResourceQuota"
configuration:
apiVersion: resourcequota.admission.k8s.io/v1beta1
kind: Configuration
limitedResources:
- resource: pods
matchScopes:
- scopeName: PriorityClass
operator: In
values: ["cluster-services"]
现在,cluster-services
类型的pod仅被允许运行在有匹配scopeSelector
的配额资源对象的名称空间里,例如
`yml scopeSelector: matchExpressions: - scopeName: PriorityClass operator: In values: ["cluster-services"]