Skip to content

Karpenter Custom NodePool as Default

karpenter

Amazon EKS Auto Mode comes pre-configured with Karpenter and a default general-purpose NodePool that provisions on-demand AMD64 instances with a default weight of 0.

While this ensures any standard pod can schedule immediately, production environments often demand customized compute defaults — such as prioritizing Spot instances, enforcing ARM64 (Graviton) for cost efficiency, or consuming pre-purchased Savings Plans / Reserved Instances.

This guide demonstrates how to define a custom NodePool with higher scheduling priority to override the default EKS Auto NodePool.


📺 Video Walkthrough


How Karpenter Weighted Scheduling Works

Karpenter allows you to prioritize NodePools using the spec.weight attribute:

graph TD
    Pod["Incoming Pod (Pending)"] --> Karpenter["Karpenter Autoscaler"]
    Karpenter --> Eval{"Evaluate NodePool Weights"}
    Eval -- "Weight: 50 (Selected First)" --> PrimNP["Custom Primary NodePool<br/>(Spot + On-Demand, Graviton/AMD64)"]
    Eval -- "Weight: 0 (Fallback)" --> DefNP["AWS Default NodePool<br/>(On-Demand AMD64)"]
  • When evaluating pending pods, Karpenter sorts eligible NodePools in descending order by weight.
  • A NodePool with weight: 50 is evaluated before a NodePool with weight: 0.
  • If the primary NodePool cannot satisfy the pod requirements (e.g. Spot capacity unavailable or limit reached), Karpenter falls back to subsequent lower-weighted pools.

Step 1. Define the Custom Primary NodePool

The NodePool below sets weight: 50 and allows both spot and on-demand capacity types across c, m, and r instance categories.

primary-nodepool.yaml

apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: primary-nodepool
spec:
  weight: 50 # Higher priority than EKS Auto default (0)
  template:
    spec:
      expireAfter: 336h
      nodeClassRef:
        group: eks.amazonaws.com
        kind: NodeClass
        name: default
      requirements:
        - key: karpenter.sh/capacity-type
          operator: In
          values: ["spot", "on-demand"]
        - key: eks.amazonaws.com/instance-category
          operator: In
          values: ["c", "m", "r"]
        - key: eks.amazonaws.com/instance-generation
          operator: Gt
          values: ["5"]
        - key: kubernetes.io/arch
          operator: In
          values:
            - amd64
            - arm64
        - key: kubernetes.io/os
          operator: In
          values:
            - linux
      terminationGracePeriod: 24h0m0s


Step 2. Apply and Verify Scheduling Priority

# 1. Apply the primary NodePool
kubectl apply -f primary-nodepool.yaml

# 2. Verify registered NodePools and weights
kubectl get nodepools -o custom-columns=NAME:.metadata.name,WEIGHT:.spec.weight

# 3. Deploy a standard workload without any special tolerations or selectors
kubectl create deployment nginx-test --image=nginx --replicas=3

# 4. Confirm that new nodes were provisioned by primary-nodepool
kubectl get nodeclaims -o wide

When checking the provisioned NodeClaim, Karpenter will record primary-nodepool as the owner, preferring Spot instances and multi-arch nodes.


Advanced Use Case: Reserved Capacity Prioritization

If your AWS account has purchased Savings Plans or Regional Reserved Instances for specific instance families (e.g. m6i.large), you can set a custom NodePool targeting m6i On-Demand with weight: 100. Karpenter will continuously saturate your committed capacity before falling back to Spot or general-purpose instances.