The cluster configuration is adjusted according to the number of cluster users to achieve the purpose of controlling the amount of resources used in a specific namespace and ultimately achieving fair usage and cost control of the cluster.

The functions to be implemented are as follows.

  • Limit the amount of compute resources used by Pods in the running state.
  • Limit the number of persistent volumes to control access to storage.
  • Limit the number of load balancers to control costs.
  • Prevent abuse of scarce resources such as network ports.
  • Provide default compute resource requests for more optimal system scheduling.

1. Create namespace

Create a namespace named quota-example with the following contents in the namespace.yaml file.

1
2
3
4
apiVersion: v1
kind: Namespace
metadata:
  name: quota-example

Create namespace.

1
2
[root@master1 ~]# kubectl create -f namespace.yaml 
namespace/quota-example created

View namespace.

1
2
3
4
[root@master1 ~]# kubectl get namespaces | grep -v 'kube'
NAME              STATUS   AGE
default           Active   17d
quota-example     Active   2m13s

2. Set resource quotas that limit the number of objects

You can control the number of persistent storage volumes, load balancers, and NodePort resources by setting a resource quota that limits the number of pairs.

Create a ResourceQuota named object-counts. object-counts.yaml file has the following contents.

1
2
3
4
5
6
7
8
9
apiVersion: v1
kind: ResourceQuota
metadata:
  name: object-counts
spec:
  hard:
    persistentvolumeclaims: "2"
    services.loadbalancers: "2"
    services.nodeports: "0"

Create resource.

1
2
[root@master1 ~]# kubectl create -f object-counts.yaml --namespace=quota-example
resourcequota/object-counts created

The quota system detects the creation of resource item quotas, counts and limits the consumption of resources in that namespace.

Check if this configuration is in effect.

