Product Management
Đăng nhập
ESC

Nhập từ khóa để tìm kiếm

↑↓ Di chuyển
Enter Mở
ESC Đóng

Bài 25 — Kubernetes Autoscaling — HPA, VPA, Cluster Autoscaler

Đã đọc 0/13 mục · còn khoảng 12 phút
Cách chúng tôi ghi nhận

Một mục được tính là đã đọc khi nó nằm giữa màn hình đủ lâu so với độ dài của nó (bảng và sơ đồ tính một nửa), bạn vẫn đang cuộn hoặc bấm phím, và bạn đã thấy tới cuối mục. Lướt nhanh hoặc để tab mở không được tính. Chúng tôi chỉ lưu thời gian đọc từng mục — không lưu gì khác.

Mở đầu — vì sao bài này quan trọng

Hãy tưởng tượng bạn đang vận hành hệ thống backend cho một sàn thương mại điện tử ở Việt Nam. Ngày thường traffic bình bình, nhưng cứ đến khung "sale 12h12" hay "flash sale 20h" thì lượng người dùng tăng gấp 10–20 lần chỉ trong vài phút. Nếu bạn cấu hình cố định số lượng container (Pod), bạn rơi vào một trong hai cái bẫy: hoặc để dư thật nhiều Pod chạy 24/7 và đốt tiền cloud vô ích, hoặc để vừa đủ rồi hệ thống sập ngay khi cao điểm. Cả hai đều tệ.

Autoscaling — tự động co giãn — chính là lời giải cho bài toán này. Nó là một trong những lý do quan trọng nhất khiến các công ty chọn Kubernetes thay vì tự quản lý server thủ công. Kubernetes cho phép hệ thống tự nhìn vào chính mình, nhận ra "à, tôi đang quá tải" hoặc "tôi đang dư thừa", rồi tự điều chỉnh.

Nhưng ở đây có một cái bẫy tư duy phổ biến: nhiều bạn mới nghĩ autoscaling chỉ là "thêm bớt Pod". Thực ra Kubernetes có ba tầng autoscaling khác nhau, giải quyết ba bài toán khác nhau, và một hệ thống production tốt thường phải phối hợp cả ba. Hiểu rõ từng tầng — nó co giãn cái gì, dựa vào tín hiệu gì, và khi nào thì mâu thuẫn nhau — là kỹ năng phân biệt một DevOps engineer thực thụ với người chỉ biết copy YAML trên mạng. Bài này sẽ giúp bạn nắm chắc điều đó.

Khái niệm cốt lõi

Trước khi đi vào ba tầng, bạn cần nhớ một nền tảng: mọi autoscaling trong Kubernetes đều phụ thuộc vào việc bạn đã khai báo resource requests và limits cho container. Nếu bạn không khai báo requests.cpu và requests.memory, thì phần lớn cơ chế autoscaling sẽ không có dữ liệu để ra quyết định. Đây là lỗi số một của người mới, chúng ta sẽ nhắc lại ở phần sau.

Ba tầng autoscaling là:

1. HPA — Horizontal Pod Autoscaler (co giãn theo chiều ngang)

HPA điều chỉnh số lượng replica (số bản sao Pod) của một Deployment, ReplicaSet hoặc StatefulSet. "Horizontal" nghĩa là scale ra rộng: khi tải cao, HPA tăng từ 3 Pod lên 10 Pod; khi tải giảm, nó rút xuống lại.

Cách hoạt động: HPA chạy một vòng lặp kiểm soát (control loop), mặc định cứ 15 giây một lần, đọc chỉ số (metric) hiện tại của các Pod — thường là CPU utilization trung bình — rồi so với ngưỡng mục tiêu bạn đặt. Công thức đơn giản hoá:

desiredReplicas = ceil( currentReplicas × (currentMetric / targetMetric) )

