Warrior, in Chapter 15 we learned HPA, which scales Pods.
Now we solve the next problem:
What happens when Kubernetes wants more Pods, but the existing worker nodes don't have enough capacity?
That's where Cluster Autoscaler (CA) comes in.
Suppose your cluster has:
Node 1
CPU: 4 cores
Memory: 16 GB
Node 2
CPU: 4 cores
Memory: 16 GBYour application currently has:
3 PodsTraffic increases.
HPA says:
3 Pods
↓
8 PodsBut the existing nodes can only fit 5 Pods.
Now you have:
Pod 1 Running
Pod 2 Running
Pod 3 Running
Pod 4 Running
Pod 5 Running
Pod 6 Pending
Pod 7 Pending
Pod 8 PendingWhy?
Because there isn't enough node capacity.
Cluster Autoscaler can detect that Pods cannot be scheduled because the cluster lacks capacity.
It can then request additional nodes from the underlying infrastructure.
HPA
│
│ increases Pods
▼
8 Pods
│
│ insufficient capacity
▼
Pending Pods
│
▼
Cluster Autoscaler
│
│ adds node
▼
New Worker Node
│
▼
Scheduler
│
▼
Pending Pods → RunningThis is one of the most important Kubernetes interview concepts.
| Component | Scales | Example |
|---|---|---|
| HPA | Pods | 3 → 8 Pods |
| Cluster Autoscaler | Nodes | 2 → 3 Nodes |
Think:
HPA
= application capacity
Cluster Autoscaler
= infrastructure capacityYou could, but that would waste resources.
Imagine:
Normal traffic:
2 Nodes neededbut you permanently run:
20 NodesYou may pay for resources you aren't using.
Autoscaling allows:
Low traffic
↓
2 Nodes
High traffic
↓
10 Nodes
Traffic decreases
↓
3 NodesSo the cluster can adapt to demand.
Remember Chapter 17 is coming later, but we already know the basic scheduler concept.
The flow is:
Pod created
↓
Scheduler looks for suitable node
↓
Node has enough capacity?
│
┌─┴─┐
YES NO
│ │
▼ ▼
Run Pending
│
▼
Cluster AutoscalerCluster Autoscaler doesn't replace the scheduler.
It reacts to situations where scheduling cannot happen because more node capacity is needed.
Suppose your Pod requests:
resources:
requests:
cpu: "1"
memory: "2Gi"But every node has insufficient allocatable resources.
The Pod may remain:
PendingCheck:
kubectl get podsThen:
kubectl describe pod <pod-name>You may see an event similar to:
0/3 nodes are available:
Insufficient cpuor:
Insufficient memoryThis is an important signal.
Suppose a node has:
8 CPUYou might think:
8 Pods × 1 CPU = 8 CPUBut Kubernetes schedules based primarily on requested resources, along with other constraints and allocatable capacity.
For example:
resources:
requests:
cpu: "2"If a node only has:
1.5 CPU allocatablethe Pod cannot fit there, even if current observed CPU usage looks low.
This is why correctly configuring requests is important.
This is a common beginner misconception.
Cluster Autoscaler isn't simply:
CPU > 80%
→ create nodeIts core concern is whether Pods are unschedulable and whether adding/removing nodes would improve scheduling.
Example:
Node CPU usage = 60%
But:
Pod requires 4 CPU
Node has only 3 CPU allocatableThe Pod may still be unschedulable.
So:
Observed utilization and schedulability are different concepts.
Imagine:
Before:
┌──────────┐
│ Node 1 │
│ 4 CPU │
└──────────┘
┌──────────┐
│ Node 2 │
│ 4 CPU │
└──────────┘HPA creates additional Pods.
Capacity is insufficient.
Cluster Autoscaler:
Cluster Autoscaler
│
▼
Add Node 3
│
▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Node 1 │ │ Node 2 │ │ Node 3 │
└──────────┘ └──────────┘ └──────────┘Scheduler then places Pods on Node 3.
In cloud Kubernetes, nodes are commonly grouped into node pools or node groups.
For example:
Cluster
│
├── General Node Pool
│ ├── Node 1
│ ├── Node 2
│ └── Node 3
│
└── GPU Node Pool
├── GPU Node 1
└── GPU Node 2Different workloads can use different node types.
Imagine your company runs:
CPU: 4
Memory: 16 GBGPU
CPU: 16
Memory: 64 GBYou might have:
Node Pool A
────────────────
General workloads
CPU optimized
Node Pool B
────────────────
AI workloads
GPU nodesThis is especially relevant for AI/LLM infrastructure.
In a cloud environment, Kubernetes doesn't necessarily manufacture a physical machine itself.
The architecture is more like:
Kubernetes
│
▼
Node Autoscaling Component
│
▼
Cloud Provider
│
▼
VM / Compute Instance
│
▼
Worker Node joins clusterFor example:
EKS → AWS infrastructure
GKE → Google Cloud infrastructure
AKS → Azure infrastructureImagine an EKS cluster:
EKS Cluster
│
├── Node Group
│ ├── EC2 Node
│ └── EC2 NodeSuppose:
Minimum nodes = 2
Maximum nodes = 10Traffic increases:
2 Nodes
↓
3 Nodes
↓
4 NodesTraffic decreases:
4 Nodes
↓
3 Nodes
↓
2 NodesThe exact implementation depends on how the EKS node groups and autoscaling are configured.
Google Kubernetes Engine:
GKE Cluster
│
└── Node Pool
│
├── Node
├── Node
└── NodeAutoscaling can adjust the node pool within configured boundaries.
Azure Kubernetes Service:
AKS Cluster
│
└── Node Pool
│
├── Node
├── Node
└── NodeNode pool autoscaling adjusts capacity according to configured constraints and workload demand.
A node autoscaling configuration commonly has:
Minimum nodes
Maximum nodesFor example:
min = 2
max = 10Means:
Never intentionally go below 2
Never intentionally exceed 10Conceptually:
Traffic ↓
↓
10 → 8 → 5 → 3 → 2
Traffic ↑
↓
2 → 3 → 5 → 8 → 10Let's understand scale-up carefully.
1. Traffic increases
↓
2. HPA increases replicas
↓
3. New Pods created
↓
4. Scheduler tries to place Pods
↓
5. No suitable node
↓
6. Pods become Pending
↓
7. Cluster Autoscaler detects unschedulable Pods
↓
8. Node capacity increases
↓
9. Scheduler places Pods
↓
10. Pods become RunningThat's the complete chain.
Now traffic decreases.
Traffic ↓
↓
HPA reduces Pods
↓
Some nodes become underutilized
↓
Cluster Autoscaler evaluates nodes
↓
Can Pods be moved elsewhere?
↓
Yes
↓
Node can be removedThe important question is:
Can the workloads on this node safely be moved elsewhere?
Autoscaling doesn't simply delete arbitrary nodes.
Before removing a node, workloads may need to be moved.
Conceptually:
Node 3
│
├── Pod A
├── Pod B
└── Pod CNode removal:
Pod A ──────→ Node 1
Pod B ──────→ Node 2
Pod C ──────→ Node 1Then:
Node 3
↓
RemovedThis is related to node draining and workload disruption.
Here's an important production concept.
Suppose:
5 replicasYou don't want maintenance or node removal to take down all 5 at once.
A PodDisruptionBudget (PDB) can limit certain forms of voluntary disruption.
Example:
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: node-api-pdb
spec:
minAvailable: 3
selector:
matchLabels:
app: node-apiThis says:
Try to keep at least 3 matching Pods available during voluntary disruptions.
Imagine:
5 Podsand:
minAvailable: 3Then Kubernetes should preserve the required availability during supported voluntary disruptions.
This helps protect applications while nodes are drained or maintained.
Important:
PDB is not a guarantee against every kind of failure.
It mainly governs voluntary disruptions.
A sudden node crash can still take Pods down.
They solve different problems.
Cluster Autoscaler
│
▼
How many nodes do I need?
PDB
│
▼
How many Pods can voluntarily be disrupted?Together they can support safer infrastructure scaling.
Suppose:
maxNodes = 5But demand requires:
8 nodesCluster Autoscaler cannot exceed its configured maximum.
You could end up with:
5 Nodes
↓
Not enough capacity
↓
Some Pods remain PendingThis is an important production failure scenario.
Now let's combine everything from Chapters 13–16.
Imagine your Node.js API:
Deployment
replicas = 2HPA:
min = 2
max = 10
CPU target = 70%Node pool:
min nodes = 2
max nodes = 5Traffic suddenly increases.
CPU increases:
CPU ↑HPA reacts:
2 Pods
↓
5 PodsMore traffic:
5 Pods
↓
10 PodsNodes don't have enough capacity:
Some Pods → PendingCluster Autoscaler:
2 Nodes
↓
3 NodesScheduler:
Pending Pods
↓
New NodePods become:
Running
ReadyService routes traffic.
Complete:
Traffic
│
▼
HPA
│
More Pods
│
▼
Scheduler
│
insufficient?
┌─────┴─────┐
No Yes
│ │
▼ ▼
Run Cluster Autoscaler
│
▼
More Nodes
│
▼
Scheduler
│
▼
PodsDon't confuse:
CPU utilizationwith:
CPU capacityExample:
Node:
8 CPU
Current usage:
4 CPUYou might think:
50% usage → plenty of spaceBut a new Pod requests:
6 CPUIt can't fit because only about 4 CPU remains, and Kubernetes scheduling considers requests and allocatable capacity, not simply current observed usage.
Therefore:
Autoscaling and scheduling are heavily influenced by resource requests.
Suppose you configure:
requests:
cpu: "2"for every tiny Node.js Pod.
Your application actually uses:
100mYou may have plenty of actual unused CPU.
But Kubernetes sees:
2 CPU requestedfor each Pod.
So the scheduler may decide:
Not enough capacityand Cluster Autoscaler might add nodes unnecessarily.
Therefore:
Overestimating requests can cause excessive infrastructure scaling.
The opposite is also dangerous.
Suppose:
requests:
cpu: "50m"but application normally needs:
500mKubernetes may pack many Pods onto the same node because their requests look tiny.
Later:
Traffic ↑
CPU ↑and nodes may become heavily loaded.
So resource sizing should be based on actual workload measurements.
This is especially important for your AI projects.
Imagine:
LLM inference serviceOne GPU node:
GPU = 1Your Pod requests:
resources:
limits:
nvidia.com/gpu: 1If you need another inference replica:
Pod 1 → GPU Node 1
Pod 2 → Pendingbecause no available GPU exists.
Node autoscaling may need to provision another GPU-capable node, assuming your cluster/cloud setup supports that behavior.
Then:
GPU Node 1
↓
Inference Pod 1
GPU Node 2
↓
Inference Pod 2This is one reason AI infrastructure autoscaling is more complicated than ordinary CPU workloads.
Suppose you have:
General Nodes
GPU NodesYour AI workload should not randomly land on a general node.
You can use scheduling constraints such as:
nodeSelector:
workload: gpuConceptually:
Pod
│
└── nodeSelector: workload=gpu
│
▼
GPU Node PoolWe'll study scheduling deeply in Chapter 17.
Let's make this extremely clear.
"How many application Pods do I need?"
"How many worker nodes do I need to run those Pods?"
Application demand
│
▼
HPA
│
Number of Pods
│
▼
Scheduler
│
Enough node capacity?
│ │
YES NO
│ │
▼ ▼
Run Cluster Autoscaler
│
▼
More NodesYou run:
kubectl get podsand see:
NAME STATUS
node-api-abc Running
node-api-def Running
node-api-ghi Pending
node-api-jkl PendingDon't immediately assume application code is broken.
Run:
kubectl describe pod node-api-ghiLook at:
EventsYou might see:
Insufficient cpuor:
Insufficient memoryNow you know:
Application may be fine
Scheduling capacity is the problemUse this mental checklist:
Pod Pending?
│
▼
kubectl describe pod
│
▼
Look at Events
│
├── Insufficient CPU?
│
├── Insufficient memory?
│
├── Node selector?
│
├── Taints/tolerations?
│
├── Affinity?
│
└── PVC problem?Not every Pending Pod is a Cluster Autoscaler problem.
That's very important.
Suppose:
Pod Pendingand the reason is:
PVC not boundAdding a node won't necessarily solve the problem.
Similarly:
nodeSelector mismatchmay require changing scheduling configuration rather than adding generic nodes.
Therefore:
Always inspect the Pod events before assuming the cluster needs more nodes.
A typical cloud application may look like:
INTERNET
│
▼
Ingress
│
▼
Service
│
┌─────────────┼─────────────┐
▼ ▼ ▼
Pod Pod Pod
└─────────────┬─────────────┘
│
HPA
│
▼
Replica Count
│
▼
Scheduler
│
insufficient capacity?
│
▼
Cluster Autoscaler
│
▼
Node Pool
┌─────────┼─────────┐
▼ ▼ ▼
Node 1 Node 2 Node 3This is the architecture you should remember.
Cluster Autoscaler automatically adjusts the number of worker nodes when Pods cannot be scheduled because of insufficient capacity, and can remove underutilized nodes when workloads can be safely relocated.
HPA
→ Pods
Cluster Autoscaler
→ NodesWhen there are Pods that cannot currently be scheduled because the cluster lacks suitable capacity.
No.
It adjusts node capacity.
The scheduler places Pods.
No.
HPA adjusts workload replicas.
New Pods may remain:
Pendingif no existing node can accommodate them.
kubectl describe pod important?#Because the Events section often explains why a Pod cannot be scheduled.
A logical group of similar worker nodes, often managed together and commonly used in cloud Kubernetes.
A mechanism that limits certain voluntary disruptions to help maintain application availability.
No. A central signal is unschedulable Pods and whether changing node count would help scheduling. Node utilization and other constraints can also matter for scale-down decisions.
HPA
↓
Scales Pods
Cluster Autoscaler
↓
Scales NodesScale-up:
Traffic ↑
↓
HPA
↓
Pods ↑
↓
Pods Pending
↓
Cluster Autoscaler
↓
Nodes ↑
↓
Scheduler
↓
Pods RunningScale-down:
Traffic ↓
↓
HPA
↓
Pods ↓
↓
Node capacity becomes unnecessary
↓
Cluster Autoscaler
↓
Nodes ↓Important concepts:
Node
Node Pool
Pending Pod
Scheduling
Resource Requests
Cluster Autoscaler
PDB
Node Drain
Scale Up
Scale DownYou should now be able to explain this entire chain in an interview:
"HPA increases the number of Pods when application demand causes configured metrics to exceed their targets. The scheduler attempts to place those Pods on available nodes. If Pods become unschedulable because the cluster lacks suitable capacity, Cluster Autoscaler can increase the node pool within its configured limits. Once capacity is available, the scheduler places the Pods. When demand falls, HPA can reduce replicas and Cluster Autoscaler can later remove nodes that are no longer needed, subject to scheduling and disruption constraints."
That's a strong production-level explanation.
This is where we go deeper into how Kubernetes decides which node gets a Pod:
Pod
│
▼
Scheduler
│
├── CPU / Memory
├── Node Selector
├── Node Affinity
├── Taints
├── Tolerations
├── Pod Affinity
├── Pod Anti-Affinity
└── Topology
│
▼
Best NodeThis chapter is particularly important for production Kubernetes, multi-node clusters, GPU workloads, high availability, and interviews.
Mark it as complete to track your mastery.