Back to all blogs
Cloud & DevOpsJuly 26, 20269 min read

Kubernetes Cost Optimization: How to Cut Cloud Spend by 60% Without Touching Your Application Code

Most engineering teams overpay for Kubernetes by 40–70% without realizing it. This deep-dive shows you the exact infrastructure patterns, tooling, and scheduling strategies to reclaim that spend — without a single line of app-level change.

L
Lucas Bennett
UI/UX Design Director
Kubernetes Cost Optimization: How to Cut Cloud Spend by 60% Without Touching Your Application Code
TL;DR Quick Answer: Kubernetes cost optimization is the practice of right-sizing workloads, eliminating idle capacity, leveraging spot/preemptible instances, and using intelligent autoscalers (Karpenter, VPA, KEDA) to reduce cloud infrastructure spend by 40–60% — without modifying your application code. The biggest wins come from fixing resource requests, adopting bin-packing schedulers, and killing zombie workloads that silently drain budgets.

The Silent Budget Drain Inside Every Kubernetes Cluster

If your team runs production workloads on Kubernetes, there is a near-certainty you are overpaying. Kubernetes cost optimization is not a niche concern reserved for hyper-scale companies — it is a survival skill for any engineering team that wants to stay profitable as it grows. Studies from CNCF and Datadog's State of Cloud Costs report consistently show that the average Kubernetes cluster runs at only 13–20% actual CPU utilization against provisioned capacity. That means for every $100,000 you spend on cloud compute, roughly $80,000 is buying you headroom you never use.

At Apargo, we have audited dozens of production clusters for clients across SaaS, fintech, and e-commerce verticals. The pattern is almost always the same: over-requested resources, static node pools, and no meaningful autoscaling strategy. In this article, we break down every lever available to you — with real configuration examples — to slash that bill without touching a single line of application code.

Why Kubernetes Cost Optimization Is Structurally Hard

Before diving into solutions, it is worth understanding why clusters become expensive in the first place. Kubernetes was designed for reliability and availability — not cost efficiency. Its default scheduling behavior is conservative, and most teams inherit configurations that prioritize "never go down" over "never overspend."

The Four Root Causes of Kubernetes Overspend

  • Inflated resource requests: Developers set CPU/memory requests based on peak load or fear, not actual profiling. A service that uses 100m CPU at p99 often has a 1000m request.
  • Static node pools: Fixed node groups provisioned for peak traffic sit idle 80% of the time, especially for batch or overnight workloads.
  • Namespace sprawl and zombie workloads: Old staging environments, forgotten cronjobs, and abandoned deployments quietly consume resources across namespaces.
  • No bin-packing awareness: Default Kubernetes scheduling spreads pods across nodes for reliability, leaving many nodes at 30–40% utilization — not enough to scale down, too little to justify the cost.

Strategy 1 — Right-Sizing Resource Requests with VPA

The single highest-ROI action in any Kubernetes cost optimization effort is fixing resource requests. The Vertical Pod Autoscaler (VPA) from the Kubernetes autoscaler project can profile your workloads and recommend — or automatically apply — accurate CPU and memory requests based on real usage data.

Install VPA in recommendation-only mode first to avoid disrupting running pods:

# Install VPA components (recommendation mode only)
kubectl apply -f https://github.com/kubernetes/autoscaler/releases/latest/download/vertical-pod-autoscaler.yaml

# VPA object for a sample API deployment
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: api-service-vpa
  namespace: production
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api-service
  updatePolicy:
    updateMode: "Off"   # Recommendation only — safe for production audit
  resourcePolicy:
    containerPolicies:
      - containerName: api
        minAllowed:
          cpu: 50m
          memory: 64Mi
        maxAllowed:
          cpu: 2
          memory: 2Gi
        controlledResources: ["cpu", "memory"]

After 24–48 hours, query VPA recommendations:

# Fetch VPA recommendations for all objects in namespace
kubectl get vpa -n production -o json | \
  jq '.items[] | {name: .metadata.name, recommendations: .status.recommendation}'

In our client audits, applying VPA recommendations alone has reduced cluster node count by 25–35%, translating directly to proportional cost savings. One SaaS platform we worked with dropped from 42 nodes to 27 nodes within two weeks of applying right-sized requests — a $14,000/month reduction with zero application changes.

