Ngừng đoán mò: Hướng dẫn thực tế về Kubernetes VPA và HPA

DevOps tutorial - IT technology blog
DevOps tutorial - IT technology blog

Vấn đề: Trò chơi đoán mò đắt đỏ về giới hạn tài nguyên

Không có gì phá hỏng buổi sáng của một kỹ sư DevOps bằng thông báo Slack lúc 3 giờ sáng về lỗi CrashLoopBackOff. Bạn kiểm tra log và thấy trạng thái OOMKilled đáng sợ—ứng dụng của bạn đã hết bộ nhớ và hiện đang bị kẹt. Tệ hơn nữa là hóa đơn đám mây cuối tháng. Bạn có thể nhận thấy mình đang trả tiền cho 80% CPU nhàn rỗi vì ai đó đã đặt resource requests là 2.0 cores “cho chắc ăn” trong khi ứng dụng chỉ sử dụng 0.1 cores.

Việc thiết lập các giới hạn tài nguyên tĩnh trong Kubernetes hiếm khi chính xác. Nếu giới hạn quá thấp, ứng dụng của bạn sẽ bị bóp hiệu năng (throttling) hoặc bị crash khi có tải. Nếu chúng quá cao, bạn đang lãng phí tiền bạc và làm giảm mật độ (density) của cluster. Các cấu hình tĩnh thất bại vì lưu lượng truy cập là không thể dự đoán và mức độ chiếm dụng bộ nhớ thường tăng lên khi ứng dụng duy trì trạng thái online.

Nguyên nhân gốc rễ: Tại sao các giới hạn tĩnh thất bại khi mở rộng quy mô

Kubernetes dựa vào requests để lập lịch và limits để giới hạn mức sử dụng. Khoảng cách giữa hai con số này là nơi xảy ra hầu hết sự lãng phí. Việc tinh chỉnh thủ công có thể hiệu quả khi bạn có ba microservices. Nhưng nó sẽ thất bại thảm hại khi bạn quản lý năm mươi cái microservices. Nếu bạn cấp dư chỉ 0.5 CPU cores cho mỗi pod trong một cluster 100 pod, bạn đang trả tiền cho 50 cores tài nguyên “ma” không bao giờ thực hiện bất kỳ công việc thực tế nào.

Hầu hết các đội ngũ đều gặp khó khăn với hai mô hình cụ thể:

  • Đột biến theo chiều ngang (Horizontal Spikes): Các đợt bùng phát lưu lượng truy cập đột ngột đòi hỏi nhiều thực thể ứng dụng hơn.
  • Tăng trưởng theo chiều dọc (Vertical Growth): Các ứng dụng Java hoặc Python cần nhiều bộ nhớ hơn trên mỗi thực thể khi chúng xử lý các tập dữ liệu lớn hơn hoặc chạy trong thời gian dài.

Bắt đầu nhanh: Tự động hóa việc mở rộng quy mô trong 5 phút

Bạn có thể ngừng đoán mò bằng cách triển khai tự động mở rộng quy mô. Đầu tiên, hãy đảm bảo Metrics Server đang chạy trong cluster của bạn. Thành phần này cung cấp dữ liệu đo lường từ xa mà các bộ tự động mở rộng (autoscalers) cần để đưa ra quyết định.

1. Triển khai Horizontal Pod Autoscaler (HPA)

HPA thay đổi số lượng pod dựa trên nhu cầu. Sử dụng lệnh này để mở rộng quy mô deployment khi mức sử dụng CPU đạt 50%:

kubectl autoscale deployment my-app --cpu-percent=50 --min=2 --max=10

2. Triển khai Vertical Pod Autoscaler (VPA)

VPA điều chỉnh kích thước của từng pod riêng lẻ. Trong khi HPA thêm nhiều công nhân hơn, VPA cung cấp cho các công nhân hiện tại một động cơ lớn hơn. Sau khi cài đặt các thành phần VPA, hãy áp dụng cấu hình này để giám sát ứng dụng của bạn:

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: my-app-vpa
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind: Deployment
    name: my-app
  updatePolicy:
    updateMode: "Auto"

Cơ chế hoạt động

Horizontal Pod Autoscaler (HPA)

HPA chạy một vòng lặp kiểm soát liên tục, truy vấn Metrics API sau mỗi 15 giây. Nó tính toán số lượng bản sao (replica) cần thiết bằng một tỷ lệ đơn giản. Nếu mục tiêu của bạn là 50% và mức sử dụng hiện tại là 100%, HPA sẽ tăng gấp đôi số lượng pod. Đây là lựa chọn tốt nhất cho các dịch vụ web không trạng thái (stateless), nơi việc phân chia tải cho nhiều “công nhân” hơn là điều dễ dàng.

Vertical Pod Autoscaler (VPA)

