Autoscaling — HPA, VPA & Cluster Autoscaler
AdvancedKubernetes has three autoscaling dimensions: HPA scales pod replicas based on CPU/memory/custom metrics, VPA adjusts pod resource requests, and Cluster Autoscaler adds/removes nodes based on pending pods.
Overview
Manual scaling is reactive and error-prone. Kubernetes's autoscaling stack handles it automatically: HPA (Horizontal Pod Autoscaler) adds or removes pod replicas when CPU or custom metrics cross thresholds — the most common form of autoscaling. VPA (Vertical Pod Autoscaler) adjusts the resource requests/limits of pods based on actual usage — useful for right-sizing without over-provisioning. Cluster Autoscaler watches for pods that cannot be scheduled due to insufficient nodes and adds nodes to the node group (ASG on AWS, MIG on GCP); it also removes underutilised nodes to reduce cost.
HPA — Horizontal Pod Autoscaler
HPA scales pod replicas based on observed metrics. It requires the Metrics Server to be installed. Custom metrics (HTTP requests/second, queue depth) need Prometheus Adapter or KEDA.
# Prerequisite: install metrics-server
# kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
# hpa.yaml — scale on CPU utilization
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: my-app-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
minReplicas: 2
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70 # target: keep avg CPU at 70%
- type: Resource
resource:
name: memory
target:
type: AverageValue
averageValue: 400Mi # keep avg memory usage under 400Mi
# Scale on custom metric (Prometheus via prometheus-adapter)
- type: External
external:
metric:
name: http_requests_per_second
selector:
matchLabels:
app: my-app
target:
type: AverageValue
averageValue: "1000" # 1000 req/s per pod
kubectl get hpa
# NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS
# my-app-hpa Deployment/my-app 45%/70% 2 20 3
# ↑ current/target
kubectl describe hpa my-app-hpa # see scale events and reasoningKEDA — Event-Driven Autoscaling
KEDA (Kubernetes Event-Driven Autoscaling) extends HPA with 50+ built-in scalers including Kafka lag, SQS queue depth, Redis list length, and Prometheus queries. It can scale to zero.
# Install KEDA
# helm install keda kedacore/keda --namespace keda --create-namespace
# ScaledObject — scale based on Kafka consumer lag
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: kafka-consumer-scaler
spec:
scaleTargetRef:
name: order-processor-deployment
minReplicaCount: 0 # scale to ZERO when no messages!
maxReplicaCount: 30
cooldownPeriod: 60 # seconds before scaling down
triggers:
- type: kafka
metadata:
bootstrapServers: kafka.production.svc.cluster.local:9092
consumerGroup: order-processors
topic: orders
lagThreshold: "100" # 1 replica per 100 messages of lag
# Scale on AWS SQS queue depth
- type: aws-sqs-queue
authenticationRef:
name: keda-aws-credentials
metadata:
queueURL: https://sqs.us-east-1.amazonaws.com/123456/my-queue
queueLength: "50" # 1 replica per 50 messages
awsRegion: us-east-1
# Scale on Prometheus query (HTTP latency p99 > 500ms → scale up)
- type: prometheus
metadata:
serverAddress: http://prometheus.monitoring.svc.cluster.local
metricName: http_request_duration_p99
query: histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[2m]))
threshold: "0.5" # 500msCluster Autoscaler & VPA
Cluster Autoscaler adds nodes when pods are pending (not enough capacity) and removes underutilised nodes. VPA right-sizes resource requests based on actual usage.
# Cluster Autoscaler (EKS example)
# Install: managed by cloud providers or helm chart
# Needs IAM permissions to modify Auto Scaling Groups
# What triggers scale-up: pods in Pending state (no node has capacity)
kubectl get events | grep "FailedScheduling"
# FailedScheduling: 0/3 nodes available: insufficient memory
# What triggers scale-down: node utilization < 50% for > 10 min
# Cluster Autoscaler annotations to prevent node scale-down:
kubectl annotate node my-node cluster-autoscaler.kubernetes.io/scale-down-disabled=true
# VPA — Vertical Pod Autoscaler
# Install: separate component from VPA project
# Mode: "Off"(recommend only), "Initial"(apply at creation), "Auto"(live update)
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: my-app-vpa
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
updatePolicy:
updateMode: "Off" # only recommend, don't apply automatically
# After running for a while:
kubectl describe vpa my-app-vpa
# Recommendation:
# Container Recommendations:
# Container Name: app
# Lower Bound: cpu: 50m memory: 64Mi
# Target: cpu: 100m memory: 128Mi ↠use these as your requests
# Upper Bound: cpu: 500m memory: 512MiKey Points to Remember
- 1HPA scales pod count based on CPU/memory/custom metrics — requires Metrics Server.
- 2KEDA extends HPA to 50+ event sources (Kafka lag, SQS depth, Redis) and can scale to zero.
- 3Cluster Autoscaler adds nodes for Pending pods and removes underutilised nodes — reduces cloud cost.
- 4VPA recommends right-sized resource requests based on observed usage — start with updateMode: Off.
- 5Never run HPA and VPA in Auto mode on the same deployment — they conflict. VPA: Off mode + HPA is safe.
- 6Scale-to-zero with KEDA dramatically reduces costs for batch/event-driven workloads with idle periods.
Interview Questions
Sign in to ask AriaHow does HPA decide when to scale?
What is the difference between HPA and Cluster Autoscaler?
Ask Aria about Autoscaling — HPA, VPA & Cluster Autoscaler
Your personal AI tutor — ask anything about this concept
Revision Status
Personal Notes
Sign in to save personal notes for this topic.
Discussion
Sign in to join the discussion.