What is Karpenter? How it picks and removes nodes

It launches nodes for pending pods and removes the ones it no longer needs. NodePools, EKS, AKS and its limits.

Published 1 November 2026 · By Swati Bhatia (opens in a new tab), Backend engineer, Zoorik · Published by Zoorik

What is Karpenter? It launches a node for pending pods and removes the node once it is empty

Short answer. Karpenter is an open-source Kubernetes node autoscaler that launches nodes sized to pending pods and removes underused ones or replaces them with cheaper machines. On Amazon EKS you run it yourself, EKS Auto Mode builds on it, and on AKS it runs as node auto-provisioning (NAP).

What is Karpenter in Kubernetes, and what is it used for?

Picture ten pods that each request 2 CPU. They’re pending, because no node in the cluster can fit them. Karpenter adds up their requests, 20 CPU in all, and allows for node overhead and DaemonSets.

It then picks a machine type with room for all of it and launches a node. When the pods finish and leave the node empty, Karpenter deletes it.

That’s the job of a node autoscaler: it changes how many machines a cluster runs. It adds a node when pods are waiting for room, and removes one the pods no longer need. Kubernetes SIG Autoscaling sponsors two of them: the Cluster Autoscaler and Karpenter.

The Kubernetes docs draw the difference in a sentence each. Cluster Autoscaler, they say, “adds or removes Nodes to pre-configured Node groups”. So every machine type it can use has to be set up in advance.

Karpenter works with individual virtual machines and doesn’t rely on cloud resource groups. That lets it pick a different machine type for each node it launches. For how each one removes nodes, see Karpenter vs Cluster Autoscaler.

Karpenter is used for three jobs:

  • Launching nodes for pending pods, with a machine type picked to fit them.
  • Consolidation, which deletes empty nodes and replaces underused ones with fewer or cheaper machines.
  • Node lifecycle, which replaces nodes that reach a set age or no longer match their configuration. It also drains spot nodes before the cloud takes them back.

Karpenter sizes a new node from the pending pods’ requests

The loop starts with pending pods that no node has room for. Karpenter batches those pods and bin-packs them by the CPU, memory and GPUs they request.

On top of those requests, it adds the node’s own overhead and the DaemonSets that will run on the new node. The EKS and AKS pricing calculator shows how much of a node type your pods can use, and what it costs a month.

Each new node must also fit the NodePool the pods match. A NodePool is the resource you write to tell Karpenter what it may launch. It can restrict capacity type, zones, instance types and architectures.

Karpenter does all of this from requests alone. The Kubernetes docs say node autoscalers “don’t directly take into account the real resource usage of the Pods after they start running”. So the ten pods from the opening get room for 20 CPU, plus overhead, however little of it they use.

Karpenter sizes a new node from the pods' requests alone Four boxes read top to bottom, joined by downward arrows. 10 pending pods, 2 CPU requested each, then an arrow labelled bin-packs by requests. 20 CPU of requests, plus node overhead and DaemonSets, highlighted as the subject with a teal requested mark, then an arrow labelled checked against. NodePool rules: capacity type, zones, instance types, architectures, then an arrow labelled picks a type that fits. New node joins. To the right of the 20 CPU box, a dashed box with a violet used mark, What the pods use once running, points at it with a dashed arrow labelled not read. 20 CPU is 10 pods times 2 CPU. Karpenter sizes a new node from the pods' requests alone 10 pending pods2 CPU requested eachbin-packs by requests20 CPU of requestsplus node overhead and DaemonSetschecked againstNodePool rulescapacity type, zones, instance types, architecturespicks a type that fitsNew node joinsWhat the pods useonce runningnot read
Illustration: the ten pods from the opening, each requesting 2 CPU.

For on-demand capacity, the Karpenter FAQ says Fleet effectively picks the lowest-priced type. For spot, Fleet weighs price against the chance of interruption, so the result may not be the strictly cheapest spot type.

A Karpenter NodePool limits the nodes it launches, and a node class sets them up

The Karpenter docs say a NodePool “sets constraints on the nodes that can be created by Karpenter”. It also sets constraints on the pods that can run on those nodes.

Its requirements use well-known node labels, such as kubernetes.io/arch (amd64 or arm64) and karpenter.sh/capacity-type (spot, on-demand or reserved). When a NodePool allows more than one capacity type, Karpenter prefers reserved capacity, then spot, then on-demand.

What you leave out matters as much as what you write. If a requirement isn’t set for a well-known label, Karpenter may choose any value the cloud offers.

So requirements: [] opens the pool to every instance type your provider supports.

When several NodePools match a pod, Karpenter uses the one with the highest weight. The docs still recommend NodePools that don’t overlap.

The spec.limits field caps the total resources, such as CPU and memory, that the pool’s nodes can add up to. The example below sets 1,000 CPU and 1000Gi of memory.

apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: default
spec:
  template:
    spec:
      requirements:
        - key: kubernetes.io/arch
          operator: In
          values: ["amd64"]
        - key: karpenter.sh/capacity-type
          operator: In
          values: ["on-demand"]
        - key: karpenter.k8s.aws/instance-category
          operator: In
          values: ["c", "m", "r"]
      nodeClassRef:
        group: karpenter.k8s.aws
        kind: EC2NodeClass
        name: default
      expireAfter: 720h
  limits:
    cpu: "1000"
    memory: 1000Gi
  disruption:
    consolidationPolicy: WhenEmptyOrUnderutilized
    consolidateAfter: 1m

The nodeClassRef points to a node class, the cloud provider’s own resource for machine settings. That’s an EC2NodeClass on AWS and an AKSNodeClass on AKS. A NodePool says which machines are allowed, and its node class says how each one is set up.

Karpenter removes nodes whose pods fit elsewhere, and replaces old ones

Karpenter’s word for removing nodes is disruption, and consolidation is the method that reduces cost.

Consolidation deletes or replaces underused nodes

Consolidation deletes empty nodes in parallel. It also tries to delete one node, or two or more at once, launching at most one replacement.

A node can be deleted when all its pods fit in free capacity on other nodes. It can be replaced when they fit in that free capacity plus one cheaper node.

Consolidation deletes a node whose pods fit elsewhere, or replaces it with one cheaper node Two panels with the same three nodes. Small grey blocks are pods and amber blocks are free room for one pod. Delete: Node A, dashed and labelled deleted, holds 2 pods. Node B and Node C each hold 2 pods and have free room for 1 pod, and arrows labelled move to free room carry one of Node A's pods to each. Replace: Node A, dashed and labelled replaced, holds 3 pods. Two move to the free room on Node B and Node C, and the third goes by an arrow labelled launches one to a smaller, highlighted box, 1 cheaper node. Block counts are an illustration. Consolidation deletes a node whose pods fit elsewhere, or replaces it with one cheaper node podfree room for one podDeleteNode AdeletedNode BNode Cmove to free roomReplaceNode AreplacedNode BNode Cmove to free room1 cheaper nodelaunches one
Illustration with no measured sizes: Replace differs only in Node A’s third pod and the one cheaper node it goes to.

Three fields in the NodePool’s disruption block decide how far it goes:

FieldWhat it setsDefault
consolidationPolicy
WhenEmpty considers only empty nodes, whose pods all have no disruption cost, such as DaemonSet pods. WhenEmptyOrUnderutilized also considers underused nodes. Balanced weighs the share of the NodePool’s cost an action saves against the share of its pod disruption it causes. It acts only when the saving is large enough.
WhenEmptyOrUnderutilized
consolidateAfter
How long Karpenter waits after a pod is added to or removed from a node before that node becomes a candidate. Never turns consolidation off for that NodePool.
0s
budgets
How many of the pool’s nodes may be disrupted at once. Percentages round up.
One budget of nodes: 10%

Consolidation reads the same numbers as provisioning. In the Kubernetes docs’ words, it “only considers Pod resource requests and not real resource usage when making decisions”.

A node full of pods that request far more than they use looks busy, so Karpenter keeps it. Karpenter consolidation covers the policies and budgets in depth.

Expiration, interruption and drift replace nodes

Karpenter also replaces nodes for age, interruptions and changed settings. Expiration and interruption are the automated forceful methods: they start draining a node as soon as their condition is met. Drift is graceful.

  • Expiration drains and removes a node once it’s older than the NodePool’s expireAfter, which defaults to 720h, or 30 days. Set it to Never if nodes shouldn’t age out.
  • Interruption handling drains a node ahead of events such as a spot interruption. On AWS, a spot interruption comes with a 2-minute notice. Interruption handling there needs an SQS queue and EventBridge rules that send it those events.
  • Drift replaces nodes that no longer match a changed NodePool or node class.

To keep a pod where it is, add the do-not-disrupt annotation, karpenter.sh/do-not-disrupt: "true". Consolidation then leaves that pod’s node alone.

Drift does too, unless the node was created with a terminationGracePeriod from its NodePool. Still, the annotation isn’t a hard guarantee. The docs say it “does not exclude nodes from the forceful disruption methods”, so those methods still apply.

Who runs Karpenter on EKS and AKS: you, AWS or Microsoft

Karpenter isn’t tied to one cloud. The Kubernetes project publishes it as a library that cloud providers build on to make their own node autoscaler.

AWS was the first provider, and Azure has one too. In October 2026, the newest release line of the shared project is Karpenter 1.15.

What is Karpenter in EKS and AWS?

On a standard Amazon EKS cluster, Karpenter is software you run. AWS describes it as “open-source software which AWS customers are responsible for installing, configuring, and managing in their Kubernetes clusters”.

AWS gives technical support when you run it unmodified, at a compatible version, on EKS. But there’s no AWS Service Level Agreement for it.