Strategy 2 — Replace Cluster Autoscaler with Karpenter

The traditional Kubernetes Cluster Autoscaler works well but has a fundamental limitation: it scales within predefined node groups. Karpenter, the open-source node provisioner from AWS, takes a radically different approach — it provisions the exact instance type that fits pending pods, rather than scaling a pre-configured group.

Why Karpenter Wins on Cost

  • Provisions nodes in under 60 seconds vs. 3–5 minutes for Cluster Autoscaler
  • Selects the cheapest compatible instance type automatically across families (m5, m6i, m6a, etc.)
  • Consolidates underutilized nodes aggressively via Disruption Budgets
  • Natively supports mixed spot/on-demand provisioning per workload priority
# Karpenter NodePool — cost-optimized with spot preference
apiVersion: karpenter.sh/v1beta1
kind: NodePool
metadata:
  name: cost-optimized-pool
spec:
  template:
    metadata:
      labels:
        billing-team: platform
    spec:
      requirements:
        - key: karpenter.sh/capacity-type
          operator: In
          values: ["spot", "on-demand"]   # Spot preferred, on-demand fallback
        - key: kubernetes.io/arch
          operator: In
          values: ["amd64", "arm64"]      # ARM (Graviton) is 20% cheaper
        - key: karpenter.k8s.aws/instance-category
          operator: In
          values: ["m", "c", "r"]
        - key: karpenter.k8s.aws/instance-generation
          operator: Gt
          values: ["5"]                   # Modern generation only
      nodeClassRef:
        apiVersion: karpenter.k8s.aws/v1beta1
        kind: EC2NodeClass
        name: default
  disruption:
    consolidationPolicy: WhenUnderutilized
    consolidateAfter: 30s               # Aggressive bin-packing
  limits:
    cpu: 1000
    memory: 4000Gi

Enabling Karpenter with this configuration on a mid-sized production cluster typically yields a 20–30% additional cost reduction on top of right-sizing wins, primarily through spot instance adoption and aggressive node consolidation.

Strategy 3 — Spot Instance Architecture for Stateless Workloads

Spot instances (AWS) or preemptible VMs (GCP) offer 60–90% discount over on-demand pricing. The catch is they can be reclaimed with a 2-minute warning. For stateless, horizontally-scalable services — which describes most microservice architectures — this is an entirely acceptable tradeoff.

Engineering Spot Tolerance Into Your Deployments

The key is designing for graceful disruption. Your pods must handle SIGTERM cleanly and your deployments must have enough replicas that a single node loss is non-catastrophic:

# Deployment configured for spot tolerance
apiVersion: apps/v1
kind: Deployment
metadata:
  name: worker-service
spec:
  replicas: 6   # Never run fewer than 3 replicas on spot
  strategy:
    rollingUpdate:
      maxUnavailable: 1   # Only 1 pod can be unavailable at a time
      maxSurge: 2
  template:
    spec:
      terminationGracePeriodSeconds: 60   # Give pods 60s to drain
      topologySpreadConstraints:
        - maxSkew: 1
          topologyKey: kubernetes.io/hostname
          whenUnsatisfiable: DoNotSchedule  # Spread across nodes
          labelSelector:
            matchLabels:
              app: worker-service
      tolerations:
        - key: "karpenter.sh/capacity-type"
          operator: "Equal"
          value: "spot"
          effect: "NoSchedule"
      containers:
        - name: worker
          image: your-registry/worker-service:latest
          lifecycle:
            preStop:
              exec:
                command: ["/bin/sh", "-c", "sleep 15"]  # Drain in-flight requests

A practical split that balances cost and reliability for most production workloads: 70% spot, 30% on-demand, with critical stateful services (databases, message brokers) always on on-demand.

Strategy 4 — KEDA for Event-Driven Scale-to-Zero

Kubernetes Event-Driven Autoscaling (KEDA) lets you scale workloads based on external signals — queue depth, Kafka lag, HTTP request rate, cron schedules — and crucially, scale all the way to zero replicas when there is no work to do.

For batch processors, async workers, and scheduled jobs, scale-to-zero can eliminate 60–80% of compute cost for those workload types entirely:

# KEDA ScaledObject — scale SQS consumer to zero when queue is empty
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: sqs-worker-scaler
  namespace: production
