Kubernetes Scaling Strategies: Zero to Hero
Kubernetes can run one Pod or tens of thousands of Pods, but running Kubernetes is not the same as scaling correctly.
A cluster can have autoscaling enabled and still fail under traffic.
Why?
Because scaling is not a single feature. It is a chain of decisions:
- How many application replicas should exist?
- How much CPU and memory should each Pod receive?
- When should new Nodes be created?
- Which metric should trigger scaling?
- How quickly should the system scale up?
- How slowly should it scale down?
- What happens if the metric system fails?
- What happens if new Pods cannot be scheduled?
- Should the system react to load, events, or predict load before it arrives?
This guide starts from the absolute basics and builds toward production-grade scaling architecture.
By the end, you should understand not only how to configure Kubernetes autoscaling, but also how to design a scaling strategy.
Table of Contents
- What Does Scaling Mean?
- The Kubernetes Resource Model
- The Three Layers of Scaling
- Strategy 1 — Manual Scaling
- Strategy 2 — Horizontal Pod Autoscaler
- How HPA Actually Calculates Replicas
- HPA with CPU and Memory
- Strategy 3 — Custom and External Metrics
- Strategy 4 — Vertical Pod Autoscaler
- Strategy 5 — Node / Cluster Autoscaling
- Strategy 6 — Event-Driven Scaling with KEDA
- Strategy 7 — Predictive Scaling
- How the Scaling Layers Work Together
- HPA + VPA: Can They Be Used Together?
- Production-Grade HPA Configuration
- Scaling Stateful Workloads
- Scaling Databases
- Scaling and Kubernetes Scheduling
- Autoscaling Failure Scenarios
- Observability for Autoscaling
- Security Considerations
- Cost Optimization
- Real-World Architectures
- Decision Matrix
- Production Checklist
- Final Mental Model
What Does Scaling Mean?
Scaling means changing the amount of computing capacity available to an application.
There are two fundamental types.
Horizontal Scaling
Horizontal scaling means:
Add or remove application instances.
In Kubernetes, that normally means changing the number of Pods.
Example:
Before:
Pod
Pod
After traffic increases:
Pod
Pod
Pod
Pod
PodThis is often called:
- scaling out — adding replicas
- scaling in — removing replicas
Vertical Scaling
Vertical scaling means:
Give an existing workload more or fewer resources.
For example:
Before:
CPU request: 250m
Memory request: 256Mi
After:
CPU request: 1000m
Memory request: 1GiThis is sometimes called rightsizing.
Cluster Scaling
There is another layer.
What happens if Kubernetes wants to create 20 Pods but your worker Nodes are already full?
The Pods remain:
PendingAt that point, the application needs more infrastructure.
That means adding Nodes.
So we have three different scaling dimensions:
These are separate mechanisms.
Understanding that separation is one of the most important Kubernetes scaling concepts.
The Kubernetes Resource Model
Before autoscaling makes sense, you must understand two values:
- requests
- limits
Example:
resources:
requests:
cpu: "500m"
memory: "512Mi"
limits:
cpu: "1"
memory: "1Gi"CPU
CPU is measured in cores or millicores.
1 CPU = 1000m
500m = 0.5 CPU
250m = 0.25 CPUMemory
Memory is usually expressed using binary units:
Mi
GiExample:
256Mi
512Mi
1Gi
2GiRequests
A request tells Kubernetes:
This container requires approximately this amount of resource for scheduling.
The scheduler uses requests when deciding where a Pod can run.
Example:
requests:
cpu: 500m
memory: 512MiIf a node has only 300m allocatable CPU remaining, this Pod cannot be scheduled there.
Limits
A limit defines the maximum amount of a resource the container is allowed to consume.
Example:
limits:
cpu: "1"
memory: "1Gi"CPU and memory limits behave differently.
If CPU usage exceeds the CPU limit, the workload can be throttled.
If memory exceeds the memory limit, the process can be killed by the kernel and Kubernetes may report:
OOMKilledWhy Requests Matter for Autoscaling
A very common production mistake is:
resources: {}and then creating an HPA based on CPU utilization.
CPU utilization for resource-based HPA is related to the configured resource request.
For example:
CPU request = 500m
Actual use = 400mThen:
CPU utilization = 400 / 500 = 80%If requests are missing for the relevant containers, resource-utilization-based HPA behavior can break because Kubernetes cannot calculate the percentage correctly.
Therefore:
Correct resource requests are the foundation of reliable autoscaling.
The Three Layers of Scaling
Think of Kubernetes autoscaling as three layers.
A mature scaling architecture usually combines multiple layers.
For example:
Traffic rises
↓
HPA creates more Pods
↓
Cluster lacks capacity
↓
Node Autoscaler creates another worker Node
↓
Scheduler places new PodsThat is a complete scaling chain.
Strategy 1 — Manual Scaling
The simplest strategy is manual scaling.
Suppose we have:
apiVersion: apps/v1
kind: Deployment
metadata:
name: payment-api
spec:
replicas: 2Two replicas will run.
You can change them manually:
kubectl scale deployment payment-api --replicas=5Now Kubernetes tries to maintain five replicas.
Architecture
When Manual Scaling Is Useful
Manual scaling is reasonable when:
- you are learning Kubernetes;
- you are troubleshooting;
- traffic is predictable;
- temporary capacity is needed before a known event;
- autoscaling is intentionally disabled during maintenance;
- you are testing system limits;
- your workload cannot be safely autoscaled.
Example:
You expect a campaign at 20:00.
You could temporarily run:
kubectl scale deployment checkout-api --replicas=20Why Manual Scaling Does Not Scale Operationally
Imagine having:
300 Deployments
50 teams
24/7 traffic
multiple regionsHumans cannot continuously watch every workload and adjust replica counts.
Manual scaling is therefore a control mechanism, not usually the final production strategy.
Strategy 2 — Horizontal Pod Autoscaler
The Horizontal Pod Autoscaler — HPA — automatically changes replica counts.
Its basic job is:
Observe metric
↓
Compare with target
↓
Calculate desired replicas
↓
Update Deployment / StatefulSet replica countBasic Architecture
HPA Example
Assume this Deployment exists:
apiVersion: apps/v1
kind: Deployment
metadata:
name: payment-api
spec:
replicas: 2
selector:
matchLabels:
app: payment-api
template:
metadata:
labels:
app: payment-api
spec:
containers:
- name: payment-api
image: example/payment-api:1.0.0
ports:
- containerPort: 8080
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: "1"
memory: 1GiNow create an HPA:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: payment-api
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: payment-api
minReplicas: 2
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70Meaning:
Keep average CPU utilization around 70%.
Never run fewer than 2 replicas.
Never scale beyond 20 replicas.Check HPA
kubectl get hpaExample:
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS
payment-api Deployment/payment-api 65%/70% 2 20 4Detailed view:
kubectl describe hpa payment-apiHow HPA Actually Calculates Replicas
A useful simplified model is:
desiredReplicas =
ceil(
currentReplicas
×
currentMetricValue
/
desiredMetricValue
)Suppose:
Current replicas: 4
Current CPU: 90%
Target CPU: 60%Then:
4 × 90 / 60
= 6So Kubernetes may want approximately:
6 replicasExample 2
Current replicas = 10
Current CPU = 30%
Target CPU = 60%Calculation:
10 × 30 / 60
= 5Desired replicas:
5The real controller includes additional behavior for:
- missing metrics;
- not-yet-ready Pods;
- stabilization;
- multiple metrics;
- tolerance;
- scale policies.
So the simple formula is the mental model, not the entire implementation.
HPA with CPU and Memory
You can scale using both CPU and memory.
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: payment-api
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: payment-api
minReplicas: 3
maxReplicas: 30
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 65
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 75When multiple metrics exist, HPA evaluates them and uses the scaling recommendation that requires the highest replica count.
Example:
CPU recommendation: 8 Pods
Memory recommendation: 12 PodsResult:
12 PodsThis behavior protects the system from ignoring a metric that is under more pressure.
Why Memory Is Tricky
CPU is generally compressible.
If CPU capacity is limited, workloads often become slower.
Memory is different.
A process that exceeds memory can be terminated.
Also, some applications intentionally retain memory.
Examples:
- JVM heap;
- caches;
- in-memory databases;
- application-level object caches.
For such workloads, memory utilization does not always fall simply because you add replicas.
Therefore:
Do not enable memory-based HPA blindly.
Understand application behavior first.
Strategy 3 — Custom and External Metrics
CPU is not always the right business signal.
Imagine an API where:
CPU = 25%but:
Request latency = 2.5 secondsCPU says:
Everything is fine.Users say:
Everything is slow.This is why advanced Kubernetes environments scale using application and business metrics.
Examples:
- HTTP requests per second;
- queue length;
- Kafka consumer lag;
- active sessions;
- request latency;
- pending jobs;
- messages waiting in RabbitMQ;
- number of active WebSocket connections;
- database connection pool pressure.
Custom Metrics Architecture
A common architecture looks like this:
Resource Metrics vs Custom Metrics vs External Metrics
Resource Metrics
Examples:
CPU
MemoryCommon API:
metrics.k8s.ioUsually supplied by Metrics Server.
Custom Metrics
Metrics associated with Kubernetes objects.
Example:
requests_per_secondCommon API:
custom.metrics.k8s.ioExternal Metrics
Metrics that may exist outside Kubernetes.
Examples:
AWS SQS queue length
Kafka lag
cloud monitoring metric
external SaaS metricCommon API:
external.metrics.k8s.ioHPA with Application Request Rate
Conceptually:
metrics:
- type: Pods
pods:
metric:
name: http_requests_per_second
target:
type: AverageValue
averageValue: "100"Meaning:
Try to keep approximately 100 requests/second per Pod.Suppose traffic reaches:
1,000 requests/secondIf each Pod should handle:
100 requests/secondthe desired capacity becomes approximately:
10 PodsThat is often a much better scaling signal than CPU alone.
Choosing the Right Metric
A good autoscaling metric should correlate with pressure on the application.
Bad metric:
Something that changes but does not actually represent load.Good metric:
Something that increases when the application needs more capacity.For HTTP applications:
RPS
latency
in-flight requests
CPUFor workers:
queue depth
queue age
consumer lag
job completion timeFor streaming:
Kafka consumer lag
records waiting
processing delayStrategy 4 — Vertical Pod Autoscaler
Horizontal scaling answers:
How many Pods do I need?
Vertical Pod Autoscaler answers:
How much CPU and memory should each Pod request?
Example
Before:
resources:
requests:
cpu: 200m
memory: 256MiBut monitoring shows the Pod usually needs:
700m CPU
850Mi memoryVPA can recommend or apply more appropriate resource requests.
Architecture
VPA has several cooperating components.
Conceptually:
Recommender
Analyzes resource consumption.
Updater
Determines when existing Pods should receive updated resources.
Depending on cluster capabilities and configuration, this may involve Pod recreation or supported in-place resource updates.
Admission Controller
Applies recommendations when Pods are created or recreated.
VPA Example
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: payment-api-vpa
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: payment-api
updatePolicy:
updateMode: "Auto"
resourcePolicy:
containerPolicies:
- containerName: payment-api
minAllowed:
cpu: 200m
memory: 256Mi
maxAllowed:
cpu: "2"
memory: 2GiVPA is not part of the core Kubernetes API in the same way HPA is. It is installed separately and uses a CRD.
Recommendation-Only Mode
One of the safest ways to introduce VPA is to begin with recommendation mode.
Conceptually:
updatePolicy:
updateMode: "Off"Then inspect:
kubectl describe vpa payment-api-vpaYou may see recommendations such as:
Target:
CPU: 650m
Memory: 700Mi
Lower Bound:
CPU: 300m
Memory: 400Mi
Upper Bound:
CPU: 1200m
Memory: 1GiThis is useful for rightsizing without immediately changing production workloads.
When VPA Is Useful
VPA is useful when:
- developers guess resource requests;
- applications are consistently over-requested;
- applications are consistently under-requested;
- cluster utilization is poor;
- Pods frequently OOM;
- teams want automated resource recommendations.
Over-Requesting
Example:
Pod actually uses:
CPU: 100m
Memory: 200Mi
Pod requests:
CPU: 2 cores
Memory: 4GiThe scheduler reserves based on the request.
That can make the cluster appear full even though real utilization is low.
Result:
Wasted infrastructure cost.Under-Requesting
Example:
Pod requests 100m CPU
but normally needs 900m.Problems can include:
- poor scheduling decisions;
- unstable performance;
- misleading HPA utilization;
- CPU contention;
- OOM risk when memory is also underestimated.
Strategy 5 — Node / Cluster Autoscaling
Now suppose HPA creates more Pods.
HPA:
4 Pods → 12 PodsBut the cluster has no room.
The scheduler produces:
PendingThe node autoscaler handles this infrastructure layer.
Architecture
Important Mental Model
HPA does not normally create Nodes.
Node autoscaling does not normally decide how many application replicas your Deployment needs.
They solve different problems.
HPA:
Application capacity
Node Autoscaler:
Cluster capacityWhy Pending Pods Matter
Node autoscalers commonly react to Pods that cannot be scheduled.
Reasons include:
Insufficient CPU
Insufficient memory
Node affinity constraints
Taints / tolerations
Topology rules
Volume constraints
GPU requirementsExample:
0/5 nodes are available:
5 Insufficient cpu.That may indicate a need for more capacity.
Cloud Interaction
Node autoscalers typically need infrastructure integration.
Depending on the environment, that could mean interacting with:
AWS
Azure
Google Cloud
OpenStack
other supported infrastructure APIsProvisioning may involve creating virtual machines that become Kubernetes worker Nodes.
Cluster Autoscaler vs Modern Node Provisioners
The traditional Kubernetes ecosystem commonly uses Cluster Autoscaler.
Modern managed/cloud environments may also provide or integrate more dynamic node provisioning systems.
The architectural principle remains:
Unschedulable workload
↓
Infrastructure capacity decision
↓
Provision / consolidate NodesNode Consolidation
Node scaling is not only about adding Nodes.
It can also remove underutilized capacity.
Example:
Node A: 15% utilized
Node B: 10% utilized
Node C: 20% utilizedIf workloads can safely fit elsewhere, the environment may consolidate resources.
Potential result:
3 Nodes → 2 NodesThis reduces cost.
But removing Nodes can be disruptive because Pods may need to be terminated and rescheduled.
That is why the following become important:
- PodDisruptionBudgets;
- topology spread;
- anti-affinity;
- graceful shutdown;
- readiness probes;
- replica count.
Strategy 6 — Event-Driven Scaling with KEDA
Many applications do not scale well using CPU.
Consider a RabbitMQ worker.
The worker might be:
CPU: 15%while the queue contains:
200,000 messagesCPU is not the business pressure signal.
Queue length is.
This is where event-driven autoscaling becomes valuable.
KEDA — Kubernetes Event-Driven Autoscaling — can monitor event sources and drive workload scaling.
Architecture
Scale to Zero
One major use case is:
Queue empty
↓
0 workersThen:
Message arrives
↓
KEDA detects backlog
↓
Workers startThis can significantly reduce infrastructure usage for intermittent workloads.
KEDA Example
A conceptual RabbitMQ-style example:
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: order-worker
spec:
scaleTargetRef:
name: order-worker
minReplicaCount: 0
maxReplicaCount: 50
pollingInterval: 15
cooldownPeriod: 120
triggers:
- type: rabbitmq
metadata:
queueName: orders
mode: QueueLength
value: "100"Conceptually:
One replica per approximately 100 queued messages,
subject to configured behavior and scaler semantics.KEDA Use Cases
KEDA is especially useful for:
Kafka
RabbitMQ
Azure Service Bus
AWS SQS
Redis
Prometheus metrics
cron/event-based workloads
cloud queues
stream processors
background workersStrategy 7 — Predictive Scaling
Most autoscaling mechanisms are reactive.
Example:
Traffic rises
↓
CPU rises
↓
HPA notices
↓
More Pods startThere is delay.
Suppose:
New Pod startup time = 90 secondsDuring those 90 seconds, the system may already be overloaded.
Predictive scaling tries to solve this problem by scaling before the load arrives.
Example
Imagine an online banking system.
Historical traffic:
08:00 low
09:00 rising
10:00 high
12:00 high
18:00 very high
02:00 very lowA prediction system may learn that traffic usually spikes at 09:00.
Instead of waiting until:
09:02it might scale at:
08:55Architecture
Predictive Scaling Is Not Simply "Turn On HPA"
Predictive scaling usually requires additional systems such as:
- scheduled scaling;
- custom controllers;
- cloud-specific autoscaling capabilities;
- Prometheus-based forecasting;
- machine-learning models;
- workload-specific prediction logic.
Kubernetes provides primitives, but generic predictive application scaling is not simply a core HPA mode you enable with one standard field.
When Predictive Scaling Is Worth It
Predictive scaling is useful when:
- load patterns are repeatable;
- Pod startup is slow;
- traffic spikes are large;
- cold starts are expensive;
- latency SLOs are strict;
- business events are scheduled.
Examples:
Black Friday
salary payment days
concert ticket launches
daily batch processing
morning banking traffic
sports events
scheduled campaignsHow the Scaling Layers Work Together
Production Kubernetes scaling often looks like this:
This diagram represents one of the core mental models of Kubernetes operations.
HPA + VPA: Can They Be Used Together?
Yes, but you must understand what each controller changes.
HPA changes:
replica countVPA changes:
resource requests / limitsThe dangerous case is when both controllers influence each other using the same resource signal.
Example:
HPA scales on CPU utilization
VPA changes CPU requestsRemember:
CPU utilization ≈ usage / requestIf VPA changes the denominator, HPA's observed utilization changes.
This can create complicated feedback behavior.
Safer Combination
A common architecture is:
VPA:
CPU / memory rightsizing
HPA:
request rate / queue size / custom metricExample:
This separates the feedback loops.
Production-Grade HPA Configuration
A basic HPA is easy.
A stable HPA requires tuning.
Consider:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: payment-api
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: payment-api
minReplicas: 3
maxReplicas: 50
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 65
behavior:
scaleUp:
stabilizationWindowSeconds: 0
policies:
- type: Percent
value: 100
periodSeconds: 60
- type: Pods
value: 4
periodSeconds: 60
selectPolicy: Max
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 20
periodSeconds: 60Why Scale-Up and Scale-Down Should Differ
In many systems:
Scale up fast.
Scale down slowly.Why?
Under-capacity can cause:
latency
timeouts
failed requests
SLO violationsTemporary over-capacity usually causes:
additional costFor critical services, reliability is usually more important than immediately reclaiming every CPU cycle.
Stabilization Window
Suppose traffic behaves like:
High
Low
High
Low
HighWithout stabilization:
5 Pods
10 Pods
5 Pods
10 Pods
5 PodsThis is called:
flapping
thrashingA scale-down stabilization window helps prevent aggressive replica removal.
Example:
scaleDown:
stabilizationWindowSeconds: 300Meaning:
Be conservative when removing replicas after load drops.Startup Probes Matter
Imagine a Java application.
At startup:
CPU jumps to 95%because of:
JVM initialization
class loading
cache warm-up
JIT compilationIf HPA immediately interprets this as real traffic pressure, it may scale unnecessarily.
Good startup/readiness probe design helps autoscaling understand when the application is truly ready.
Example:
startupProbe:
httpGet:
path: /health/startup
port: 8080
failureThreshold: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /health/ready
port: 8080
periodSeconds: 5Scaling Stateful Workloads
Stateless applications are easiest to scale.
Example:
REST API Pod 1
REST API Pod 2
REST API Pod 3Any replica can process the next request.
Stateful systems are harder.
Examples:
databases
Kafka brokers
stateful caches
distributed storage
stateful processing systemsAdding replicas is not always equivalent to adding usable capacity.
Example: StatefulSet
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: example
spec:
serviceName: example
replicas: 3Scaling:
kubectl scale statefulset example --replicas=5may create:
example-3
example-4But the application itself may require:
- shard rebalancing;
- leader election;
- data replication;
- quorum rules;
- disk provisioning;
- topology awareness.
Therefore:
Kubernetes can create the Pods, but the application must support the scaling model.
Scaling Databases
A common beginner mistake is:
Database slow?
Just increase replicas.Database scaling is more complex.
Consider a relational database.
You may have:
1 writer
3 read replicasAdding read replicas helps:
read-heavy trafficbut may not solve:
write contention
locking
slow queries
poor indexes
transaction bottlenecks
connection exhaustionDatabase Scaling Layers
Kubernetes HPA is not a replacement for proper database architecture.
Scaling and Kubernetes Scheduling
Autoscaling creates desired capacity.
Scheduling determines whether that capacity can actually run.
This distinction is critical.
HPA may say:
Need 20 Pods.But scheduling constraints may make that impossible.
Resource Requests
resources:
requests:
cpu: "2"
memory: 4GiIf Nodes have insufficient remaining capacity:
PendingNode Affinity
Example:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: workload
operator: In
values:
- paymentNow only specific Nodes are eligible.
Taints and Tolerations
A Node may have:
dedicated=payment:NoScheduleThe Pod needs a matching toleration.
Otherwise:
HPA creates Pod
Pod remains PendingTopology Spread
Production workloads often need replicas distributed across failure domains.
Example:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app: payment-apiThis improves resilience but can make scheduling more constrained.
Your node autoscaling strategy must understand those constraints.
Autoscaling Failure Scenarios
Autoscaling architecture should be designed around failures, not only the happy path.
Failure 1 — Metrics Server Down
Architecture:
Pods
↓
Metrics Server ❌
↓
HPA cannot read resource metricsEffect:
HPA may be unable to calculate desired scale.Monitor the metrics pipeline itself.
Failure 2 — Missing Resource Requests
HPA based on CPU utilization needs meaningful resource requests.
Bad:
resources: {}Better:
resources:
requests:
cpu: 500m
memory: 512MiFailure 3 — maxReplicas Too Low
Example:
maxReplicas: 5Traffic requires:
20 replicasHPA reaches:
5and can go no further.
Your dashboard may show:
HPA healthywhile the service is overloaded.
Always monitor:
desired replicas
current replicas
max replicas
latency
errors
saturationFailure 4 — Node Capacity Exhausted
HPA creates:
20 Podsbut only:
8 Podscan schedule.
Remaining Pods:
PendingThis is why Pod autoscaling and Node autoscaling should be designed together.
Failure 5 — Slow Node Provisioning
Suppose:
HPA needs 20 more Podsbut new Nodes require:
4 minutesDuring those four minutes, the application may remain under-provisioned.
Solutions may include:
- minimum spare capacity;
- faster node pools;
- pre-warmed Nodes;
- higher minReplicas;
- predictive scaling;
- scheduled scaling.
Failure 6 — Slow Pod Startup
Example:
Container image download: 30 seconds
Application startup: 45 seconds
Readiness warm-up: 30 seconds
Total:
~105 secondsScaling is not instantaneous.
Optimize:
image size
registry placement
startup time
dependency initialization
readiness logicFailure 7 — Scaling on the Wrong Metric
Example:
Queue = 100,000 messages
CPU = 20%CPU-based HPA may do almost nothing.
Use:
queue depth
consumer lag
queue ageinstead.
Failure 8 — Downstream Dependency Is the Bottleneck
Suppose your application scales:
5 Pods → 50 Podsbut every Pod opens:
20 database connectionsNow:
50 × 20 = 1000 connectionsYour database supports:
300Congratulations: autoscaling made the incident worse.
Scaling must consider the entire dependency chain.
Observability for Autoscaling
You should never run autoscaling without visibility.
At minimum, monitor:
Application
request rate
latency
error rate
saturation
queue depth
active sessionsPods
CPU usage
memory usage
CPU throttling
OOM kills
restart count
readiness
startup durationHPA
current replicas
desired replicas
minimum replicas
maximum replicas
current metric
target metric
scaling eventsNodes
CPU allocation
memory allocation
Pod count
unschedulable Pods
node provisioning duration
node consolidationInfrastructure
VM launch failures
cloud capacity errors
quota exhaustion
network limits
IP exhaustion
storage capacityExample Monitoring Flow
Security Considerations
Autoscaling is also a security topic.
A scaling system automatically consumes resources based on observed demand.
That means attackers may be able to influence cost and capacity.
Economic Denial of Sustainability
An attacker sends large volumes of requests.
Autoscaling reacts:
2 Pods
10 Pods
50 Pods
200 PodsNode autoscaling reacts:
3 Nodes
10 Nodes
30 NodesThe service may remain available, but the cloud bill explodes.
This is sometimes described as a cost-amplification or economic denial scenario.
Autoscaling does not replace:
rate limiting
WAF controls
API quotas
bot protection
authentication
abuse detection
budget controlsScaling Architecture with Security Controls
Without controls before the scaling layer, attackers can intentionally generate scaling signals.
Metrics Integrity
If HPA uses custom metrics, ask:
Who can publish the metric?
Who can modify the adapter?
Who can change the HPA?
Who can change maxReplicas?
Who can modify KEDA ScaledObjects?Protect autoscaling resources using Kubernetes RBAC.
Example conceptual policy:
Developers:
read HPA
Platform Team:
modify HPA
Security / Platform:
modify metric adapters
Production automation:
controlled GitOps deploymentGitOps
Production scaling configuration should preferably be version-controlled.
Example:
Git
↓
Pull Request
↓
Review
↓
CI Policy Checks
↓
GitOps Controller
↓
KubernetesThis gives:
auditability
review
rollback
change history
policy enforcementPolicy Controls
Admission policy engines can enforce requirements such as:
Every production Deployment must define resource requests.
Every HPA must define maxReplicas.
Production HPA maxReplicas cannot exceed an approved threshold.
Critical workloads must have PodDisruptionBudgets.
Critical workloads must use multiple replicas.Cost Optimization
Autoscaling and cost optimization are closely related.
A badly configured cluster can waste significant money.
Common Waste Pattern
100 Pods
Each requests 2 CPUs
Actual average usage: 200mRequested:
200 CPUsActual:
20 CPUsThe scheduler plans around requests, not just what your application happens to consume at a given instant.
VPA recommendations can expose such waste.
Cost Optimization Loop
Do Not Optimize Only for Cost
The cheapest configuration is often:
1 Pod
1 Node
tiny resourcesIt is also fragile.
A good optimization target is:
reliability + performance + costnot:
minimum possible billReal-World Architectures
Architecture A — Standard Web API
Recommended starting point:
Deployment
+
HPA CPU/RPS
+
Metrics Server
+
Node AutoscalerArchitecture B — Queue Worker
Use:
KEDA
+
queue length / consumer lag
+
Node AutoscalerArchitecture C — Java Microservice
Potential design:
HPA on request rate
+
VPA recommendations for CPU/memory
+
startupProbe
+
Node AutoscalerWhy request rate?
Because Java startup and JVM behavior can make CPU a noisy scaling signal.
Architecture D — High-Traffic Banking API
Possible layered design:
This design handles:
security
reactive scaling
predictive scaling
infrastructure scaling
observabilityDecision Matrix
| Workload | Recommended Scaling Signal | Main Tool |
|---|---|---|
| Stateless REST API | CPU + RPS | HPA |
| High-latency API | latency / in-flight requests | HPA + custom metrics |
| Kafka consumer | consumer lag | KEDA / custom metrics |
| RabbitMQ worker | queue depth | KEDA |
| Background job processor | pending jobs | KEDA |
| Over-requested workloads | historical CPU/memory | VPA |
| Under-requested workloads | historical CPU/memory | VPA |
| Cluster capacity | unschedulable Pods | Node Autoscaler |
| Predictable traffic spike | schedule / forecast | predictive or scheduled scaling |
| Irregular burst traffic | event/business metric | HPA/KEDA |
| Stateful data system | application-specific | operator / workload-specific mechanism |
Production Checklist
Before saying:
"Our Kubernetes cluster supports autoscaling"verify the following.
Application
- [ ] Application is horizontally scalable where appropriate.
- [ ] Sessions are not accidentally tied to one Pod.
- [ ] Startup time is known.
- [ ] Graceful shutdown works.
- [ ] Readiness probes are correct.
- [ ] Startup probes are configured when needed.
- [ ] Downstream dependency limits are known.
Resources
- [ ] CPU requests are configured.
- [ ] Memory requests are configured.
- [ ] Limits are intentional rather than copied blindly.
- [ ] OOM behavior has been tested.
- [ ] CPU throttling is monitored.
- [ ] VPA recommendations have been reviewed.
HPA
- [ ] autoscaling/v2 is used where appropriate.
- [ ] minReplicas is intentional.
- [ ] maxReplicas is based on tested system capacity.
- [ ] Scaling metric represents real application pressure.
- [ ] Scale-up behavior is tuned.
- [ ] Scale-down stabilization is configured.
- [ ] HPA reaches desired replicas during load tests.
Metrics
- [ ] Metrics Server is healthy when resource metrics are used.
- [ ] Custom metric adapters are monitored when used.
- [ ] Metrics are not stale.
- [ ] Metrics cannot easily be spoofed by unauthorized actors.
- [ ] Metric pipeline failure generates alerts.
Node Scaling
- [ ] Node autoscaling is enabled where required.
- [ ] Node provisioning latency is measured.
- [ ] Cloud quotas are sufficient.
- [ ] Worker IP capacity is sufficient.
- [ ] Node pools match workload constraints.
- [ ] Taints and affinities are tested.
- [ ] Consolidation will not violate availability requirements.
Reliability
- [ ] PodDisruptionBudgets exist for critical services.
- [ ] Multiple replicas exist across failure domains.
- [ ] Topology spread is considered.
- [ ] Capacity exists for rolling deployments.
- [ ] Failure tests include node loss.
- [ ] Failure tests include metrics failure.
- [ ] Failure tests include traffic spikes.
Security
- [ ] Rate limiting exists before autoscaling-sensitive workloads.
- [ ] DDoS controls are enabled where applicable.
- [ ] RBAC protects HPA/VPA/KEDA configuration.
- [ ] Scaling configuration is version-controlled.
- [ ] Admission policies validate production resources.
- [ ] Cost anomaly alerts exist.
- [ ] Resource quotas are configured where appropriate.
Observability
- [ ] Current vs desired replicas are visible.
- [ ] HPA metric vs target metric is visible.
- [ ] Pending Pods are alerted.
- [ ] Unschedulable reasons are visible.
- [ ] Node provisioning events are visible.
- [ ] Latency and errors are correlated with scaling events.
Final Mental Model
Do not memorize Kubernetes autoscaling as a list of controllers.
Think in control loops.
Loop 1 — Application Capacity
Question:
Do I need more application instances?Tools:
HPA
KEDA
custom autoscalersLoop 2 — Pod Size
Question:
Are my CPU and memory requests correct?Tool:
VPALoop 3 — Cluster Capacity
Question:
Can the cluster physically run the Pods that Kubernetes wants?Tool:
Node AutoscalerLoop 4 — Future Demand
Question:
Can I prepare capacity before traffic arrives?Tools:
scheduled scaling
predictive scaling
forecasting
custom controllersThe Complete Picture
The key idea is:
Autoscaling is not one Kubernetes feature. It is a coordinated set of feedback loops between demand, metrics, replicas, resource requests, scheduling, and infrastructure capacity.
If you understand that architecture, you can reason about almost every Kubernetes scaling problem.
Bonus: A Complete Example
Below is a practical example of a stateless API designed for autoscaling.
Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: payment-api
labels:
app: payment-api
spec:
replicas: 3
selector:
matchLabels:
app: payment-api
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0
maxSurge: 1
template:
metadata:
labels:
app: payment-api
spec:
terminationGracePeriodSeconds: 30
containers:
- name: payment-api
image: example/payment-api:1.0.0
ports:
- containerPort: 8080
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: "1"
memory: 1Gi
startupProbe:
httpGet:
path: /health/startup
port: 8080
periodSeconds: 5
failureThreshold: 30
readinessProbe:
httpGet:
path: /health/ready
port: 8080
periodSeconds: 5
livenessProbe:
httpGet:
path: /health/live
port: 8080
periodSeconds: 10HPA
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: payment-api
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: payment-api
minReplicas: 3
maxReplicas: 30
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 65
behavior:
scaleUp:
stabilizationWindowSeconds: 0
policies:
- type: Percent
value: 100
periodSeconds: 60
- type: Pods
value: 4
periodSeconds: 60
selectPolicy: Max
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 20
periodSeconds: 60PodDisruptionBudget
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: payment-api
spec:
minAvailable: 2
selector:
matchLabels:
app: payment-apiTopology Spread
Add to the Pod template:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app: payment-apiNow the architecture starts to look like a real production workload rather than a demo.
Useful kubectl Commands
Inspect resource use
kubectl top podskubectl top nodesInspect HPA
kubectl get hpakubectl describe hpa payment-apiWatch scaling live
kubectl get pods -wor:
kubectl get hpa -wFind pending Pods
kubectl get pods --field-selector=status.phase=PendingInspect scheduling problems
kubectl describe pod <pod-name>Look at:
Events:Possible messages:
Insufficient cpu
Insufficient memory
node(s) had untolerated taint
node affinity conflict
volume node affinity conflictLoad Testing Autoscaling
Never assume autoscaling works because YAML applied successfully.
Test it.
A simple conceptual test plan:
1. Record baseline replicas.
2. Start controlled load.
3. Watch latency.
4. Watch CPU/RPS/queue metric.
5. Watch HPA desired replicas.
6. Watch Pods being created.
7. Watch Pods become Ready.
8. Watch Node capacity.
9. Confirm Node scale-up if necessary.
10. Stop load.
11. Observe stabilization.
12. Confirm safe scale-down.Example Timeline
Common Beginner Mistakes
Mistake 1
HPA configured = scaling solvedWrong.
You still need:
correct metrics
resource requests
node capacity
startup performance
dependency capacity
observabilityMistake 2
High CPU always means add PodsNot necessarily.
The real problem may be:
infinite loop
bad query
CPU-heavy bug
GC pressure
crypto operation
compression
serializationAutoscaling can hide a performance bug by throwing more infrastructure at it.
Mistake 3
Low CPU means application is healthyFalse.
An application can have low CPU and still be blocked on:
database
network
locks
external API
disk
queue
thread pool
connection poolMistake 4
Maximum replicas should be extremely high just in caseDangerous.
A runaway scale event may overload:
database
third-party API
message broker
NAT gateway
cloud quota
budgetmaxReplicas should be based on tested downstream capacity.
Mistake 5
Scale down as fast as possible to save moneyThis often causes flapping.
Production systems usually benefit from more conservative scale-down behavior.
Scaling Maturity Model
Level 0 — Static
replicas: 3No autoscaling.
Level 1 — Manual
Engineers run:
kubectl scaleLevel 2 — Basic HPA
CPU-based autoscaling.
CPU → HPA → replicasLevel 3 — Production HPA
Includes:
resource requests
stabilization
probes
load testing
monitoringLevel 4 — Business-Metric Autoscaling
Uses:
RPS
queue depth
Kafka lag
latencyLevel 5 — Full-Stack Autoscaling
Combines:
HPA/KEDA
+
VPA recommendations
+
Node Autoscaling
+
cost controls
+
observabilityLevel 6 — Predictive / Adaptive Platform
Uses:
forecasting
scheduled pre-scaling
dynamic node provisioning
business-aware metrics
SLO-aware control loopsAt this stage, autoscaling becomes a platform engineering capability rather than a few YAML files.
Interview-Level Summary
If someone asks:
What Kubernetes scaling strategies do you know?
A strong answer is:
Kubernetes scaling happens at multiple layers. Horizontal scaling changes the number of workload replicas using HPA or event-driven systems such as KEDA. Vertical scaling adjusts CPU and memory requests using VPA. Node autoscaling adds or consolidates worker Nodes when the scheduler lacks capacity. HPA can use resource, custom, or external metrics, while predictive or scheduled scaling can prepare capacity before expected traffic. In production these mechanisms have to be designed together with resource requests, probes, scheduling constraints, PodDisruptionBudgets, observability, rate limiting, dependency limits, and cloud capacity.
That answer demonstrates architecture knowledge rather than memorization.
References and Further Reading
This article is aligned with the current Kubernetes autoscaling model documented by the Kubernetes project and the official KEDA documentation.
Recommended topics to continue with:
- Kubernetes Documentation — Horizontal Pod Autoscaling
- Kubernetes Documentation — Horizontal Manual Scaling for a Deployment
- Kubernetes Documentation — Vertical Pod Autoscaling
- Kubernetes Documentation — Node Autoscaling
- Kubernetes Documentation — Autoscaling Workloads
- Kubernetes API Reference — autoscaling/v2
- Kubernetes Autoscaler project — Vertical Pod Autoscaler
- KEDA Documentation — Scaling Deployments, StatefulSets and Custom Resources
- KEDA Documentation — Event-Driven Autoscaling Concepts
Conclusion
The picture many engineers first see looks simple:
Manual Scaling
Custom Metrics
VPA
Cluster Autoscaling
HPA
Predictive ScalingBut production Kubernetes scaling is not six isolated boxes.
It is a system.
Demand
↓
Metrics
↓
Scaling Decision
↓
Replica Count
↓
Scheduling
↓
Infrastructure Capacity
↓
Application Performance
↓
MetricsEvery arrow can fail.
The best Kubernetes engineers do not ask only:
"How do I configure HPA?"They ask:
"What signal represents demand?"
"How fast must capacity arrive?"
"What dependency fails first?"
"What happens when metrics disappear?"
"What happens when Nodes are full?"
"What prevents an attacker from forcing unlimited scaling?"
"What happens when we scale down?"
"How do we know the control loop is healthy?"Once you start asking those questions, you are no longer merely configuring Kubernetes.
You are designing a resilient distributed system.