By Raúl Pérez · Last updated: October 2026 · Reading time: 13 min
If you want one change that can noticeably reduce your Kubernetes compute bill, Spot instances are near the top of the list. Cloud providers sell their spare capacity at a steep discount, and Kubernetes, with its ability to reschedule pods automatically, is one of the best platforms to take advantage of it.
The catch is in the name: Spot capacity can be taken back by the provider at short notice. Teams that treat Spot nodes like normal nodes tend to learn this at 3 a.m. Teams that design for interruption can run a large share of their fleet on Spot with very little drama.
This guide covers how Spot works on each cloud, how much you can realistically save, which workloads are a good fit, the real risks, and a set of best practices with configuration you can adapt, including EKS managed node groups, Karpenter, AKS and GKE.
What Are Spot Instances?
Spot instances (called Spot VMs on Azure and GCP, and previously preemptible VMs on GCP) are spare compute capacity sold at a discount compared with on-demand prices, with the condition that the provider can reclaim it when it needs the capacity back.
| AWS EC2 Spot | Azure Spot VMs | GCP Spot VMs | |
|---|---|---|---|
| Advertised discount | Up to roughly 90% vs on-demand | Up to roughly 90% vs pay-as-you-go | Typically large discounts, varying by machine type and region |
| Interruption notice | About 2 minutes | About 30 seconds | About 30 seconds |
| Pricing | Market-based, changes slowly | Variable, with optional max price | Fixed discount-style pricing, varying by type |
| Kubernetes integration | EKS managed node groups, self-managed groups, Karpenter | AKS Spot node pools | GKE Spot node pools and Spot Pods |
Discounts, notice periods and behaviors change over time and vary by instance type, region and time of day. Check each provider’s current documentation, and treat advertised maximum discounts as upper bounds, not expectations.
How Much Can You Really Save?
A realistic way to think about it: Spot nodes commonly cost 50 to 70 percent less than on-demand for many instance types, with cheaper pools sometimes going further. Your blended savings depend on what share of your cluster runs on Spot.
Illustrative example (numbers are simplified):
| Scenario | On-demand node-hours | Spot node-hours | Relative node cost |
|---|---|---|---|
| All on-demand | 1,000 | 0 | 100% |
| 30% on Spot at 65% discount | 700 | 300 | about 80% |
| 60% on Spot at 65% discount | 400 | 600 | about 61% |
So moving 60 percent of compute to Spot at a 65 percent discount cuts the node bill by roughly 40 percent in this example. Combine it with Savings Plans or reservations for the stable on-demand baseline and the savings compound.
Two caveats keep expectations honest. First, savings only apply to the node portion of your bill, not to data transfer, load balancers or storage. Second, interruptions have a cost (restarts, rescheduling, occasionally lost work), so measure net savings, not just the discount.
The Real Risks of Spot on Kubernetes
1. Interruptions and capacity shortages
When the provider needs the capacity, your node receives a termination notice and then disappears. All pods on it are killed. If many of your replicas were on the same instance type or zone, a single capacity event can remove a large part of your service at once.
2. Simultaneous interruptions
Interruptions are correlated. If your Spot pool uses one instance type in one zone, a shortage hits every node together. This is the most common cause of Spot-related outages.
3. Stateful workloads and data loss
Databases, caches and any pod holding unsaved state in memory or on local disks are poor candidates. Data stored on instance storage is lost, and attached volumes may need to detach and reattach in another zone, which for zone-bound volumes can be impossible.
4. Insufficient capacity at launch
Sometimes there is no Spot capacity available at all for the types you requested. Without fallbacks, pods stay Pending.
5. Slow drains and ungraceful shutdowns
With a 2-minute (or 30-second) notice, applications must shut down quickly. Long-running requests, slow connection draining and large in-memory buffers may not finish in time.
6. Control plane and critical add-ons on Spot
Putting CoreDNS, ingress controllers, the cluster autoscaler or monitoring on Spot nodes can cascade a single interruption into a cluster-wide incident.
7. Operational surprises
Price and availability shift constantly. Configurations that worked well last quarter may need adjustment, so Spot is a practice, not a one-off migration.
Which Workloads Belong on Spot?
Good candidates
- Stateless web and API services with several replicas behind a load balancer
- Background workers consuming from a queue, especially with idempotent jobs
- CI/CD runners and build agents
- Batch processing, ETL and data pipelines with checkpointing
- Machine learning training with checkpoints, and some inference tiers
- Development, test and preview environments
- Stream processors that can recover from offsets
Poor candidates (keep on on-demand or reserved)
- Databases and stateful stores (unless using replication designed for node loss)
- Single-replica services
- Control plane components, CoreDNS, ingress controllers, service mesh control planes
- Cluster autoscaler or Karpenter itself
- Latency-critical services with no spare capacity
- Long jobs that cannot be checkpointed or restarted
A simple test: if this pod disappeared right now with 30 seconds notice, would the user notice? If the answer is no, it is a Spot candidate.
Best Practices for Running Kubernetes on Spot
1. Diversify instance types and zones
The single most important practice. Instead of one instance type, offer many that are equivalent for your needs (for example m5.large, m5a.large, m6i.large, m6a.large, m7i.large), across all availability zones. Deeper pools mean fewer simultaneous interruptions and better prices.
- On AWS, use the price-capacity-optimized allocation strategy, which balances low price and deep capacity pools.
- Choose instances with similar vCPU and memory so the scheduler behaves predictably.
- Use tools such as the Spot Instance Advisor to look at historical interruption frequencies, and favor less-interrupted pools.
2. Keep a stable on-demand baseline
Run a minimum of on-demand (or reserved/Savings Plan-covered) capacity for critical and stateful workloads, and let Spot handle the elastic portion. A common starting ratio for stateless fleets is 60 to 70 percent Spot and the remainder on-demand, adjusted as you observe interruption patterns.
3. Separate node pools and use taints
Keep Spot and on-demand capacity in distinct pools. Taint Spot nodes so only workloads that explicitly tolerate them land there.
# Pod that tolerates and prefers Spot nodes
spec:
tolerations:
- key: "spot"
operator: "Equal"
value: "true"
effect: "NoSchedule"
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 80
preference:
matchExpressions:
- key: eks.amazonaws.com/capacityType
operator: In
values: ["SPOT"]
Use preferred (soft) affinity where possible so pods can fall back to on-demand if Spot is unavailable. Label names differ by platform: EKS managed node groups use eks.amazonaws.com/capacityType, Karpenter uses karpenter.sh/capacity-type, AKS uses kubernetes.azure.com/scalesetpriority=spot, and GKE uses cloud.google.com/gke-spot=true.
4. Spread replicas across nodes and zones
Never let all replicas share a node or a zone. Topology spread constraints do this cleanly:
spec:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app: checkout-api
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app: checkout-api
Run at least three replicas for any service you put on Spot, so losing one or two nodes does not take the service down.
5. Protect availability with PodDisruptionBudgets
A PDB limits how many replicas may be voluntarily disrupted at once (for example during node drains and consolidation). It does not stop provider-initiated terminations, but it makes the drain that follows an interruption notice behave well.
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: checkout-api
spec:
maxUnavailable: 1
selector:
matchLabels:
app: checkout-api
Avoid PDBs so strict (for example minAvailable equal to the replica count) that they block node draining entirely.
6. Handle interruption notices gracefully
Kubernetes only reacts well if something tells it that the node is about to go.
- AWS Node Termination Handler (queue processor mode) listens to EC2 Spot interruption warnings, rebalance recommendations and scheduled events through SQS and EventBridge, then cordons and drains the node.
- Karpenter has native interruption handling when configured with an interruption queue.
- On AKS and GKE, node eviction events and graceful shutdown settings handle the drain, with a shorter 30-second window.
Also tune the application itself:
spec:
terminationGracePeriodSeconds: 25
containers:
- name: app
lifecycle:
preStop:
exec:
command: ["sh", "-c", "sleep 5"] # give the load balancer time to deregister
Make sure the app handles SIGTERM by finishing in-flight requests, closing connections and flushing buffers within the available window. Keep the grace period shorter than the notice you get.
7. Design workloads to be restartable
- Keep services stateless and store state in managed databases, object storage or external caches.
- Make jobs idempotent and write checkpoints periodically.
- Use durable queues with visibility timeouts and retries so that interrupted work is picked up again.
- For batch frameworks (Spark, Flink, Argo Workflows, Kubernetes Jobs), configure retries and checkpointing.
8. Use priority classes to protect important pods
When capacity is tight, PriorityClasses decide which pods are rescheduled first:
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: critical-service
value: 100000
globalDefault: false
description: "Revenue-critical workloads"
Critical workloads get priority over best-effort batch jobs, which are the cheapest to restart.
9. Keep a fallback to on-demand
If Spot capacity disappears for a while, you want pods to land on on-demand nodes rather than stay Pending. Karpenter handles this by allowing both capacity types in a NodePool. With managed node groups or ASGs, keep an on-demand group with a higher cost but guaranteed capacity, and let Cluster Autoscaler’s expander or your affinities choose.
10. Monitor interruptions and net savings
Track:
- Spot interruption count and rate per instance type and zone
- Pods rescheduled per day and time-to-ready after an interruption
- Pending pod count and duration
- Error rate and latency during interruptions
- Actual cost per workload on Spot vs on-demand, using [OpenCost or Kubecost]
If a particular instance type or zone interrupts constantly, remove it from your allowed list.
Setup Examples by Platform
Amazon EKS: managed node group with Spot
Using eksctl:
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
name: my-cluster
region: eu-west-1
managedNodeGroups:
- name: spot-workers
spot: true
instanceTypes: ["m5.large", "m5a.large", "m6i.large", "m6a.large", "m7i.large"]
minSize: 2
maxSize: 30
desiredCapacity: 3
labels:
workload-type: spot
taints:
- key: spot
value: "true"
effect: NoSchedule
Managed node groups with the Spot capacity type use an allocation strategy that favors deep capacity pools, and cordon and drain nodes on rebalance recommendations. Use several instance types of similar size, as shown.
Amazon EKS: Karpenter NodePool with Spot and on-demand
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: spot-first
spec:
template:
spec:
nodeClassRef:
group: karpenter.k8s.aws
kind: EC2NodeClass
name: default
requirements:
- key: karpenter.sh/capacity-type
operator: In
values: ["spot", "on-demand"]
- key: karpenter.k8s.aws/instance-category
operator: In
values: ["c", "m", "r"]
- key: karpenter.k8s.aws/instance-generation
operator: Gt
values: ["4"]
limits:
cpu: "400"
disruption:
consolidationPolicy: WhenEmptyOrUnderutilized
consolidateAfter: 2m
Karpenter prefers Spot when it can satisfy the request and falls back to on-demand otherwise. Make sure the interruption queue is configured so it can react to Spot warnings. For a comparison with the classic approach, see [Karpenter vs Cluster Autoscaler: Cost Efficiency Comparison].
Azure AKS: Spot node pool
az aks nodepool add \
--resource-group my-rg \
--cluster-name my-aks \
--name spotpool \
--priority Spot \
--eviction-policy Delete \
--spot-max-price -1 \
--enable-cluster-autoscaler \
--min-count 1 \
--max-count 20 \
--node-vm-size Standard_D4s_v5
AKS applies a taint kubernetes.azure.com/scalesetpriority=spot:NoSchedule to Spot pools automatically, so workloads need a matching toleration. A --spot-max-price of -1 means you will pay up to the on-demand price. Spot pools cannot be used as the system node pool.
Google GKE: Spot node pool
gcloud container node-pools create spot-pool \
--cluster=my-cluster \
--spot \
--machine-type=e2-standard-4 \
--enable-autoscaling --min-nodes=0 --max-nodes=20 \
--node-taints=cloud.google.com/gke-spot=true:NoSchedule
Workloads select Spot using the node selector cloud.google.com/gke-spot: "true" plus a toleration if you tainted the pool. GKE also supports Spot Pods on Autopilot, which bill per pod resource with a discount.
Spot and Cost Optimization Together
Spot works best as one layer in a broader strategy:
- Right-size first. Do not spend effort getting discounts on capacity you do not need. See [Preventing Cloud Waste Caused by Over-Provisioned Pods and CPU Limits].
- Cover the stable baseline with commitments such as Savings Plans, reservations or committed use discounts.
- Run the elastic, fault-tolerant portion on Spot.
- Use consolidation so you are not paying for half-empty Spot nodes either.
- Track unit costs so you know the savings are real.
For the complete picture, read our [Complete Guide to Kubernetes Cost Optimization (K8s FinOps)].
A Safe Adoption Plan
Week 1: Prepare
- Identify stateless, multi-replica workloads and tag them as Spot-ready.
- Add PDBs, topology spread, graceful shutdown handling and sensible grace periods.
- Install interruption handling (Node Termination Handler or Karpenter’s queue).
Week 2: Pilot in non-production
- Create a Spot pool with 5 or more instance types across all zones.
- Move dev and staging workloads and run chaos tests by draining nodes.
Week 3 to 4: Introduce production gradually
- Move low-risk production services first, keeping a fixed on-demand minimum.
- Start with 20 to 30 percent of capacity on Spot and watch error rates.
Month 2 and beyond
- Increase the Spot ratio where results are clean.
- Prune noisy instance types and add alerts for Pending pods.
- Review monthly savings against interruptions.
Common Mistakes
- Using a single instance type or zone. It concentrates risk and raises the cost.
- Putting critical add-ons on Spot. Keep CoreDNS, ingress, controllers and autoscalers on stable nodes.
- Running one or two replicas. There is no buffer when a node is reclaimed.
- Ignoring graceful shutdown. Requests get dropped when pods are killed mid-flight.
- No fallback. Pods sit Pending when Spot capacity runs out.
- Moving too fast. Start small and observe.
- Judging only by the discount. Include the cost of interruptions and engineering time.
Frequently Asked Questions
Are Spot instances safe for production Kubernetes? Yes, for the right workloads and with the right design: stateless, replicated, spread across zones and instance types, and with graceful shutdown. They are not safe for singleton or stateful workloads without extra safeguards.
How often are Spot instances interrupted? It varies widely by instance type, region and zone. AWS publishes interruption frequency ranges per instance type in its Spot Instance Advisor, and historically many pools see low monthly interruption rates, but you should design for interruptions at any time.
Can I run databases on Spot? Generally no. A few replicated systems can tolerate node loss, but most teams keep data stores on on-demand or reserved capacity.
Do Spot instances work with Karpenter and Cluster Autoscaler? Yes. Karpenter handles Spot natively with flexible instance selection. Cluster Autoscaler works with Spot node groups, typically with mixed instance policies.
What happens to pods when a Spot node is reclaimed? The node receives a termination notice, drains if an interruption handler is configured, and pods are rescheduled on remaining or newly provisioned nodes. Pods that cannot be placed stay Pending until capacity is available.
Should I use Spot for the cluster autoscaler or system pods? No. Keep control and system components on on-demand nodes.
Conclusion
Spot instances can cut Kubernetes compute costs dramatically, but only if the platform is designed for interruption. Pick stateless, replicated workloads, diversify across many instance types and zones, keep a stable on-demand baseline, spread replicas with topology constraints, protect availability with PDBs and graceful shutdowns, and keep a fallback to on-demand. Roll out gradually, measure net savings, and Spot becomes a reliable part of your FinOps toolkit rather than a gamble.