spec:
  scaleTargetRef:
    name: sqs-worker-deployment
  minReplicaCount: 0        # True scale-to-zero
  maxReplicaCount: 50       # Burst capacity
  cooldownPeriod: 300       # 5 min cooldown before scaling down
  triggers:
    - type: aws-sqs-queue
      metadata:
        queueURL: https://sqs.us-east-1.amazonaws.com/123456789/jobs-queue
        queueLength: "5"    # 1 replica per 5 messages
        awsRegion: us-east-1
        scaleOnInFlight: "true"

Combined with Karpenter's fast node provisioning (sub-60s), KEDA scale-to-zero means your batch infrastructure costs nothing when idle — which for most teams is 14–18 hours per day.

Strategy 5 — Namespace Cost Attribution and Zombie Hunting

You cannot optimize what you cannot measure. Kubernetes cost optimization requires visibility into which teams, services, and namespaces are consuming what resources. Tools like Kubecost or OpenCost (the CNCF-donated open-source version) provide per-namespace, per-deployment cost breakdowns with 15-minute granularity.

Setting Up OpenCost for Free Cost Visibility

# Install OpenCost via Helm
helm repo add opencost https://opencost.github.io/opencost-helm-chart
helm repo update

helm install opencost opencost/opencost \
  --namespace opencost \
  --create-namespace \
  --set opencost.exporter.cloudProviderApiKey="your-aws-pricing-key" \
  --set opencost.ui.enabled=true

Once instrumented, set up automated alerts for:

  • Namespaces with zero traffic for more than 72 hours (zombie environments)
  • Deployments with CPU utilization below 5% of their request for 7+ days
  • PersistentVolumes that are unattached (orphaned storage still billed at full rate)
  • LoadBalancer services with no active endpoints (idle LB charges add up fast)

In a recent audit for an e-commerce platform, we identified 11 forgotten staging namespaces and 23 orphaned PersistentVolumes totaling $3,200/month in completely wasted spend. Cleaning those up took one afternoon.

Strategy 6 — ARM/Graviton Nodes for a Free 20% Discount

AWS Graviton3 (arm64) instances are consistently 20% cheaper than equivalent x86 instances and often 40% more energy-efficient. For containerized workloads using standard base images, migration is often as simple as building a multi-arch image and updating your NodePool selector.

# Multi-arch Docker build for ARM + x86 support
docker buildx create --use
docker buildx build \
  --platform linux/amd64,linux/arm64 \
  --tag your-registry/api-service:latest \
  --push .

Most Go, Node.js, Python, and JVM workloads run on ARM without any code changes. The Kubernetes cost optimization gain here is passive — just rebuild your images as multi-arch and let Karpenter pick Graviton nodes when they are cheaper.

Strategy 7 — LimitRanges and ResourceQuotas to Prevent Future Overspend

The best Kubernetes cost optimization is the overspend that never happens. LimitRanges enforce default and maximum resource constraints at the namespace level, preventing developers from accidentally deploying with no limits

Share this article:
Cloud & DevOpsApargo Lab

Related Articles

Explore more insights from our engineering and product teams.

View all blogs
WebSocket vs Server-Sent Events: How to Choose the Right Real-Time Protocol for Your Production Application
June 20, 2026
Web Development

WebSocket vs Server-Sent Events: How to Choose the Right Real-Time Protocol for Your Production Application

Choosing between WebSocket vs Server-Sent Events can make or break your real-time feature's performance, scalability, and cost. This deep-dive breaks down the architecture, trade-offs, and exact use cases so your engineering team ships the right solution the first time.

How to Verify Documents Online and Detect Fake, Forged, or AI-Generated Files
April 28, 2026
Engineering

How to Verify Documents Online and Detect Fake, Forged, or AI-Generated Files

Learn how to verify documents online and detect fake, forged, edited, or AI-generated files instantly with VerifyDocs. Secure, fast, and AI-powered fraud detection.

Online Document Verification: Detect Fake, Edited & AI-Generated Files Instantly
May 1, 2026
Engineering

Online Document Verification: Detect Fake, Edited & AI-Generated Files Instantly

Learn how to verify documents online and detect fake, forged, edited, or AI-generated files instantly using VerifyDocs. Fast, secure, and AI-powered.