How to Configure Karpenter Spot Instances Without Getting Burned

It’s July 2026. You probably already know Karpenter is the default autoscaler for EKS. But here’s what the blog posts won’t tell you: spot instance con...

configure karpenter spot instances without getting burned
By Nishaant Dixit
How to Configure Karpenter Spot Instances Without Getting Burned

How to Configure Karpenter Spot Instances Without Getting Burned

Stop 3AM Pages

Free K8s Audit

Get Started →
How to Configure Karpenter Spot Instances Without Getting Burned

It’s July 2026. You probably already know Karpenter is the default autoscaler for EKS. But here’s what the blog posts won’t tell you: spot instance configuration is where most people lose money before they start saving it.

I spent the last 18 months building data pipelines at SIVARO. We process 200K events/second on Kubernetes. Spot instances saved us 60% on compute. But only after we stopped treating Karpenter like a magic wand.

If you’re reading this, you already know is kubernetes used in production? is a dead question. It is. The real question is: is your Kubernetes running on spot configured to not fall apart at 3 AM?

This guide covers what I wish I knew before I lost three production clusters to a single AWS reclamation event. I’ll show you exactly how we configure Karpenter spot instances — the trade-offs, the gotchas, and the configs that actually work.


Why Most Karpenter Spot Setups Fail

Everyone starts the same way. You read the Karpenter docs, create a provisioner with "karpenter.sh/capacity-type": "spot", and watch the costs drop. But then the interruptions start.

A spot instance gets reclaimed. Karpenter launches a replacement. The pod can’t schedule because the new node doesn’t match the taints or the topology spread constraints. Or the replacement takes 90 seconds and your application times out.

Most people think the fix is more replicas. They’re wrong. The fix is understanding how Karpenter actually selects instances and how to give it choice without giving it chaos.

I’ll show you the exact provisioner configuration we use in production. But first, let me explain why you shouldn’t just copy-paste a template from 2024.


The Core Philosophy: Give Karpenter Options, Not a Menu

Karpenter doesn’t pick a random spot instance. It uses a bin-packing algorithm that balances price and availability. But if you constrain it too much (e.g., force a single instance type like c5.xlarge), it will either fail to find spot capacity or launch in a single AZ — making interruption risk catastrophic.

The best practice is to define a fallback hierarchy:

  1. Spot instances from a wide family (compute-optimized, general-purpose, memory-optimized)
  2. OD instances as a fallback when spot interruption rates exceed 5%
  3. Consolidation to right-size after the workload stabilizes

Here’s the provisioner we use at SIVARO. It’s been battle-tested through three AWS re:Invent traffic spikes and one unexpected reclamation wave in us-east-1b.

yaml
apiVersion: karpenter.sh/v1beta1
kind: NodePool
metadata:
  name: default
spec:
  template:
    spec:
      requirements:
        - key: "karpenter.sh/capacity-type"
          operator: In
          values: ["spot", "on-demand"]
        - key: "node.kubernetes.io/instance-type"
          operator: In
          values:
            - "c5.*"      # compute-optimized
            - "c6a.*"     # AMD compute
            - "m5.*"      # general purpose
            - "m6a.*"     # AMD general
            - "r5.*"      # memory optimized
            - "r6a.*"     # AMD memory
        - key: "topology.kubernetes.io/zone"
          operator: In
          values:
            - "us-east-1a"
            - "us-east-1b"
            - "us-east-1c"
        - key: "kubernetes.io/arch"
          operator: In
          values: ["amd64"]
      nodeClassRef:
        name: default
  limits:
    cpu: "1000"
  disruption:
    consolidationPolicy: WhenEmptyOrUnderutilized
    consolidateAfter: 30s

Notice what we did: wildcard instance types. Karpenter can choose any size within the c5, m5, and r5 families. That gives it the flexibility to find spot capacity while still matching your workload’s general shape.

But here’s the key: we list both spot and on-demand as capacity types. Karpenter will prefer spot (due to price ordering), but fall back to OD when spot isn't available. No more stuck pods because every spot instance in us-east-1b just got reclaimed.


Consolidation: Karpenter’s Superpower (If You Use It Right)

Understanding Karpenter Consolidation: Detailed Overview describes consolidation as the mechanism that replaces underutilized nodes with smaller or cheaper ones. But here’s the nuance: consolidation doesn’t just happen because you enable it. It depends on your consolidationPolicy and the actual resource requests from your pods.