Karpenter publishes the Kubernetes versions each of its releases supports. AWS asks you to test when you upgrade either Karpenter or the cluster.

EKS Auto Mode is the managed route. AWS says Auto Mode “builds upon Karpenter”, and AWS runs its scaling for you. It creates a node when a pod can’t fit, consolidates workloads and deletes nodes.

Auto Mode ships default NodePools and NodeClasses that you shouldn’t edit, and you add your own beside them. By default it terminates nodes after 336 hours (14 days). No node lives more than 21 days, a limit you can make shorter.

Karpenter on AKS: node auto-provisioning

On AKS, Microsoft can run Karpenter for you. NAP deploys and manages it on your cluster, built on the open-source project and the AKS Karpenter provider.

You write NodePool and AKSNodeClass resources, and NAP shows the nodes it launches as NodeClaims. NAP comes preconfigured on AKS Automatic clusters.

It doesn’t support Windows node pools or IPv6 clusters. To turn it on, see how to enable AKS node auto-provisioning.

Karpenter never changes the requests it sizes nodes from

Karpenter chooses and removes machines from the requests it’s given, and it never edits them. A container whose request is four times its real use gets four times the room. That holds on whatever machine type Karpenter picks.

Consolidation counts requests the same way, so it keeps that room too. Even a carefully tuned NodePool pays for every request that’s set too high, which is the limit of Karpenter cost optimization.

The pods use 10 × 0.5 = 5 CPU of it. That leaves 20 − 5 = 15 CPU reserved and idle, three-quarters of the requested CPU. That’s because each request is 2 ÷ 0.5 = 4 times its use.

Ten pods reserve 20 CPU to run 5 CPU of work Two bars for the same 10 pods on one shared CPU scale from 0 to 20, with ticks at 0, 5, 10, 15 and 20. Requested: a teal bar to 20 CPU, 10 times 2 CPU. Used: a violet bar to 5 CPU, 10 times 0.5 CPU, followed by an amber span from 5 to 20 CPU labelled 15 CPU reserved and idle, three-quarters of the requests. Illustration. Ten pods reserve 20 CPU to run 5 CPU of work Requested20 CPU (10 × 2 CPU)Used5 CPU (10 × 0.5 CPU)15 CPU reserved and idle, 3/4 of requests05101520CPU
Illustration: the opening’s ten pods, each requesting 2 CPU and using 0.5 CPU, before node overhead and DaemonSets.

Setting requests from measured use is a separate job, covered in Kubernetes pod right sizing. The Kubernetes cost optimization guide puts the two jobs in order: requests first, then nodes. HPA vs VPA vs Cluster Autoscaler shows which tool owns which layer: pod count, pod size or node count.

How Coral works with Karpenter

Coral optimizes Kubernetes on AKS and EKS, and it works on the layer Karpenter leaves alone. It rebalances CPU and memory requests to what containers really use. So the same Karpenter NodePools can run fewer or smaller nodes.

Coral never adds nodes for demand, so scaling up stays Karpenter’s job. Coral works with Karpenter sets out who does what, job by job.

  • Pools Karpenter already consolidates: Coral’s consolidation leaves them to Karpenter.
  • Protected workloads: Coral respects karpenter.sh/do-not-disrupt on pods and nodes. A marked pod is never moved and its node stays, and a marked node is kept.
  • Cheaper machines: where Karpenter runs, Coral can also move work to smaller or cheaper machines. Its rebalancing creates fixed-size NodePools named zoorik-rb-…, and your Karpenter launches the new machines. The old nodes are then drained and removed one by one.

If an EKS cluster has no node autoscaler yet, connecting it to Coral can install Karpenter, with your approval. Connect lists every cloud change and asks once. Its --dry-run prints every cloud command and every object it would install without changing anything.

Check two things before you approve. On a cluster that uses only aws-auth, installing Karpenter switches authentication to API_AND_CONFIG_MAP, and that can’t be undone. On AKS the same step turns on NAP, which needs Azure CNI, not kubenet.

Sources: Karpenter, “NodePools” (opens in a new tab); Karpenter, “Disruption” (opens in a new tab); Karpenter, “FAQs” (opens in a new tab); Kubernetes, “Node Autoscaling” (opens in a new tab); AWS, “Scale cluster compute with Karpenter and Cluster Autoscaler” (opens in a new tab); AWS, “Automate cluster infrastructure with EKS Auto Mode” (opens in a new tab); AWS, “Create a Node Pool for EKS Auto Mode” (opens in a new tab); Microsoft Learn, “Overview of Node Auto-Provisioning (NAP) in Azure Kubernetes Service (AKS)” (opens in a new tab).

Find your own number

One line in your cloud console. One PDF report with your estimated saving at list price.

Estimate your saving

Talk to the builders

Thirty minutes with the people who build Coral.

Book a demo (opens in a new tab)

Or write to founders@zoorik.com