Ví dụ bạn đặt target CPU = 50%, hiện đang chạy 4 Pod với CPU trung bình 100%. Thì 4 × (100/50) = 8 → HPA scale lên 8 Pod. HPA lấy metric qua Metrics Server (cho CPU/RAM cơ bản) hoặc qua custom/external metrics (ví dụ số lượng message trong hàng đợi RabbitMQ, số request per second qua Prometheus Adapter).

HPA phù hợp nhất với ứng dụng stateless có thể chạy nhiều bản song song: web server, API service, worker xử lý job. Đây là tầng autoscaling được dùng nhiều nhất và nên là lựa chọn đầu tiên của bạn.

2. VPA — Vertical Pod Autoscaler (co giãn theo chiều dọc)

VPA không đổi số lượng Pod, mà đổi kích thước của mỗi Pod — tức là điều chỉnh requests và limits về CPU/RAM cho phù hợp với nhu cầu thực tế. "Vertical" nghĩa là làm cho từng Pod "to hơn" hoặc "nhỏ hơn".

VPA quan sát mức tiêu thụ tài nguyên thực tế của workload theo thời gian (dùng lịch sử metric), rồi đề xuất giá trị request tối ưu. Nó có ba chế độ chính:

  • Off (recommendation only): chỉ đưa ra khuyến nghị, không tự thay đổi. Rất hợp để bạn "đo đạc" xem nên đặt request bao nhiêu — dùng con số này rồi tự cập nhật thủ công.
  • Auto / Recreate: VPA tự cập nhật request và khởi động lại Pod để áp dụng giá trị mới. Lưu ý điểm này: cho tới các phiên bản phổ biến hiện nay, thay đổi request thường yêu cầu recreate Pod, gây gián đoạn ngắn.
VPA phù hợp với workload khó chạy nhiều bản (stateful, single-leader như một số database, hoặc batch job) — nơi HPA không dùng được nhiều. VPA cũng cực kỳ hữu ích ở chế độ "recommendation" để chống lãng phí: rất nhiều team đặt request quá cao "cho chắc" và đốt tiền, VPA sẽ chỉ ra con số hợp lý.

Cảnh báo quan trọng: KHÔNG dùng VPA (chế độ Auto) và HPA cùng lúc trên cùng một metric (ví dụ cùng dựa trên CPU). Chúng sẽ đánh nhau: HPA muốn thêm Pod khi CPU cao, VPA lại muốn tăng request CPU của từng Pod — hai bên phản ứng chồng chéo gây dao động (thrashing). Nếu muốn kết hợp, hãy để HPA scale theo một metric (ví dụ CPU hoặc custom metric), còn VPA chỉ quản RAM, hoặc VPA chỉ chạy ở chế độ recommendation.

3. Cluster Autoscaler (co giãn số lượng Node)

Hai tầng trên co giãn Pod, nhưng Pod phải chạy trên Node (máy chủ vật lý/ảo). Nếu HPA muốn tạo thêm 5 Pod mà cluster không còn chỗ trống trên Node nào, thì các Pod đó rơi vào trạng thái Pending — treo mãi không chạy được. Đây là lúc Cluster Autoscaler (CA) vào cuộc.

CA quan sát: có Pod nào đang Pending vì thiếu tài nguyên không? Nếu có, nó gọi API của cloud provider (AWS EKS, Google GKE, Azure AKS...) để thêm Node mới vào node group. Ngược lại, nếu có Node đang trống hoặc dùng rất ít mà các Pod trên đó có thể dồn sang Node khác, CA sẽ rút Node đó ra để tiết kiệm tiền.

Một biến thể hiện đại rất đáng nhắc là Karpenter (của AWS, mã nguồn mở) — thay vì làm việc với các node group cố định, Karpenter chọn đúng loại máy phù hợp nhất cho tập Pod đang pending, cấp phát nhanh hơn và tối ưu chi phí tốt hơn. Nhiều công ty ở Đông Nam Á đang chuyển từ Cluster Autoscaler cổ điển sang Karpenter vì lý do này.

