Giao diện
Horizontal Pod Autoscaler (HPA) & Metrics Server
💰 Góc nhìn Cloud Cost Optimization
Module này được viết từ góc nhìn của Cloud Cost Optimization Engineer tại HPN. Mục tiêu: Tối ưu chi phí và đảm bảo hiệu năng thông qua autoscaling thông minh.
📋 Prerequisites: Điều Kiện Tiên Quyết
🚨 KHÔNG ĐÁP ỨNG = HPA KHÔNG HOẠT ĐỘNG
Trước khi cấu hình HPA, bạn PHẢI đảm bảo hai điều kiện sau:
1️⃣ Metrics Server phải được cài đặt
HPA cần dữ liệu metrics để ra quyết định. Không có Metrics Server = HPA mù hoàn toàn.
Kiểm tra Metrics Server:
bash
# Kiểm tra Metrics Server có đang chạy
kubectl get pods -n kube-system | grep metrics-server
# Kiểm tra API có available
kubectl top nodes
kubectl top podsNếu chưa có, cài đặt:
bash
# Cài đặt Metrics Server (phiên bản chính thức)
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
# Đối với môi trường local (minikube, kind) - cần thêm flag
# --kubelet-insecure-tls⚠️ LƯU Ý QUAN TRỌNG
Metrics Server thu thập metrics từ kubelet trên mỗi node. Dữ liệu này được lưu trong memory và chỉ giữ 15 giây gần nhất. Đây KHÔNG phải là giải pháp monitoring dài hạn (dùng Prometheus cho việc đó).
2️⃣ Pods PHẢI có resources.requests
📚 Tham khảo Module 2
Nếu chưa hiểu về resources.requests, hãy xem lại Resources & QoS.
HPA tính toán dựa trên % utilization của requests:
yaml
# ❌ THIẾU requests → HPA KHÔNG THỂ TÍNH TOÁN
spec:
containers:
- name: app
image: myapp:1.0
# Không có resources → HPA sẽ báo error!
# ✅ CÓ requests → HPA hoạt động
spec:
containers:
- name: app
image: myapp:1.0
resources:
requests:
cpu: "500m" # 0.5 CPU
memory: "256Mi" # 256 MiB
limits:
cpu: "1000m"
memory: "512Mi"Error khi thiếu requests:
text
$ kubectl describe hpa myapp-hpa
Warning FailedGetResourceMetric
missing request for cpu in container app of Pod myapp-xxx🧮 Thuật Toán HPA: Công Thức Scaling
📐 CÔNG THỨC CỐT LÕI
DesiredReplicas = ceil(CurrentReplicas × (CurrentMetricValue / TargetMetricValue))Ví dụ thực tế
Scenario: Bạn có Deployment với 2 replicas, target CPU 50%
yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: myapp-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: myapp
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50 # Target 50% CPUCase 1: Traffic spike - Cần SCALE OUT
text
📊 Current State:
└── CurrentReplicas: 2
└── CurrentCPU: 100% (mỗi pod đang dùng 100% của request)
└── TargetCPU: 50%
🧮 Tính toán:
DesiredReplicas = ceil(2 × (100 / 50))
= ceil(2 × 2)
= 4
📈 Action: Scale từ 2 → 4 podsCase 2: Traffic giảm - Cần SCALE IN
text
📊 Current State:
└── CurrentReplicas: 4
└── CurrentCPU: 25% (traffic đã giảm)
└── TargetCPU: 50%
🧮 Tính toán:
DesiredReplicas = ceil(4 × (25 / 50))
= ceil(4 × 0.5)
= ceil(2)
= 2
📉 Action: Scale từ 4 → 2 pods⚡ Behavior: Scale Out Nhanh, Scale In Chậm
💡 NGUYÊN TẮC VÀNG
- Scale Out: Nhanh nhất có thể (users đang đợi!)
- Scale In: Chậm và cẩn thận (tránh "Thrashing")
Thrashing là gì?
Thrashing (hay Flapping) là tình trạng HPA liên tục scale up rồi scale down trong thời gian ngắn:
text
Time 0:00 → 2 pods (traffic spike)
Time 0:30 → 4 pods (HPA scale out)
Time 1:00 → 2 pods (traffic drop → scale in ngay)
Time 1:30 → 4 pods (traffic spike lại)
Time 2:00 → 2 pods (...)
❌ Vấn đề:
- Pods liên tục bị terminate → startup overhead
- Connections bị drop
- User experience tệHPA Behavior Configuration (K8s 1.18+)
yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: myapp-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: myapp
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
# 🎛️ BEHAVIOR CONFIGURATION
behavior:
# ⚡ SCALE OUT: Aggressive
scaleUp:
stabilizationWindowSeconds: 0 # Không đợi, scale ngay!
policies:
- type: Percent
value: 100 # Có thể double pods mỗi 15s
periodSeconds: 15
- type: Pods
value: 4 # Hoặc thêm tối đa 4 pods mỗi 15s
periodSeconds: 15
selectPolicy: Max # Chọn policy nào cho nhiều pods hơn
# 🐢 SCALE IN: Conservative
scaleDown:
stabilizationWindowSeconds: 300 # Đợi 5 phút ổn định
policies:
- type: Percent
value: 10 # Giảm tối đa 10% mỗi phút
periodSeconds: 60
selectPolicy: Min # Chọn policy nào giảm ít pods hơnGiải thích các tham số
| Tham số | Scale Up | Scale Down |
|---|---|---|
stabilizationWindowSeconds | 0 (tức thì) | 300 (5 phút) |
policies | Aggressive (100%, 4 pods) | Conservative (10%) |
selectPolicy | Max (scale mạnh) | Min (scale nhẹ) |
Visualization của quá trình:
📊 HPA với Multiple Metrics
HPA có thể scale dựa trên nhiều metrics cùng lúc:
yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: myapp-hpa-multi
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: myapp
minReplicas: 2
maxReplicas: 20
metrics:
# Metric 1: CPU
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 50
# Metric 2: Memory
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 70💡 LOGIC KHI CÓ NHIỀU METRICS
HPA sẽ tính DesiredReplicas cho mỗi metric, sau đó chọn GIÁ TRỊ LỚN NHẤT.
Ví dụ:
- CPU metric → cần 4 pods
- Memory metric → cần 6 pods
- Kết quả: HPA scale lên 6 pods
🎯 Custom Metrics: Vượt xa CPU/Memory
💡 SỰ THẬT PHŨ PHÀNG
Scale theo CPU là baseline, nhưng thường KHÔNG ĐỦ TỐT cho production.
Tại sao?
- CPU cao có thể do garbage collection, không phải traffic
- Memory tăng có thể do memory leak, không phải load
- Metric tốt nhất là Request Per Second (RPS) hoặc Latency P99
Kiến trúc Custom Metrics
Ví dụ: Scale theo RPS (Requests Per Second)
Bước 1: Application expose metrics
python
# Python Flask với prometheus_client
from prometheus_client import Counter, generate_latest
REQUEST_COUNT = Counter('http_requests_total', 'Total HTTP Requests')
@app.route('/api/orders')
def orders():
REQUEST_COUNT.inc()
return handle_orders()
@app.route('/metrics')
def metrics():
return generate_latest()Bước 2: Cài Prometheus Adapter
bash
helm install prometheus-adapter prometheus-community/prometheus-adapter \
--set prometheus.url=http://prometheus-server.monitoring.svcBước 3: Cấu hình HPA với custom metric
yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: myapp-hpa-rps
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: myapp
minReplicas: 2
maxReplicas: 50
metrics:
- type: Pods
pods:
metric:
name: http_requests_per_second
target:
type: AverageValue
averageValue: "1000" # Target: 1000 RPS per pod⚠️ COMPLEXITY WARNING
Custom Metrics yêu cầu:
- Prometheus đang chạy và thu thập metrics
- Prometheus Adapter được cấu hình đúng
- Application expose đúng metrics
Đây là advanced topic - bắt đầu với CPU/Memory trước, sau đó nâng cấp lên custom metrics khi cần.
🏭 HPN Production Template
yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: hpn-production-hpa
namespace: production
labels:
app: myapp
team: backend
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: myapp
# 📊 Replica Bounds
minReplicas: 3 # Luôn có ít nhất 3 pods (HA)
maxReplicas: 20 # Giới hạn chi phí
# 🎯 Metrics
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 60 # Conservative target
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 75
# 🎛️ Behavior
behavior:
scaleUp:
stabilizationWindowSeconds: 0
policies:
- type: Percent
value: 100
periodSeconds: 15
selectPolicy: Max
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 10
periodSeconds: 60
selectPolicy: Min🔍 Debugging HPA
Kiểm tra trạng thái HPA
bash
# Xem HPA overview
kubectl get hpa
# Output mẫu:
# NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
# myapp-hpa Deployment/myapp 45%/50% 2 10 4 1h
# Xem chi tiết
kubectl describe hpa myapp-hpaCác vấn đề thường gặp
| Vấn đề | Nguyên nhân | Giải pháp |
|---|---|---|
TARGETS: <unknown>/50% | Metrics Server chưa cài | Cài Metrics Server |
TARGETS: <unknown>/50% | Pod thiếu resources.requests | Thêm requests vào Pod spec |
ScalingActive: False | minReplicas = maxReplicas | Điều chỉnh replica range |
| Scale không như mong đợi | Stabilization window | Đợi hoặc điều chỉnh behavior |
📊 Tổng Kết
| Khái niệm | Mô tả |
|---|---|
| Metrics Server | Thu thập CPU/Memory từ kubelet |
| resources.requests | Baseline để tính % utilization |
| Algorithm | ceil(CurrentReplicas × (Current / Target)) |
| Scale Out | Nhanh, aggressive |
| Scale In | Chậm, conservative (tránh thrashing) |
| Custom Metrics | RPS, Latency - cần Prometheus Adapter |
⚠️ CHECKLIST TRƯỚC KHI DÙNG HPA
- ✅ Metrics Server đã cài đặt
- ✅ Pods có
resources.requests - ✅ Hiểu behavior: scale out nhanh, scale in chậm
- ✅ Set
minReplicas≥ 2 (HA) - ✅ Set
maxReplicashợp lý (budget constraint)
📐 Vertical Pod Autoscaler (VPA)
💡 VPA LÀ GÌ?
VPA tự động điều chỉnh CPU/Memory requests của pods dựa trên usage thực tế. Trong khi HPA scale số lượng pods, VPA scale kích thước mỗi pod.
VPA vs HPA: Khi Nào Dùng Cái Nào?
| Tiêu chí | HPA | VPA |
|---|---|---|
| Scale gì? | Số lượng pods | CPU/Memory của pod |
| Phù hợp với | Stateless apps | Stateful apps, JVM apps |
| Restart pods? | Không | Có (khi updateMode=Auto) |
| Phản ứng | Nhanh (seconds) | Chậm hơn (minutes) |
| Use case | Traffic spikes | Right-sizing resources |
VPA updateMode: 3 Chế Độ
yaml
# 🔍 MODE 1: Off - Chỉ recommend, không apply
# Dùng để phân tích trước khi enable
updatePolicy:
updateMode: "Off"
# 🚀 MODE 2: Initial - Apply cho pods MỚI
# Pods đang chạy không bị ảnh hưởng
updatePolicy:
updateMode: "Initial"
# ⚡ MODE 3: Auto - Tự động restart pods để apply
# ⚠️ CẢNH BÁO: Có thể gây disruption!
updatePolicy:
updateMode: "Auto"| Mode | Apply cho pods mới? | Restart pods hiện tại? | Production-safe? |
|---|---|---|---|
| Off | ❌ | ❌ | ✅ Rất an toàn |
| Initial | ✅ | ❌ | ✅ An toàn |
| Auto | ✅ | ✅ | ⚠️ Cẩn thận |
VPA Minimal Configuration
yaml
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: myapp-vpa
namespace: production
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: myapp
updatePolicy:
updateMode: "Off" # 🔍 Bắt đầu với Off để phân tích
resourcePolicy:
containerPolicies:
- containerName: "*"
minAllowed:
cpu: "100m"
memory: "128Mi"
maxAllowed:
cpu: "4"
memory: "8Gi"
controlledResources: ["cpu", "memory"]Đọc VPA Recommendations
bash
# Xem recommendations từ VPA
kubectl describe vpa myapp-vpa
# Output mẫu:
# Recommendation:
# Container Recommendations:
# Container Name: myapp
# Lower Bound:
# Cpu: 100m
# Memory: 256Mi
# Target: # 👈 GIÁ TRỊ NÊN DÙNG
# Cpu: 500m
# Memory: 512Mi
# Upper Bound:
# Cpu: 2
# Memory: 2Gi📊 HIỂU CÁC GIÁ TRỊ
- Lower Bound: Minimum khuyến nghị (P10)
- Target: Giá trị tối ưu khuyến nghị (P50)
- Upper Bound: Maximum khuyến nghị (P95)
- Uncapped Target: Giá trị không bị giới hạn bởi policy
Combined VPA + HPA Strategy
🚨 XUNG ĐỘT NGUY HIỂM
VPA và HPA KHÔNG THỂ cùng scale trên cùng một metric (CPU hoặc Memory).
yaml
# ❌ SAI: Cả hai cùng dùng CPU
HPA: targetCPUUtilization: 50%
VPA: controlledResources: ["cpu", "memory"]
# → Vòng lặp vô hạn: VPA tăng CPU → HPA nghĩ load giảm → scale in
# → Pods giảm → Load tăng → VPA tăng tiếp → ...Giải pháp: Tách biệt metrics
yaml
# ✅ ĐÚNG: VPA quản lý Memory, HPA quản lý CPU
---
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: myapp-vpa
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: myapp
updatePolicy:
updateMode: "Auto"
resourcePolicy:
containerPolicies:
- containerName: myapp
controlledResources: ["memory"] # 👈 CHỈ MEMORY
minAllowed:
memory: "256Mi"
maxAllowed:
memory: "4Gi"
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: myapp-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: myapp
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu # 👈 CHỈ CPU
target:
type: Utilization
averageUtilization: 60VPA Production Pitfalls
⚠️ NHỮNG LỖI THƯỜNG GẶP
1. Auto mode gây downtime không mong muốn
text
Vấn đề: VPA với updateMode=Auto restart pods bất kỳ lúc nào
Giải pháp:
- Dùng PodDisruptionBudget
- Bắt đầu với updateMode=Off, sau đó chuyển sang Initial2. OOM Kill vì VPA underestimate memory
text
Vấn đề: VPA dựa trên historical data, không predict spikes
Giải pháp:
- Set minAllowed.memory cao hơn baseline
- Monitor OOMKilled events
- Kết hợp với memory limits3. VPA không hoạt động với DaemonSets
text
Vấn đề: VPA chỉ hỗ trợ Deployments, StatefulSets, Jobs
Giải pháp: Dùng manual tuning cho DaemonSets4. Startup spike bị VPA "học" sai
text
Vấn đề: JVM warmup, cache loading tạo false signal
Giải pháp: Đợi VPA thu thập đủ data (24-48h) trước khi enable AutoVPA Deployment Checklist
✅ CHECKLIST TRƯỚC KHI DÙNG VPA
Prerequisites:
- [ ] Cài đặt VPA components (Recommender, Updater, Admission Controller)
- [ ] Pods có
resources.requestsđã được define - [ ] Metrics Server đang hoạt động
Configuration:
- [ ] Bắt đầu với
updateMode: Offđể phân tích - [ ] Set
minAllowedvàmaxAllowedhợp lý - [ ] Nếu dùng HPA, tách biệt controlled resources
- [ ] Cấu hình PodDisruptionBudget nếu dùng Auto mode
Monitoring:
- [ ] Theo dõi VPA recommendations trong 24-48h
- [ ] Check OOMKilled events
- [ ] Alert khi VPA recommendations thay đổi đột ngột
Cài Đặt VPA
bash
# Clone VPA repository
git clone https://github.com/kubernetes/autoscaler.git
cd autoscaler/vertical-pod-autoscaler
# Cài đặt VPA components
./hack/vpa-up.sh
# Kiểm tra
kubectl get pods -n kube-system | grep vpa
# vpa-admission-controller-xxx Running
# vpa-recommender-xxx Running
# vpa-updater-xxx Running🔗 Liên kết
- Trước đó: Module 9: Probes (Health Check)
- Tham khảo: Resources & QoS (bắt buộc đọc trước)
- Tiếp theo: Module 11: Observability