Skip to content
Techsense Developers
TrustLet's Talk
Insights
Cloud & Infrastructure8 min readAug 29, 2026

FinOps on Kubernetes: How to Cut Cloud Costs Without Throttling Performance

If you want to reduce your Kubernetes bill without slowing down your applications, the answer is disciplined kubernetes finops: measure actual resource consumption, right-size requests and limits…

If you want to reduce your Kubernetes bill without slowing down your applications, the answer is disciplined kubernetes finops: measure actual resource consumption, right-size requests and limits against that data, use autoscaling and spot capacity for elastic workloads, and set guardrails so cost decisions never silently degrade latency or availability. The mistake teams make is treating cost and performance as a single dial. They are two separate signals. Once you instrument both and tie changes to evidence, you can cut spend by trimming waste rather than starving your services.

This post walks through how I approach it in production: where the money actually goes, how to find idle capacity, and which levers move cost without introducing risk.

Why Kubernetes Bills Balloon

Kubernetes makes it easy to allocate capacity and hard to see who is actually using it. The cluster runs, the nodes are billed by your cloud provider, and the money leaks in the gap between what you requested and what your pods consumed.

The usual culprits:

  • Over-provisioned requests. Engineers copy a resources block from another service, pad it "to be safe," and the scheduler reserves that capacity whether or not the pod uses it.
  • No limits, or wildly high limits. Without limits, a noisy neighbor can consume a whole node. With limits set too high, you never get bin-packing efficiency.
  • Static node pools. Fixed-size clusters pay for peak capacity 24/7 even when traffic is nightly-batch-only.
  • Orphaned resources. Unattached persistent volumes, idle load balancers, and abandoned namespaces keep billing after the workload is gone.
  • On-demand for everything. Fault-tolerant batch jobs run on full-price instances when spot or preemptible capacity would cut the compute line item substantially.

The core problem is allocation vs. utilization. You pay for allocation. You get value from utilization. FinOps closes that gap.

Step 1: Make Cost Visible Before You Cut Anything

You cannot optimize what you cannot attribute. Start by mapping spend to teams, namespaces, and workloads.

Enforce labels on everything so cost can be sliced by owner:

metadata:
  labels:
    app: checkout-api
    team: payments
    environment: production
    cost-center: cc-4821

Open-source tools like OpenCost give you per-namespace and per-workload cost breakdowns from real usage, and the CNCF hosts the project as a vendor-neutral standard for Kubernetes cost monitoring. Whatever tool you choose, the goal is the same: a dashboard where a team lead can see their monthly spend and the utilization behind it.

Pull the two numbers that matter for every workload:

  1. Requested CPU and memory (what you pay the scheduler to reserve).
  2. Actual CPU and memory over a representative window (P50, P95, P99).

A quick way to eyeball request efficiency across the cluster:

kubectl get pods --all-namespaces \
  -o custom-columns='NS:.metadata.namespace,POD:.metadata.name,CPU_REQ:.spec.containers[*].resources.requests.cpu,MEM_REQ:.spec.containers[*].resources.requests.memory'

Pair that with kubectl top pods or your metrics backend to compare requests against consumption. Any workload requesting 2 cores while peaking at 300m is a candidate.

Step 2: Right-Size Requests and Limits With Data

Right-sizing is the single highest-leverage move in kubernetes cost optimization, because requests directly drive how many nodes you need.

The principle: set requests near your steady-state P95 usage, and set limits to protect the node from runaway containers. Do not set requests at peak; that reserves capacity you rarely use.

Use the Vertical Pod Autoscaler (VPA) in recommendation mode to generate data-backed targets without automatically mutating pods:

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: checkout-api-vpa
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: checkout-api
  updatePolicy:
    updateMode: "Off"   # recommend only, no live changes

Read the recommendations, apply them through your normal deploy pipeline, and watch latency dashboards after each change.

A few rules I hold to:

  • CPU limits are usually a trap for latency-sensitive services. CPU is compressible; when a pod hits its CPU limit it gets throttled, which shows up as tail-latency spikes. For user-facing APIs, set a CPU request and often no CPU limit, then rely on requests plus node capacity planning.
  • Memory limits are mandatory. Memory is not compressible. A pod over its memory limit gets OOM-killed. Set memory requests and limits close together for predictable behavior.
  • Change one thing at a time and let the service run through a full traffic cycle before the next adjustment.

Step 3: Scale With Demand, Not With Fear

Autoscaling is how you avoid paying for peak capacity during off-peak hours.

Horizontal Pod Autoscaler

The HPA adds and removes pod replicas based on a metric. CPU is the default, but custom or external metrics (queue depth, requests per second) often correlate better with real load.

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: checkout-api-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: checkout-api
  minReplicas: 3
  maxReplicas: 30
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70