Điểm mấu chốt để nhớ về quan hệ ba tầng: HPA/VPA quyết định cần bao nhiêu Pod và Pod to cỡ nào; Cluster Autoscaler đảm bảo có đủ Node để chứa chúng. Ba tầng phối hợp: HPA phản ứng nhanh (giây–phút) với biến động traffic, CA phản ứng chậm hơn (phút) để cấp hạ tầng, VPA chỉnh dài hạn để tối ưu kích thước.

Tình huống thực tế

Ví dụ 1: Sàn TMĐT gặp flash sale — HPA + Cluster Autoscaler phối hợp

Một sàn thương mại điện tử tầm trung ở TP.HCM (gọi là ShopViet) chạy API giỏ hàng trên EKS. Ngày thường họ giữ 6 Pod, mỗi Pod request 500m CPU. Vào 20h mỗi tối có flash sale, request tăng vọt.

Trước khi có autoscaling, họ cố định 30 Pod cả ngày "cho an toàn" — tốn tiền cả 24 tiếng chỉ để phục vụ 30 phút cao điểm. Sau khi triển khai HPA với target CPU 60%, min 6 / max 40, hệ thống tự động: lúc 19h55 traffic bắt đầu lên, HPA scale dần từ 6 lên 34 Pod. Nhưng cluster chỉ đủ Node cho ~20 Pod, nên 14 Pod bị Pending. Cluster Autoscaler nhận ra, thêm 3 Node m5.xlarge trong khoảng 90 giây, các Pod pending được xếp chỗ và chạy.

Bài học: HPA một mình là chưa đủ nếu cluster không có sẵn "đất trống". Bạn phải bật Cluster Autoscaler song song. Và họ học thêm một bài quan trọng: 90 giây chờ Node mới là quá lâu cho một đợt spike đột ngột — nên họ cấu hình HPA scale sớm hơn một chút (giảm target xuống 55%) và giữ một lượng "overprovision" nhỏ (vài Pod placeholder priority thấp) để hấp thụ cú sốc trong khi Node mới đang khởi động.

Ví dụ 2: Startup fintech tối ưu chi phí bằng VPA ở chế độ recommendation

Một startup fintech ở Singapore phục vụ thị trường Đông Nam Á có khoảng 40 microservice. Đội DevOps phát hiện hoá đơn GKE tăng mạnh nhưng CPU cluster trung bình chỉ dùng 18%. Nguyên nhân: mỗi team tự đặt requests.cpu và requests.memory theo cảm tính, thường gấp 3–4 lần nhu cầu thật "cho chắc".

Họ bật VPA ở chế độ Off (recommendation only) cho toàn bộ service trong 2 tuần để thu thập khuyến nghị. Kết quả: VPA chỉ ra rằng một service đang request 2Gi RAM nhưng thực tế chỉ dùng đỉnh 600Mi. Sau khi điều chỉnh request theo khuyến nghị (thủ công, qua Pull Request để review), tổng request tài nguyên của cluster giảm ~45%, và nhờ đó Cluster Autoscaler tự rút bớt Node — hoá đơn giảm khoảng 30%.

Bài học: VPA không nhất thiết phải tự động sửa mọi thứ. Dùng nó như một "cố vấn đo lường" đã đủ tạo giá trị lớn. Và request được đặt đúng còn giúp HPA lẫn CA ra quyết định chính xác hơn — vì mọi tầng đều tính toán dựa trên request.

Ví dụ 3: Sự cố "autoscaling đánh nhau" tại một công ty logistics

