Kubernetes

Kubernetes Autoscaling Explained: HPA, VPA, and Cluster Autoscaler with kubectl

August 6, 2026 Kubezilla Team 3 min read
Kubernetes autoscaling architecture diagram showing Metrics Server feeding HPA and VPA, a Deployment scaling Pods, and Cluster Autoscaler adding nodes to the node pool

Kubernetes autoscaling has three independent knobs: the HorizontalPodAutoscaler (HPA) changes replica count, the VerticalPodAutoscaler (VPA) changes per-Pod CPU/memory requests, and the Cluster Autoscaler changes the number of Nodes. All three read from the same Metrics Server.

Architecture Overview

Kubernetes autoscaling architecture diagram showing Metrics Server feeding HPA and VPA, a Deployment scaling Pods, and Cluster Autoscaler adding nodes to the node pool

Prerequisites

kubectl version --client
kubectl get deployment metrics-server -n kube-system

Step 1: Install the Metrics Server

kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

kubectl get deployment metrics-server -n kube-system
kubectl top nodes
kubectl top pods

Step 2: Deploy a Workload with Resource Requests

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
      - name: web
        image: registry.example.com/web:2.1.0
        resources:
          requests:
            cpu: "200m"
            memory: "256Mi"
          limits:
            cpu: "500m"
            memory: "512Mi"
kubectl apply -f deployment.yaml
kubectl get deployment web

Step 3: Create a HorizontalPodAutoscaler

kubectl autoscale deployment web \
  --cpu-percent=60 \
  --min=3 \
  --max=10

kubectl get hpa web
kubectl describe hpa web
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: web
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web
  minReplicas: 3
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 60

Step 4: Load Test and Watch It Scale

# In one terminal, watch the HPA react
kubectl get hpa web --watch

# In another terminal, generate load
kubectl run load-generator --image=busybox --restart=Never -- \
  /bin/sh -c "while true; do wget -q -O- http://web; done"
kubectl get pods -l app=web
kubectl delete pod load-generator

Step 5: Right-Size Requests with a VerticalPodAutoscaler

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: web-vpa
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web
  updatePolicy:
    updateMode: "Auto"
kubectl apply -f vpa.yaml
kubectl describe vpa web-vpa
# recommendation section shows suggested CPU/memory requests

Step 6: Scale Nodes with the Cluster Autoscaler

kubectl -n kube-system get deployment cluster-autoscaler

kubectl -n kube-system logs deployment/cluster-autoscaler \
  --tail=50 | grep -i "scale"
# Pods that cannot be scheduled trigger a scale-up
kubectl get pods --field-selector=status.phase=Pending
kubectl describe pod <pending-pod> | grep -A5 Events

Autoscaling Cheat Sheet

kubectl top nodes                          # node CPU/memory usage
kubectl top pods                           # pod CPU/memory usage
kubectl get hpa                            # list HorizontalPodAutoscalers
kubectl describe hpa <name>                # see current/target metrics
kubectl get vpa                            # list VerticalPodAutoscalers
kubectl autoscale deployment <name> \
  --cpu-percent=60 --min=2 --max=10        # quick HPA from the CLI
kubectl get pods --field-selector=status.phase=Pending  # find scale-up triggers

FAQ

Can I run HPA and VPA on the same Deployment? Not safely for CPU/memory at the same time; they can fight over the same signal. A common pattern is HPA on custom or memory metrics while VPA manages CPU/memory requests, or VPA in recommendation-only mode.

Does HPA work without the Metrics Server? No, the default CPU/memory-based HPA needs the metrics.k8s.io API that the Metrics Server provides. Custom or external metrics need a separate adapter.

What triggers the Cluster Autoscaler? Pods stuck in Pending because no Node has enough allocatable CPU or memory. It then adds Nodes from a configured node group, and removes underutilized Nodes later.

Summary

You installed the Metrics Server, created an HPA that scales replicas on CPU utilization, added a VPA to right-size resource requests, and confirmed how the Cluster Autoscaler reacts to Pending Pods by adding Nodes, all through kubectl.

Leave a comment