When working with the Kubernetes containerization platform, it is important to control resource usage for cluster objects such as pods. The requests and limits parameters allow you to configure resource consumption limits, such as how many resources a pod can use in a Kubernetes cluster. This article will explore the use of requests and limits in Kubernetes through practical examples.
To work with requests and limits in a Kubernetes cluster, we need:
A Kubernetes cluster (you can create one in the Hostman control panel). For testing purposes, a cluster with two nodes will suffice. The cluster can also be deployed manually by renting the necessary number of cloud or dedicated (physical) servers, setting up the operating system, and installing the required packages.
Lens or kubectl for connecting to and managing your Kubernetes clusters.
First, go to the cluster management page in your Hostman panel. Download the Kubernetes cluster configuration file (the kubeconfig
file).
Once Lens is installed on your system, launch the program, and from the left menu, go to the Catalog (app) section:
Select Clusters and click the blue plus button at the bottom right.
Choose the directory where you downloaded the Kubernetes configuration file by clicking the Sync button at the bottom right.
After this, our cluster will appear in the list of available clusters. Click on the cluster's name to open its dashboard:
First, let's understand what requests and limits are in Kubernetes.
Requests are a mechanism in Kubernetes that is responsible for allocating physical resources, such as memory and CPU cores, to the container being launched. In simple terms, requests in Kubernetes are the minimum system requirements for an application to function properly.
Limits are a mechanism in Kubernetes that limits the physical resources (memory and CPU cores) allocated to the container being launched. In other words, limits in Kubernetes are the maximum values for physical resources, ensuring that the launched application cannot consume more resources than specified in the limits. The container can only use resources up to the limit specified in the Limits.
The request and limit mechanisms apply only to objects of type pod and are defined in the pod configuration files, including deployment, StatefulSet, and ReplicaSet files.
Requests are added in the containers block using the resources
parameter. In the resources section, you need to add the requests block, which consists of two values: cpu
(CPU resource request) and memory
(memory resource request). The syntax for requests is as follows:
containers:
...
resources:
requests:
cpu: "1.0"
memory: "150Mi"
In this example, for the container to be launched on a selected node in the cluster, at least one free CPU core and 150 megabytes of memory must be available.
Limits are set in the same way. For example:
containers:
...
resources:
limits:
cpu: "2.0"
memory: "500Mi"
In this example, the container cannot use more than two CPU cores and no more than 500 megabytes of memory.
The units of measurement for requests and limits are as follows:
For CPU resources, cores are used. For example, if we need to allocate one physical CPU core to a container, the manifest should specify 1.0. To allocate half a core, specify 0.5. A core can be logically divided into millicores, so you can allocate, for example, 100m, which means one-thousandth of a core (1 full CPU core contains 1000 millicores).
For RAM, we specify values in bytes. You can use numbers with the suffixes E, P, T, G, M, k. For example, if a container needs to be allocated 1 gigabyte of memory, you should specify 1G. In megabytes, it would be 1024M, in kilobytes, it would be 1048576k, and so on.
The requests and limits parameters are optional; however, it is important to note that if both parameters are not set, the container will be able to run on any available node in the cluster regardless of the free resources and will consume as many resources as are physically available on each node. Essentially, the cluster will allocate excess resources. This practice can negatively affect the stability of the entire cluster, as it significantly increases the risk of errors such as OOM (Out of Memory) and OutOfCPU (lack of CPU resources). To prevent these errors, Kubernetes introduced the request and limit mechanisms.
Let's look at the practical use of requests and limits. First, we will deploy a deployment file with an Nginx image where we will set only the requests.
In the configuration below, to launch a pod with a container, the node must have at least 100 millicores of CPU (1/1000 of a CPU core) and 150 megabytes of free memory:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-test-deployment
namespace: ns-for-nginx
labels:
app: nginx-test
spec:
selector:
matchLabels:
app: nginx-test
template:
metadata:
labels:
app: nginx-test
spec:
containers:
- name: nginx-test
image: nginx:1.25
resources:
requests:
cpu: "100m"
memory: "150Mi"
Before deploying the deployment, let's create a new namespace named ns-for-nginx
:
kubectl create ns ns-for-nginx
After creating the namespace, we will deploy the deployment file using the following command:
kubectl apply -f nginx-test-deployment.yml
Now, let's check if the deployment was successfully created:
kubectl get deployments -A
Also, check the status of the pod:
kubectl get po -n ns-for-nginx
The deployment file and the pod have been successfully launched. To ensure that the minimum resource request was set for the Nginx pod, we will use the kubectl describe pod
command (where nginx-test-deployment-786d6fcb57-7kddf
is the name of the running pod):
kubectl describe pod nginx-test-deployment-786d6fcb57-7kddf -n ns-for-nginx
In the output of this command, you can find the requests
block, which contains the previously set minimum requirements for our container to run:
In the example above, we created a deployment that sets only the minimum required resources for deployment. Now, let's add limits for the container to run with 1 full CPU core and 1 gigabyte of RAM by creating a new deployment file:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-test-deployment-2
namespace: ns-for-nginx
labels:
app: nginx-test2
spec:
selector:
matchLabels:
app: nginx-test2
template:
metadata:
labels:
app: nginx-test2
spec:
containers:
- name: nginx-test2
image: nginx:1.25
resources:
requests:
cpu: "100m"
memory: "150Mi"
limits:
cpu: "1.0"
memory: "1G"
Let's create the deployment in the cluster:
kubectl apply -f nginx-test-deployment2.yml
Using the kubectl describe
command, let's verify that both requests and limits have been applied (where nginx-test-deployment-2-6d5df6c95c-brw8n
is the name of the pod):
kubectl describe pod nginx-test-deployment-2-6d5df6c95c-brw8n -n ns-for-nginx
In the screenshot above, both requests and limits have been set for the container. With these quotas, the container will be scheduled on a node with at least 150 megabytes of RAM and 100 milli-CPU. At the same time, the container will not be allowed to consume more than 1 gigabyte of RAM and 1 CPU core.
In addition to manually assigning resources for each container, Kubernetes provides a way to allocate quotas to specific namespaces in the cluster. The ResourceQuota mechanism allows setting resource usage limits within a particular namespace. ResourceQuota is intended to limit resources such as CPU and memory.
The practical use of ResourceQuota looks like this:
Create a new namespace with quota settings:
kubectl create ns ns-for-resource-quota
Create a ResourceQuota object:
apiVersion: v1
kind: ResourceQuota
metadata:
name: resource-quota-test
namespace: ns-for-resource-quota
spec:
hard:
pods: "2"
requests.cpu: "0.5"
requests.memory: "800Mi"
limits.cpu: "1"
limits.memory: "1G"
In this example, for all objects created in the ns-for-resource-quota
namespace, the following limits will apply:
Apply the configuration file:
kubectl apply -f test-resource-quota.yaml
Check the properties of the ResourceQuota object:
kubectl get resourcequota resource-quota-test -n ns-for-resource-quota
As you can see, resource quotas have been set.
Also, verify the output of the kubectl describe ns
command:
kubectl describe ns ns-for-resource-quota
The previously created namespace ns-for-resource-quota
will have the corresponding resource quotas.
Example of an Nginx pod with the following configuration:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-with-quota
namespace: ns-for-resource-quota
labels:
app: nginx-with-quota
spec:
selector:
matchLabels:
app: nginx-with-quota
replicas: 3
template:
metadata:
labels:
app: nginx-with-quota
spec:
containers:
- name: nginx
image: nginx:1.22.1
resources:
requests:
cpu: 100m
memory: 100Mi
limits:
cpu: 100m
memory: 100Mi
Here we define 3 replicas of the Nginx pod to test the quota mechanism. We also set minimum resource requests for the containers and apply limits to ensure the containers don't exceed the defined resources.
kubectl apply -f nginx-deployment-with-quota.yaml
kubectl get all -n ns-for-resource-quota
As a result, only two of the three replicas of the pod will be successfully created. The deployment will show an error message indicating that the resource quota for pod creation has been exceeded (in this case, we're trying to create more pods than allowed):
However, the remaining two Nginx pods were successfully started:
Requests and limits are critical mechanisms in Kubernetes that allow for flexible resource allocation and control within the cluster, preventing unexpected errors in running applications and ensuring the stability of the cluster itself.
We offer an affordable Kubernetes hosting platform, with transparent and scalable pricing for all workloads.