ALL THINGS KUBERNETES

Managing Memory and CPU Resources for Kubernetes Namespaces

From the previous tutorials, you already know that Kubernetes allows specifying CPU and RAM requests and limits for containers running in a pod, a feature that is very useful for the management of resource consumption by individual pods.

However, if you are a Kubernetes cluster administrator, you might also want to control global consumption of resources in your cluster and/or configure default resource requirements for all containers.

Fortunately, Kubernetes supports cluster resource management at the namespace level. As you might already know, Kubernetes namespaces provide scopes for names and resource quota, which allow efficiently dividing cluster resources between multiple users, projects, and teams. In Kubernetes, you can define default resource request and limits, resource constraints (minimum and maximum resource requests and limits), and resource quota for all containers running in a given namespace. These features enable efficient resource utilization by applications in your cluster and help divide resources productively between different teams. For example, using resource constraints for the namespaces allows you to control how resources are used by your production and development workloads, allowing them to consume their fair share of the limited cluster resources. This can be achieved by creating separate namespaces for production and development workloads and assigning different resource constraints to them.

In this tutorial, we show your three strategies for the efficient management of your cluster resources: setting default resource requests and limits for containers, defining minimum and maximum resource constraints, and setting resource quotas for all containers in the namespace. These strategies will help you address a wide variety of use cases leveraging the full power of Kubernetes namespaces and resource management.

Tutorial

To complete examples in this tutorial, you’ll need the following prerequisites:

  • A running Kubernetes cluster. See Supergiant GitHub wiki for more information about deploying a Kubernetes cluster with Supergiant. As an alternative, you can install a single-node Kubernetes cluster on a local system using Minikube.
  • A kubectl command line tool installed and configured to communicate with the cluster. See how to install kubectl here.

Example #1: Defining Default Resource Requests and Limits for Containers in a Namespace

In this example, we’re going to define default requests and limits for containers in your namespace. These default values will be automatically applied to containers that do not specify their custom resource requests and limits. In this way, default resource requests and limits can impose binding resource usage policy for containers in your namespace.

As you already know, default resource requests and limits are defined at the namespace level, so we need to create a new namespace:

Default values for resource requests and limits for a namespace must be defined in a LimitRange  object. We chose to use the following spec:

The spec.limits.default  field of this spec sets default resource limits and the spec.limits.defaultRequest  field sets the default requests for the containers running in our namespace.

Save this spec in the limit-range-1.yaml  file and create the LimitRange  running the following command:

Now, if we create a pod in the default-resources-config  namespace and omit memory or CPU requests and limits for its container, it will be assigned the default values defined for the LimitRange  above. Let’s create a pod to see how this works:

Let’s save thispPod spec in the default-resources-demo-pod.yaml  and create a pod in our namespace:

As you see, the Apache HTTP server container in the pod has no resource requests and limits. However, since we have specified default namespace resources, they will be assigned to the container automatically.

As you see in the output below, the default resource requests and limits were automatically applied to our container:

It’s as simple as that!

However, what happens if we specify only requests or limits but not both? Let’s create a new pod with only resource limits specified to check this:

Let’s save this spec in default-resources-demo-pod-2.yaml  and create the pod in our namespace:

Now, check the container resources assigned:

The response should be:

As you see, Kubernetes automatically set resource requests to match the limits specified by the container. Please pay attention to the fact that these values are applied even though the container did not initially specify resource requests.

Next, let’s see what happens if memory and CPU requests are specified and resource limits are omitted. Create a spec for the third pod:

Let’s save the spec in the default-resources-demo-pod-3.yaml  and create the pod in our namespace:

After the pod has been created, check the container resources assigned:

You should get the following output in your terminal:

As you see, the container was assigned the default limits and resource requests specified above.

Note: if the container’s memory and CPU requests are greater than the default resource limits, the pod won’t be created.

Cleaning Up

Let’s clean up after this example is completed.

Delete the namespace:

Example #2 : Setting Min and Max Resource Constraints for the Namespace

In this example, we’re going to create resource constraints for the namespace. These constraints are essentially minimum and maximum resource amounts which containers can use in their resource requests and limits. Let’s see how it works!

As in the previous example, create a namespace first:

Next, you are going to create a LimitRange for this namespace:

Save this LimitRange in the limit-range-2.yaml  and create it:

