Autoscaling with the HPA

How the HorizontalPodAutoscaler turns CPU or memory use into a replica count, what it needs to work, how to slow it down with behavior, and where the other autoscalers fit.

35 min 2 hands-on tasksWorkloads · 15% of the exam

Key ideas in this lesson · tap one for a simple explanation

What you will be able to do

  • Create an autoscaling/v2 HPA with one command or in YAML, with min, max and a CPU or memory target.
  • Explain why an HPA shows its targets as unknown, and fix it by adding requests.
  • Control how fast an HPA scales up and down with behavior: stabilization windows and policies.
  • Say what the Vertical Pod Autoscaler and the Cluster Autoscaler change, and why neither runs on this lab.

Your Django app is quiet at night and busy at lunch. You do not want to pick its replica count by hand. A (HPA) watches how much CPU or memory the use, and adds or removes Pods to match. Horizontal means more or fewer Pods, not bigger ones.

On the exam, that means an HPA with exact numbers. Sometimes it also needs a behavior block, which kubectl autoscale cannot write. The grader reads the HPA object; it does not create load and wait for scaling. It can also check whether your Pods request the resource the HPA measures. That is the step most people miss.

How the HPA decides

The HPA loop

metrics-server

measures each Pod's CPU and memory

HPA

compares the usage with your target

Deployment

its replica count goes up or down

The HPA checks every 15 seconds. It only changes the replica count; the Deployment does the rest.

  1. 1.The HPA reads each Pod's usage from , which this lab has installed.
  2. 2.It divides the usage by the Pod's request. That gives a percentage, called utilization.
  3. 3.It averages that over all the Pods and compares it with your target.
  4. 4.It sets a new replica count, kept between minReplicas and maxReplicas.

The formula is desired = ceil(current replicas × current value / target value), where ceil means round up. Example: 4 replicas average 90% CPU, and the target is 60%. Then ceil(4 × 90 / 60) = 6 replicas.

  • Utilization is measured against requests. So if a has no CPU request, the HPA cannot compute anything, and it reports missing request for cpu.
  • Once an HPA manages a , leave spec.replicas out of you apply again. Otherwise every apply fights the autoscaler.

So before you create an HPA, check the two things it needs: working metrics, and requests on the containers.

Check the prerequisites first
kubectl get apiservice v1beta1.metrics.k8s.io           # Available True means metrics-server answers
kubectl -n wl-hpa top pods                                 # usage per Pod
kubectl -n wl-hpa get deploy api -o jsonpath='{.spec.template.spec.containers[*].resources}'; echo
kubectl -n wl-hpa set resources deploy/api -c nginx --requests=cpu=100m   # add the missing request (starts a rollout)

Create one

kubectl autoscale writes an autoscaling/v2 object
# Current kubectl (the exam's v1.37 included)
kubectl -n wl-hpa autoscale deployment api --min=2 --max=8 --cpu=60%
# Older kubectl only knows this form; newer releases still accept it with a deprecation warning
kubectl -n wl-hpa autoscale deployment api --min=2 --max=8 --cpu-percent=60

kubectl -n wl-hpa autoscale deployment api --min=2 --max=8 --cpu=60% --dry-run=client -o yaml > hpa.yaml

Recent uses --cpu and --memory instead of the older --cpu-percent. Anything beyond min, max and one CPU or memory target needs . A target comes in two types, and they are easy to mix up:

Target typeMeansExample
UtilizationA percentage of the Pod's requestaverageUtilization: 75, or --cpu=75%
AverageValueAn amount per Pod, whatever the requestaverageValue: 100Mi, or --cpu=500m

Here is a full HPA with two metrics and a behavior block:

autoscaling/v2 with two metrics and a behavior block
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: worker
  namespace: wl-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: worker
  minReplicas: 1
  maxReplicas: 5
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization          # percent of the request
          averageUtilization: 75
    - type: Resource
      resource:
        name: memory
        target:
          type: AverageValue         # absolute usage per Pod
          averageValue: 100Mi
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 60 # act on the highest recommendation of the last 60s
      policies:
        - type: Pods
          value: 1                   # remove at most 1 Pod ...
          periodSeconds: 30          # ... per 30 seconds

With several metrics, the HPA works out a replica count for each one and uses the largest. Other metric types exist for custom metrics, but they need an extra metrics adapter.

When one direction has several policies, selectPolicy decides which one wins:

  • Max (the default): the policy that allows the biggest change.
  • Min: the policy that allows the smallest change.
  • Disabled: no scaling in that direction at all.

If you leave behavior out, these defaults apply. Note the 300-second window on scale-down: an HPA waits 5 minutes before it removes Pods.

behavior defaultscaleUpscaleDown
stabilizationWindowSeconds0300
policies4 Pods or 100% per 15s, whichever is more100% per 15s
selectPolicyMaxMax

Reading an HPA

Targets, conditions and events
kubectl -n wl-hpa get hpa
# NAME   REFERENCE        TARGETS              MINPODS   MAXPODS   REPLICAS
# api    Deployment/api   cpu: <unknown>/60%   2         8         2        <- no metrics or no requests
kubectl -n wl-hpa describe hpa api | sed -n '/Conditions/,$p'
#   ScalingActive  False  FailedGetResourceMetric  ... missing request for cpu in container nginx ...
ConditionWhat it tells you
AbleToScaleWhether the HPA can change the target's replica count
ScalingActiveWhether a metric could be computed. False means no metrics, Pods too new, or missing requests
ScalingLimitedTrue when min, max or a policy held the count back

A new HPA shows <unknown> for up to a minute, while metrics-server collects its first numbers. If it stays that way, read the condition message.

Other autoscalers

Two other autoscalers change different things. Keep the three apart:

AutoscalerIt changesExample
HorizontalPodAutoscalerThe number of Pods2 to 6 nginx Pods at lunchtime
Vertical Pod AutoscalerEach Pod's requests100m to 300m CPU per Pod
Cluster AutoscalerThe number of Adds a node when Pods are Pending for lack of room

Neither of the last two runs on kind, and the exam treats both as concepts.

In the official docs· open on exam day too

Hands-on task 1 of 2wl-hpa-1
~6 min5% weightWorkloads

Autoscale a Deployment on CPU

The Deployment api in namespace wl-hpa must scale automatically between 2 and 8 replicas, keeping the average CPU utilization of its Pods at 60%. Create a HorizontalPodAutoscaler named api for it. The autoscaler can only compute utilization if the Pods request CPU, so also give the Deployment's nginx container a CPU request of 100m.

Cluster:kubectl config use-context kind-cka

  1. 1

    Set up the scenario

    curl -fsSL https://codewithmuh.com/labs/cka/t/wl-hpa-1/setup | bash
  2. 2

    Solve it in your terminal

    Use kubectl and the Kubernetes docs, like on exam day. Save any answer files under /tmp/cka/.

  3. 3

    Check your work

    curl -fsSL https://codewithmuh.com/labs/cka/t/wl-hpa-1/verify | bash
    Got FAIL? Read which check failed, fix it, run it again.
  4. 4

    Clean up (optional)

    curl -fsSL https://codewithmuh.com/labs/cka/t/wl-hpa-1/cleanup | bash
Hands-on task 2 of 2wl-hpa-2
~7 min6% weightWorkloads

An HPA with two metrics and a slow scale-down

In namespace wl-hpa, create an autoscaling/v2 HorizontalPodAutoscaler worker for the Deployment worker. It keeps between 1 and 5 replicas and scales on two metrics: an average CPU utilization of 75%, and an average memory usage of 100Mi per Pod. Scale-downs must use a 60-second stabilization window and remove at most 1 Pod every 30 seconds.

Cluster:kubectl config use-context kind-cka

  1. 1

    Set up the scenario

    curl -fsSL https://codewithmuh.com/labs/cka/t/wl-hpa-2/setup | bash
  2. 2

    Solve it in your terminal

    Use kubectl and the Kubernetes docs, like on exam day. Save any answer files under /tmp/cka/.

  3. 3

    Check your work

    curl -fsSL https://codewithmuh.com/labs/cka/t/wl-hpa-2/verify | bash
    Got FAIL? Read which check failed, fix it, run it again.
  4. 4

    Clean up (optional)

    curl -fsSL https://codewithmuh.com/labs/cka/t/wl-hpa-2/cleanup | bash

Finished this lesson?

0 of 2 tasks passed. Your readiness counts tasks, so run them before you move on.