Tối ưu chi phí Kubernetes 2026: Karpenter, Spot Instances và Right-Sizing giảm 55% bill cloud

Posted on: 4/21/2026 10:12:34 AM

Hơn 68% tổ chức đang trả quá nhiều cho Kubernetes — từ 20% đến 40% ngân sách cloud bị lãng phí do pod request thổi phồng, node chạy không tải, và thiếu chiến lược autoscaling thông minh. Bài viết này đi sâu vào bộ công cụ tối ưu chi phí Kubernetes mạnh nhất năm 2026: Karpenter cho node provisioning thông minh, Spot Instances giảm 70-90% compute, VPA cho right-sizing chính xác, và mô hình FinOps để duy trì kết quả lâu dài. Với case study thực tế giảm từ $48K xuống $21.5K/tháng.

1. Tại sao Kubernetes lại đắt đến vậy?

Kubernetes không đắt — cách chúng ta cấu hình mới đắt. Phần lớn cluster production rơi vào pattern "set-and-forget": developer request 500m CPU và 1Gi memory cho mỗi pod "cho an toàn", nhưng thực tế pod chỉ dùng 25m CPU và 262Mi memory. Kết quả: cluster chạy ở mức 10-15% utilization nhưng trả tiền cho 100% capacity.

68% Tổ chức đang overspend cho K8s
10-15% CPU utilization trung bình cluster
80-90% Pod có request bị thổi phồng
40-70% Tiềm năng giảm chi phí

Ba nguồn lãng phí chính:

Nguồn lãng phíNguyên nhân% chi phí dư thừa
Over-provisioned podsRequest CPU/memory cao hơn thực tế sử dụng 5-20 lần30-60%
Idle nodesCluster Autoscaler phản ứng chậm, không consolidate15-25%
On-Demand mặc địnhKhông tận dụng Spot/Preemptible cho stateless workloads20-40%

2. Karpenter — Node Provisioning thế hệ mới

Karpenter (nay thuộc Kubernetes SIGs, hỗ trợ cả AWS và Azure) là node autoscaler thay thế hoàn toàn Cluster Autoscaler truyền thống. Thay vì mở rộng node group cố định, Karpenter nhìn vào pending pods và hỏi trực tiếp Cloud Provider API để chọn instance type tối ưu nhất — đúng size, đúng giá, trong vài giây.

