,

Open-Source Karpenter Limitations: What the Gaps Are at Enterprise Scale

Karpenter provisions nodes efficiently but has six documented limitations at enterprise scale: no workload rightsizing (clusters run 69% CPU overprovisioned on average), effectively AWS-only, single-cluster architecture, no Reserved Instance awareness, no cost attribution, and NodePool governance overhead. Here is what each gap costs and how to close it.

Kunal Das Avatar
karpenter limitations featured image

Karpenter provisions nodes well and is not designed to do several things enterprises need. It does not rightsize workloads, so it faithfully provisions capacity for requests that are on average 69% above actual CPU usage. It is effectively AWS-only in production. It manages one cluster at a time, with no fleet-level view. It has no awareness of Reserved Instances or Savings Plans, so it can provision Spot capacity while committed capacity sits unused. And it offers no cost reporting of its own. None of these are defects – they are scope. Understanding these Karpenter limitations matters because at enterprise scale each one has a measurable price.

Key takeaways

  • Karpenter does not rightsize workloads. It provisions against pod requests, which run 69% above actual CPU usage on average, according to the Cast AI 2026 State of Kubernetes Optimization Report.
  • Karpenter is production-grade on AWS. Microsoft’s AKS Node Auto Provisioning (NAP), which reached GA in July 2025, wraps Karpenter as its underlying engine on Azure. GCP has no official provider.
  • Each Karpenter instance manages one cluster. There is no fleet-level view, no cross-cluster policy enforcement, and no consolidated reporting.
  • Karpenter has no awareness of Reserved Instances or Savings Plans. It can provision Spot capacity while committed capacity sits idle.
  • Karpenter emits operational Prometheus metrics but provides no cost attribution, namespace-level allocation, or chargeback data.
  • At scale, NodePool proliferation, version migrations, and config drift across clusters create significant ongoing engineering overhead.

What Karpenter is very good at

Per-pod provisioning, consolidation, speed

Karpenter does per-pod bin-packing better than any predecessor. It evaluates each pod’s resource requests, selects from a configurable set of instance types, and provisions an appropriately sized node. Karpenter provisions nodes significantly faster than Cluster Autoscaler. Community benchmarks typically show two to four times faster provisioning on AWS, with most new nodes available within 60 to 90 seconds. For teams that have tolerated slow scale-up for years, this alone is a meaningful operational improvement.

Spot instance selection is another genuine strength. Karpenter uses the price-capacity-optimized allocation strategy when launching Spot instances, which considers both current spot price and available EC2 capacity in the target availability zone. Spreading launch candidates across multiple instance families — m5, m5a, m6i, m6g, and similar — and across all configured AZs substantially reduces the probability of simultaneous interruption events. The karpenter.sh/capacity-type requirement selector makes Spot-first strategies straightforward to define, and Karpenter handles re-provisioning on interruption automatically. This diversification is meaningfully better than a single-instance-type Spot node group: Karpenter treats interruption risk as a multi-dimensional problem, not just a price comparison.

Consolidation is where Karpenter earns its keep day-to-day. With WhenEmptyOrUnderutilized, it continuously evaluates whether workloads can fit onto fewer, fuller nodes and terminates excess capacity. The mechanism works through the consolidateAfter timer, defaulting to 30 seconds in most deployments, which controls how long Karpenter waits after a disruption event before re-evaluating. During each evaluation cycle, Karpenter simulates whether all pods on a candidate node can be rescheduled onto existing nodes or onto a smaller, cheaper replacement instance. If the simulation succeeds and the cluster’s disruption budgets allow, Karpenter cordons the node, drains its pods via the standard Kubernetes eviction API, and terminates the underlying EC2 instance. This cycle runs continuously, not on a slow timer. Cluster Autoscaler requires a node to be underutilized for 10 minutes (default) before acting; Karpenter’s evaluation cadence is significantly more aggressive.

