How to Optimize Resource Allocation in Kubernetes Pods

Updated: January 30, 2024 By: Guest Contributor Post a comment

Introduction

When working with Kubernetes, orchestrating containers efficiently is critical for the performance and reliability of your applications. This tutorial covers how to optimize resource allocation in Kubernetes pods, ensuring that your clusters run smoothly without wasting resources.

Understanding Resources in Kubernetes

Before we dive into optimization, it’s important to understand Kubernetes’ resource types:

  • CPU – measured in CPU units. In Kubernetes, 1 CPU is equivalent to 1 vCPU/Core for cloud providers and 1 hyperthread for bare-metal Intel processors.
  • Memory – specified in bytes. Kubernetes understands the suffixes like MiB, GiB for mebibyte and gibibyte, respectively.

Resources can be specified for each container in the pod. When declaring resources, you can set ‘requests’ and ‘limits’:

  • Requests: This is the amount of resource Kubernetes will guarantee for the container. If your container tries to use more than the requested amount, it might be throttled, but never killed.
  • Limits: This is the maximum amount of resource the container is allowed to use. If the container exceeds this limit, it may be terminated.

Basic Resource Allocation

apiVersion: v1
kind: Pod
metadata:
  name: basic-allocation-pod
spec:
  containers:
  - name: simple-container
    image: nginx
    resources:
      requests:
        memory: "256Mi"
        cpu: "0.5"
      limits:
        memory: "512Mi"
        cpu: "1"

The above manifest defines a basic pod with an Nginx container. It sets requests and limits for CPU and memory. ‘0.5’ CPU here signifies half a CPU core, while ‘512Mi’ is 512 mebibytes of RAM.

Quality of Service Classes

Kubernetes assigns a Quality of Service (QoS) class to each pod which has implications on the scheduling and eviction of pods:

  • Guaranteed: Every container in the pod must have memory and CPU limits, and they must equal the requests.
  • Burstable: The pod will receive requests and limits, but they don’t need to match.
  • BestEffort: The pod does not have any requests or limits.

Advance Resource Allocation: Overcommitting

Overcommitting resources means allocating more resources to the pods than are actually available on the node. It can be beneficial if your containers do not always use the full amount of requested resources.

apiVersion: v1
kind: Pod
metadata:
  name: overcommit-pod
spec:
  containers:
  - name: busy-container
    image: ubuntu
    command: ["/bin/sh"]
    args: ["-c", "while true; do echo hello; sleep 10;done"]
    resources:
      requests:
        cpu: "0.5"

This pod has a request set, but no limit, making it ‘Burstable’. Because it’s requesting half a CPU, Kubernetes will try to schedule it on a node that can guarantee this.

Managing Node Resources with Resource Quota

Resource quotas are a way to manage cluster resources. They limit the amount of resources a namespace can consume:

apiVersion: v1
kind: ResourceQuota
metadata:
  name: example-quota
spec:
  hard:
    requests.cpu: "400m"
    requests.memory: 1Gi
    limits.cpu: "600m"
    limits.memory: 2Gi

Monitoring and Autoscaling Pods

Deploying metrics-server in your cluster can provide resource utilization data, enabling Horizontal Pod Autoscaler (HPA) to automatically adjust the number of pod replicas based on CPU utilization.

apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  name: nginx-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: nginx-deployment
  minReplicas: 1
  maxReplicas: 10
  targetCPUUtilizationPercentage: 50

This HPA configuration adjusts the number of replicas of ‘nginx-deployment’ between 1 and 10 to maintain an average CPU utilization across all pods at 50%.

Using Node Affinity for Optimal Allocation

Node affinity can constrain which nodes your pod is eligible to be scheduled on, based on labels:

apiVersion: v1
kind: Pod
metadata:
  name: with-node-affinity
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: disktype
            operator: In
            values:
            - ssd
  containers:
  - name: with-affinity
    image: nginx

The above pod will only be placed on nodes with the ‘ssd’ label under ‘disktype’.

Conclusion

Optimizing resource allocation within your Kubernetes pods is crucial for maximizing resource utilization and for ensuring the stability of the applications. By using techniques like setting appropriate requests and limits, understanding QoS classes, overcommitting with caution, enforcing quotas, autoscaling, and using node affinities, you can fine-tune your resources to achieve better performance and minimize costs.