Một công ty logistics triển khai cả HPA (theo CPU) lẫn VPA (chế độ Auto, cũng đụng tới CPU) trên cùng một service xử lý đơn hàng, vì "muốn tối ưu tối đa". Kết quả là hệ thống dao động liên tục: HPA thấy CPU cao nên thêm Pod; VPA thấy CPU cao nên tăng request CPU rồi recreate Pod; Pod bị giết và tạo lại làm metric nhảy loạn, HPA lại phản ứng sai. Trong giờ cao điểm, một số Pod bị restart liên tục, độ trễ đơn hàng tăng vọt.

Họ khắc phục bằng cách tách bạch: HPA quản CPU (scale số Pod), VPA chỉ quản memory và chỉ ở chế độ recommendation. Hệ thống ổn định trở lại.

Bài học: Đừng để hai bộ điều khiển cùng phản ứng trên cùng một tín hiệu. Autoscaling là các control loop, và giống mọi hệ thống điều khiển, hai vòng lặp chống nhau sẽ tạo dao động thay vì cân bằng.

Hướng dẫn từng bước

Dưới đây là quy trình triển khai HPA cơ bản — tầng bạn sẽ dùng nhiều nhất.

Bước 1 — Cài Metrics Server. HPA cần nguồn metric. Trên hầu hết cluster managed (EKS/GKE/AKS) Metrics Server đã có sẵn hoặc cài một dòng:

kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
kubectl top pods   # kiểm tra: nếu ra số liệu là OK

Bước 2 — Khai báo resource requests trong Deployment. Không có bước này thì HPA theo CPU vô dụng:

resources:
  requests:
    cpu: 250m
    memory: 256Mi
  limits:
    cpu: 500m
    memory: 512Mi

Bước 3 — Tạo HPA. Cách nhanh bằng lệnh:

kubectl autoscale deployment cart-api --cpu-percent=60 --min=3 --max=20

Hoặc khai báo bằng YAML (khuyến nghị vì quản lý được bằng Git/IaC):

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: cart-api
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: cart-api
  minReplicas: 3
  maxReplicas: 20
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 60
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 300

Lưu ý behavior.scaleDown.stabilizationWindowSeconds: 300 — bắt HPA chờ 5 phút trước khi rút Pod, tránh việc giảm Pod quá vội rồi lại phải thêm ngay.

Bước 4 — Bật Cluster Autoscaler ở tầng hạ tầng. Trên EKS/GKE, bạn cấu hình node group có minSize/maxSize và bật autoscaler (hoặc dùng Karpenter). Đây là việc thiết lập cluster, thường làm qua Terraform.

Bước 5 — Kiểm chứng. Tạo tải giả để xem HPA phản ứng:

kubectl run -it load --rm --image=busybox -- /bin/sh -c "while true; do wget -q -O- http://cart-api; done"
kubectl get hpa cart-api --watch

Quan sát cột TARGETS (CPU hiện tại/mục tiêu) và REPLICAS tăng dần.

Lỗi thường gặp & mẹo

  • Quên khai báo resource requests → HPA hiển thị TARGETS: <unknown>/60% và không scale. Đây là lỗi phổ biến nhất. Luôn đặt requests.
  • Không cài / lỗi Metrics Server → HPA không có dữ liệu. Kiểm tra bằng kubectl top pods.
  • HPA scale nhưng Pod kẹt Pending → cluster hết Node và chưa bật Cluster Autoscaler. HPA và CA phải đi cùng nhau.
  • Đặt maxReplicas quá cao mà không đặt limit chi phí → một bug gây spike CPU giả có thể khiến hệ thống scale lên hàng trăm Pod, hoá đơn cloud "nổ". Đặt max hợp lý và có cảnh báo (alert).
  • Dùng HPA + VPA Auto trên cùng metric → dao động, restart liên tục (như ví dụ 3). Tách metric hoặc để VPA ở chế độ recommendation.
  • Scale down quá nhanh gây "flapping" → dùng stabilizationWindowSeconds để làm mượt.
  • PodDisruptionBudget (PDB): khi Cluster Autoscaler muốn rút Node, nó phải evict Pod. Đặt PDB để đảm bảo tối thiểu số Pod luôn sẵn sàng, tránh gián đoạn dịch vụ khi scale down.
  • Mẹo scale theo tín hiệu đúng: CPU không phải lúc nào cũng là chỉ số tốt. Một API bị nghẽn bởi I/O hoặc chờ database có thể CPU thấp nhưng độ trễ cao. Với những trường hợp này, dùng custom metric (request per second, độ dài hàng đợi) qua Prometheus Adapter hoặc KEDA. KEDA đặc biệt mạnh khi bạn cần scale theo event (số message Kafka/SQS) và thậm chí scale về 0 khi không có việc.
  • Cold start: nhớ rằng Node mới cần thời gian khởi động (kéo image, healthcheck). Giữ overprovision nhỏ hoặc dùng image nhẹ để giảm độ trễ phản ứng.

