Skip to content

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íđả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 pods

Nế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% CPU

Case 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 pods

Case 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ơn

Giải thích các tham số

Tham sốScale UpScale Down
stabilizationWindowSeconds0 (tức thì)300 (5 phút)
policiesAggressive (100%, 4 pods)Conservative (10%)
selectPolicyMax (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 CPUbaseline, 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.svc

Bướ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:

  1. Prometheus đang chạy và thu thập metrics
  2. Prometheus Adapter được cấu hình đúng
  3. 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-hpa

Các vấn đề thường gặp

Vấn đềNguyên nhânGiải pháp
TARGETS: <unknown>/50%Metrics Server chưa càiCài Metrics Server
TARGETS: <unknown>/50%Pod thiếu resources.requestsThêm requests vào Pod spec
ScalingActive: FalseminReplicas = maxReplicasĐiều chỉnh replica range
Scale không như mong đợiStabilization windowĐợi hoặc điều chỉnh behavior

📊 Tổng Kết

Khái niệmMô tả
Metrics ServerThu thập CPU/Memory từ kubelet
resources.requestsBaseline để tính % utilization
Algorithmceil(CurrentReplicas × (Current / Target))
Scale OutNhanh, aggressive
Scale InChậm, conservative (tránh thrashing)
Custom MetricsRPS, Latency - cần Prometheus Adapter

⚠️ CHECKLIST TRƯỚC KHI DÙNG HPA

  1. ✅ Metrics Server đã cài đặt
  2. ✅ Pods có resources.requests
  3. ✅ Hiểu behavior: scale out nhanh, scale in chậm
  4. ✅ Set minReplicas ≥ 2 (HA)
  5. ✅ Set maxReplicas hợ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íHPAVPA
Scale gì?Số lượng podsCPU/Memory của pod
Phù hợp vớiStateless appsStateful apps, JVM apps
Restart pods?KhôngCó (khi updateMode=Auto)
Phản ứngNhanh (seconds)Chậm hơn (minutes)
Use caseTraffic spikesRight-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"
ModeApply 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: 60

VPA 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 Initial

2. 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 limits

3. 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 DaemonSets

4. 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 Auto

VPA 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 minAllowedmaxAllowed hợ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