VPA mang tính can thiệp sâu hơn. Nó sử dụng ba thành phần nội bộ để quản lý kích thước pod:

  1. Recommender: Phân tích lịch sử sử dụng để đề xuất các giá trị CPU và bộ nhớ “vừa vặn”.
  2. Admission Controller: Sửa đổi các pod mới tại thời điểm tạo để sử dụng các giá trị được khuyến nghị.
  3. Updater: Thu hồi các pod có thiết lập tài nguyên lỗi thời để chúng có thể được tạo lại với kích thước mới, chính xác.

Cảnh báo: Ở chế độ Auto, VPA sẽ khởi động lại các pod của bạn để áp dụng các thay đổi. Điều này có thể gây ra thời gian gián đoạn ngắn (downtime) nếu bạn chưa cấu hình đủ số lượng bản sao hoặc chưa thiết lập Pod Disruption Budgets (PDBs).

Triển khai chiến lược: Giải quyết xung đột

Một sai lầm phổ biến là chạy cả HPA và VPA trên cùng một chỉ số, chẳng hạn như CPU. Điều này tạo ra hiệu ứng “cuộc chiến giằng co”. VPA cố gắng tăng CPU cho mỗi pod, trong khi HPA cố gắng thêm nhiều pod hơn để giảm mức CPU trung bình. Chúng sẽ đối đầu nhau, dẫn đến một môi trường không ổn định và hiệu suất biến động.

Chiến lược được khuyến nghị

Để chúng hoạt động hài hòa, hãy tuân theo hai quy tắc sau:

  • Sử dụng HPA để mở rộng quy mô: Hãy để HPA xử lý các đợt tăng lưu lượng dựa trên CPU hoặc thông lượng yêu cầu.
  • Sử dụng VPA để điều chỉnh kích cỡ: Sử dụng VPA ở chế độ Initial hoặc Off để quản lý bộ nhớ. Bộ nhớ là tài nguyên không thể nén được; nếu hết, ứng dụng sẽ bị crash. VPA đảm bảo các memory requests của bạn khớp với các mức đỉnh trong thực tế.

Tôi khuyên bạn nên bắt đầu với updateMode: "Off". Điều này cho phép bạn xem các đề xuất mà không để bộ điều khiển tự động khởi động lại pod của mình:

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: my-app-vpa-recommend
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind: Deployment
    name: my-app
  updatePolicy:
    updateMode: "Off" # Chế độ chỉ đưa ra đề xuất

Các mẹo vận hành thực tế để đảm bảo sự ổn định

1. Áp dụng Pod Disruption Budgets (PDB)

Thay đổi kích thước yêu cầu khởi động lại pod. Nếu bạn sử dụng VPA ở chế độ Auto, PDB là lưới an toàn của bạn. Nó đảm bảo rằng ngay cả trong quá trình thay đổi kích thước hàng loạt, một số lượng pod tối thiểu vẫn khả dụng để phục vụ lưu lượng truy cập.

2. Quy tắc “Quan sát trước”

Đừng nhảy ngay vào việc khởi động lại tự động. Hãy chạy VPA ở chế độ Off trong ít nhất một tuần. Kiểm tra các đề xuất trong dashboard Grafana của bạn và so sánh chúng với cài đặt hiện tại. Chỉ chuyển sang Auto sau khi các đề xuất chứng minh được sự nhất quán và an toàn.

3. Quản lý bộ nhớ cẩn thận

CPU có thể bị bóp (throttled), nghĩa là ứng dụng của bạn chỉ chạy chậm lại. Bộ nhớ thì không. Khi một pod đạt đến giới hạn bộ nhớ, kernel sẽ kill tiến trình đó ngay lập tức. VPA là lá chắn tốt nhất của bạn ở đây vì nó học được các yêu cầu bộ nhớ đỉnh của ứng dụng theo thời gian và điều chỉnh mức sàn để ngăn chặn những sự cố lúc 3 giờ sáng.

4. Tinh chỉnh cửa sổ ổn định (Stabilization Window)

HPA đôi khi có thể giảm quy mô quá mạnh mẽ, gây ra tình trạng “thrashing” (pod liên tục được tạo và xóa). Các phiên bản Kubernetes hiện đại cho phép bạn tinh chỉnh stabilizationWindowSeconds. Việc đặt giá trị này thành 300 giây (5 phút) cho các hoạt động scale-down giúp ngăn chặn việc chấm dứt pod sớm trong các đợt sụt giảm lưu lượng tạm thời.

Lời kết

Tối ưu hóa Kubernetes không phải là tìm ra một bộ số ma thuật. Đó là về việc xây dựng một hệ thống quan sát và phản ứng với thực tế. Bằng cách kết hợp HPA cho các đợt tăng lưu lượng và VPA để điều chỉnh kích cỡ dài hạn, bạn có thể cắt giảm chi phí đám mây đồng thời làm cho các ứng dụng của mình linh hoạt hơn đáng kể. Hãy bắt đầu nhỏ, tin tưởng vào dữ liệu và để các bộ điều khiển xử lý gánh nặng vận hành của việc quản lý tài nguyên.

Share: