Task 8 - Auto Scaling Deployment
Objective: Automate Deployment Scaling with HPA
Learn to configure the Horizontal Pod Autoscaler (HPA) for a deployment and simulate traffic to test scaling.
Using kubectl autoscale
When Kubernetes has Resouce Metrics API installed, We can using the kubectl autoscale command kubectl autoscale deployment to automatically scale a deployment based on CPU utilization (or any other metric) requires that the Kubernetes Metrics Server (or an equivalent metrics API) is installed and operational in your cluster. The Metrics Server collects resource metrics from Kubelets and exposes them in the Kubernetes API server through the Metrics API for use by Horizontal Pod Autoscaler (HPA) and other components.
using the kubectl autoscale command to automatically scale a deployment based on CPU utilization (or any other metric) requires that the Kubernetes Metrics Server (or an equivalent metrics API) is installed and operational in your cluster. The Metrics Server collects resource metrics from Kubelets and exposes them in the Kubernetes API server through the Metrics API for use by Horizontal Pod Autoscaler (HPA) and other components.
Enable resource-API
The Resource Metrics API in Kubernetes is crucial for providing core metrics about Pods and nodes within a cluster, such as CPU and memory usage to enable feature like Horizontal Pod Autoscaler (HPA), Vertical Pod Autoscaler (VPA) and enable efficent resource scheduling.
Preflight check
This task installs the Metrics Server and then creates its own nginx-deployment Deployment, Service and HPA, so the default namespace must not already have them. Confirm the cluster from Task 3 - Install Kubernetes is healthy and empty:
kubectl get nodes
kubectl get deploymentBoth nodes must report Ready, and no Deployment should be listed — kubectl reports the empty list on stderr:
NAME STATUS ROLES AGE VERSION
node-worker Ready <none> 10m v1.30.x
node-master Ready control-plane 15m v1.30.x
No resources found in default namespace.If a node is missing or NotReady, go back to Task 3 and finish it. If nginx-deployment is already listed, it is left over from Task 4 - Scaling Application, whose scripts/deploy_application_with_hpa_masternode.sh creates a deployment with the same name. Remove it with kubectl delete deployment nginx-deployment and kubectl delete svc nginx-deployment before continuing.
- copy/paste below command to enable resource-api
curl --insecure --retry 3 --retry-connrefused -fL "https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml" -o components.yaml
sed -i '/- --metric-resolution/a \ \ \ \ \ \ \ \ - --kubelet-insecure-tls' components.yaml
kubectl apply -f components.yaml
kubectl rollout status deployment metrics-server -n kube-systemuse kubectl top node and kubectl top pod to check the Pod and node resource usage
Create a deployment with resource constrain
In this deployment , we add some resource restriction like memory and cpu for a POD.
when POD reach the CPU or memory limit, if HPA configured, new POD will be created according HPA policy.
- create deployment with CPU and Memory constraints
cat <<EOF | tee nginx-deployment_resource.yaml apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment labels: app: nginx spec: replicas: 2 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:latest ports: - containerPort: 80 resources: requests: memory: "64Mi" # Minimum memory requested to start the container cpu: "10m" # 100 millicpu (0.1 CPU) requested to start the container limits: memory: "128Mi" # Maximum memory limit for the container cpu: "40m" # 200 millicpu (0.2 CPU) maximum limit for the container EOF kubectl apply -f nginx-deployment_resource.yaml kubectl rollout status deployment nginx-deployment cat << EOF | tee nginx-deployment_clusterIP.yaml apiVersion: v1 kind: Service metadata: labels: app: nginx name: nginx-deployment namespace: default spec: ipFamilies: - IPv4 ipFamilyPolicy: SingleStack ports: - port: 80 protocol: TCP targetPort: 80 selector: app: nginx sessionAffinity: None type: ClusterIP EOF kubectl apply -f nginx-deployment_clusterIP.yamlcheck the deployment and service
kubectl get deployment nginx-deployment kubectl get svc nginx-deployment
Use autoscale (HPA) to scale your application
- We can use
kubectl autoscalecommand or use create a hpa yaml file then follow akubectl apply -fto create hpa.
use kubectl command to create hpa
kubectl autoscale deployment nginx-deployment --name=nginx-deployment-hpa --min=2 --max=10 --cpu-percent=50 --save-configexpected Outcome
horizontalpodautoscaler.autoscaling/nginx-deployment-hpa autoscaledor use yaml file to create hpa
cat << EOF | tee > nginx-deployment-hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: nginx-deployment-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: nginx-deployment
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
EOF
kubectl apply -f nginx-deployment-hpa.yaml- Target CPU Utilization: This is set to 50%. It means the HPA will aim to adjust the number of Pods so that the average CPU utilization across all Pods is around 50% of the allocated CPU resources for each Pod.
- Scaling Out: If the average CPU utilization across all Pods in the nginx-deployment exceeds 50%, the HPA will increase the number of Pods, making more resources available to handle the workload, until it reaches the maximum limit of 10 Pods.
- Scaling In: If the average CPU utilization drops below 50%, indicating that the resources are underutilized, the HPA will decrease the number of Pods to reduce resource usage, but it won’t go below the minimum of 2 Pod.
- Check Result
use kubectl get hpa nginx-deployment-hpa to check deployment
kubectl get hpa nginx-deployment-hpaExpected Outcome
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
nginx-deployment-hpa Deployment/nginx-deployment 0%/50% 2 10 2 23suse kubectl get deployment nginx-deployment to check the change of deployment.
use kubectl get hpa and kubectl describe hpa to check the size of replicas.
Send http traffic to application
since the nginx-deployment service is cluster-ip type service which can only be accessed from cluster internal, so we need to create a POD which can send http traffic to nginx-deployment service.
- create deployment for generate http traffic, in this deployment, we will use wget to similuate the real traffic towards ngnix-deployment cluster-ip service which has service name
http://nginx-deployment.default.svc.cluster.local.
cat <<EOF | tee infinite-calls-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: infinite-calls
labels:
app: infinite-calls
spec:
replicas: 2
selector:
matchLabels:
app: infinite-calls
template:
metadata:
name: infinite-calls
labels:
app: infinite-calls
spec:
containers:
- name: infinite-calls
image: busybox
command:
- /bin/sh
- -c
- "while true; do wget -q -O- http://nginx-deployment.default.svc.cluster.local; done"
EOF
kubectl apply -f infinite-calls-deployment.yaml- check the creation of infinite-calls deployment
kubectl get deployment infinite-calls- check the log from infinite-calls Pods. {.items[0]} means use first Pod
podName=$(kubectl get pod -l app=infinite-calls -o=jsonpath='{.items[0].metadata.name}')
kubectl logs po/$podNameyou will see the response from nginx web server container. use ctr-c to stop.
use kubectl top pod and kubectl top node to check the resource usage status
user expected to see the number of Pod increased
You shall see that expected Pod now increased automatically without use attention.
kubectl get pod -l app=nginxexpected outcome
NAME READY STATUS RESTARTS AGE nginx-deployment-55c7f467f8-f2qbp 1/1 Running 0 19m nginx-deployment-55c7f467f8-hxs79 1/1 Running 0 2m2s nginx-deployment-55c7f467f8-jx2k9 1/1 Running 0 19m nginx-deployment-55c7f467f8-r7vdv 1/1 Running 0 3m2s nginx-deployment-55c7f467f8-w6r8l 1/1 Running 0 3m17sUse
kubectl get hpashall tell you that hpa is action which increased the replicas from 2 to other numbers.kubectl get hpaexpected outcome
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE nginx-deployment-hpa Deployment/nginx-deployment 50%/50% 2 10 5 11mcheck hpa detail
kubectl describe hpaexpected outcome
Name: nginx-deployment-hpa Namespace: default Labels: <none> Annotations: <none> CreationTimestamp: Wed, 08 Jul 2026 16:21:40 +0000 Reference: Deployment/nginx-deployment Metrics: ( current / target ) resource cpu on pods (as a percentage of request): 117% (11m) / 50% Min replicas: 2 Max replicas: 10 Deployment pods: 10 current / 10 desired Conditions: Type Status Reason Message ---- ------ ------ ------- AbleToScale True ReadyForNewScale recommended size matches current size ScalingActive True ValidMetricFound the HPA was able to successfully calculate a replica count from cpu resource utilization (percentage of request) ScalingLimited True TooManyReplicas the desired replica count is more than the maximum replica count Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal SuccessfulRescale 58s horizontal-pod-autoscaler New size: 4; reason: cpu resource utilization (percentage of request) above target Normal SuccessfulRescale 43s horizontal-pod-autoscaler New size: 8; reason: cpu resource utilization (percentage of request) above target Normal SuccessfulRescale 28s horizontal-pod-autoscaler New size: 10; reason: cpu resource utilization (percentage of request) above targetdelete infinite-calls to stop generate the traffic
kubectl delete deployment infinite-callsafter few minutes later, due to no more traffic is hitting the nginx server. hpa will scale in the number of Pod to save resource.
kubectl get hpaexpected output
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE nginx-deployment-hpa Deployment/nginx-deployment 0%/50% 2 10 5 12muse
kubectl describe hpawill tell you the reason why hpa scale in the number of Pod.
kubectl describe hpaexpected outcome
Name: nginx-deployment-hpa
Namespace: default
Labels: <none>
Annotations: <none>
CreationTimestamp: Wed, 08 Jul 2026 16:21:40 +0000
Reference: Deployment/nginx-deployment
Metrics: ( current / target )
resource cpu on pods (as a percentage of request): 0% (0) / 50%
Min replicas: 2
Max replicas: 10
Deployment pods: 2 current / 2 desired
Conditions:
Type Status Reason Message
---- ------ ------ -------
AbleToScale True ReadyForNewScale recommended size matches current size
ScalingActive True ValidMetricFound the HPA was able to successfully calculate a replica count from cpu resource utilization (percentage of request)
ScalingLimited True TooFewReplicas the desired replica count is less than the minimum replica count
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulRescale 10m horizontal-pod-autoscaler New size: 4; reason: cpu resource utilization (percentage of request) above target
Normal SuccessfulRescale 10m horizontal-pod-autoscaler New size: 8; reason: cpu resource utilization (percentage of request) above target
Normal SuccessfulRescale 10m horizontal-pod-autoscaler New size: 10; reason: cpu resource utilization (percentage of request) above target
Normal SuccessfulRescale 96s horizontal-pod-autoscaler New size: 2; reason: All metrics below targetclean up
kubectl delete hpa nginx-deployment-hpa
kubectl delete deployment nginx-deployment
kubectl delete svc nginx-deploymentSummary
Choosing the right scaling method depends on your specific needs, such as whether you need to quickly adjust resources, maintain performance under varying loads, or integrate scaling into a CI/CD pipeline. Manual methods like kubectl scale or editing the deployment are straightforward for immediate needs, while kubectl autoscale and HPA provide more dynamic, automated scaling based on actual usage, making them better suited for production environments with fluctuating workloads.