Bài tập thực hành

  • Dựng HPA cơ bản: Trên một cluster thử nghiệm (minikube hoặc kind), deploy một web app đơn giản có khai báo requests, tạo HPA target CPU 50%, min 2 max 10. Dùng lệnh tạo tải và quan sát kubectl get hpa --watch cho tới khi replica tăng. Ghi lại mất bao lâu để scale lên và bao lâu để scale xuống.
  • Trải nghiệm VPA recommendation: Cài VPA, tạo một VPA object ở chế độ Off cho một Deployment. Chạy workload vài phút rồi xem kubectl describe vpa <ten> để đọc phần khuyến nghị (Target/Lower/Upper bound). So sánh với request bạn đang đặt — bạn đang đặt dư hay thiếu?
  • Mô phỏng Pending: Giới hạn cluster còn ít tài nguyên, đặt maxReplicas cao và tạo tải mạnh để một số Pod rơi vào Pending. Chạy kubectl describe pod <pod-pending> và đọc phần Events — bạn sẽ thấy thông báo thiếu CPU/memory. Đây chính là tín hiệu Cluster Autoscaler dùng để quyết định thêm Node.
  • Tư duy thiết kế: Với một service database single-leader (không scale ngang được), bạn sẽ chọn tầng autoscaling nào và chế độ gì? Viết 3–4 câu giải thích lựa chọn của bạn.

Tóm tắt

Kubernetes có ba tầng autoscaling, mỗi tầng giải quyết một bài toán khác nhau:

  • HPA (Horizontal Pod Autoscaler): thêm/bớt số lượng Pod theo metric (CPU, RAM, hoặc custom). Phản ứng nhanh, dùng nhiều nhất, hợp với service stateless. Đây là lựa chọn mặc định của bạn.
  • VPA (Vertical Pod Autoscaler): điều chỉnh kích thước request/limit của từng Pod. Tuyệt vời ở chế độ recommendation để chống lãng phí và đặt request đúng; ở chế độ Auto thì cẩn thận vì phải recreate Pod và không được đụng cùng metric với HPA.
  • Cluster Autoscaler (hoặc Karpenter): thêm/bớt số lượng Node để đảm bảo luôn có chỗ cho Pod. Bắt buộc đi kèm HPA nếu bạn muốn scale thật.
Ba nguyên tắc cần khắc cốt ghi tâm: (1) mọi autoscaling đều dựa trên resource requests — luôn khai báo chúng; (2) HPA và CA phải song hành, không thì Pod kẹt Pending; (3) đừng để hai control loop đánh nhau trên cùng một tín hiệu. Nắm chắc ba tầng và ba nguyên tắc này, bạn đã có nền tảng để xây một hệ thống vừa chịu được flash sale, vừa không đốt tiền cloud vô ích.

Học xong bài này rồi? Tạo tài khoản miễn phí để lưu lại — lần sau vào là biết ngay đang dở ở đâu, và học hết khóa thì có chứng chỉ. Lưu tiến độ của tôi