1
2
3
4
5
6
7
8
[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

At this point, the quota system automatically blocks requests that push resource usage over the resource quota limit.

3. Set a resource quota that limits computing resources

Create a compute-resources-qualified resource quota to limit the total amount of compute resources used in this namespace.

Create a ResourceQuota named compute-resources. compute-resources.yaml file has the following contents.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
apiVersion: v1
kind: ResourceQuota
metadata:
  name: compute-resources
spec:
  hard:
    pods: "4"
    requests.cpu: "1"
    requests.memory: 1Gi
    limits.cpu: "2"
    limits.memory: 2Gi

Create resource.

1
2
[root@master1 ~]# kubectl create -f compute-resources.yaml --namespace=quota-example 
resourcequota/compute-resources created

Check if the quota is in effect.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
[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

The quota system automatically prevents more than 4 non-terminating Pods in the namespace at the same time, and because the resource quota limits the total number of CPU and memory Limits and Requests, it forces all containers in the namespace to explicitly define the CPU and memory Limits, Requests (default values can be used, Requests equals Limits by default).

4. Configuring Default Requests and Limits

If you try to create a Pod in a namespace that does not specify Requests and Limits when the namespace has been configured with a limited compute resource quota, the Pod creation may fail. Here is an example of this failure.

Create a Deployment of Nginx.

1
2
[root@master1 ~]# kubectl create deployment nginx --image=nginx --replicas=1 --namespace=quota-example
deployment.apps/nginx created

When you look at the created Pod, you will see that the Pod was not created successfully.

1
2
3
4
5
[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

Further details on Deployment.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
[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

The Deployment tries to create a Pod, but fails. See the details of the ReplicaSet there.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
[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

Prompting a creation failure, the Master rejects the creation of a Pod by this ReplicaSet because the Requests, Limits for CPU and memory are not specified in this Pod.

To avoid this failure, you can use LimitRange to provide a default value for resource configuration for all Pods in this namespace.

Create a LimitRange named limits. limits.yaml file has the following contents.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
apiVersion: v1
kind: LimitRange
metadata:
  name: limits
spec:
  limits:
    - default:
        cpu: 200m
        memory: 512Mi
      defaultRequest:
        cpu: 100m
        memory: 256Mi
      type: Container

Create resource.

1
2
[root@master1 ~]# kubectl create -f limits.yaml --namespace=quota-example 
limitrange/limits created

View LimitsRange resource configuration.

1
2
3
4
5
6
7
[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          -

After a LimitRange is successfully created, if a user creates a Pod in that namespace without specifying a resource limit, the system automatically sets a default resource limit for that Pod.

For example, each newly created Pod without a resource limit is equivalent to using the following resource limit.

1
2
[root@master1 ~]# kubectl run nginx --image=nginx --requests=cpu=100m,memory=256Mi --limits=cpu=200m,memory=512Mi --namespace=quota-example
pod/nginx created

At this point, the namespace has been configured with default compute resources, and the ReplicaSet is ready to create Pods.

1
2
3
[root@master1 10.4]# kubectl get pods --namespace=quota-example
NAME                     READY   STATUS    RESTARTS   AGE
nginx-6799fc88d8-kvbpm   1/1     Running   0          39s

Next, check the resource quota usage.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
[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

You can see that each Pod consumes a specified amount of resources when it is created.

5. Specifying the scope of resource quotas

Suppose that instead of configuring a default compute resource quota for a namespace, you want to limit the total number of Pods running in the namespace with a QoS of BestEffort (all container Requests and Limits in the Pod are undefined and have the lowest priority).

For example, by having some resources in the cluster running services with non-BestEffort QoS and idle resources running services with BestEffort QoS, you can avoid having all resources of the cluster exhausted by only a large number of BestEffort Pods. This can be achieved by creating two resource quotas.

Create a namespace named quota-scopes.

1
2
[root@master1 ~]# kubectl create namespace quota-scopes
namespace/quota-scopes created

Create a ResourceQuota named best-effort, specify the Scope as BestEffort, and the contents of the best-effort.yaml file as follows.

1
2
3
4
5
6
7
8
9
apiVersion: v1
kind: ResourceQuota
metadata:
  name: best-effort
spec:
  hard:
    pods: "10"
  scopes:
    - BestEffort

Create resource.

1
2
[root@master1 ~]# kubectl create -f best-effort.yaml --namespace=quota-scopes 
resourcequota/best-effort created

Create another ResourceQuota named not-best-effort, specifying the Scope as NotBestEffort, and the content of the not-best-effort.yaml file as follows.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
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

Create resource.

1
2
[root@master1 ~]# kubectl create -f not-best-effort.yaml --namespace=quota-scopes 
resourcequota/not-best-effort created

View the successfully created ResourceQuota.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
[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

Pods that are not configured with Requests will be restricted by a ResourceQuota named best-effort; Pods that are configured with Requests will be restricted by a ResourceQuota named not-best-effort.

Create a Deployment of bestEffort. The best-effort-nginx.yaml file is as follows.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
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

Create the Deployment for NotbestEffort. not-best-effort-nginx.yaml file has the following contents.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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

Create two resources.

1
2
3
[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

The Deployment named best-effort-nginx has a QoS level of BestEffort because it does not have Requests and Limits configured, so its creation process is limited by the best-effort resource quota item, while the not-best-effort resource quota item does not limit it. The best-effort resource quota item does not limit Requests and Limits, so best-effort-nginx Deployment can successfully create 8 Pods.

Deployment named not-best-effort-nginx has a Burstable QoS level because it is configured with Requests and Limits, which are not equal, so its creation process is limited by the not-best-effort resource quota item, while the best-effort resource The not-best-effort resource quota restricts the total limit of Requests and Limits for the Pod. not-best-effort-nginx Deployment does not exceed this limit, so it can successfully create two Pods.

Looking at the Pods that have been created, you can see that all 10 Pods were created successfully.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
[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

When you look at the usage of the two resource quota entries, you see that the best-effort resource quota entry has counted the resource usage of the 8 Pods created in best-effort-nginx Deployment. The not-best-effort resource quota item has also counted the resource usage of the two Pods created in not-best-effort-nginx Deployment.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
[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

This example reveals that the resource quota scopes (Scopes) provide a mechanism to partition the set of resources, making it easier for cluster administrators to monitor and restrict the use of various types of resources by different types of objects, while providing better flexibility and convenience for resource allocation and restriction.

6. Resource Management Summary

Resource management in Kubernetes is based on the resource allocations (Requests and Limits) of containers and Pods. A container’s resource allocation specifies the resources requested by the container and the maximum amount of resources the container can use, and a Pod’s resource allocation is the sum of the resource allocations of all the containers in the Pod.

The resource quota mechanism allows us to limit the total number of resources used by all Pods in a namespace, as well as the number of objects of a specified type in that namespace. Using scopes allows resource quotas to be restricted only to objects that fit a specific scope, so the scoping mechanism allows for a richer, more flexible resource quota policy.

If more restrictions need to be placed on the resource allocation of a user’s Pod or container, this can be achieved using a LimitRange, which effectively limits the maximum and minimum range of resource allocations for Pods and containers, as well as limiting the maximum ratio of Limits to Requests for Pods and containers. LimitRange can also provide default resource allocation for containers in Pods.

Kubernetes implements resource quality of service (QoS) based on the resource allocation of Pods. Pods with different QoS levels have different priorities in the system: Pods with higher priorities have higher reliability and can be used to run services with higher reliability requirements; Pods with lower priorities can oversell cluster resources and effectively improve cluster resource utilization.