Kubernetes: Investigate Excessive CPU Usage in a StatefulSet via ResourceQuotas

Kubernetes: Investigating Excessive CPU Usage in a StatefulSet via ResourceQuotas

Kubernetes: Investigating Excessive CPU Usage in a StatefulSet via ResourceQuotas

This tutorial focuses on identifying and mitigating excessive CPU usage within a Kubernetes StatefulSet, utilizing ResourceQuotas for granular control. We’ll walk through a practical scenario, examining common causes and employing diagnostic tools to pinpoint the issue and implement solutions.

Scenario: Excessive CPU Usage in a Database StatefulSet

We’ll simulate a scenario where a PostgreSQL StatefulSet running in a Kubernetes cluster is consistently consuming excessive CPU resources. This can be due to various factors, including resource constraints, inefficient queries, or application-level issues. Our goal is to use ResourceQuotas to limit the resources available to the StatefulSet and then investigate the logs and metrics to determine the cause.

Example 1: Initial Setup and ResourceQuota Creation

First, let’s create a basic PostgreSQL StatefulSet and then introduce a ResourceQuota to limit its CPU resources.


apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgresql-statefulset
spec:
  serviceName: postgresql-service
  replicas: 3
  selector:
    matchLabels:
      app: postgresql
  template:
    metadata:
      labels:
        app: postgresql
    spec:
      containers:
      - name: postgresql
        image: postgres:15
        resources:
          requests:
            cpu: "100m"
          limits:
            cpu: "500m"
---
apiVersion: v1
kind: Service
metadata:
  name: postgresql-service
spec:
  selector:
    app: postgresql
  ports:
  - protocol: TCP
    port: 5432
    targetPort: 5432
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: postgresql-reader
  namespace: default
rules:
- apiGroups: [""]
  verbs: ["get", "list"]
  resources: ["pods"]
- apiGroups: [""]
  verbs: ["get", "list"]
  resources: ["services"]
- apiGroups: [""]
  verbs: ["get", "list"]
  resources: ["configmaps"]

kubectl apply -f statefulset_with_resourcequota.yaml

This creates a PostgreSQL StatefulSet with three replicas, each requesting 100m of CPU and having a limit of 500m. We also create a service and a minimal Role for basic access.

Example 2: Introducing a ResourceQuota and Monitoring CPU Usage

Now, let’s introduce a ResourceQuota to limit the total CPU resources the StatefulSet can consume. We'll then monitor CPU usage to see the effect.


apiVersion: v1
kind: ResourceQuota
metadata:
  name: postgresql-quota
  namespace: default
spec:
  hard:
    cpu: "1"

kubectl apply -f resourcequota.yaml

This creates a ResourceQuota named `postgresql-quota` in the `default` namespace, limiting the total CPU resources to 1. This will severely constrain the StatefulSet's resource consumption.

kubectl describe resourcequota postgresql-quota

Observe the output. Pay attention to the `Used` field. This shows how much CPU the StatefulSet has actually consumed. If the `Used` value is significantly exceeding the `hard` limit of 1, it indicates a problem with the StatefulSet’s workload or configuration.

kubectl top pods --all-namespaces | grep postgresql

This command displays the CPU usage of all pods in all namespaces. Examine the output for pods labeled with "app: postgresql" to see the actual CPU consumption. If the CPU usage is consistently high, it confirms the issue.

Example 3: Investigating Logs and Correcting the Problem (Simulated)

Let's assume that after monitoring, you discover that the excessive CPU usage is due to a poorly optimized PostgreSQL query that's running repeatedly. We'll simulate this by adding a delay to a query to artificially increase CPU usage.


# Simulate a slow query by introducing a delay in the postgresql container's command.
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgresql-statefulset
spec:
  serviceName: postgresql-service
  replicas: 3
  selector:
    matchLabels:
      app: postgresql
  template:
    metadata:
      labels:
        app: postgresql
    spec:
      containers:
      - name: postgresql
        image: postgres:15
        command: ["/usr/bin/pg_activity"]
        args: ["-c","SELECT sleep(5)"] # Introducing a 5-second sleep

kubectl apply -f statefulset_with_slow_query.yaml

Now, run kubectl top pods --all-namespaces | grep postgresql again. You should see the CPU usage of the PostgreSQL pods significantly increased due to the delayed query. The ResourceQuota will limit the overall CPU consumption, preventing the StatefulSet from exceeding its allocated limit.

To resolve the issue, you'd then optimize the PostgreSQL query to remove the unnecessary delay. Alternatively, you could adjust the ResourceQuota limit if the query is a legitimate workload requiring more CPU.

Leave a Reply

Your email address will not be published. Required fields are marked *

We use cookies and similar technologies to enhance your experience on wobizdu.com, analyze site traffic, personalize content, and deliver relevant ads. Some cookies are essential for the site to function, while others help us improve performance and user experience. You may accept all cookies, decline optional ones, or customize your settings. Review our Privacy Policy to learn more.