We tested two policies:

  • WhenEmptyOrUnderutilized (default) — Replaces nodes when they fall below a utilization threshold. Works great for batch workloads that surge and drain.
  • WhenEmpty — Only consolidates nodes that have zero pods. Safer but leaves money on the table.

For spot instances, I strongly recommend WhenEmptyOrUnderutilized with a short consolidateAfter (30 seconds). Here’s why: spot interruptions can leave behind nodes with a few pods that don’t justify keeping the large instance. Without consolidation, you’re paying for wasted capacity.

The AWS blog Optimizing your Kubernetes compute costs with Karpenter consolidation shows a real example: one company reduced their node count from 12 to 7, saving 42% on compute. We saw similar numbers — 35-45% reduction depending on workload.

But here’s the trap: consolidation can trigger cascading evictions if your Pod Disruption Budgets (PDBs) aren’t set correctly. A node gets underutilized, Karpenter cordons it, drains it — and if your PDB says “maxUnavailable: 1” for a deployment with 2 replicas, the drain stalls. Suddenly your node stays up, costing you money, and your autoscaler is stuck.

I’ll cover PDBs in a moment. First, let’s talk about what happens when a spot instance dies.


Handling Spot Interruptions Without Panicking

Cut AWS costs by 20% while scaling with EKS, Karpenter... shares Tinybird’s approach: they set up interruption monitoring using AWS Health events and Karpenter’s built-in handling. Karpenter already watches for the two-minute notice from AWS and starts replacing pods immediately. But two minutes isn’t always enough.

We learned this the hard way: during the AWS us-east-1 outage of December 2025 (yes, still happening), we lost 40 nodes in 90 seconds. Karpenter’s two-minute notice? Some instances got terminated without it.

The solution is three-fold:

  1. Run a grace period replica — Use spec.template.spec.terminationGracePeriodSeconds: 30 to give pods time to drain.
  2. Enable Karpenter’s spot-to-spot consolidation — This setting (available since v0.37) tells Karpenter to proactively replace spot instances at risk of interruption before AWS sends the notice. It uses prediction models based on historical interruption rates.
  3. Use Pod Topology Spread Constraints — Spread pods across zones. If one AZ gets a reclamation wave, the other AZs stay up.

Here’s an example deployment config that survives interruptions:

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 6
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      terminationGracePeriodSeconds: 30
      topologySpreadConstraints:
        - maxSkew: 1
          topologyKey: topology.kubernetes.io/zone
          whenUnsatisfiable: ScheduleAnyway
          labelSelector:
            matchLabels:
              app: my-app
      containers:
        - name: app
          image: myapp:1.0
          resources:
            requests:
              cpu: "500m"
              memory: "512Mi"

The maxSkew: 1 ensures no single zone gets more than one extra replica. Combined with 6 replicas across 3 AZs, a full zone failure leaves you with 4 replicas — enough to handle traffic while Karpenter spins up replacements.

But here’s the counterintuitive part: increasing replicas isn’t always smart. More replicas mean more nodes = more spot exposure. We tested 3 vs 6 replicas for a stateless API. The 3-replica setup had 40% lower spot cost because we could run on fewer, larger instances. The trade-off: if two replicas go down simultaneously (rare), we have a brief capacity crunch. We chose lower cost. You might not.


Pod Disruption Budgets: The Hidden Bottleneck

A Personal Take on Pod Disruption Budgets and Karpenter lays out exactly why PDBs can break your Karpenter setup. The author describes a cluster where PDBs blocked all node drains, causing the cluster to freeze during an outage.

We saw the same. A developer set maxUnavailable: 1 on a deployment with 2 replicas. Karpenter tried to consolidate nodes. It couldn’t drain any node because a single pod eviction would violate the PDB. The cluster grew to 20 nodes — each underutilized — while costs spiraled.

The fix: set maxUnavailable: 25% for most stateless services. Or use minAvailable: 1 for critical ones. Never set maxUnavailable: 1 on a 2-replica deployment. It’s a self-imposed straitjacket.

For stateful workloads with Kafka or Redis, you need a different approach. I recommend using minAvailable: N-1 (where N is the number of replicas) but only after you’ve tested Karpenter’s interruption handling. Keep your PDBs loose enough to allow Karpenter to consolidate, but tight enough to prevent total data loss.

Here’s the PDB we use for our Kafka consumer group of 10 pods:

yaml
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: kafka-consumer-pdb
spec:
  maxUnavailable: 2
  selector:
    matchLabels:
      app: kafka-consumer