graph TB
    PENDING["Pending Pods
(unschedulable)"] --> KARPENTER["Karpenter Controller"] KARPENTER --> EVAL["Evaluate Pod
Requirements"] EVAL --> SELECT["Select Optimal
Instance Type"] SELECT --> SPOT{"Spot
available?"} SPOT -->|"Yes"| LAUNCH_SPOT["Launch Spot
Instance"] SPOT -->|"No"| LAUNCH_OD["Launch On-Demand
Instance"] LAUNCH_SPOT --> SCHEDULE["Schedule Pods"] LAUNCH_OD --> SCHEDULE SCHEDULE --> MONITOR["Monitor
Utilization"] MONITOR -->|"Underutilized"| CONSOLIDATE["Consolidate:
Bin-pack & Terminate"] MONITOR -->|"Healthy"| MONITOR CONSOLIDATE --> KARPENTER style KARPENTER fill:#e94560,stroke:#fff,color:#fff style CONSOLIDATE fill:#e94560,stroke:#fff,color:#fff style LAUNCH_SPOT fill:#4CAF50,stroke:#fff,color:#fff style LAUNCH_OD fill:#2c3e50,stroke:#fff,color:#fff style PENDING fill:#f8f9fa,stroke:#e94560,color:#333 style EVAL fill:#f8f9fa,stroke:#e94560,color:#333 style SELECT fill:#f8f9fa,stroke:#e94560,color:#333 style MONITOR fill:#f8f9fa,stroke:#e94560,color:#333 style SCHEDULE fill:#f8f9fa,stroke:#e94560,color:#333

Hình 1: Vòng đời Karpenter — từ pending pod đến consolidation tự động

2.1. Karpenter vs Cluster Autoscaler

Tiêu chíCluster AutoscalerKarpenter
Thời gian scale-up2-5 phút~30-60 giây
Instance selectionCố định theo Node GroupDynamic — chọn từ toàn bộ instance catalog
ConsolidationScale-down sau 10 phút idleBin-pack liên tục, terminate node thừa
Spot handlingCần cấu hình Mixed Instance PolicyNative Spot + On-Demand fallback
Multi-archCần node group riêng cho ARM64Tự chọn ARM64/AMD64 theo requirements
Pod awarenessChỉ đếm pending podsPhân tích topology, affinity, taints

2.2. Cấu hình NodePool tối ưu chi phí

NodePool là đơn vị cấu hình chính của Karpenter, định nghĩa "loại node nào được phép tạo" và "khi nào nên consolidate":

apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: cost-optimized
spec:
  template:
    spec:
      nodeClassRef:
        group: karpenter.k8s.aws
        kind: EC2NodeClass
        name: default
      requirements:
        # Chỉ dùng instance thế hệ 6+  (giá/hiệu năng tốt hơn)
        - key: "karpenter.k8s.aws/instance-generation"
          operator: Gt
          values: ["5"]
        # Ưu tiên ARM64 (Graviton) — rẻ hơn ~20%
        - key: "kubernetes.io/arch"
          operator: In
          values: ["arm64", "amd64"]
        # Spot trước, On-Demand fallback
        - key: "karpenter.sh/capacity-type"
          operator: In
          values: ["spot", "on-demand"]
        # Instance families phù hợp
        - key: "karpenter.k8s.aws/instance-category"
          operator: In
          values: ["c", "m", "r"]
        # Tránh instance quá nhỏ (overhead cao)
        - key: "karpenter.k8s.aws/instance-size"
          operator: NotIn
          values: ["nano", "micro", "small"]
  # Consolidation: gộp pods và terminate node thừa
  disruption:
    consolidationPolicy: WhenEmptyOrUnderutilized
    consolidateAfter: 1m
    budgets:
      - nodes: "20%"
      - nodes: "0"
        schedule: "0 9 * * 1-5"
        duration: 1h
    expireAfter: 168h  # Recycle node mỗi 7 ngày
  limits:
    cpu: "1000"
    memory: "4000Gi"

Disruption Budgets là gì?

Disruption Budget kiểm soát tốc độ Karpenter terminate nodes. Ví dụ nodes: "20%" nghĩa là tại bất kỳ thời điểm nào, Karpenter chỉ được disrupting tối đa 20% tổng số node. Bạn cũng có thể tạo "maintenance window" — ví dụ chặn mọi disruption vào 9h sáng thứ 2-6 (giờ peak traffic) bằng nodes: "0" với schedule cron.

2.3. EC2NodeClass — Cấu hình AMI và storage

apiVersion: karpenter.k8s.aws/v1
kind: EC2NodeClass
metadata:
  name: default
spec:
  amiFamily: AL2023
  role: eks-karpenter-node
  blockDeviceMappings:
    - deviceName: /dev/xvda
      ebs:
        volumeSize: 50Gi
        volumeType: gp3
        iops: 3000
        encrypted: true
  subnetSelectorTerms:
    - tags:
        karpenter.sh/discovery: my-cluster
  securityGroupSelectorTerms:
    - tags:
        karpenter.sh/discovery: my-cluster

3. Spot Instances — Giảm 70-90% chi phí compute

Spot Instances là capacity dư thừa của cloud provider, bán với giá giảm 70-90% so với On-Demand. Đổi lại, provider có thể thu hồi instance bất kỳ lúc nào với 2 phút cảnh báo trước. Đây là công cụ tiết kiệm mạnh nhất nếu biết cách sử dụng đúng.

graph LR
    subgraph SPOT["Spot Instances — Stateless Workloads"]
        API["API Servers"]
        WORKER["Workers"]
        BATCH["Batch Jobs"]
        CI["CI/CD Runners"]
    end
    subgraph OD["On-Demand — Stateful / Critical"]
        DB["Databases"]
        KAFKA["Message Brokers"]
        CTRL["Control Plane"]
        MONITOR["Monitoring"]
    end
    style SPOT fill:#4CAF50,stroke:#fff,color:#fff
    style OD fill:#2c3e50,stroke:#fff,color:#fff
    style API fill:#f8f9fa,stroke:#4CAF50,color:#333
    style WORKER fill:#f8f9fa,stroke:#4CAF50,color:#333
    style BATCH fill:#f8f9fa,stroke:#4CAF50,color:#333
    style CI fill:#f8f9fa,stroke:#4CAF50,color:#333
    style DB fill:#f8f9fa,stroke:#e94560,color:#333
    style KAFKA fill:#f8f9fa,stroke:#e94560,color:#333
    style CTRL fill:#f8f9fa,stroke:#e94560,color:#333
    style MONITOR fill:#f8f9fa,stroke:#e94560,color:#333

Hình 2: Phân loại workload — Spot cho stateless, On-Demand cho stateful/critical

3.1. Chiến lược đa dạng hoá Instance Family

Quy tắc vàng khi dùng Spot: không bỏ hết trứng vào một giỏ. Khi chỉ chọn một instance type (ví dụ m5.xlarge), xác suất bị interruption cao hơn nhiều. Cần diversify qua nhiều instance families và Availability Zones:

# Karpenter NodePool cho Spot workloads
spec:
  template:
    spec:
      requirements:
        - key: "karpenter.sh/capacity-type"
          operator: In
          values: ["spot"]
        # Diversify: nhiều family = ít interruption hơn
        - key: "karpenter.k8s.aws/instance-category"
          operator: In
          values: ["c", "m", "r"]
        - key: "karpenter.k8s.aws/instance-generation"
          operator: Gt
          values: ["5"]
        # Cho phép cả ARM64 và AMD64
        - key: "kubernetes.io/arch"
          operator: In
          values: ["arm64", "amd64"]
      # Topology spread qua nhiều AZ
      topologySpreadConstraints:
        - maxSkew: 1
          topologyKey: topology.kubernetes.io/zone
          whenUnsatisfiable: DoNotSchedule

3.2. PriorityClass — Bảo vệ workload quan trọng

Dùng PriorityClass để đảm bảo workload critical luôn chạy trên On-Demand, trong khi batch/CI chấp nhận Spot interruption:

apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: critical-production
value: 1000000
globalDefault: false
description: "Workloads không thể bị interrupt"
---
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: batch-workload
value: 100
preemptionPolicy: Never
description: "Batch jobs chấp nhận chạy Spot"
---
# Deployment critical → On-Demand
apiVersion: apps/v1
kind: Deployment
metadata:
  name: payment-service
spec:
  template:
    spec:
      priorityClassName: critical-production
      nodeSelector:
        karpenter.sh/capacity-type: on-demand
---
# Batch job → Spot
apiVersion: batch/v1
kind: Job
metadata:
  name: data-pipeline
spec:
  template:
    spec:
      priorityClassName: batch-workload
      tolerations:
        - key: "karpenter.sh/capacity-type"
          operator: "Equal"
          value: "spot"

4. VPA & Right-Sizing — Từ 12% lên 50%+ Utilization

Vertical Pod Autoscaler (VPA) phân tích lịch sử sử dụng CPU/memory của pods và đề xuất hoặc tự động điều chỉnh resource requests. Đây thường là bước mang lại ROI cao nhất — giảm request từ 500m xuống 25m CPU cho một pod đơn lẻ có thể free up hàng chục node.

4.1. Triển khai VPA hai giai đoạn

Giai đoạn 1 — Chỉ quan sát (7+ ngày):

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: api-service-vpa
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind: Deployment
    name: api-service
  updatePolicy:
    updateMode: "Off"  # Chỉ recommend, không tự động thay đổi

Kiểm tra recommendation sau 7 ngày:

kubectl describe vpa api-service-vpa
# Output:
# Recommendation:
#   Container Recommendations:
#     Container Name: api-service
#     Lower Bound:   Cpu: 15m,  Memory: 128Mi
#     Target:        Cpu: 25m,  Memory: 262Mi  ← Đề xuất
#     Upper Bound:   Cpu: 100m, Memory: 512Mi
#     Uncapped Target: Cpu: 25m, Memory: 262Mi
#
# So sánh với request hiện tại: 500m CPU, 1Gi memory
# → Giảm 20x CPU, 4x memory!

Giai đoạn 2 — Tự động điều chỉnh (sau khi validate):

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: api-service-vpa
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind: Deployment
    name: api-service
  updatePolicy:
    updateMode: "Auto"
  resourcePolicy:
    containerPolicies:
      - containerName: api-service
        minAllowed:
          cpu: "50m"
          memory: "64Mi"
        maxAllowed:
          cpu: "2"
          memory: "2Gi"

Cẩn thận: VPA + HPA conflict

Không nên dùng VPA Auto mode cho cùng metric với HPA. Ví dụ nếu HPA scale theo CPU, thì VPA cũng điều chỉnh CPU requests → xung đột. Giải pháp: dùng VPA cho memory (thường ổn định), HPA cho CPU (thường biến động theo traffic). Hoặc chuyển sang KEDA với event-driven scaling để tránh conflict hoàn toàn.

5. Consolidation — Nghệ thuật bin-packing

Consolidation là quá trình Karpenter gộp pods từ nhiều node vào ít node hơn, sau đó terminate các node trống hoặc kém hiệu quả. Đây là tính năng giúp cluster duy trì utilization cao liên tục, không chỉ khi scale-down.

graph LR
    subgraph BEFORE["Trước Consolidation"]
        N1["Node 1
20% used"] N2["Node 2
15% used"] N3["Node 3
25% used"] end subgraph AFTER["Sau Consolidation"] N4["Node 1
60% used"] N5["Node 2 — Terminated ✓"] end BEFORE -->|"Karpenter
bin-pack"| AFTER style BEFORE fill:#fff,stroke:#e0e0e0,color:#333 style AFTER fill:#fff,stroke:#e0e0e0,color:#333 style N1 fill:#f8f9fa,stroke:#ff9800,color:#333 style N2 fill:#f8f9fa,stroke:#ff9800,color:#333 style N3 fill:#f8f9fa,stroke:#ff9800,color:#333 style N4 fill:#f8f9fa,stroke:#4CAF50,color:#333 style N5 fill:#f8f9fa,stroke:#e94560,color:#333

Hình 3: Consolidation gộp pods từ 3 node kém hiệu quả thành 1 node tối ưu

5.1. Hai chính sách Consolidation

PolicyHành viPhù hợp khi
WhenEmptyChỉ terminate node khi không còn pod nàoWorkload nhạy cảm với rescheduling
WhenEmptyOrUnderutilizedTerminate node trống HOẶC gộp pods khi node kém hiệu quảHầu hết production clusters
# Cấu hình consolidation với protection windows
disruption:
  consolidationPolicy: WhenEmptyOrUnderutilized
  consolidateAfter: 2m  # Chờ 2 phút trước khi consolidate
  budgets:
    # Bình thường: tối đa 20% nodes bị disrupt
    - nodes: "20%"
    # Peak hours: chặn mọi disruption
    - nodes: "0"
      schedule: "0 8 * * 1-5"   # 8h-9h thứ 2-6
      duration: 1h
    # Drifted nodes: cho phép nhanh hơn (50%)
    - nodes: "50%"
      reasons:
        - Drifted

6. Case Study: Từ $48K xuống $21.5K/tháng

Một hệ thống e-commerce production với ~200 microservices đã áp dụng toàn bộ chiến lược trên và đạt kết quả:

Trước tối ưu

MetricGiá trị
Node fleet45× m5.2xlarge (8 vCPU, 32GB mỗi node)
CPU utilization12%
Memory utilization22%
Chi phí/tháng$48,000

Sau tối ưu

MetricGiá trị
Critical nodes (On-Demand)8× r7g.xlarge (Graviton, 4 vCPU, 32GB)
Variable nodes (Spot)12-35× mixed instances
CPU utilization48%
Memory utilization61%
Chi phí/tháng$21,500

Chi tiết tiết kiệm

$8,000 VPA right-sizing
$5,000 Karpenter consolidation
$7,000 Spot Instances
$4,500 Graviton ARM64
$2,000 Night-time scaling
55% Tổng giảm chi phí

7. Azure AKS: Node Auto-Provisioning (NAP)

Không chỉ AWS, Azure AKS cũng đã tích hợp Karpenter dưới tên Node Auto-Provisioning (NAP) từ cuối 2025. NAP mang đến cùng khả năng intelligent provisioning nhưng tối ưu cho hệ sinh thái Azure:

Tính năngAWS EKS + KarpenterAzure AKS + NAP
Config formatNodePool + EC2NodeClassNodePool + AKSNodeClass
Spot equivalentEC2 Spot InstancesAzure Spot VMs
ARM equivalentGraviton (arm64)Ampere Altra (arm64)
ConsolidationWhenEmptyOrUnderutilizedTương tự (Karpenter core)
Savings PlansAWS Savings Plans / RIsAzure Reservations

GKE cũng có tương đương

Google GKE sử dụng GKE Autopilot — một bước xa hơn nữa, nơi Google quản lý toàn bộ node layer. Bạn chỉ cần deploy pods, GKE tự chọn instance type, scale, và consolidate. Tuy nhiên Autopilot ít flexible hơn Karpenter khi cần fine-tuning instance selection hoặc Spot strategies.

8. FinOps & Governance — Duy trì kết quả lâu dài

Tối ưu chi phí không phải việc làm một lần. Nếu không có quy trình FinOps, cluster sẽ "drift" trở lại trạng thái lãng phí trong vài tháng. Một số công cụ governance cần thiết:

8.1. ResourceQuota & LimitRange

# Giới hạn resource cho mỗi team/namespace
apiVersion: v1
kind: ResourceQuota
metadata:
  name: team-backend-quota
  namespace: team-backend
spec:
  hard:
    requests.cpu: "20"
    requests.memory: "40Gi"
    limits.cpu: "40"
    limits.memory: "80Gi"
    pods: "100"
---
# Default requests cho pods không khai báo
apiVersion: v1
kind: LimitRange
metadata:
  name: default-limits
  namespace: team-backend
spec:
  limits:
    - type: Container
      defaultRequest:
        cpu: "100m"
        memory: "128Mi"
      default:
        cpu: "500m"
        memory: "512Mi"
      max:
        cpu: "4"
        memory: "8Gi"

8.2. Cost Labeling — Visibility theo team

Enforce labeling chuẩn cho mọi resource để phân bổ chi phí chính xác:

# OPA/Gatekeeper ConstraintTemplate bắt buộc labels
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
  name: require-cost-labels
spec:
  match:
    kinds:
      - apiGroups: ["apps"]
        kinds: ["Deployment", "StatefulSet"]
  parameters:
    labels:
      - key: "app.kubernetes.io/team"
      - key: "app.kubernetes.io/cost-center"
      - key: "app.kubernetes.io/environment"

8.3. Orphaned Resources — Dọn dẹp định kỳ

Một CronJob đơn giản scan và alert orphaned resources hàng tuần:

# Tìm PVC không được mount bởi pod nào
kubectl get pvc --all-namespaces -o json | jq -r '
  .items[] |
  select(.status.phase == "Bound") |
  select(.metadata.name as $pvc |
    [env.pods[] | select(.spec.volumes[]?.persistentVolumeClaim?.claimName == $pvc)] | length == 0
  ) |
  "\(.metadata.namespace)/\(.metadata.name) - \(.spec.resources.requests.storage)"
'

# Tìm Services type LoadBalancer không có endpoints
kubectl get svc --all-namespaces -o json | jq -r '
  .items[] |
  select(.spec.type == "LoadBalancer") |
  select((.spec.selector | length) == 0 or
    (.metadata.annotations["service.beta.kubernetes.io/aws-load-balancer-internal"] == null)) |
  "\(.metadata.namespace)/\(.metadata.name)"
'

9. Lộ trình triển khai 4 tuần

Tuần 1: Đo lường
Cài metrics-server + Prometheus. Đo baseline utilization (CPU, memory, cost). Deploy VPA ở mode "Off" cho tất cả Deployments.
Tuần 2: Right-sizing
Phân tích VPA recommendations. Điều chỉnh resource requests cho pods có chênh lệch lớn nhất. Deploy LimitRange defaults cho mọi namespace.
Tuần 3: Karpenter + Spot
Migrate từ Cluster Autoscaler sang Karpenter. Cấu hình NodePool với Spot + diversification. Thiết lập PriorityClass cho critical vs batch workloads.
Tuần 4: Governance
Deploy ResourceQuota per namespace. Enforce cost labels qua OPA/Gatekeeper. Setup weekly cost report dashboard. Cấu hình Disruption Budgets.

10. Kết luận

Tối ưu chi phí Kubernetes không phải "bấm nút giảm giá" — đó là một quy trình kỹ thuật cần đo lường, right-sizing, autoscaling thông minh, và governance liên tục. Ba trụ cột chính:

  1. Karpenter thay thế Cluster Autoscaler — provisioning nhanh hơn 5x, consolidation tự động, instance selection thông minh.
  2. Spot Instances + Diversification — giảm 70-90% compute cho stateless workloads với PriorityClass protection.
  3. VPA Right-Sizing — phát hiện và loại bỏ 80-90% resource requests bị thổi phồng.

Kết quả thực tế cho thấy mức giảm 40-70% chi phí là hoàn toàn khả thi khi áp dụng đúng. Điểm mấu chốt: bắt đầu bằng việc đo lường (metrics-server + VPA Off mode), không phải bằng việc cắt giảm. Bạn không thể tối ưu thứ mình chưa đo được.

Nguồn tham khảo