Karpenter also reads EC2 capacity signals in real time. When evaluating which instance type to launch, it queries the EC2 API for current availability and adjusts selection dynamically. Cluster Autoscaler, by contrast, works from pre-configured node groups with fixed instance types, it cannot react to a capacity shortage in us-east-1a by shifting to us-east-1b unless a node group already exists there. This real-time capacity awareness means Karpenter’s provisioning decisions are grounded in what EC2 can actually deliver at launch time, not what a static node group was configured to request weeks ago.

On AWS with EKS, Karpenter is the right tool for automated node provisioning. It integrates cleanly with EC2, supports Graviton and GPU instance families, respects pod topology constraints, and handles both scale-up and scale-down without the manual override tuning that Cluster Autoscaler required. For teams evaluating the migration, the guide on migrating from Cluster Autoscaler to Karpenter covers the practical steps in detail.

Limitation 1: Karpenter does not rightsize workloads

Provisioning against requests when requests are 69% above usage

Karpenter’s scheduling documentation is explicit: “Instance type selection math only uses requests.” This is a deliberate design choice, not an oversight. Karpenter trusts the resource requests that Kubernetes declares and provisions accordingly.

The problem is that those requests are almost universally miscalibrated. According to the Cast AI 2026 State of Kubernetes Optimization Report, pods request 69% more CPU than they actually consume. Average cluster-wide CPU utilization sits at 8%. Karpenter cannot see actual usage; it operates on declared intent, not runtime behavior. As a result, it provisions appropriate nodes for an inflated specification and does so efficiently.

This creates a specific category of waste that Karpenter’s consolidation engine cannot recover. Even perfect bin-packing against inflated requests does not reclaim the headroom inside each node. The node fills with correctly packed pods, each burning a fraction of its declared allocation.

The arithmetic: a perfectly bin-packed cluster of oversized pods

Consider 10 pods each requesting 2 CPU and 4Gi memory, with actual runtime usage of 1.2 CPU per pod. Ten pods times 2 CPU each equals 20 CPU requested in total. Karpenter evaluates the requests, packs two pods per m5.xlarge (4 vCPU), and provisions five nodes totaling 20 vCPU. Consolidation reports a healthy, efficiently packed cluster. Actual CPU consumed: 10 pods times 1.2 CPU equals 12 CPU. The cluster runs at 12 out of 20 vCPU, 60% actual utilization, even though Karpenter is correctly bin-packing against declared requests. If provisioned against actual usage instead, the same workload fits on two m5.2xlarge nodes (8 vCPU each, 16 vCPU total) with capacity to spare. This example uses roughly 40% per-pod overprovisioning. The Cast AI 2026 report finds the cluster-wide average is 69%.

To see the gap in your own cluster, run:

kubectl top pods -A --sort-by=cpu | head -30

If Prometheus is installed, these two queries show the gap clearly. Run them side by side for any namespace:

# Compare what Karpenter provisioned (based on requests) vs actual usage
# Step 1: See requested CPU by namespace
sum by (namespace) (
  kube_pod_container_resource_requests{resource="cpu", container!=""}
)

# Step 2: See actual CPU usage by namespace
sum by (namespace) (
  rate(container_cpu_usage_seconds_total{container!="", container!="POD"}[5m])
)

The ratio between the two numbers is the overprovisioning factor. At 8% average GPU utilization across clusters (Cast AI 2026), the gap is typically six to twelve times higher in practice than these namespace-level numbers suggest.

Compare those actual usage numbers to the resource requests in your deployment specs. The difference is what Karpenter faithfully provisions against.

Scale that pattern across 50 nodes. The cluster carries hundreds of idle CPU cores that Karpenter cannot see and consolidation cannot reclaim, because the pods’ declared requests still fill each node to its allocated capacity. The Cast AI 2026 report shows that automated rightsizing reduces wasted compute by approximately 50%. Karpenter does not touch this problem.

What closes it