Keep minReplicas high enough to absorb a sudden burst while your scale-up completes. That headroom is a performance decision, not waste.

Cluster and Node Autoscaling

Pods scaling is pointless if nodes cannot follow. Use the Cluster Autoscaler, or a faster provisioner like Karpenter on AWS, to add and remove nodes based on pending pods. This is what lets you drop idle nodes overnight instead of paying for a static fleet.

KEDA for Event-Driven Workloads

For consumers tied to queues or streams, KEDA scales on backlog and can scale to zero when there is no work. Batch and async pipelines that idle most of the day are ideal candidates.

Step 4: Buy Compute Smarter

Once utilization is healthy, attack the unit price of compute itself. This is where k8s cost management meets cloud purchasing.

  • Spot / preemptible instances for fault-tolerant, stateless, or retryable work. Isolate them in a dedicated node pool and use taints plus tolerations so only interruption-tolerant pods land there.
  • Committed-use discounts (Savings Plans, Reserved Instances, CUDs) for your steady baseline. Cover the floor with commitments and let autoscaling handle the variable top on on-demand or spot.
  • Right node shapes. Match instance families to workload profile. Memory-heavy services on compute-optimized nodes waste RAM you still pay for.

Steer workloads with taints and tolerations:

tolerations:
  - key: "capacity-type"
    operator: "Equal"
    value: "spot"
    effect: "NoSchedule"
nodeSelector:
  capacity-type: spot

Always pair spot with a PodDisruptionBudget so an interruption cannot take down too many replicas at once:

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: checkout-api-pdb
spec:
  minAvailable: 2
  selector:
    matchLabels:
      app: checkout-api

Step 5: Guardrails So Cost Cuts Never Throttle Performance

Container cost reduction goes wrong when nobody notices the SLO regression until customers do. Wire the safeguards in from the start.

  • Set SLOs first. Define your latency and error budgets, then treat any cost change that burns budget as a failed change to roll back.
  • Alert on throttling. Track container_cpu_cfs_throttled_periods_total and OOM-kill counts. Rising throttling after a right-sizing pass means you cut too far.
  • Use LimitRanges and ResourceQuotas to keep teams inside sane bounds without central bottlenecks.
  • Load-test before promoting any request reduction to production.
  • Make cost a review metric, not a one-time cleanup. Bills drift back up the moment attention leaves.

If you want a partner to stand up this instrumentation and the automation around it, our cloud and infrastructure capabilities cover exactly this kind of production tuning. Cost pressures also vary sharply by sector, and our industries work reflects the different reliability and compliance constraints that shape how aggressively you can push spot and autoscaling.

A Practical Order of Operations

  1. Instrument cost and utilization. Enforce labels.
  2. Right-size requests to P95 with VPA recommendations.
  3. Add HPA and cluster autoscaling for elasticity.
  4. Move tolerant workloads to spot; cover baseline with commitments.
  5. Lock in SLO alerts and throttling monitors.
  6. Review monthly and repeat.

Done in that order, most teams find meaningful savings in the first two steps alone, because over-provisioned requests are almost universal. The later steps compound the gain without adding operational risk.

FAQ

What is Kubernetes FinOps?

Kubernetes FinOps is the practice of managing and optimizing cloud spend for Kubernetes workloads by connecting engineering decisions to cost data. It combines cost visibility, right-sizing, autoscaling, and smart compute purchasing, with performance guardrails so savings do not degrade service reliability.

Will right-sizing my pods hurt performance?

Only if you cut below actual demand. Set requests near your P95 usage rather than peak, keep memory requests and limits close, and be cautious with CPU limits on latency-sensitive services since CPU throttling causes tail-latency spikes. Monitor CFS throttling and OOM kills after every change.

Are spot instances safe for production Kubernetes?

They are safe for interruption-tolerant workloads: stateless services, batch jobs, and anything that can be rescheduled. Isolate spot capacity in a dedicated node pool, use taints and tolerations to control placement, and protect availability with PodDisruptionBudgets. Keep stateful or single-replica critical workloads on on-demand or committed capacity.

What tools should I start with for Kubernetes cost management?

Begin with a cost visibility tool such as OpenCost, plus your existing metrics stack for utilization. Add the Vertical Pod Autoscaler in recommendation mode for right-sizing, the Horizontal Pod Autoscaler and Cluster Autoscaler (or Karpenter on AWS) for elasticity, and KEDA for event-driven scale-to-zero workloads.

How often should we revisit cost optimization?

Treat it as continuous, not a one-off. Review spend and utilization monthly, and re-run right-sizing whenever a workload's traffic profile changes. Bills drift upward as new services ship, so recurring review is what keeps the savings in place.

Production-grade cloud, software, and engineering teams for scaling companies.