About the Karpenter NodePool Generator
A Karpenter NodePool is a set of constraints rather than a description of a node. You state which instance families, architectures, capacity types and zones are acceptable, and Karpenter picks something that satisfies both those bounds and the pending pods. Writing one is mostly deciding how much freedom to grant.
Too narrow is the common error. Restricting to a single instance type recreates the node group rigidity Karpenter exists to remove, and it makes spot capacity fragile — diversification across families and sizes is what keeps interruption rates low. Give it a broad list unless a workload genuinely requires specific hardware.
Disruption settings are the half people skip. Consolidation replaces under-utilised nodes during normal operation, which is where the savings come from, and expiry caps how long a node lives so patched AMIs actually roll out. Both move workloads, so budgets and PodDisruptionBudgets need to reflect what your applications tolerate.
Frequently asked questions
How broad should the instance type list be?
Broader than feels comfortable. Listing several families and a range of sizes lets Karpenter bin-pack properly and, on spot, spread across pools so a single pool's interruption does not take everything. Narrow it only where a workload needs specific hardware, and prefer expressing that as a requirement on architecture or capability rather than a hardcoded instance type.
What is the difference between a NodePool and an EC2NodeClass?
The NodePool holds scheduling constraints and disruption policy — what may be provisioned and when it may be replaced. The EC2NodeClass holds AWS-specific configuration such as AMI family, subnets, security groups and instance profile. One EC2NodeClass is commonly shared by several NodePools that differ only in their constraints.
How do I stop consolidation disrupting sensitive workloads?
Set realistic PodDisruptionBudgets on those workloads and use disruption budgets on the NodePool to bound how much churn can happen at once. For genuinely undisruptable pods, the do-not-disrupt annotation blocks voluntary eviction — use it sparingly, because a node that cannot be consolidated stays around and undermines the cost model.
Should I set an expiry on nodes?
Yes, in almost all cases. Without expiry, a long-lived node keeps running an old AMI indefinitely, so security patches never roll out. Expiry forces regular replacement, which also keeps you honest about whether workloads tolerate rescheduling — a cluster that cannot replace a node is one that cannot be patched.
Can I run Karpenter alongside existing managed node groups?
Yes, and it is the normal migration path. Keep existing node groups for workloads you have not moved, and use labels and taints so both provisioners are not competing for the same pending pods. Treat it as a transition rather than a permanent arrangement, since running two autoscaling models indefinitely doubles what you have to reason about.