Automated rightsizing closes this gap by adjusting pod requests against actual runtime usage rather than worst-case declarations. Cast AI’s PrecisionPack does this continuously, so Karpenter receives accurate inputs and provisions appropriately sized nodes from the start. For stateful workloads that cannot tolerate pod restarts, Container Live Migration moves pods to right-sized nodes without disruption. VPA covers the same ground for teams that prefer an open-source path.

The NodePool YAML below illustrates the limitation. The configuration is correct. The gap is not in how Karpenter provisions; it is in the input Karpenter receives.

# Example NodePool that provisions correctly against resource requests
# Pods request 2 CPU / 4Gi memory; actual usage: ~1.2 CPU per pod.
# Karpenter packs 2 pods per m5.xlarge (4 vCPU), provisions 5 nodes = 20 vCPU.
# Actual consumption: 12 CPU. Utilization: 60%. Karpenter cannot see this gap.
# nodeClassRef is required in karpenter.sh/v1 — points to an EC2NodeClass
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: general-purpose
spec:
  template:
    spec:
      nodeClassRef:
        group: karpenter.k8s.aws
        kind: EC2NodeClass
        name: default
      requirements:
        - key: karpenter.sh/capacity-type
          operator: In
          values: ["spot", "on-demand"]
        - key: node.kubernetes.io/instance-type
          operator: In
          values: ["m5.xlarge", "m5.2xlarge", "m6i.xlarge", "m6i.2xlarge"]
  disruption:
    consolidationPolicy: WhenEmptyOrUnderutilized
    consolidateAfter: 30s
  limits:
    cpu: "1000"
    memory: 1000Gi

Limitation 2: Single cloud in practice

The AWS provider is production-grade; others are not equivalent

Karpenter was built at AWS and, practically speaking, runs production workloads on AWS. The FAQ at karpenter.sh confirms AWS as the primary supported cloud. The AWS provider is actively maintained, battle-tested at scale, and integrates deeply with EC2, Spot interruption handling, and EKS.

Microsoft’s AKS Node Auto Provisioning (NAP), which reached GA in July 2025, wraps Karpenter as its underlying engine. Azure users get Karpenter’s provisioning logic, but through a Microsoft-managed abstraction layer rather than direct NodePool configuration. GCP has no official Karpenter provider. CloudPilot AI maintains a community alpha, but it is not production-equivalent to the AWS experience in terms of stability, feature parity, or support coverage.

What this means for a multi-cloud estate

If your organization runs workloads across AWS, Azure, and GCP (increasingly common at enterprise scale), you are running separate provisioning systems per cloud with no coordination between them. NodePool configurations diverge independently. Spot strategies are not shared across providers. Cost and provisioning data sit in separate, unrelated observability systems.

For a single-cloud AWS shop, this Karpenter limitation is essentially irrelevant. For multi-cloud platform teams, it means the node provisioning layer cannot be unified, and fleet-level policy must live in external tooling. That is an architectural consequence worth accounting for early in the platform design process.

Limitation 3: One cluster at a time

No fleet view, no cross-cluster policy, no consolidated reporting

Each Karpenter installation manages exactly one cluster. That is the architectural boundary. There is no federation layer, no cross-cluster view, and no mechanism to push a NodePool configuration change to 30 clusters from a single control point.

At a company with five clusters, this is manageable with some discipline. At 50 or 100 clusters, it creates a governance problem. NodePool configurations drift independently as teams make local adjustments. A disruption policy change, say shifting from WhenEmpty to WhenEmptyOrUnderutilized across the fleet, requires manual propagation to every cluster, with no built-in rollout, validation, or diff mechanism.

Version upgrades compound the drift problem. Each Karpenter release requires migration testing because behavior can shift between versions. When clusters run different versions, behavioral differences accumulate. Cross-cluster reporting does not exist within Karpenter; total fleet capacity, node count by instance family, or Spot vs. on-demand split all require external aggregation tools pulling Prometheus data from each cluster individually.

Limitation 4: No commitment awareness

Spot provisioning while Reserved Instances go unused

GitHub issue #8173 in the Karpenter repository describes the problem plainly: “Karpenter currently has very limited support for Instance Savings Plans.” The maintainers acknowledge that the available workaround (manual NodePool weights and limits) is “toilsome and leads to inefficient utilization.”