After the LimitRange was created, let’s see if our minimum and maximum resource constraints were applied to the namespace:

The response should be:

As you see, the default resource requests and limits for your namespace were automatically set equal to the max resource constraint specified in the LimitRange . Now, when we create containers in the resource-constraints-demo  namespace, the following rules automatically apply:

  • If the container does not specify its resource request and limit, the default resource request and limit are applied.
  • All containers in the namespace need to have resource requests greater than or equal to 300m for CPU and 500 Mi for memory.
  • All containers in the namespace need to have resource limits less than or equal to 800m for CPU and 1Gi for memory.

Let’s create a pod to illustrate how namespace resource constraints are applied to containers:

This spec requests 600Mi of RAM and 0.4 CPU and sets a limit of 900Mi RAM and 0.7 CPU for the httpd  container within this pod. These resource requirements meet the minimum and maximum constraints for the namespace.

Let’s save this spec in the resource-constraints-pod.yaml  and create the pod in our namespace:

Next, check the resources assigned to the container in the pod:

You should get the following output:

That’s it! The pod was successfully created because the container’s request and limit are within the minimum and maximum constraints for the namespace.

Now, let’s see what happens if we specify requests and limits beyond the minimum and maximum values defined for the namespace. Let’s create a new pod with new requests and limits:

Save this spec in the resource-constraints-pod-2.yaml  and create the pod in our namespace:

Since resource requests are below the minimum LimitRange  value and resource limits are above the maximum values for this namespace, the pod won’t be created as expected:

Cleaning Up

This example is over, so let’s delete the namespace with all associated pods and other resources:

Example # 3: Setting Memory and CPU Quotas for a Namespace

In the previous example, we set resource constraints for individual containers running within a namespace. However, it is also possible to restrict the resource request and limits total for all containers running in a namespace. This can be easily achieved with a ResourceQuota  resource object defined for the namespace.

To illustrate how resource quotas work, let’s first create a new namespace so that resources created in this exercise are isolated from the rest of your cluster:

Next, let’s create a ResourceQuota object with resources quotas for our namespace:

This ResourceQuota  sets the following requirements for the namespace:

  • ResouceQuota  imposes the requirement for each container to define its memory and CPU requests and limits.
  • The memory request total for all containers must not exceed 2Gi.
  • The CPU request total for all containers in the namespace should not exceed 1.4 CPU.
  • The memory limit total for all containers in the namespace should not exceed 3Gi.
  • The CPU limit total for all containers in the namespace should not exceed 2 CPU.

Save this spec in the resource-quota.yaml  and create the ResourceQuota  running the following command:

The ResouceQuota  object was created in our namespace and is ready to control total requests and limits by all containers in that namespace. Let’s see the ResourceQuota description:

The response should be:

This output shows that no memory and CPU have been yet consumed in the namespace. Let’s create two pods to change this situation.

The first pod will request 1.3Gi of RAM and 0.8 CPU and have a resource limit of 1.2 CPU and 2Gi of RAM.

Save this spec in the resource-quota-pod-1.yaml  and create the pod in our namespace:

The pod was successfully created because the container’s requests and limits are within the resource quota set for the namespace. Let’s verify this by checking the current amount of used resources in the ResourceQuota  object:

The response should be:

As you see, the first pod has consumed some of the resources available in the ResourceQuota. Let’s create another pod to increase the consumption of available resources even further:

Save this spec in the resource-quota-pod-2.yaml  and create the pod:

Running this command will cause the following error:

As you see, Kubernetes does not allow us to create this pod because the container’s CPU and RAM requests and limits exceed the ResourceQuota  requirements for this namespace.

Cleaning Up

This example is completed, so let’s clean up:

Delete the namespace:

Conclusion

That’s it! We have discussed how to set default resource requests and limits, and how to create resource constraints and resource quotas for containers in Kubernetes namespaces.

As you’ve seen, by setting default requests and limits for containers in your namespace, you can impose namespace-wide resource policies automatically applicable to all containers without manually specified resource requests and limits.

In addition, you learned how to use resource constraints to impose limitations on the quantity of resources consumed by containers in your namespace. This feature facilitates the efficient management of resources by different application classes and teams and ensures constant availability of free resources in your cluster. The same effect (but at a larger scale) can be achieved by resource quotas which allow defining resource constraints for the total consumption of resources by all containers in the namespace.

 

Subscribe to our newsletter