Skip to content

Karpenter — Deploy to a Specific Node Type

karpenter

Amazon EKS Auto Mode includes Karpenter pre-installed with a default general-purpose NodePool that provisions standard AMD64 on-demand instances.

However, specialized workloads often require specific instance families (e.g. Memory-Optimized r series, Compute-Optimized c series, GPU instances, or Spot instances).

By combining custom Karpenter NodePools with Kubernetes taints, tolerations, and nodeSelectors, you can pin specific workloads to tailor-made EC2 instance types while preventing other pods from scheduling on them.

NodeClass Scope

In EKS Auto Mode, the default NodeClass (group: eks.amazonaws.com) is managed by AWS. You can reference it directly in your custom NodePools without creating a custom NodeClass unless you need bespoke subnets or storage.


📺 Video Walkthrough


Architecture: Workload Pinning with Taints & Labels

graph TD
    Pod["Pod with Toleration & nodeSelector<br/>(instancegroup: spot-m)"]
    DefaultNP["Default NodePool<br/>(General Purpose On-Demand)"]
    SpotMNP["Custom NodePool: spot-m-nodepool<br/>Taint: instance-type=spot-m:NoSchedule<br/>Label: instancegroup=spot-m-instancegroup"]

    Pod -. "Bypasses Taint & Matches Label" .-> SpotMNP
    SpotMNP --> EC2["EC2 Memory-Optimized Spot Instance (m7i, m6i)"]

Step 1. Define Custom NodePool with Taints & Labels

The NodePool below restricts instance generation to m series Spot instances, applies a label to newly created nodes, and places a NoSchedule taint so general workloads do not schedule here.

spot-m-nodepool.yaml

apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: spot-m-nodepool
spec:
  template:
    metadata:
      labels:
        instancegroup: spot-m-instancegroup
    spec:
      expireAfter: 336h
      nodeClassRef:
        group: eks.amazonaws.com
        kind: NodeClass
        name: default
      requirements:
        - key: karpenter.sh/capacity-type
          operator: In
          values: ["spot"]
        - key: eks.amazonaws.com/instance-category
          operator: In
          values: ["m"]
      taints:
        - key: instance-type
          value: "spot-m"
          effect: NoSchedule


Step 2. Configure Application with Tolerations & NodeSelector

The deployment below specifies both: 1. tolerations: Allows the pod to tolerate the instance-type=spot-m:NoSchedule taint. 2. nodeSelector: Directs Karpenter to match the node label instancegroup: spot-m-instancegroup.

spot-m-echoserver.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: echoserver
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: echoserver
  template:
    metadata:
      labels:
        app: echoserver
    spec:
      nodeSelector:
        instancegroup: spot-m-instancegroup
      tolerations:
        - key: "instance-type"
          operator: "Equal"
          value: "spot-m"
          effect: "NoSchedule"
      containers:
        - name: demo-echo
          image: k8s.gcr.io/e2e-test-images/echoserver:2.5
          ports:
            - containerPort: 8080
          resources:
            requests:
              cpu: "500m"
              memory: "512Mi"


Verification

# 1. Apply NodePool and Deployment
kubectl apply -f spot-m-nodepool.yaml
kubectl apply -f spot-m-echoserver.yaml

# 2. Watch Karpenter provision the dedicated Spot instance
kubectl get nodeclaims -o wide

# 3. Verify the pod is running on the newly created node
kubectl get pods -l app=echoserver -o wide