Day 9: Scaling and Update Strategies
What You'll Learn Today
- Horizontal Pod Autoscaler (HPA) for automatic scaling
- Vertical Pod Autoscaler (VPA) overview
- Blue/Green and Canary deployment strategies
- StatefulSet basics
Automatic Scaling
In Day 4, you learned manual scaling with kubectl scale. Kubernetes also provides automatic Pod count adjustment based on load.
flowchart TB
subgraph Scaling["Scaling Types"]
HPA["Horizontal Pod Autoscaler\n(adjust Pod count)"]
VPA["Vertical Pod Autoscaler\n(adjust resource amounts)"]
CA["Cluster Autoscaler\n(adjust node count)"]
end
style HPA fill:#3b82f6,color:#fff
style VPA fill:#8b5cf6,color:#fff
style CA fill:#22c55e,color:#fff
| Type | Target | Description |
|---|---|---|
| HPA | Pod count | Adjusts replicas based on CPU/memory usage |
| VPA | Resource amounts | Adjusts Pod requests/limits automatically |
| Cluster Autoscaler | Node count | Adjusts cluster node count (cloud environments) |
Horizontal Pod Autoscaler (HPA)
HPA automatically scales Deployment replicas based on CPU utilization or custom metrics.
Prerequisites: Metrics Server
# Verify Metrics Server
kubectl top nodes
kubectl top pods
# For Minikube
minikube addons enable metrics-server
Creating an HPA
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: web-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: web-app
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 70
# Or create via command
kubectl autoscale deployment web-app \
--min=2 --max=10 --cpu-percent=50
How HPA Works
flowchart LR
MS["Metrics Server"] -->|"collect metrics"| HPA["HPA"]
HPA -->|"CPU > 50%"| UP["Scale Up\n(increase Pods)"]
HPA -->|"CPU < 50%"| DOWN["Scale Down\n(decrease Pods)"]
UP --> DEP["Deployment"]
DOWN --> DEP
style HPA fill:#3b82f6,color:#fff
style UP fill:#22c55e,color:#fff
style DOWN fill:#f59e0b,color:#fff
Testing HPA
# Check HPA status
kubectl get hpa
# NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS
# web-hpa Deployment/web-app 10%/50% 2 10 2
# Generate load
kubectl run load-test --image=busybox:1.37 --rm -it -- \
/bin/sh -c "while true; do wget -q -O- http://web-service; done"
# Watch HPA in another terminal
kubectl get hpa -w
HPA Parameters
| Parameter | Description |
|---|---|
minReplicas |
Minimum replica count |
maxReplicas |
Maximum replica count |
averageUtilization |
Target usage percentage |
scaleDown.stabilizationWindowSeconds |
Cooldown before scale-down (default 300s) |
Deployments using HPA must have
resources.requestsset on their Pods.
Update Strategies
Beyond the rolling update from Day 4, there are several deployment strategies.
1. Recreate
Stops all Pods before starting new ones. Causes downtime.
spec:
strategy:
type: Recreate
2. Rolling Update
Gradual Pod replacement (default). Covered in Day 4.
3. Blue/Green Deployment
Not a native Kubernetes feature, but achievable using Service label selectors and Deployments.
flowchart TB
SVC["Service\nselector: version=green"]
subgraph Blue["Blue (old version)"]
B1["Pod v1"]
B2["Pod v1"]
end
subgraph Green["Green (new version)"]
G1["Pod v2"]
G2["Pod v2"]
end
SVC -->|"switch"| Green
style Blue fill:#3b82f6,color:#fff
style Green fill:#22c55e,color:#fff
style SVC fill:#8b5cf6,color:#fff
# blue-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-blue
spec:
replicas: 3
selector:
matchLabels:
app: myapp
version: blue
template:
metadata:
labels:
app: myapp
version: blue
spec:
containers:
- name: app
image: myapp:1.0
---
# green-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-green
spec:
replicas: 3
selector:
matchLabels:
app: myapp
version: green
template:
metadata:
labels:
app: myapp
version: green
spec:
containers:
- name: app
image: myapp:2.0
---
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: app-service
spec:
selector:
app: myapp
version: blue # Change to green to switch
ports:
- port: 80
# Switch Blue β Green
kubectl patch service app-service -p '{"spec":{"selector":{"version":"green"}}}'
# Rollback to Blue
kubectl patch service app-service -p '{"spec":{"selector":{"version":"blue"}}}'
4. Canary Deployment
Deploy the new version to a small subset of Pods for testing, then gradually expand.
flowchart TB
SVC["Service\nselector: app=myapp"]
subgraph Stable["Stable (90%)"]
S1["Pod v1"]
S2["Pod v1"]
S3["Pod v1"]
S4["Pod v1"]
S5["Pod v1"]
S6["Pod v1"]
S7["Pod v1"]
S8["Pod v1"]
S9["Pod v1"]
end
subgraph Canary["Canary (10%)"]
C1["Pod v2"]
end
SVC --> Stable
SVC --> Canary
style Stable fill:#3b82f6,color:#fff
style Canary fill:#f59e0b,color:#fff
# stable-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-stable
spec:
replicas: 9
selector:
matchLabels:
app: myapp
track: stable
template:
metadata:
labels:
app: myapp
track: stable
spec:
containers:
- name: app
image: myapp:1.0
---
# canary-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-canary
spec:
replicas: 1
selector:
matchLabels:
app: myapp
track: canary
template:
metadata:
labels:
app: myapp
track: canary
spec:
containers:
- name: app
image: myapp:2.0
---
# service.yaml (routes to both)
apiVersion: v1
kind: Service
metadata:
name: app-service
spec:
selector:
app: myapp # No track specified β routes to both
ports:
- port: 80
Strategy Comparison
| Strategy | Downtime | Rollback | Resources | Complexity |
|---|---|---|---|---|
| Recreate | Yes | Slow | Low | Low |
| Rolling Update | No | Automatic | Medium | Low |
| Blue/Green | No | Instant | Double | Medium |
| Canary | No | Instant | Slightly more | High |
StatefulSet
Deployments are for stateless applications. For stateful applications like databases and message queues, use StatefulSets.
Deployment vs. StatefulSet
| Property | Deployment | StatefulSet |
|---|---|---|
| Pod names | Random (app-7f8b-abc) | Sequential (app-0, app-1, app-2) |
| Startup order | Parallel | Sequential (0 β 1 β 2) |
| Storage | Shared PVC | Per-Pod PVC |
| Network | Random IP | Stable DNS names |
StatefulSet Example
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
spec:
serviceName: postgres-headless
replicas: 3
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:17
ports:
- containerPort: 5432
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
---
apiVersion: v1
kind: Service
metadata:
name: postgres-headless
spec:
clusterIP: None
selector:
app: postgres
ports:
- port: 5432
StatefulSet Pods get stable DNS names:
postgres-0.postgres-headless.default.svc.cluster.localpostgres-1.postgres-headless.default.svc.cluster.localpostgres-2.postgres-headless.default.svc.cluster.local
Summary
| Concept | Description |
|---|---|
| HPA | Automatic Pod scaling based on CPU/memory |
| VPA | Automatic Pod resource adjustment |
| Blue/Green | Switch between two environments instantly |
| Canary | Gradually roll out new version to a subset of Pods |
| StatefulSet | Controller for stateful applications |
Key Takeaways
- HPA automatically adjusts Pod count based on load.
resources.requestsis required - Blue/Green enables instant switching; Canary enables gradual rollouts
- Use StatefulSets for stateful applications like databases
Practice Exercises
Exercise 1: HPA
Configure HPA for a web Deployment. Scale between 2-8 Pods at 50% CPU utilization.
Exercise 2: Blue/Green
Implement Blue/Green deployment with two app versions (nginx:1.26 and nginx:1.27). Practice switching the Service.
Challenge
Set up a 3-node Redis cluster using StatefulSet with per-Pod PVCs and stable DNS names.
References
Next up: In Day 10, you'll learn about "Production Readiness and Best Practices" β Namespaces, RBAC, resource management, monitoring, and comprehensive production best practices.