Notice we use maxUnavailable: 2 (20% of replicas). It gives Karpenter room to drain nodes while keeping enough consumers alive. We saw zero consumer lag during spot interruptions after switching to this.


Karpenter Cost Allocation: Who Spent What?

Karpenter Cost Allocation: Who Spent What?

Karpenter cost allocation kubernetes is the least sexy but most important practice. If you can’t attribute compute costs to teams or workloads, you can’t optimize. We use Karpenter’s built-in karpenter.sh/provisioner-name label combined with AWS Cost Explorer tags.

Every NodePool gets a unique tag:

yaml
metadata:
  name: data-pipeline
spec:
  template:
    spec:
      labels:
        environment: production
        team: data

Then in AWS Cost Explorer, you can filter by tag team:data. Simple, but 80% of teams don’t do it. They see one big “EKS Compute” line item and have no idea which team is blowing the budget.

At SIVARO, we also use ScaleOps for granular visibility. Their 2026 guide points out that most Kubernetes cost optimization tools still can’t handle spot instance pricing correctly — they calculate cost based on OD rates, not actual spot prices. That’s misleading. Karpenter’s own metrics (karpenter_nodes_created and karpenter_nodes_terminated) combined with spot price history give accurate cost per workload.

My rule of thumb: if you can’t answer “how much did team X spend on compute last week?”, you’re not ready to adopt spot instances at scale. Because you won’t know if your savings are real or if you’re just shifting costs to application instability.


Monitoring What Matters

You don’t need a dashboard with 50 charts. You need five numbers:

  1. Spot interruption rate per AZ per hour (AWS publishes this via CloudWatch metric SpotInterruptionRate).
  2. Node utilization — average CPU and memory across all nodes. Below 40% means you’re paying for waste.
  3. Consolidation success rate — how many times Karpenter successfully replaced a node vs. how many times it was blocked (by PDBs or constraints).
  4. Scheduling latency — time from pod creation to pod ready. High latency means Karpenter can’t find suitable spot instances.
  5. Spot vs. OD ratio — percentage of nodes running on spot. If it drops below 50%, you might be falling back too often (meaning your instance selection is too narrow).

We use Prometheus + Grafana with the Karpenter metrics endpoint. The karpenter_pods_state metric tells you exactly how many pods are pending due to spot capacity issues. I’ve seen clusters with karpenter_cost_allocation_kubernetes labels misconfigured — every pod got labeled as capacityType: on-demand even though they ran on spot. Check your labels.


Advanced: Spot-to-Spot Consolidation and Predictions

In late 2025, Karpenter introduced a prediction model for spot interruptions. It’s not perfect, but it works. The model analyzes historical interruption patterns by instance family and AZ, and proactively terminates instances that are “likely” to be reclaimed soon. Karpenter then launches replacement spot instances in less risky AZs.

To enable this, set:

yaml
spec:
  disruption:
    consolidationPolicy: WhenEmptyOrUnderutilized
    consolidateAfter: 30s
    budgets:
      - nodes: "10%"
        duration: 30m

The budgets field limits how many nodes can be disrupted at once. We find that 10% of nodes per 30 minutes is safe for most workloads. For critical services, reduce that to 5%.

But here’s a contrarian take: don’t rely entirely on Karpenter’s predictions. They’re based on AWS data, and AWS can still terminate instances with zero notice (we saw it happen in early 2026 during an AWS capacity crunch). Always have a fallback OD node pool with a higher price threshold.

We set up a second NodePool with capacity-type: on-demand and a lower priority (via priority: 50) so Karpenter prefers spot but fails over to OD when predictions indicate high risk. Here’s how:

yaml
apiVersion: karpenter.sh/v1beta1
kind: NodePool
metadata:
  name: on-demand-fallback
spec:
  priority: 50
  template:
    spec:
      requirements:
        - key: "karpenter.sh/capacity-type"
          operator: In
          values: ["on-demand"]
        - key: "node.kubernetes.io/instance-type"
          operator: In
          values: ["c5.*", "m5.*", "r5.*"]
      nodeClassRef:
        name: default
  limits:
    cpu: "200"
  disruption:
    consolidationPolicy: WhenEmptyOrUnderutilized
    consolidateAfter: 30s

The priority: 50 ensures this pool is used only when the spot pool (priority defaults to 100) can’t schedule. This gives you a safety net without breaking the bank.


Common Pitfalls (That I’ve Made)