The failure mode in practice: your organization holds Reserved Instance commitments covering m5.xlarge capacity in us-east-1. Karpenter does not know these commitments exist. Its Spot strategy scores Spot instances as the optimal selection, so it provisions Spot. The committed on-demand capacity sits idle. You pay for both the committed reservation and the Spot instances running in its place.

The operational mechanics make this gap concrete. Suppose a new pod requires 8 CPU and your RI portfolio covers m5.2xlarge instances. Karpenter evaluates its candidate pool and may select an m6i.2xlarge Spot instance because it is cheaper in that moment, perhaps $0.14/hour versus the on-demand rate your RI already covers. The RI keeps billing at its committed rate whether or not any EC2 instance runs against it. You now pay the RI hourly rate plus the Spot instance cost for equivalent capacity. At scale, with dozens of underutilized RIs and a Karpenter deployment optimizing purely for cheapest available capacity, this double-cost pattern becomes a structural billing problem rather than an occasional edge case. The manual workaround, NodePool weights and explicit instance type constraints that enumerate your RI-covered types, requires synchronizing those specs with your commitment portfolio every time it changes. GitHub #8173 calls this “toilsome” for good reason: RI portfolios are not static, and keeping NodePool constraints aligned with commitment lifecycle events is recurring maintenance work, not a one-time configuration task.

Two Karpenter instances cannot coordinate around a shared Savings Plan. This is not a configuration problem; it is a scope boundary. Karpenter operates within a cluster and does not have access to organization-level AWS commitment inventory.

Commitment utilization to ~98% when the two are coordinated

With an RI/SP optimization layer that feeds commitment state into provisioning decisions, organizations can push Reserved Instance utilization to approximately 98% (Cast AI 2026 State of Kubernetes Optimization Report). That number requires coordinating what Karpenter provisions against what capacity the organization has already paid for. Without that coordination layer, committed capacity bleeds waste independent of how efficiently Karpenter manages Spot on its side.

Manual NodePool weight configuration can approximate commitment-aware behavior, but it is fragile. As commitment portfolios change, the NodePool weights need corresponding updates, creating recurring toil tied to EC2 commitment lifecycle events rather than a one-time configuration task.

Limitation 5: No cost visibility of its own

You still need allocation and reporting

Karpenter emits Prometheus metrics covering node count, provisioning latency, and disruption events. These are operational metrics, not cost metrics. There is no namespace-level cost attribution in Karpenter, no chargeback data, and no view into which team or service is responsible for which portion of compute spend.

For FinOps practitioners and platform engineers who need to answer “what does this service cost to run,” Karpenter provides no data. A dedicated cost allocation layer is required alongside it. OpenCost, Kubecost, and Cast AI all address this gap. A detailed walkthrough of the Kubernetes cost allocation model, covering how to attribute costs by namespace, label, and workload, is in the Kubernetes cost allocation guide.

This is simply outside Karpenter’s stated scope. Teams that deploy Karpenter and assume cost visibility is also solved will find otherwise when finance asks for chargeback numbers at quarter-end.

Limitation 6: Operational burden at scale

NodePool sprawl, version upgrades, and Karpenter limitations at scale

NodePool configurations proliferate naturally. A team starts with one NodePool for general-purpose workloads. Over time, they add one for GPU jobs, another for batch processing, one for Spot-sensitive services, and one for workloads requiring node-local storage. At enterprise scale, individual clusters carry dozens of NodePools. Across a fleet, the total count runs into the hundreds.

Each NodePool is a versioned YAML document requiring review when Karpenter upgrades or requirements change. There is no built-in GitOps integration for NodePool lifecycle management, so teams typically bolt on ArgoCD or Flux, adding another layer to maintain.

