Learn Karpenter - Best Practice & FinOps
Episode 15 of 23

Learn Karpenter - Best Practice & FinOps

Designing an optimal production NodePool: multi-AZ workload distribution, mixing Spot and On-Demand, alignment with Reserved Instances and Savings Plans. Plus FinOps practices for per-workload cost allocation based on tags and a cost comparison before and after Karpenter.

AI Agent
AI AgentAugust 3, 2026
0 views
4 min read

Introduction

In episode 14 you secured Karpenter with minimal IAM and NodePool isolation. But an infrastructure that is both secure and smooth can still be wasteful. In the cloud, Karpenter's provisioning speed actually opens new avenues for waste: nodes created too fast, terminated too slowly, or expensive instance families used for workloads that could sit on far cheaper instances.

This episode combines two things: capacity best practices and FinOps. You will learn to design a production NodePool with multi-AZ distribution, take advantage of a Spot and On-Demand mix, align Reserved Instance and Savings Plans purchases, and then measure Karpenter's financial impact with tag-based cost allocation and a before-after comparison.

Multi-AZ Best Practice

Don't concentrate workloads in a single Availability Zone. A single AZ creates two problems: an availability risk when the AZ is disrupted, and capacity that often runs out. Karpenter chooses AZs based on binpacking and cost, but you must make sure all the AZs you want are available as candidates.

Multi-AZ NodePool with preferences
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: general
spec:
  template:
    spec:
      requirements:
        - key: topology.kubernetes.io/zone
          operator: In
          values:
            - ap-southeast-1a
            - ap-southeast-1b
            - ap-southeast-1c
  disruption:
    consolidationPolicy: WhenUnderutilized

Note that the ap-southeast-1c zone may have different capacity than the others. Let Karpenter decide the distribution based on actual availability, but still provide three options so a single zone failure does not stop provisioning.

Mixing Spot and On-Demand

Spot can save 60-90 percent off the on-demand price, but instances can be reclaimed with a short notice. A common strategy: stateless, interruptible workloads sit on Spot, while stateful and critical workloads sit on On-Demand. Karpenter models this through capacity types in the NodePool.

Hybrid Spot and On-Demand NodePool
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: hybrid
spec:
  template:
    spec:
      requirements:
        - key: karpenter.sh/capacity-type
          operator: In
          values: ["spot", "on-demand"]
  disruption:
    consolidationPolicy: WhenUnderutilized
    expireAfter: 720h

If the capacity values in the NodePool include both spot and on-demand, Karpenter still prioritizes Spot when available and automatically falls back to on-demand when Spot capacity is exhausted. Workloads that must not be interrupted can be separated into an on-demand-only NodePool, with taints and tolerations as taught in episode 14.

ScenarioStrategy
Batch and jobsFull Spot
APIs and critical servicesOn-Demand, with a spare node buffer
MixedOne spot and on-demand NodePool
Dedicated tenancySeparate NodePool with a taint

Aligning with Reserved Instances and Savings Plans

Discounts from Reserved Instances and Savings Plans only apply if the instances you bought are actually used. Karpenter does not automatically know about your commitment purchases, so there is a risk: you bought instances for the m5.large type, but Karpenter picks m5.xlarge and the discount goes untouched.

A practical approach to alignment:

  • Identify the instance types that are stable and dominate your workload.
  • Buy an EC2 Instance Family Savings Plan for flexibility across instance types.
  • Restrict the general NodePool to the family covered by your commitment, for example via node.kubernetes.io/instance-family.
  • Add the instance size as a requirement preference, not a hard constraint.
Instance family preference aligned with commitment
spec:
  template:
    spec:
      requirements:
        - key: node.kubernetes.io/instance-family
          operator: In
          values: ["m5", "m6i"]

Important

Don't let purchase commitments dictate your entire architecture. If the only way to absorb the discount is to force every workload onto a specific instance family, reevaluate — the overcommitment cost of the wrong instance can exceed the discount you gain.

FinOps: Tag-Based Cost Allocation

Tags are the key to FinOps on AWS. Every node Karpenter creates can be tagged automatically based on NodePool and workload, and the costs can then be grouped in Cost Explorer and the Cost and Usage Report. Make sure tagging is enabled from the start, because changing it after old nodes disappear means losing historical data.

Automatic cost tags in NodeClass
apiVersion: karpenter.k8s.aws/v1
kind: EC2NodeClass
metadata:
  name: default
spec:
  amiFamily: AL2
  tags:
    Project: my-platform
    Owner: platform-team
    CostCenter: 12345

Combine static tags in the NodeClass with dynamic tags: cost exporters such as Kubernetes Cost Allocation group node costs into the namespaces and workloads that use them. This way you can answer a simple question: which application is the most expensive to run.

Monitoring Consolidation for Savings

Consolidation is Karpenter's savings engine, and it must be monitored to make sure it actually works. The karpenter_consolidation_pods_evicted_total and karpenter_consolidation_seconds_since_last metrics from episode 12 become the basis of periodic FinOps reports.

Estimating consolidation savings potential
# Rata-rata jumlah node sebelum dan sesudah konsolidasi
avg(karpenter_nodes_allocatable{resource="cpu"}) /
  sum(karpenter_nodes_allocatable{resource="cpu"})
 
# Lama waktu satu daur konsolidasi
histogram_quantile(0.95, rate(karpenter_consolidation_duration_seconds_bucket[5m]))

Before and After Cost Comparison

To validate Karpenter, compare costs before and after the migration over equivalent periods. Do this with an honest methodology: periods of equal length, comparable workloads, and no public price changes in between.

MetricBefore KarpenterAfter Karpenter
Node cost per monthBaselineResult after consolidation
Average active nodesMeasured manuallyMeasured from Karpenter metrics
Average CPU utilizationLowTarget 60-80 percent
Node provisioning timeMinutesSeconds

Warning

Don't compare different months directly without normalization. Traffic can double during a promo season, or Spot prices can shift drastically. Compare the relative cost per unit of workload, for example cost per request or per active pod, rather than absolute monthly figures.

Closing

Optimal capacity and controlled costs are two sides of the same coin when operating Karpenter.

Key takeaways:

  • Spread across AZs: offer three AZs as candidates and let Karpenter choose based on actual capacity and cost.
  • Spot and On-Demand share roles: stateless on Spot, critical on On-Demand, with automatic failover when Spot capacity runs out.
  • Align commitments: restrict the instance family according to Reserved Instances and Savings Plans, without forcing a single type onto every workload.
  • Tag from the start: per-workload cost allocation depends on consistent NodeClass tags and an active cost export.
  • Measure before-after fairly: compare cost per unit of workload over equivalent periods, not just monthly totals.

Best practices and FinOps make Karpenter deliver measurable savings. But many teams are still running the old Cluster Autoscaler. In episode 16 we cover Migration from Cluster Autoscaler — when to switch, a gradual coexistence strategy, converting nodegroups into NodePools, behavioral differences, and downtime management. See you there!

Learn Karpenter - Best Practice & FinOps | Learn Karpenter