当多个用户或团队共享具有固定节点数目的集群时,人们会担心有人使用超过其基于公平原则所分配到的资源量。我们可以通过ResourceQuota来解决这个问题,对每个namespace的资源消耗总量提供限制。它可以限制命名空间中某种类型的对象的总数目上限,也可以限制命名空间中的 Pod 可以使用的计算资源的总上限。
资源配额的工作方式如下:
提示: 可使用 LimitRange 准入控制器来为没有设置计算资源需求的Pod设置默认值。
ResourceQuota官方文档地址https://kubernetes.io/zh-cn/docs/concepts/policy/resource-quotas/
资源配额的支持在很多Kubernetes版本中是默认开启的。当 apiserver 的 --admission-control= 参数中包含 ResourceQuota 时,资源配额会被启用。当namespace中存在一个 ResourceQuota 对象时,该namespace即开始实施资源配额管理。
用户可以对指定namespace下的计算资源可使用总量进行限制。目前配额机制所支持的资源类型如下:
资源名称 | 描述 |
---|---|
cpu | 所有非终止状态的Pod中,其CPU需求(request)总量上限 |
limits.cpu | 所有非终止状态的Pod中,其CPU限额(limit)总量上限 |
limits.memory | 所有非终止状态的Pod中,其内存限额总量上限 |
memory | 所有非终止状态的Pod中,其内存需求总量上限 |
requests.cpu | 所有非终止状态的Pod中,其CPU需求总量上限 |
requests.memory | 所有非终止状态的Pod中,其内存需求总量上限 |
requests.nvidia.com/gpu | 所有非终止状态的Pod中,其GPU资源总数使请求上限 |
用户可以对指定namespace下的存储资源总量进行限制。此外,还可以根据相关的存储类(Storage Class)来限制存储资源的消耗。
资源名称 | 描述 |
---|---|
requests.storage | 所有的PVC中,存储资源的需求声明总上限 |
persistentvolumeclaims | namespace中所允许的 PVC个数上限 |
所有该storage-class-name相关的PVC中, 存储资源的需求声明总上限 | |
namespace中所允许的 PVC个数上限 |
资源名称 | 描述 |
---|---|
configmaps | 在该命名空间中允许存在的 ConfigMap 总数上限 |
persistentvolumeclaims | 在该命名空间中允许存在的 PVC 的总数上限 |
pods | 在该命名空间中允许存在的非终止状态的 Pod 总数上限。Pod 终止状态等价于 Pod 的 .status.phase in (Failed, Succeeded) 为真 |
replicationcontrollers | 在该命名空间中允许存在的 ReplicationController 总数上限 |
resourcequotas | 在该命名空间中允许存在的 ResourceQuota 总数上限 |
services | 在该命名空间中允许存在的 Service 总数上限 |
services.loadbalancers | 在该命名空间中允许存在的 LoadBalancer 类型的 Service 总数上限 |
services.nodeports | 在该命名空间中允许存在的 NodePort 类型的 Service 总数上限 |
secrets | 在该命名空间中允许存在的 Secret 总数上限 |
每个配额都有一组相关的作用域(scope),配额只会对作用域内的资源生效。当一个作用域被添加到配额中后,它会对作用域相关的资源数量作限制。如配额中指定了允许(作用域)集合之外的资源,会导致验证错误。
范围 | 描述 |
---|---|
Terminating | 匹配 spec.activeDeadlineSeconds >= 0 的pod。 |
NotTerminating | 匹配 spec.activeDeadlineSeconds is nil 的pod。 |
BestEffort | 匹配"尽力而为(best effort)"服务类型的pod。 |
NotBestEffort | 匹配非"尽力而为(best effort)"服务类型的pod。 |
PriorityClass | 匹配所有引用了所指定的优先级类的 Pods。 |
CrossNamespacePodAffinity | 匹配那些设置了跨名字空间 (反)亲和性条件的 Pod。 |
BestEffort 作用域限制配额跟踪以下资源: pods
而Terminating、 NotTerminating 和 NotBestEffort 限制配额跟踪以下资源:
需要注意的是,不可以在同一个配额对象中同时设置 Terminating 和 NotTerminating 作用域,也不可以在同一个配额中同时设置 BestEffort 和 NotBestEffort 作用域。
scopeSelector 支持在 operator 字段中使用以下值:
如果 operator 是 In 或 NotIn 之一,则 values 字段必须至少包含一个值。 例如:
scopeSelector:
matchExpressions:
- scopeName: PriorityClass
operator: In
values:
- middle
而如果 operator 为 Exists 或 DoesNotExist,则不可以设置 values 字段。
[root@k8s-m1 k8s-resource]# cat resource-list.yaml
apiVersion: v1
kind: List
items:
- apiVersion: v1
kind: ResourceQuota
metadata:
name: pods-high
spec:
hard:
cpu: "100"
memory: 50Gi
pods: "10"
scopeSelector:
matchExpressions:
- operator: In
scopeName: PriorityClass
values: ["high"]
- apiVersion: v1
kind: ResourceQuota
metadata:
name: pods-medium
spec:
hard:
cpu: "60"
memory: 30Gi
pods: "10"
scopeSelector:
matchExpressions:
- operator: In
scopeName: PriorityClass
values: ["medium"]
- apiVersion: v1
kind: ResourceQuota
metadata:
name: pods-low
spec:
hard:
cpu: "40"
memory: 10Gi
pods: "10"
scopeSelector:
matchExpressions:
- operator: In
scopeName: PriorityClass
values: ["low"]
[root@k8s-m1 k8s-resource]# kubectl apply -f resource-list.yaml
resourcequota/pods-high created
resourcequota/pods-medium created
resourcequota/pods-low created
[root@k8s-m1 k8s-resource]# kubectl get resourcequotas
NAME AGE REQUEST LIMIT
pods-high 5s cpu: 0/100, memory: 0/50Gi, pods: 0/10
pods-low 5s cpu: 0/40, memory: 0/10Gi, pods: 0/10
pods-medium 5s cpu: 0/60, memory: 0/30Gi, pods: 0/10
[root@k8s-m1 k8s-resource]# kubectl describe quota
Name: pods-high
Namespace: default
Resource Used Hard
-------- ---- ----
cpu 0 100
memory 0 50Gi
pods 0 10
Name: pods-low
Namespace: default
Resource Used Hard
-------- ---- ----
cpu 0 40
memory 0 10Gi
pods 0 10
Name: pods-medium
Namespace: default
Resource Used Hard
-------- ---- ----
cpu 0 60
memory 0 30Gi
pods 0 10
#priorityclass也需要自己手动创建,系统默认自带了两个
[root@k8s-m1 k8s-resource]# cat priorityclass.yaml
apiVersion: scheduling.k8s.io/v1beta1
kind: PriorityClass
metadata:
name: high
value: 10000
globalDefault: true
description: "high priority"
[root@k8s-m1 k8s-resource]# kubectl apply -f priorityclass.yaml
Warning: scheduling.k8s.io/v1beta1 PriorityClass is deprecated in v1.14+, unavailable in v1.22+; use scheduling.k8s.io/v1 PriorityClass
priorityclass.scheduling.k8s.io/high created
[root@k8s-m1 k8s-resource]# kubectl get priorityclasses.scheduling.k8s.io
NAME VALUE GLOBAL-DEFAULT AGE
high 10000 true 14s
system-cluster-critical 2000000000 false 431d
system-node-critical 2000001000 false 431d
[root@k8s-m1 k8s-resource]# cat higi-priority-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: high-priority-pod
spec:
containers:
- name: high-priority
image: centos:7
command: ["/bin/sh"]
args: ["-c", "while true; do echo hello; sleep 10;done"]
resources:
requests:
memory: "2Gi"
cpu: "500m"
limits:
memory: "4Gi"
cpu: "500m"
priorityClassName: high
[root@k8s-m1 k8s-resource]# kubectl apply -f higi-priority-pod.yaml
pod/high-priority created
[root@k8s-m1 k8s-resource]# kubectl describe resourcequotas pods-high
Name: pods-high
Namespace: default
Resource Used Hard
-------- ---- ----
cpu 500m 100
memory 2Gi 50Gi
pods 1 10
分配计算资源时,可以为每个容器指定CPU或内存请求和约束,也可以设置两者中的任何一个。
如果配额中指定了 requests.cpu 或 requests.memory 的值,那么它要求每个进来的容器针对这些资源有明确的请求。 如果配额中指定了 limits.cpu 或 limits.memory的值,那么它要求每个进来的容器针对这些资源指定明确的约束。
[root@k8s-m1 k8s-resource]# kubectl create namespace myspace
[root@k8s-m1 k8s-resource]# cat compute-resources.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-resources
namespace: myspace
spec:
hard:
requests.cpu: "1"
requests.memory: 1Gi
limits.cpu: "2"
limits.memory: 2Gi
requests.nvidia.com/gpu: 4
[root@k8s-m1 k8s-resource]# cat object-counts.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: object-counts
namespace: myspace
spec:
hard:
configmaps: "10"
persistentvolumeclaims: "4"
pods: "4"
replicationcontrollers: "20"
secrets: "10"
services: "10"
services.loadbalancers: "2"
[root@k8s-m1 k8s-resource]# kubectl create -f compute-resources.yaml
resourcequota/compute-resources created
[root@k8s-m1 k8s-resource]# kubectl create -f object-counts.yaml
resourcequota/object-counts created
[root@k8s-m1 k8s-resource]# kubectl get quota --namespace=myspace
NAME AGE REQUEST LIMIT
compute-resources 15s requests.cpu: 0/1, requests.memory: 0/1Gi, requests.nvidia.com/gpu: 0/4 limits.cpu: 0/2, limits.memory: 0/2Gi
object-counts 3s configmaps: 0/10, persistentvolumeclaims: 0/4, pods: 0/4, replicationcontrollers: 0/20, secrets: 1/10, services: 0/10, services.loadbalancers: 0/2
创建nginx测试,如果pod所需资源超过resourcequota设置的pod将不能正常创建出来
[root@k8s-m1 k8s-resource]# kubectl apply -f nginx-resourcequota-deployment.yml
deployment.apps/my-nginx created
[root@k8s-m1 k8s-resource]# cat nginx-resourcequota-deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
namespace: myspace
labels:
app: nginx
spec:
selector:
matchLabels:
tier: frontend
replicas: 2
template:
metadata:
labels:
tier: frontend
spec:
containers:
- name: nginx-gateway
image: nginx
resources:
requests:
cpu: 1
memory: 1Gi
limits:
cpu: 1
memory: 1Gi
ports:
- containerPort: 80
[root@k8s-m1 k8s-resource]# kubectl apply -f nginx-resourcequota-deployment.yml
deployment.apps/my-nginx created
[root@k8s-m1 k8s-resource]# kubectl get pod -n myspace
NAME READY STATUS RESTARTS AGE
my-nginx-5c45dd8bc5-7zhw5 1/1 Running 0 83s
#只创建出来一个pod,而预期是2个
[root@k8s-m1 k8s-resource]# kubectl describe replicasets.apps -n myspace my-nginx-5c45dd8bc5
Name: my-nginx-5c45dd8bc5
Namespace: myspace
Selector: pod-template-hash=5c45dd8bc5,tier=frontend
Labels: pod-template-hash=5c45dd8bc5
tier=frontend
Annotations: deployment.kubernetes.io/desired-replicas: 2
deployment.kubernetes.io/max-replicas: 3
deployment.kubernetes.io/revision: 1
Controlled By: Deployment/my-nginx
Replicas: 1 current / 2 desired
Pods Status: 1 Running / 0 Waiting / 0 Succeeded / 0 Failed
Pod Template:
Labels: pod-template-hash=5c45dd8bc5
tier=frontend
Containers:
nginx-gateway:
Image: nginx
Port: 80/TCP
Host Port: 0/TCP
Limits:
cpu: 1
memory: 1Gi
Requests:
cpu: 1
memory: 1Gi
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
ReplicaFailure True FailedCreate
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulCreate 98s replicaset-controller Created pod: my-nginx-5c45dd8bc5-7zhw5
Warning FailedCreate 98s replicaset-controller Error creating: pods "my-nginx-5c45dd8bc5-5hjqq" is forbidden: exceeded quota: compute-resources, requested: requests.cpu=1,requests.memory=1Gi, used: requests.cpu=1,requests.memory=1Gi, limited: requests.cpu=1,requests.memory=1Gi
可以看到,由于所需资源已经超出当前命名空间设置的resourcequota,pod将不能正常创建。
更多关于kubernetes的知识分享,请前往博客主页。编写过程中,难免出现差错,敬请指出