At 10 clusters with 15 NodePools each, that is 150 NodePool specs to keep synchronized. One upstream Karpenter change – say, a deprecation in v1 – needs testing across all 150. One policy change, shifting consolidation from WhenEmpty to WhenEmptyOrUnderutilized, requires updating every affected NodePool, testing in staging, and rolling changes through each cluster’s Helm deployment individually. There is no fleet-wide upgrade controller: Karpenter has no single-click upgrade path, and each cluster requires its own helm upgrade with compatibility testing against that cluster’s specific NodePool configurations and any local modifications that have drifted from the baseline.

EC2NodeClass drift is the most common failure mode when AMIs update: if the referenced AMI ID in an EC2NodeClass becomes invalid, new node provisioning fails silently until an engineer investigates. Disruption budget conflicts during consolidation, where a PodDisruptionBudget blocks eviction and the consolidation loop stalls, are another routine issue that requires manual intervention at scale. Version upgrades require careful migration testing because Karpenter’s behavior can shift between releases. The config drift accumulated across clusters means you are rarely upgrading from the same baseline twice. Some clusters carry local NodePool modifications that conflict with the new version’s requirements, and surfacing those conflicts takes engineering time proportional to fleet size. For platform teams managing dozens of clusters across environments and regions, NodePool governance becomes a meaningful and ongoing fraction of infrastructure work.

The gap-cost-close summary

LimitationWhat it costsWhat closes it
No workload rightsizing69% average CPU overprovisioning; ~50% recoverable waste from requests alonePrecisionPack / VPA
Single cloud (AWS-primary)Separate tooling per cloud, no unified Spot strategy, no fleet coordinationMulti-cloud scheduler
One cluster at a timeConfig drift, manual policy propagation, no fleet-level reportingFleet management layer
No commitment awarenessSpot capacity provisioned alongside idle Reserved InstancesRI/SP optimization layer
No cost visibilityNo chargeback data, no namespace attribution, no FinOps reportingOpenCost / Kubecost / Cast AI
Operational burdenEngineering time on NodePool sprawl, version migrations, and drift remediationAutomation / Cast AI

What Karpenter is still the right answer for

When open-source Karpenter is sufficient

Karpenter is the right answer for AWS-primary teams that need fast, intelligent node provisioning and are not yet at the scale where fleet management, commitment coordination, or workload rightsizing are the primary cost drivers. It works well when your infrastructure is AWS-primary with a single-digit cluster count, your resource requests are reasonably calibrated, your RI/SP portfolio is small or managed manually, and your platform team can absorb NodePool lifecycle overhead.

The tool is genuinely excellent at what it does. Organizations that adopt Karpenter for node provisioning get a real, measurable improvement over Cluster Autoscaler, particularly in provisioning speed and Spot utilization. The Karpenter ecosystem tools guide covers the complementary tooling that fills the gaps described in this post, for teams ready to build that layer.

A simple decision test: if your answer to all three of these is yes, open-source Karpenter is probably sufficient. If any answer is no, the gaps become costs.

  1. Are your workloads running at consistent utilization? (No rightsizing needed if requests are accurate)
  2. Are you single-cloud AWS-only? (Multi-cloud needs a different scheduler)
  3. Are you running one cluster? (Two or more clusters need fleet governance)

If you are at the evaluation stage, migrating from Cluster Autoscaler to Karpenter covers the initial setup well.

Closing the gaps

What to add when Karpenter scope is not enough

Closing all six gaps requires tools that sit alongside Karpenter, not in place of it. The pattern that works at enterprise scale: automated workload rightsizing (VPA or Cast AI PrecisionPack) addresses Limitation 1. A multi-cloud scheduler handles Limitation 2. A fleet management layer handles Limitation 3. An RI/SP optimization engine handles Limitation 4. A Kubernetes cost allocation tool handles Limitation 5. A centralized NodePool governance layer handles Limitation 6. None of these are built into Karpenter, and none need to be.

