根据集群用户数量来调整集群配置,以达到这个目的:能控制特定命名空间中的资源使用量,最终实现集群的公平使用和成本控制。
需要实现的功能如下:
- 限制运行状态的 Pod 的计算资源用量。
- 限制持久卷的数量以控制对存储的访问。
- 限制负载均衡器的数量以控制成本。
- 防止滥用网络端口这类稀缺资源。
- 提供默认的计算资源 Requests 以便系统做出更优化的调度。
1. 创建命名空间
创建名为 quota-example 的命名空间,namespace.yaml 文件内容如下:
apiVersion: v1
kind: Namespace
metadata:
name: quota-example
创建命名空间:
[root@master1 ~]# kubectl create -f namespace.yaml
namespace/quota-example created
查看命名空间:
[root@master1 ~]# kubectl get namespaces | grep -v 'kube'
NAME STATUS AGE
default Active 17d
quota-example Active 2m13s
2. 设置限定对象数量的资源配额
通过设置限定对数量的资源配额,可以控制持久存储卷、负载均衡器、NodePort 这些资源的数量。
创建名为 object-counts 的 ResourceQuota,object-counts.yaml 文件内容如下:
apiVersion: v1
kind: ResourceQuota
metadata:
name: object-counts
spec:
hard:
persistentvolumeclaims: "2"
services.loadbalancers: "2"
services.nodeports: "0"
创建资源:
[root@master1 ~]# kubectl create -f object-counts.yaml --namespace=quota-example
resourcequota/object-counts created
配额系统会检测到资源项配额的创建,统计和限制该命名空间中的资源消耗。
查看该配置是否生效:
[root@master1 ~]# kubectl describe quota object-counts --namespace=quota-example
Name: object-counts
Namespace: quota-example
Resource Used Hard
-------- ---- ----
persistentvolumeclaims 0 2
services.loadbalancers 0 2
services.nodeports 0 0
至此,配额系统会自动阻止那些使资源用量超过资源配额限定值的请求。
3. 设置限定计算资源的资源配额
创建一项限定计算资源的资源配额,以限制该命名空间中计算资源的使用总量。
创建名为 compute-resources 的 ResourceQuota,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
创建资源:
[root@master1 ~]# kubectl create -f compute-resources.yaml --namespace=quota-example
resourcequota/compute-resources created
查看该配额是否生效:
[root@master1 ~]# kubectl describe quota compute-resources --namespace=quota-example
Name: compute-resources
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
配额系统会自动防止在该命名空间中同时拥有超过4个非“终止态”的 Pod。此外,由于该项资源配额限制了 CPU 和 内存的 Limits 和 Requests 总量,因此会强制要求该命名空间中所有的容器都显式定义 CPU 和内存的 Limits、Requests(可使用默认值,Requests 默认等于 Limits)。
4. 配置默认的 Requests 和 Limits
在命名空间已经配置了限定计算资源配额的情况下,如果尝试在该命名空间中创建一个不指定 Requests 和 Limits 的 Pod,那么 Pod 的创建可能会失败。 下面是一个失败的例子。
创建一个 Nginx 的 Deployment:
[root@master1 ~]# kubectl create deployment nginx --image=nginx --replicas=1 --namespace=quota-example
deployment.apps/nginx created
查看创建的 Pod,会发现 Pod 没有创建成功:
[root@master1 ~]# kubectl get pods --namespace=quota-example
No resources found in quota-example namespace.
[root@master1 ~]# kubectl get deployments --namespace=quota-example
NAME READY UP-TO-DATE AVAILABLE AGE
nginx 0/1 0 0 2m38s
再查看 Deployment 的详细信息:
[root@master1 ~]# kubectl describe deployments nginx --namespace=quota-example
Name: nginx
Namespace: quota-example
CreationTimestamp: Tue, 02 Aug 2022 15:31:30 +0800
Labels: app=nginx
Annotations: deployment.kubernetes.io/revision: 1
Selector: app=nginx
Replicas: 1 desired | 0 updated | 0 total | 0 available | 1 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=nginx
Containers:
nginx:
Image: nginx
Port: <none>
Host Port: <none>
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Progressing True NewReplicaSetCreated
Available False MinimumReplicasUnavailable
ReplicaFailure True FailedCreate
OldReplicaSets: <none>
NewReplicaSet: nginx-6799fc88d8 (0/1 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 104s deployment-controller Scaled up replica set nginx-6799fc88d8 to 1
该 Deployment 会尝试创建一个 Pod,但是失败,查看其中 ReplicaSet 的详细信息:
[root@master1 ~]# kubectl describe replicasets nginx-6799fc88d8 --namespace=quota-example
Name: nginx-6799fc88d8
Namespace: quota-example
Selector: app=nginx,pod-template-hash=6799fc88d8
Labels: app=nginx
pod-template-hash=6799fc88d8
Annotations: deployment.kubernetes.io/desired-replicas: 1
deployment.kubernetes.io/max-replicas: 2
deployment.kubernetes.io/revision: 1
Controlled By: Deployment/nginx
Replicas: 0 current / 1 desired
Pods Status: 0 Running / 0 Waiting / 0 Succeeded / 0 Failed
Pod Template:
Labels: app=nginx
pod-template-hash=6799fc88d8
Containers:
nginx:
Image: nginx
Port: <none>
Host Port: <none>
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
ReplicaFailure True FailedCreate
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedCreate 4m5s replicaset-controller Error creating: pods "nginx-6799fc88d8-vt4t2" is forbidden: failed quota: compute-resources: must specify limits.cpu,limits.memory,requests.cpu,requests.memory
Warning FailedCreate 4m5s replicaset-controller Error creating: pods "nginx-6799fc88d8-xrj66" is forbidden: failed quota: compute-resources: must specify limits.cpu,limits.memory,requests.cpu,requests.memory
Warning FailedCreate 4m5s replicaset-controller Error creating: pods "nginx-6799fc88d8-scqxt" is forbidden: failed quota: compute-resources: must specify limits.cpu,limits.memory,requests.cpu,requests.memory
Warning FailedCreate 4m5s replicaset-controller Error creating: pods "nginx-6799fc88d8-m672m" is forbidden: failed quota: compute-resources: must specify limits.cpu,limits.memory,requests.cpu,requests.memory
Warning FailedCreate 4m5s replicaset-controller Error creating: pods "nginx-6799fc88d8-62pcx" is forbidden: failed quota: compute-resources: must specify limits.cpu,limits.memory,requests.cpu,requests.memory
Warning FailedCreate 4m5s replicaset-controller Error creating: pods "nginx-6799fc88d8-j7p8m" is forbidden: failed quota: compute-resources: must specify limits.cpu,limits.memory,requests.cpu,requests.memory
Warning FailedCreate 4m5s replicaset-controller Error creating: pods "nginx-6799fc88d8-5tv47" is forbidden: failed quota: compute-resources: must specify limits.cpu,limits.memory,requests.cpu,requests.memory
Warning FailedCreate 4m4s replicaset-controller Error creating: pods "nginx-6799fc88d8-4dfch" is forbidden: failed quota: compute-resources: must specify limits.cpu,limits.memory,requests.cpu,requests.memory
Warning FailedCreate 4m4s replicaset-controller Error creating: pods "nginx-6799fc88d8-hffdc" is forbidden: failed quota: compute-resources: must specify limits.cpu,limits.memory,requests.cpu,requests.memory
Warning FailedCreate 81s (x7 over 4m3s) replicaset-controller (combined from similar events): Error creating: pods "nginx-6799fc88d8-p2rmx" is forbidden: failed quota: compute-resources: must specify limits.cpu,limits.memory,requests.cpu,requests.memory
提示创建失败,Master 拒绝这个 ReplicaSet 创建 Pod,因为在这个 Pod 中没有指定 CPU 和 内存的 Requests、Limits。
为了避免这种失败,可以使用 LimitRange 为这个命名空间中所有 Pod 都提供一个资源配置的默认值。
创建一个名为 limits 的 LimitRange,limits.yaml 文件内容如下:
apiVersion: v1
kind: LimitRange
metadata:
name: limits
spec:
limits:
- default:
cpu: 200m
memory: 512Mi
defaultRequest:
cpu: 100m
memory: 256Mi
type: Container
创建资源:
[root@master1 ~]# kubectl create -f limits.yaml --namespace=quota-example
limitrange/limits created
查看 LimitsRange 资源配置:
[root@master1 ~]# kubectl describe limitranges --namespace=quota-example
Name: limits
Namespace: quota-example
Type Resource Min Max Default Request Default Limit Max Limit/Request Ratio
---- -------- --- --- --------------- ------------- -----------------------
Container cpu - - 100m 200m -
Container memory - - 256Mi 512Mi -
在 LimitRange 创建成功后,若用户在该命名空间中创建了未指定资源限制的 Pod,系统就会自动为该 Pod 设置默认的资源限制。
例如,每个新建的未指定资源限制的 Pod 都等价于使用下面的资源限制:
[root@master1 ~]# kubectl run nginx --image=nginx --requests=cpu=100m,memory=256Mi --limits=cpu=200m,memory=512Mi --namespace=quota-example
pod/nginx created
至此,已经为该命名空间配置好默认的计算资源,ReplicaSet 就能够创建 Pod了:
[root@master1 10.4]# kubectl get pods --namespace=quota-example
NAME READY STATUS RESTARTS AGE
nginx-6799fc88d8-kvbpm 1/1 Running 0 39s
接下来查看资源配额的使用情况:
[root@master1 ~]# 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
Name: object-counts
Namespace: quota-example
Resource Used Hard
-------- ---- ----
persistentvolumeclaims 0 2
services.loadbalancers 0 2
services.nodeports 0 0
看到每个 Pod 在创建时都会消耗指定的资源量。
5. 指定资源配额的作用域
假设并不想为某个命名空间配置默认的计算资源配额,而是希望限定在命名空间中运行的 QoS 为 BestEffort(Pod 中所有容器 Requests 和 Limits 都未定义,优先级最低) 的 Pod 总数。
例如让集群中的部分资源运行 QoS 为非 BestEffort 的服务,并让闲置的资源运行 QoS 为 BestEffort 的服务,即可避免集群的所有资源仅被大量的 BestEffort Pod 耗尽。这可以通过创建两个资源配额来实现:
创建一个名为 quota-scopes 的命名空间:
[root@master1 ~]# kubectl create namespace quota-scopes
namespace/quota-scopes created
创建一个名为 best-effort 的 ResourceQuota,指定 Scope 为 BestEffort,best-effort.yaml 文件内容如下:
apiVersion: v1
kind: ResourceQuota
metadata:
name: best-effort
spec:
hard:
pods: "10"
scopes:
- BestEffort
创建资源:
[root@master1 ~]# kubectl create -f best-effort.yaml --namespace=quota-scopes
resourcequota/best-effort created
再创建一个名为 not-best-effort 的 ResourceQuota,指定 Scope 为 NotBestEffort,not-best-effort.yaml 文件内容如下:
apiVersion: v1
kind: ResourceQuota
metadata:
name: not-best-effort
spec:
hard:
pods: "4"
requests.cpu: "1"
requests.memory: 1Gi
limits.cpu: "2"
limits.memory: 2Gi
scopes:
- NotBestEffort
创建资源:
[root@master1 ~]# kubectl create -f not-best-effort.yaml --namespace=quota-scopes
resourcequota/not-best-effort created
查看创建成功的 ResourceQuota:
[root@master1 ~]# kubectl describe quota --namespace=quota-scopes
Name: best-effort
Namespace: quota-scopes
Scopes: BestEffort
* Matches all pods that do not have resource requirements set. These pods have a best effort quality of service.
Resource Used Hard
-------- ---- ----
pods 0 10
Name: not-best-effort
Namespace: quota-scopes
Scopes: NotBestEffort
* Matches all pods that have at least one resource requirement set. These pods have a burstable or guaranteed quality of service.
Resource Used Hard
-------- ---- ----
limits.cpu 0 2
limits.memory 0 2Gi
pods 0 4
requests.cpu 0 1
requests.memory 0 1Gi
之后没有配置 Requests 的 Pod 将被名为 best-effort 的 ResourceQuota 限制;而配置了 Requests 的 Pod 会被名为 not-best-effort 的 ResourceQuota 限制。
创建 bestEffort 的 Deployment , best-effort-nginx.yaml 文件内容如下:
apiVersion: apps/v1
kind: Deployment
metadata:
name: best-effort-nginx
spec:
replicas: 8
selector:
matchLabels:
app: best-effort-nginx
template:
metadata:
labels:
app: best-effort-nginx
spec:
containers:
- name: nginx
image: nginx
创建 NotbestEffort 的 Deployment,not-best-effort-nginx.yaml 文件内容如下:
apiVersion: apps/v1
kind: Deployment
metadata:
name: not-best-effort-nginx
spec:
replicas: 2
selector:
matchLabels:
app: not-best-effort-nginx
template:
metadata:
labels:
app: not-best-effort-nginx
spec:
containers:
- name: nginx
image: nginx
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: 200m
memory: 512Mi
创建两个资源:
[root@master1 ~]# kubectl create -f best-effort-nginx.yaml -f not-best-effort-nginx.yaml --namespace=quota-scopes
deployment.apps/best-effort-nginx created
deployment.apps/not-best-effort-nginx created
名为 best-effort-nginx 的 Deployment 因为没有配置 Requests 和 Limits,所以它的 QoS 级别为 BestEffort,因此它的创建过程由 best-effort 资源配额项来限制,而 not-best-effort 资源配额项不会对它进行限制。best-effort 资源配置项没有限制 Requests 和 Limits,因此 best-effort-nginx Deployment 可以成功创建 8 个 Pod。
名为 not-best-effort-nginx 的 Deployment 因为配置了 Requests 和 Limits,且二者不相等,所以它的 QoS 级别为 Burstable,因此所以它的创建过程由 not-best-effort 资源配额项限制,而 best-effort资源配额项不会对它进行限制。not-best-effort 资源配额项限制了 Pod 的 Requests 和 Limits 的总上限,not-best-effort-nginx Deployment 并没有超过这个上限,所以可以成功创建两个 Pod。
查看已经创建的 Pod,可以看到 10 个 Pod 都创建成功:
[root@master1 ~]# kubectl get pods --namespace=quota-scopes
NAME READY STATUS RESTARTS AGE
best-effort-nginx-78bb6d5d9d-6cxg7 1/1 Running 0 45s
best-effort-nginx-78bb6d5d9d-ckrdx 1/1 Running 0 44s
best-effort-nginx-78bb6d5d9d-jw6cq 1/1 Running 0 44s
best-effort-nginx-78bb6d5d9d-llm42 1/1 Running 0 44s
best-effort-nginx-78bb6d5d9d-pzkkk 1/1 Running 0 45s
best-effort-nginx-78bb6d5d9d-rhjps 1/1 Running 0 45s
best-effort-nginx-78bb6d5d9d-tl6g5 1/1 Running 0 44s
best-effort-nginx-78bb6d5d9d-zghvp 1/1 Running 0 40s
not-best-effort-nginx-54cfd5bd8-v68dr 1/1 Running 0 45s
not-best-effort-nginx-54cfd5bd8-v7mt8 1/1 Running 0 45s
再查看两个资源配额项的使用情况,看到 best-effort 资源配额项已经统计了在 best-effort-nginx Deployment 中创建的 8 个 Pod 的资源使用信息。not-best-effort 资源配额项也已经统计了在 not-best-effort-nginx Deployment 中创建的两个 Pod 的资源使用信息。
[root@master1 ~]# kubectl describe quota --namespace=quota-scopes
Name: best-effort
Namespace: quota-scopes
Scopes: BestEffort
* Matches all pods that do not have resource requirements set. These pods have a best effort quality of service.
Resource Used Hard
-------- ---- ----
pods 8 10
Name: not-best-effort
Namespace: quota-scopes
Scopes: NotBestEffort
* Matches all pods that have at least one resource requirement set. These pods have a burstable or guaranteed quality of service.
Resource Used Hard
-------- ---- ----
limits.cpu 400m 2
limits.memory 1Gi 2Gi
pods 2 4
requests.cpu 200m 1
requests.memory 512Mi 1Gi
通过这个例子可以发现:资源配额的作用域(Scopes)提供了一种将资源集合分割的机制,可以使集群管理员更加方便地监控和限制不同类型的对象对各类资源的使用情况,同时为资源分配和限制提供更好的灵活性和便利性。
6.资源管理小结
Kubernetes 中资源管理的基础是容器和 Pod 的资源配置(Requests 和 Limits)。容器的资源配置指定了容器请求的资源和容器能使用的资源上限,Pod 的资源配置则是 Pod 中所有容器的资源配置总和上限。
通过资源配额机制,我们可以对命名空间中所有 Pod 使用资源的总量进行限制,也可以对这个命名空间中指定类型的对象的数量进行限制。使用作用域可以让资源配额只对符合特定范围的对象加以限制,因此作用域机制可以使资源配额的策略更加丰富、灵活。
如果需要对用户的 Pod 或容器的资源配置做更多的限制,则可以使用资源配置范围(LimitRange)来达到这个目的。LimitRange 可以有效限制 Pod 和容器的资源配置的最大、最小范围,也可以限制 Pod 和容器的 Limits 与 Requests 的最大比例上限,LimitRange 还可以为 Pod 中的容器提供默认的资源配置。
Kubernetes 基于 Pod 的资源配置实现了资源服务质量(QoS)。不同 QoS 级别的 Pod 在系统中拥有不同的优先级:高优先级的 Pod 有更高的可靠性,可以用于运行对可靠性要求较高的服务;低优先级的 Pod 可以实现集群资源的超售,有效提高集群资源利用率。
参考:《Kubernetes权威指南(第五版)》