Kubernetes Cost Optimization
A comprehensive guide to Kubernetes cost optimization covering resource optimization, spot instances, committed use discounts, rightsizing, and practical implementation strategies for reducing cloud costs.
Kubernetes cost optimization is essential for managing cloud expenses while maintaining performance and reliability. Without optimization, costs can spiral due to:
- Over-provisioning: Allocating more resources than needed
- Idle Resources: Running unused or underutilized resources
- Inefficient Workloads: Poor resource requests and limits
- Lack of Visibility: No insight into cost drivers
- Poor Scaling: Not scaling down when demand drops
- Right-size: Match resources to actual needs
- Scale Dynamically: Scale up and down with demand
- Use Spot Instances: Leverage discounted capacity
- Commit to Use: Use reserved instances for steady workloads
- Monitor Continuously: Track and optimize regularly
Resource Rightsizing
Spot Instances
Committed Use Discounts
Cluster Autoscaling
Storage Optimization
Efficient Networking
Rightsizing involves adjusting resource requests and limits based on actual usage. It's one of the most effective cost optimization strategies.
# Check current resource usage
kubectl top pods --all-namespaces
kubectl top nodes
# Identify over-provisioned pods
kubectl get pods -o json | jq '.items[] | {
name: .metadata.name,
namespace: .metadata.namespace,
requests: .spec.containers[].resources.requests,
limits: .spec.containers[].resources.limits
}'
# Use VPA for recommendations
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: app-vpa
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
updatePolicy:
updateMode: "Off" # Only recommend, don't apply
resourcePolicy:
containerPolicies:
- containerName: '*'
minAllowed:
cpu: 50m
memory: 64Mi
maxAllowed:
cpu: 2000m
memory: 2Gi
# Get VPA recommendations
kubectl get vpa app-vpa -o yaml | grep -A 20 recommendation
# Manual rightsizing based on usage
# Original requests
requests:
cpu: 500m
memory: 512Mi
# After analysis (based on actual usage)
# Actual usage: CPU 150m, Memory 200Mi
requests:
cpu: 200m # Reduced from 500m
memory: 256Mi # Reduced from 512Mi
# Goldilocks tool for VPA recommendations
helm repo add fairwinds-stable https://charts.fairwinds.com/stable
helm repo update
helm install goldilocks fairwinds-stable/goldilocks --namespace goldilocks --create-namespace
# Goldilocks dashboard
kubectl port-forward -n goldilocks svc/goldilocks-dashboard 8080:80
- Use VPA recommendations as a starting point
- Monitor actual usage over time (weeks)
- Set requests based on steady-state usage
- Set limits based on peak usage
- Gradually adjust values to avoid instability
- Review and adjust regularly (monthly)
Spot instances offer significant cost savings (60-90%) but can be interrupted. They're ideal for stateless, fault-tolerant workloads.
# AWS Spot Node Group (eksctl)
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
name: my-cluster
region: us-east-1
nodeGroups:
- name: spot-workers
instanceType: t3.medium
desiredCapacity: 3
spot: true # Enable spot instances
spotPrice: "0.02"
labels:
node-type: spot
taints:
- key: spot
value: "true"
effect: NoSchedule
# Pod toleration for spot nodes
apiVersion: v1
kind: Pod
metadata:
name: spot-workload
spec:
tolerations:
- key: spot
operator: Equal
value: "true"
effect: NoSchedule
nodeSelector:
node-type: spot
containers:
- name: app
image: myapp:latest
# AWS Node Termination Handler
helm repo add aws https://aws.github.io/eks-charts
helm repo update
helm install aws-node-termination-handler aws/aws-node-termination-handler \
--namespace kube-system \
--set enableSpotInterruptionDraining=true \
--set enableScheduledEventDraining=true
# GCP Preemptible VM
# Node pool with preemptible instances
gcloud container node-pools create spot-pool \
--cluster=my-cluster \
--zone=us-central1-a \
--preemptible \
--num-nodes=3 \
--machine-type=n1-standard-2
# Azure Spot VM
az aks nodepool add \
--resource-group my-rg \
--cluster-name my-cluster \
--name spotpool \
--node-count 3 \
--enable-spot \
--spot-eviction-policy Delete
- Use only for stateless, fault-tolerant workloads
- Implement node termination handling
- Set appropriate pod disruption budgets
- Monitor spot interruption rates
- Have fallback capacity (on-demand) for critical workloads
- Test spot handling in staging
Committed use discounts (reserved instances) provide significant savings (20-70%) for predictable workloads by committing to use specific resources for 1-3 years.
# AWS Reserved Instances
# Purchase standard or convertible RIs
# Standard RIs: Up to 72% savings, fixed instance type
# Convertible RIs: Up to 54% savings, flexible instance type
# AWS Compute Savings Plan
# Up to 66% savings, flexible across instance types and regions
# AWS EC2 Savings Plan
# Up to 72% savings, specific to EC2
# GCP Committed Use Discounts
# Up to 70% savings, 1-3 year commitment
gcloud compute commitments create \
--region=us-central1 \
--resources=vcpu=4,memory=16GB \
--commitment-type=1-year
# Azure Reserved VM Instances
# Up to 72% savings, 1-3 year commitment
az reservation purchase \
--reserved-resource-type VirtualMachines \
--instance-flexibility Enabled \
--quantity 3 \
--term P1Y
# Kubernetes cluster with reservations
# Ensure reserved capacity matches your steady-state usage
# Monitor and adjust reservations based on usage
- Analyze historical usage to identify steady workloads
- Purchase reservations for baseline capacity (e.g., 50-70% of usage)
- Use spot/on-demand for variable capacity
- Monitor utilization of reservations (aim for 80%+ utilization)
- Use savings plans for flexibility
- Review and adjust reservations regularly
# Install Kubecost for cost visibility
helm repo add kubecost https://kubecost.github.io/cost-analyzer
helm repo update
helm install kubecost kubecost/cost-analyzer \
--namespace kubecost \
--create-namespace \
--set prometheus.enabled=true \
--set grafana.enabled=true
# Access Kubecost UI
kubectl port-forward -n kubecost svc/kubecost-cost-analyzer 9090:9090
# Check cost by namespace
kubectl get pods -n kubecost
# Access: http://localhost:9090
# Kubecost API for cost data
# Total monthly cost
curl http://localhost:9090/api/v1/allocation/aggregated?aggregate=namespace
# Cost by pod
curl http://localhost:9090/api/v1/allocation/aggregated?aggregate=pod
# Cloud provider cost monitoring
# AWS Cost Explorer
aws ce get-cost-and-usage --time-period Start=2025-01-01,End=2025-01-31
# GCP Cost Management
gcloud beta billing accounts describe
# Azure Cost Management
az consumption usage list --start-date 2025-01-01 --end-date 2025-01-31
# OpenCost (open-source alternative)
helm repo add opencost https://opencost.github.io/opencost-helm-chart
helm repo update
helm install opencost opencost/opencost --namespace opencost --create-namespace
- Implement cost visibility tools (Kubecost, OpenCost)
- Monitor cost trends and anomalies
- Set cost budgets and alerts
- Track cost by namespace, team, and application
- Regularly review cost reports
- Share cost visibility with teams
| Strategy | Savings | Risk | Effort | Best For |
|---|---|---|---|---|
| Rightsizing | 20-40% | Low | Medium | All workloads |
| Spot Instances | 60-90% | High | High | Stateless, fault-tolerant |
| Committed Use | 20-70% | Low | Low | Steady workloads |
| Cluster Autoscaling | 10-30% | Low | Medium | Variable workloads |
| Storage Optimization | 10-30% | Low | Medium | Storage-heavy workloads |
| Network Optimization | 5-20% | Low | Medium | Network-intensive |
Cost optimization is an ongoing process. Start with visibility, implement rightsizing, then gradually adopt spot instances and committed use discounts. Monitor continuously and adjust strategies based on changing usage patterns.