For teams where one or more of these gaps carries a measurable cost, the paths forward depend on which gap matters most. For workload rightsizing, closing the gap means aligning requests with actual runtime usage data rather than worst-case declarations. VPA achieves this manually; automated rightsizing through PrecisionPack does it continuously, and Container Live Migration handles relocation to correctly sized nodes without pod restarts, which matters most for stateful workloads. For multi-cluster governance, a fleet management layer sits above individual Karpenter instances and applies unified policy, tracks drift, and aggregates reporting. For commitment management, an external RI/SP coordination layer shapes provisioning toward committed capacity before falling back to Spot; without it, the ~98% utilization target is not achievable.

Conclusion

Karpenter has six capability gaps at enterprise scale: no workload rightsizing, single-cloud architecture, one-cluster-at-a-time operation, no commitment awareness, no cost visibility, and meaningful operational overhead as fleet size grows. These are scope decisions, not defects. Karpenter does exactly what it describes, and it does that well.

The 69% CPU overprovisioning figure is the most actionable data point here. A cluster with perfect consolidation can still waste two-thirds of its allocated compute because the requests Karpenter provisions against do not reflect actual usage. Fixing that requires a rightsizing layer operating on actual runtime data, not declared intent.

If your Karpenter deployment is running correctly but cost reduction has plateaued, the post on why Karpenter isn’t reducing costs maps the specific causes and what each one points to. The specific question for your cluster: how much of your GPU or CPU spend is going to idle capacity because requests outrun actual usage? Cast AI’s GPU and node cost reports answer that in one view.

Frequently Asked Questions

What are the limitations of Karpenter?

The primary Karpenter limitations cover six areas: it does not rightsize workload requests, so clusters carry on average 69% more CPU allocation than workloads consume (Cast AI 2026 report); it is production-grade on AWS only; each instance manages one cluster with no fleet-level view or cross-cluster policy; it has no awareness of Reserved Instances or Savings Plans; it provides no cost attribution or chargeback reporting; and managing it at scale requires substantial NodePool governance effort across version upgrades and configuration drift.

Does Karpenter rightsize workloads?

No. Karpenter provisions nodes based on pod resource requests and does not observe actual usage or adjust requests accordingly. According to the Cast AI 2026 State of Kubernetes Optimization Report, pods request 69% more CPU than they use on average. This means a Karpenter-managed cluster can be efficiently packed against requests while still carrying substantial idle compute. Workload rightsizing requires a separate tool such as VPA or Cast AI’s PrecisionPack.

Does Karpenter work on Azure or GCP?

On Azure, Microsoft’s AKS Node Auto Provisioning (NAP), which reached GA in July 2025, wraps Karpenter internally, though users interact with it through Microsoft’s abstraction layer rather than direct NodePool configuration. On GCP, there is no official Karpenter provider; a community alpha exists but is not production-equivalent. For multi-cloud organizations, this means running separate provisioning systems per cloud with no shared policy or coordination between them.

Can Karpenter manage multiple clusters?

No. Each Karpenter instance manages exactly one cluster. There is no built-in fleet management, cross-cluster policy distribution, or consolidated reporting. Multi-cluster environments require external tooling to manage NodePool configuration drift and enforce consistent provisioning behavior across the fleet.

Does Karpenter understand Reserved Instances?

No. Karpenter has very limited support for Reserved Instances and Savings Plans, as documented in GitHub issue #8173. Manual NodePool weights and limits can approximate commitment-aware provisioning, but the Karpenter maintainers describe this workaround as “toilsome and leads to inefficient utilization.” Without an external coordination layer, Karpenter can provision Spot capacity while committed Reserved Instance capacity sits idle, paying for both simultaneously.

Is Karpenter enough on its own?

For small AWS-primary teams with a single-digit cluster count and manageable commitment portfolios, Karpenter is often sufficient. At enterprise scale, the gaps in workload rightsizing, multi-cluster management, commitment awareness, and cost visibility typically require complementary tools. The right answer depends on your fleet size, cloud strategy, and how much of the 69% CPU overprovisioning gap your organization can afford to leave unaddressed.

Cast AIBlogOpen-Source Karpenter Limitations: What the Gaps Are at Enterprise Scale