Pitfall 1: Not using instance family wildcards. I convinced myself that my workload only needed c5.xlarge. Then a reclamation wave hit us-east-1a — all c5.xlarge spot instances were gone. Karpenter couldn’t launch replacements. The cluster filled up with pending pods. We had to manually update the provisioner to include c5.2xlarge and c5a.*. Hours of downtime. Don’t be me.

Pitfall 2: Ignoring Karpenter’s node expiry. By default, nodes live forever. That’s fine if you have steady workloads. But spot instances can drift in price. We set maxLifetime: 720h (30 days) on all spot nodes to force Karpenter to periodically recycle them, re-evaluating the best spot prices. This alone saved us 8% on compute.

Pitfall 3: Not testing interruption handling. You can’t simulate spot interruptions perfectly, but you can cordon and drain nodes manually to see how your pods react. We do chaos engineering once a month: randomly taint a node with node.kubernetes.io/unschedulable:NoSchedule and watch Karpenter respond. If any pod fails to reschedule within 60 seconds, we fix the configuration.


FAQ

Q: Should I use Karpenter’s spot-to-spot consolidation or just rely on OD fallback?
Both. Spot-to-spot keeps your spot ratio high, but OD fallback is essential for peak traffic. We use spot-to-spot with a 10% budget and OD fallback as a safety net.

Q: What instance types should I include for spot?
Include at least two families per category (e.g., c5.* and c6a.* for compute; m5.* and m6a.* for general purpose). Also include c7g.* and m7g.* for Graviton if your workload supports ARM. The more variety, the better Karpenter can find cheap, available spot capacity.

Q: How do I handle stateful workloads with spot instances?
You can’t run stateful workloads (like databases) directly on spot unless you have replication and TTL-based failover (e.g., TiDB or CockroachDB). For Kafka, run brokers on OD and consumers on spot. For Redis, use spot for replicas but keep the primary on OD.

Q: Do PodDisruptionBudgets prevent Karpenter from consolidating?
Yes, if they’re too strict. Always set maxUnavailable to at least 20% of replicas for stateless services. For stateful services, use minAvailable with a count that allows at least one pod loss.

Q: How do I track karpenter cost allocation kubernetes across teams?
Use AWS tags on NodePools and configure Cost Explorer to break down by tag key team. Also export Karpenter metrics (karpenter_nodes_created with provisioner name) to correlate node lifetime cost with teams.

Q: What’s the best consolidation policy for spot instances?
WhenEmptyOrUnderutilized. WhenEmpty is safer but you’ll waste money on partially-filled nodes. With spot, every percent utilization matters because the savings are already large — don’t give them back by leaving nodes underused.

Q: Can I use Karpenter with mixed spot and OD in the same pool?
Yes. List both capacity types in requirements. Karpenter will prefer spot by default. But you can also set nodeClassRef.spec.amiFamily: Bottlerocket for faster boot times (Bottlerocket boots in ~10 seconds vs. 45 for Amazon Linux). That’s critical during spot interruptions.


The Bottom Line

The Bottom Line

Karpenter with spot instances is the single biggest cost lever you have for Kubernetes compute. But it’s not a set-and-forget. You need:

  • Wide instance type selection (wildcards)
  • A fallback OD pool
  • Loose PDBs
  • Proactive monitoring of interruption rates
  • Periodic chaos testing

We cut our monthly EKS bill from $42K to $16K at SIVARO. That’s a 62% reduction. But it took three iterations of our NodePool configuration to get there. The first version lost us a production deployment for 12 minutes. The second version failed to consolidate because our PDBs were too tight. The third version — the one I shared above — has been running for 8 months without a single incident.

Is kubernetes used in production? Yes. And if you want to keep it that way, treat your spot configuration like the critical infrastructure it is.


Nishaant Dixit — Founder of SIVARO. Building data infrastructure and production AI systems since 2018. Built systems processing 200K events/sec.

Free · No Commitment · 48-Hour Delivery

Get a free infrastructure audit

2-hour remote session. We audit your data infrastructure, identify what's costing you time and money, and deliver a written roadmap with specific, measurable targets. No pitch.

Book Your Free Audit
N
Nishaant Dixit
Founder & Lead Engineer at SIVARO

Building data-intensive systems since 2018. 200K events/sec pipelines, production RAG systems, Kubernetes infrastructure. LinkedIn →

Start a Project
Need help with infrastructure?

Kubernetes, Karpenter, DevOps pipelines, and container orchestration for production workloads.

Explore MVP to Production