By Alwyn Botha, Alibaba Cloud Tech Share Author. Tech Share is Alibaba Cloud's incentive program to encourage the sharing of technical knowledge and best practices within the cloud community.
When several teams of people share Kubernetes development and production nodes (servers running Kubernetes), it is typically a requirement to divide the computing resources equally (CPU, RAM, various types of disk space).
Kubernetes namespaces help with this via creating logically isolated work environments. But namespaces does not enforce limitations / quotas.
We need to use Kubernetes quotas to precisely specify strict quota limits for around 15 Kubernetes API resources.
All the exercises in this tutorial run in the default namespace. At your work you need to divide your nodes into namespaces and define quotas for each of those ... separately for development and for production. That specific topic is outside the scope of this tutorial.
This tutorial focus on how to define quotas.
Defining quotas are easy. Checking to see quotas get enforced is easy too, so this tutorial is quite repetitive. Just reading the Kubernetes docs does not let the facts sink in, you need practice and experience, hence this tutorial.
Enter this using your favorite Linux editor.
It defines a ResourceQuota that specifies a hard limit of 2 Pods.
nano myQuota.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: count-quotas
spec:
hard:
pods: "2"
Create the Quota
kubectl create -f myQuota.yaml
resourcequota/count-quotas created
Get a list of all quotas on your node.
kubectl get quota
NAME CREATED AT
object-counts 2019-01-22T05:53:02Z
Currently only 1 quota object: the one just created.
Describe how Kubernetes interpreted our YAML spec file.
kubectl describe quota object-counts
Name: object-counts
Namespace: default
Resource Used Hard
-------- ---- ----
pods 0 2
Quota of 2 Pods available, zero used so far.
Let's create one Pod to use one of the available Pods.
nano myQuota-Pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: quota-pod-1
spec:
containers:
- name: quota-container
image: busybox
imagePullPolicy: IfNotPresent
command: ['sh', '-c', 'echo Pod is Running ; sleep 3600']
restartPolicy: Never
terminationGracePeriodSeconds: 0
Nothing special about this Pod spec. Pods need no special action or spec definition to use quota-limited resource.
Quotas are automatically enforced.
WARNING. All Pod specs in this tutorial specifies terminationGracePeriodSeconds: 0
( By default, all deletes are graceful within 30 seconds. This allows time for shutdown routines to run. )
I do this to speed of the deletion of the many Pods throughout this tutorial. Only adjust terminationGracePeriodSeconds during production after careful consideration.
Create the Pod.
kubectl create -f myQuota-Pod.yaml
pod/quota-pod-1 created
We want to exceed quota, so we need more Pods.
Edit just the name of the Pod in myQuota-Pod.yaml
name: quota-pod-2
Create this second Pod.
kubectl create -f myQuota-Pod.yaml
pod/quota-pod-2 created
Investigate the status of our quota :
kubectl describe quota object-counts
Name: object-counts
Namespace: default
Resource Used Hard
-------- ---- ----
pods 2 2
2 Pods created so far, full quota used up.
Here are our Pods:
kubectl get po
NAME READY STATUS RESTARTS AGE
quota-pod-1 1/1 Running 0 2m36s
quota-pod-2 1/1 Running 0 90s
We want to exceed quota, so we need 1 more Pod.
Edit just the name of the Pod in myQuota-Pod.yaml
name: quota-pod-3
Create the Pod.
kubectl create -f myQuota-Pod.yaml
Error from server (Forbidden): error when creating "myQuota-Pod.yaml": pods "quota-pod-3" is forbidden: exceeded quota: object-counts, requested: pods=1, used: pods=2, limited: pods=2
As expected, create failed ( Quota enforced ). Error message easy to interpret.
This ends this demo:
Delete Pods and resourcequota objects.
kubectl delete pod/quota-pod-1
pod "quota-pod-1" deleted
kubectl delete pod/quota-pod-2
pod "quota-pod-2" deleted
kubectl delete quota/object-counts
resourcequota "object-counts" deleted
kubectl get po
No resources found.
CPU resources are usually high on list of resources to limit via quotas.
Kubernetes supports 2 CPU quotas:
Below is our ResourceQuota for :
( One Millicores is 1/1000 of a CPU, therefore 1000m equals 1 CPU. 1000m equals one CPU on all computers. )
A four core server has a CPU capacity of 4000m.
nano myQuota.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: object-counts
spec:
hard:
requests.cpu: "1000m"
limits.cpu: "2000m"
Create the Quota
kubectl create -f myQuota.yaml
resourcequota/count-quotas created
Now we define a Pod that will use a part of those resources.
nano myQuota-Pod-1.yaml
apiVersion: v1
kind: Pod
metadata:
name: quota-pod-1
spec:
containers:
- name: quota-container
image: busybox
imagePullPolicy: IfNotPresent
command: ['sh', '-c', 'echo Pod is Running ; sleep 3600']
resources:
requests:
cpu: "500m"
limits:
cpu: "1500m"
restartPolicy: Never
terminationGracePeriodSeconds: 0
Define a Pod that will use the remaining part of those resources.
nano myQuota-Pod-2.yaml
apiVersion: v1
kind: Pod
metadata:
name: quota-pod-2
spec:
containers:
- name: quota-container
image: busybox
imagePullPolicy: IfNotPresent
command: ['sh', '-c', 'echo Pod is Running ; sleep 3600']
resources:
requests:
cpu: "500m"
limits:
cpu: "500m"
restartPolicy: Never
terminationGracePeriodSeconds: 0
Define a Pod that will exceed the CPU resources quota. ( When running simultaneously with 2 previous Pods )
nano myQuota-Pod-3.yaml
apiVersion: v1
kind: Pod
metadata:
name: quota-pod-3
spec:
containers:
- name: quota-container
image: busybox
imagePullPolicy: IfNotPresent
command: ['sh', '-c', 'echo Pod is Running ; sleep 3600']
resources:
requests:
cpu: "10m"
limits:
cpu: "50m"
restartPolicy: Never
terminationGracePeriodSeconds: 0
Create the first 2 Pods.
kubectl create -f myQuota-Pod-1.yaml
pod/quota-pod-1 created
kubectl create -f myQuota-Pod-2.yaml
pod/quota-pod-2 created
Investigate if quota usage is as expected.
kubectl describe quota object-counts
Name: object-counts
Namespace: default
Resource Used Hard
-------- ---- ----
limits.cpu 2 2
requests.cpu 1 1
Our 2 Pods use exactly the total CPU quotas.
Attempt to use even more CPU resources.
kubectl create -f myQuota-Pod-3.yaml
Error from server (Forbidden): error when creating "myQuota-Pod-3.yaml": pods "quota-pod-3" is forbidden: exceeded quota: object-counts, requested: limits.cpu=50m,requests.cpu=10m, used: limits.cpu=2,requests.cpu=1, limited: limits.cpu=2,requests.cpu=1
As expected: even exceeding quota by 10% results in error.
Demo done, delete ...
kubectl delete -f myQuota-Pod-1.yaml
pod "quota-pod-1" deleted
kubectl delete -f myQuota-Pod-2.yaml
pod "quota-pod-2" deleted
kubectl delete quota/object-counts
resourcequota "object-counts" deleted
We will now create a quota of 2 secret API objects using the previous syntax.
Then we test its enforcement.
Then we define the quota using count/ syntax.
nano myQuota.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: object-counts
spec:
hard:
secrets: "2"
Create the Quota
kubectl create -f myQuota.yaml
resourcequota/count-quotas created
Describe quota:
kubectl describe quota object-counts
Name: object-counts
Namespace: default
Resource Used Hard
-------- ---- ----
secrets 1 2
Unexpectedly one secret already used ?
List all current secrets:
kubectl get secrets
NAME TYPE DATA AGE
default-token-gs2wt kubernetes.io/service-account-token 3 26d
This is the default secret token automatically created by Kubernetes. It is used by Pods to access the Kubernetes API.
So this secret uses 1 of our 2 quota slots.
One very simple and INSECURE way to create a secret is to use this one-liner command:
kubectl create secret generic my-insecure-secret-1 --from-literal=literalkey1=insecure-secret-value-1
secret/my-insecure-secret-1 created
Run it to create a second secret.
List all secrets:
kubectl get secrets
NAME TYPE DATA AGE
default-token-gs2wt kubernetes.io/service-account-token 3 26d
my-insecure-secret-1 Opaque 1 3s
Describe the quota status:
kubectl describe quota object-counts
Name: object-counts
Namespace: default
Resource Used Hard
-------- ---- ----
secrets 2 2
As expected, 2 secrets using full quota.
Attempting to create another secret results in error.
kubectl create secret generic my-insecure-secret-2 --from-literal=literalkey2=insecure-secret-value-2
Error from server (Forbidden): secrets "my-insecure-secret-2" is forbidden: exceeded quota: object-counts, requested: secrets=1, used: secrets=2, limited: secrets=2
This used the ( by now familiar ) first syntax.
Delete my-insecure-secret-1:
kubectl delete secret/my-insecure-secret-1
secret "my-insecure-secret-1" deleted
Delete quota object:
kubectl delete quota/object-counts
Second syntax for specifying count limit quotas:
Just prefix the API object you want to quota with count/
nano myQuota.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: object-counts
spec:
hard:
count/secrets: "2"
Create the Quota
kubectl create -f myQuota.yaml
resourcequota/count-quotas created
Describe the quota.
kubectl describe quota object-counts
Name: object-counts
Namespace: default
Resource Used Hard
-------- ---- ----
count/secrets 1 2
It works exactly as the previous syntax quota.
It correctly already counts the default secret token as one secret already being used.
kubectl get secrets
NAME TYPE DATA AGE
default-token-gs2wt kubernetes.io/service-account-token 3 26d
The effect of syntax 1 and 2 is identical:
Syntax 1:
spec:
hard:
pods: "2"
secrets: "2"
Syntax 2:
spec:
hard:
count/pods: "2"
count/secrets: "2"
Pick one of these as your standard way of defining quotas.
Delete Quota
kubectl delete -f myQuota.yaml
resourcequota "counts-quota" deleted
From https://kubernetes.io/docs/concepts/policy/resource-quotas/#object-count-quota
List of resources you can limit via object count quota:
You can limit Pods based on their Quality of Service (QoS) class.
For a Pod to be given a QoS class of BestEffort , the Containers in the Pod must not have any memory or CPU limits or requests.
Let's define a quota of 2 Pods in the BestEffort QoS class.
Terminology: Pods running in the BestEffort class are in the scope of the quota.
nano myQuota.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: object-counts
spec:
hard:
count/pods: "2"
scopes:
- BestEffort
Create the Quota
kubectl create -f myQuota.yaml
resourcequota/count-quotas created
Describe the quota:
kubectl describe quota object-counts
Name: object-counts
Namespace: default
Scopes: BestEffort
* Matches all pods that do not have resource requirements set. These pods have a best effort quality of service.
Resource Used Hard
-------- ---- ----
count/pods 0 2
It clearly describes the BestEffort scope.
Now we need to define BestEffort Pods: one that does not have resource requirements.
None of the Pods below have such lines in their YAML spec files.
resources:
requests:
cpu: "500m"
limits:
cpu: "500m"
We need 3 Pods since 2 Pods will fall within quota limits, the 3rd will attempt to exceed quota.
( Only Pod names differ below )
nano myQuota-Pod-1.yaml
apiVersion: v1
kind: Pod
metadata:
name: quota-pod-1
spec:
containers:
- name: quota-container
image: busybox
imagePullPolicy: IfNotPresent
command: ['sh', '-c', 'echo Pod is Running ; sleep 3600']
restartPolicy: Never
terminationGracePeriodSeconds: 0
nano myQuota-Pod-2.yaml
apiVersion: v1
kind: Pod
metadata:
name: quota-pod-2
spec:
containers:
- name: quota-container
image: busybox
imagePullPolicy: IfNotPresent
command: ['sh', '-c', 'echo Pod is Running ; sleep 3600']
restartPolicy: Never
terminationGracePeriodSeconds: 0
nano myQuota-Pod-3.yaml
apiVersion: v1
kind: Pod
metadata:
name: quota-pod-3
spec:
containers:
- name: quota-container
image: busybox
imagePullPolicy: IfNotPresent
command: ['sh', '-c', 'echo Pod is Running ; sleep 3600']
restartPolicy: Never
terminationGracePeriodSeconds: 0
Create the first Pod.
kubectl create -f myQuota-Pod-1.yaml
pod/quota-pod-1 created
Check quota stats are as expected.
kubectl describe quota object-counts
Name: object-counts
Namespace: default
Scopes: BestEffort
* Matches all pods that do not have resource requirements set. These pods have a best effort quality of service.
Resource Used Hard
-------- ---- ----
count/pods 1 2
Our Pod correctly classified as BestEffort. It counts as 1 Pod against the quota.
Create 2nd Pod.
kubectl create -f myQuota-Pod-2.yaml
pod/quota-pod-2 created
Check quota again.
kubectl describe quota object-counts
Name: object-counts
Namespace: default
Scopes: BestEffort
* Matches all pods that do not have resource requirements set. These pods have a best effort quality of service.
Resource Used Hard
-------- ---- ----
count/pods 2 2
As expected: bot Pod quotas used.
Attempt to create a third BestEffort Pod:
kubectl create -f myQuota-Pod-3.yaml
Error from server (Forbidden): error when creating "myQuota-Pod-3.yaml": pods "quota-pod-3" is forbidden: exceeded quota: object-counts, requested: count/pods=1, used: count/pods=2, limited: count/pods=2
Fails since it exceeds quota.
If we kubectl describe our first 2 Pods we will see their QoS is BestEffort.
kubectl describe pod/quota-pod-1|grep Best
QoS Class: BestEffort
kubectl describe pod/quota-pod-2|grep Best
QoS Class: BestEffort
Done, delete ...
kubectl delete -f myQuota-Pod-1.yaml
pod "quota-pod-1" deleted
kubectl delete -f myQuota-Pod-2.yaml
pod "quota-pod-2" deleted
kubectl delete quota/object-counts
resourcequota "object-counts" deleted
Another scope is NotTerminating
Matches all pods that do not have an active deadline. These pods usually include long running pods whose container command is not expected to terminate.
In this exercise we are going to :
nano myQuota.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: object-counts
spec:
hard:
count/pods: "2"
scopes:
- NotTerminating
Create NotTerminating quota and describe it:
kubectl create -f myQuota.yaml
resourcequota/object-counts created
kubectl describe quota object-counts
Name: object-counts
Namespace: default
Scopes: NotTerminating
* Matches all pods that do not have an active deadline. These pods usually include long running pods whose container command is not expected to terminate.
Resource Used Hard
-------- ---- ----
count/pods 0 2
Create one Pod and check it gets counted as NotTerminating / running.
kubectl create -f myQuota-Pod-1.yaml
pod/quota-pod-1 created
kubectl describe quota object-counts
Name: object-counts
Namespace: default
Scopes: NotTerminating
* Matches all pods that do not have an active deadline. These pods usually include long running pods whose container command is not expected to terminate.
Resource Used Hard
-------- ---- ----
count/pods 1 2
Is Pod running?
kubectl get po
NAME READY STATUS RESTARTS AGE
quota-pod-1 1/1 Running 0 10s
NotTerminating correctly counts this running Pod against NotTerminating quota.
Create second running Pod:
kubectl create -f myQuota-Pod-2.yaml
pod/quota-pod-2 created
kubectl get po
NAME READY STATUS RESTARTS AGE
quota-pod-1 1/1 Running 0 20s
quota-pod-2 1/1 Running 0 4s
Show status of quota counters:
kubectl describe quota object-counts
Name: object-counts
Namespace: default
Scopes: NotTerminating
* Matches all pods that do not have an active deadline. These pods usually include long running pods whose container command is not expected to terminate.
Resource Used Hard
-------- ---- ----
count/pods 2 2
Both running Pods count against NotTerminating quota.
Attempt to run a third Pod should result in error:
kubectl create -f myQuota-Pod-3.yaml
Error from server (Forbidden): error when creating "myQuota-Pod-3.yaml": pods "quota-pod-3" is forbidden: exceeded quota: object-counts, requested: count/pods=1, used: count/pods=2, limited: count/pods=2
Delete objects:
kubectl delete quota/object-counts
resourcequota "object-counts" deleted
kubectl delete -f myQuota-Pod-1.yaml
pod "quota-pod-1" deleted
kubectl delete -f myQuota-Pod-2.yaml
pod "quota-pod-2" deleted
https://kubernetes.io/docs/concepts/policy/resource-quotas/#requests-vs-limits
If the quota has a value specified for requests.cpu or requests.memory, then it requires that every incoming container makes an explicit request for those resources.
If the quota has a value specified for limits.cpu or limits.memory, then it requires that every incoming container specifies an explicit limit for those resources
To see this in action we define a ResourceQuota with requests.cpu and limits.cpu.
nano myQuota.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: object-counts
spec:
hard:
requests.cpu: "1000m"
limits.cpu: "2000m"
count/pods: "2"
Create the Quota
kubectl create -f myQuota.yaml
resourcequota/count-quotas created
Describe quota:
kubectl describe quota object-counts
Name: object-counts
Namespace: default
Resource Used Hard
-------- ---- ----
count/pods 0 2
limits.cpu 0 2
requests.cpu 0 1
Now we attempt to create a Pod without specifying CPU limits and resources:
nano myQuota-Pod-1.yaml
apiVersion: v1
kind: Pod
metadata:
name: quota-pod-1
spec:
containers:
- name: quota-container
image: busybox
imagePullPolicy: IfNotPresent
command: ['sh', '-c', 'echo Pod is Running ; sleep 3600']
restartPolicy: Never
terminationGracePeriodSeconds: 0
Create the Pod.
kubectl create -f myQuota-Pod-1.yaml
Error from server (Forbidden): error when creating "myQuota-Pod-1.yaml": pods "quota-pod-1" is forbidden: failed quota: object-counts: must specify limits.cpu,requests.cpu
Error message is exactly as expected.
Delete Quota
kubectl delete -f myQuota.yaml
resourcequota "counts-quota" deleted
The Kubernetes documentation provides a complete example of this ...
https://kubernetes.io/docs/concepts/policy/resource-quotas/#resource-quota-per-priorityclass
Just follow those instructions.
https://kubernetes.io/docs/concepts/policy/resource-quotas/#storage-resource-quota
You can limit the total sum of storage resources that can be requested in a given namespace.
In addition, you can limit consumption of storage resources based on associated storage-class.
This tutorial gave several repetitively similar exercises for several differences Kubernetes resources.
Once you need quotas on your storage resources you should be able to easily apply your knowledge learnt here.
From https://kubernetes.io/docs/concepts/policy/resource-quotas/#quota-and-cluster-capacity
ResourceQuotas are independent of the cluster capacity. They are expressed in absolute units.
So, if you add nodes to your cluster, this does not automatically give each namespace the ability to consume more resources.
Note that resource quota divides up aggregate cluster resources, but it creates no restrictions around nodes : pods from several namespaces may run on the same node .
If you only start using quotas months after starting to use Kubernetes you will have several different Kubernetes objects that already exists on your nodes.
You may then create quotas that are too small for even your current environment.
One way around this is to create temporary quotas that are 100 or 1000 more than your planned values.
You can then immediately run kubectl describe quota to instantly see accurate current counts for all Kubernetes objects you need quotas for. Then just adjust your quota values downwards as needed.
If you create quotas below your current usage that quota will be created without giving an error message.
This is bad, since if for example Pods are under specified, a Pod delete and recreate will fail since you are over quota already.
Therefore every time before you create a new quota run kubectl describe quota to see current resource usage levels.
After you create that quota run kubectl describe quota immediately to check its values are correct.
2,599 posts | 764 followers
FollowAlibaba Container Service - April 28, 2020
Alibaba Cloud Native - March 28, 2024
Alibaba Cloud Native Community - August 15, 2024
Alibaba Cloud Native Community - December 1, 2022
Alibaba Clouder - June 11, 2020
PM - C2C_Yuan - May 29, 2024
2,599 posts | 764 followers
FollowAlibaba Cloud Container Service for Kubernetes is a fully managed cloud container management service that supports native Kubernetes and integrates with other Alibaba Cloud products.
Learn MoreProvides a control plane to allow users to manage Kubernetes clusters that run based on different infrastructure resources
Learn MoreA secure image hosting platform providing containerized image lifecycle management
Learn MoreAn agile and secure serverless container instance service.
Learn MoreMore Posts by Alibaba Clouder