- Define taints to limit which pods run on Karpenter-managed nodes
- Define startup taints that are temporary and removed by another system (e.g., a DaemonSet)
- Limit node creation to certain zones, instance types, and architectures
- Set defaults for node expiration
Objects for configuring kubelet features have been moved from the NodePool spec to the EC2NodeClass spec so other Karpenter providers are not required to support those fields.
- Karpenter won’t do anything if there is not at least one NodePool configured.
- Each NodePool is looped through when finding a placement for a pod.
- If Karpenter encounters a taint in the NodePool that is not tolerated by a pod, it won’t use that NodePool to provision the pod.
- If Karpenter encounters a startup taint, the taint is applied to the node, but pods don’t need to tolerate it.
- It is recommended to create mutually exclusive NodePools. If multiple NodePools match, Karpenter uses the one with the highest weight.
Full NodePool example
Field reference
spec.template.metadata
spec.template.metadata
spec.template.spec.nodeClassRef
spec.template.spec.nodeClassRef
Points to the cloud provider NodeClass resource. For AWS, this references an EC2NodeClass.See EC2NodeClasses for details.
spec.template.spec.taints and startupTaints
spec.template.spec.taints and startupTaints
spec.template.spec.taints
Taints added to provisioned nodes. Pods must tolerate these taints to be scheduled. See Taints and Tolerations.spec.template.spec.startupTaints
Taints applied to nodes on launch to indicate a condition (like network setup) that must be met before other pods schedule. Some other system (e.g., a DaemonSet) must remove these taints. Pods don’t need to tolerate startup taints to be provisioned by this NodePool.spec.template.spec.expireAfter
spec.template.spec.expireAfter
The maximum time a node can live on the cluster before Karpenter deletes it. Nodes begin draining when their expiration is reached.Set to Changes to
Never to disable expiration. Default is 720h (30 days).expireAfter on the NodePool cause drift on existing NodeClaims — they will be replaced with the updated value.spec.template.spec.terminationGracePeriod
spec.template.spec.terminationGracePeriod
The maximum time Karpenter waits for a node to drain before forcefully cleaning it up. Pods with blocking PDBs or the Changes to this field cause drift on existing NodeClaims.
karpenter.sh/do-not-disrupt annotation are respected until this period elapses, at which point they are forcibly deleted.spec.template.spec.requirements
spec.template.spec.requirements
Requirements constrain the parameters of provisioned nodes. These are combined with pod scheduling constraints such as
topologySpreadConstraints, nodeAffinity, podAffinity, and nodeSelector.Supported operators: In, NotIn, Exists, DoesNotExist, Gt, Lt, Gte, Lte.There is a limit of 100 on the total number of requirements on both the NodePool and the NodeClaim.
spec.template.metadata.labels are also propagated as requirements when a NodeClaim is created, so you can’t have more than 100 requirements and labels combined.Well-known labels
The following labels can be used inspec.template.spec.requirements or in pod scheduling constraints.
Instance types
Instance types
| Label | Description |
|---|---|
node.kubernetes.io/instance-type | Specific instance type (e.g., m5.large) |
karpenter.k8s.aws/instance-family | Instance family (e.g., m5) |
karpenter.k8s.aws/instance-category | Instance category (e.g., c, m, r) |
karpenter.k8s.aws/instance-generation | Generation number within a category |
karpenter.k8s.aws/instance-cpu | Number of vCPUs |
karpenter.k8s.aws/instance-memory | Memory in MiB |
Availability zones
Availability zones
- Key:
topology.kubernetes.io/zone - Example value:
us-east-1c
The zone
us-east-1a for your AWS account may not correspond to the same physical location as us-east-1a in another account. Use Zone IDs for globally consistent references.Architecture
Architecture
- Key:
kubernetes.io/arch - Values:
amd64,arm64
Operating system
Operating system
- Key:
kubernetes.io/os - Values:
linux,windows
Capacity type
Capacity type
- Key:
karpenter.sh/capacity-type - Values:
spot,on-demand,reserved
reserved first, then spot, then on-demand. If a capacity type is unavailable, Karpenter falls back to the next priority within milliseconds.The
reserved capacity type refers to capacity reservations (on-demand capacity reservations and capacity blocks), not reserved instances (RIs).karpenter.sh/capacity-type can also be used as a topology key for topology spread constraints.Tenancy
Tenancy
- Key:
karpenter.k8s.aws/instance-tenancy - Values:
default,dedicated
dedicated tenancy, it launches on a Dedicated Instance.minValues
TheminValues field in requirements tells the scheduler to consider at least that number of unique values for a given key when scheduling pods. This ensures the scheduler maintains flexibility to avoid over-optimization onto a single instance type.
If Karpenter cannot meet the specified minimum, behavior depends on the --min-values-policy flag:
Strict— fail the scheduling loop, fall back to another NodePool or fail scheduling entirelyBestEffort— relaxminValuesuntil they can be met
minValues is defined multiple times for the same key, Karpenter uses the maximum of all defined values.
spec.disruption
The disruption block controls how Karpenter removes or replaces nodes.Determines which nodes are eligible for consolidation.
WhenEmptyOrUnderutilized— consider all nodes; remove or replace when empty or underutilizedWhenEmpty— only consider nodes with no workload pods
How long Karpenter waits after a pod is added or removed before considering the node for consolidation. Set to
Never to disable consolidation.Default: 0sRate limits on how many nodes Karpenter can disrupt at once. Karpenter uses the most restrictive budget. See Disruption budgets for details.
spec.replicas
Optional. Enables static capacity mode where the NodePool maintains a fixed number of nodes regardless of pod demand.- Cannot be removed once set (a NodePool cannot switch between static and dynamic modes)
- Only
limits.nodesis supported in the limits section weightcannot be set- Nodes are not considered for consolidation
- Scaling bypasses node disruption budgets (but respects PodDisruptionBudgets)
spec.limits
Constrains the total resources that this NodePool can consume. If unspecified, no limit is enforced (cloud provider quotas apply).limits.nodes is supported.
Karpenter provisioning is highly parallel so limit checking is eventually consistent. This can result in brief overruns during rapid scale-out events.
spec.weight
Sets the priority for this NodePool relative to others. Higher weight = higher priority. When no weight is specified, it defaults to0.
See Weighted NodePools for examples.
weight cannot be set on static NodePools (those with spec.replicas configured).status
| Field | Description |
|---|---|
status.nodes | Current number of nodes managed by this NodePool |
status.resources | Current consumption of cpu, memory, and ephemeral-storage |
status.conditions | Readiness conditions |
Status conditions
| Condition | Description |
|---|---|
NodeClassReady | The referenced NodeClass is ready |
ValidationSucceeded | CRD validation passed |
Ready | All conditions are true; NodePool is considered for scheduling |
Examples
GPU workloads with isolation
GPU workloads with isolation
A NodePool that only provisions GPU nodes and requires pods to explicitly tolerate the GPU taint:Pods must tolerate
nvidia.com/gpu to schedule on these nodes.Static NodePool
Static NodePool
Maintain a fixed pool of 10 nodes in a single availability zone:
Cilium startup taint
Cilium startup taint
Per the Cilium docs, place a taint on nodes to allow Cilium to configure networking before other pods start: