Last year we were paying $12,400/month for a Kubernetes cluster running a logistics platform. Three months later, after methodically applying these techniques, the bill was $3,800. Here's exactly what we did.
Step 1: Right-Sizing with VPA
Most K8s deployments are massively over-provisioned. Developers set resource requests conservatively to avoid OOM kills, and nobody ever revises them. VPA (Vertical Pod Autoscaler) fixes this automatically.
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: api-server-vpa
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: api-server
updatePolicy:
updateMode: "Off" # Start in Off mode — just collect recommendations
resourcePolicy:
containerPolicies:
- containerName: api
minAllowed:
cpu: 100m
memory: 128Mi
maxAllowed:
cpu: 2
memory: 2GiRun VPA in 'Off' mode for 2 weeks first. Check `.status.recommendation` to see what it would set. We found 70% of pods were using <30% of their requested CPU.
Step 2: Spot Instances for Stateless Workloads
Spot instances (AWS) or Preemptible VMs (GCP) are 60-90% cheaper than on-demand. The catch: they can be terminated with 2-minute notice. For stateless API pods, this is fine with proper disruption budgets.
# Node pool with spot instances
apiVersion: v1
kind: NodePool
spec:
template:
spec:
nodeClassRef:
name: spot-node-class
requirements:
- key: karpenter.sh/capacity-type
operator: In
values: ["spot", "on-demand"] # Fallback to on-demand
- key: kubernetes.io/arch
operator: In
values: ["amd64"]
disruption:
consolidationPolicy: WhenUnderutilized
consolidateAfter: 30s# PodDisruptionBudget — always keep 80% of pods up
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: api-pdb
spec:
minAvailable: "80%"
selector:
matchLabels:
app: api-serverStep 3: HPA with Custom Metrics
Default CPU-based HPA is too slow to react to traffic spikes. We switched to request-per-second metrics via Prometheus, which scales 3x faster.
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: api-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: api-server
minReplicas: 2
maxReplicas: 50
metrics:
- type: Pods
pods:
metric:
name: http_requests_per_second
target:
type: AverageValue
averageValue: "100" # Scale when > 100 req/s per pod
behavior:
scaleDown:
stabilizationWindowSeconds: 300 # Wait 5 min before scaling downCost Savings Summary
- Right-sizing with VPA: -$2,100/month (removed 40% of unused CPU/memory)
- Spot instances for API tier: -$3,800/month (moved 70% of workload to spot)
- HPA tuning (fewer idle replicas): -$1,900/month
- Karpenter bin-packing (fewer nodes): -$800/month
- Total savings: $8,600/month (69%)

