Skip to content

EKS with Karpenter Autoscaling (v1)

karpenter

Karpenter is a high-performance, open-source Kubernetes node autoscaler built by AWS. Unlike the legacy Kubernetes Cluster Autoscaler — which is bound to EC2 Auto Scaling Groups — Karpenter evaluates unscheduled pod resource requirements directly and provisions optimal EC2 instances in seconds.

Key Benefits of Karpenter v1

  • Cost-Optimized Provisioning: Automatically selects the most cost-effective instance types, including Spot instances.
  • Sub-Minute Scaling: Boots up right-sized instances directly via EC2 Fleet API without ASG latency.
  • Automated Node Consolidation: Continuously packs workloads and terminates underutilized nodes (WhenEmptyOrUnderutilized).
  • Drift & Lifecycle Management: Automatically recycles nodes when AMIs change or max expiration thresholds (expireAfter) are reached.

📁 Source Code: aws-eks-terraform / EKS-Cluster-karpenter-V1


📺 Video Walkthrough


Architecture & Karpenter v1 Constructs

Karpenter v1 uses two decoupled Custom Resource Definitions (CRDs):

graph LR
    NP["NodePool (karpenter.sh/v1)<br/>Limits, Constraints, Disruption"] --> |nodeClassRef| NC["EC2NodeClass (karpenter.k8s.aws/v1)<br/>AMI, Subnets, Security Groups, IAM Role"]
  1. EC2NodeClass: Controls AWS-specific infrastructure settings (AMI family, subnets, security groups, instance profile/IAM role, storage, block device mappings).
  2. NodePool: Defines scheduling constraints, resource limits (CPU/Memory), instance requirements (arch, capacity type, generation), and disruption/consolidation policies.

Karpenter Configuration

1. Helm Values (karpenter-values.yaml)

settings:
  clusterName: eks-demo
replicas: 2
serviceAccount:
  name: "karpenter-controller"
  annotations:
    eks.amazonaws.com/role-arn: "arn:aws:iam::<AWS-ACCOUNT-ID>:role/karpenter-controller-eks-demo"

2. EC2NodeClass (ec2nodeclass.yaml)

apiVersion: karpenter.k8s.aws/v1
kind: EC2NodeClass
metadata:
  name: karpenter-default
spec:
  amiFamily: AL2023 # Alternatively: Bottlerocket
  amiSelectorTerms:
    - alias: al2023@latest
  role: "karpenter-node-eks-demo"
  subnetSelectorTerms:
    - tags:
        karpenter.sh/discovery: "eks-demo" # Subnet must have this tag
  securityGroupSelectorTerms:
    - tags:
        karpenter.sh/discovery: "eks-demo" # Node security group tag
  tags:
    Name: karpenter-provisioned-node
    Environment: dev

3. NodePool (nodepool.yaml)

apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: karpenter-default
spec:
  template:
    spec:
      nodeClassRef:
        group: karpenter.k8s.aws
        kind: EC2NodeClass
        name: karpenter-default
      requirements:
        - key: "karpenter.k8s.aws/instance-hypervisor"
          operator: In
          values: ["nitro"]
        - key: kubernetes.io/arch
          operator: In
          values: ["amd64"]
        - key: kubernetes.io/os
          operator: In
          values: ["linux"]
        - key: karpenter.sh/capacity-type
          operator: In
          values: ["spot", "on-demand"]
        - key: karpenter.k8s.aws/instance-category
          operator: In
          values: ["c", "m", "r"]
        - key: karpenter.k8s.aws/instance-generation
          operator: Gt
          values: ["5"]
  limits:
    cpu: 50
    memory: 100Gi
  disruption:
    consolidationPolicy: WhenEmptyOrUnderutilized
    consolidateAfter: 1m
    expireAfter: 336h # 14 days

Installation & Deployment

# 1. Apply Terraform to create VPC, EKS cluster, and Karpenter IAM roles
terraform init -upgrade
terraform apply

# 2. Update kubeconfig
aws eks --profile labs --region eu-west-1 update-kubeconfig --name eks-demo

# 3. Install Karpenter controller Helm chart
helm install karpenter oci://public.ecr.aws/karpenter/karpenter \
  --version 1.0.6 \
  --namespace karpenter \
  --create-namespace \
  -f Karpenter-app/karpenter-values.yaml

# 4. Apply EC2NodeClass and NodePool
kubectl apply -f Karpenter-app/karpenter-nodeclass.yaml
kubectl apply -f Karpenter-app/karpenter-nodepool.yaml

# 5. Verify custom resources
kubectl get ec2nodeclass,nodepool

Testing Karpenter Autoscaling

Deploy a test workload requesting significant CPU to trigger Karpenter node provisioning:

scale-test.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: inflate
  namespace: default
spec:
  replicas: 5
  selector:
    matchLabels:
      app: inflate
  template:
    metadata:
      labels:
        app: inflate
    spec:
      containers:
        - name: inflate
          image: public.ecr.aws/eks-distro/kubernetes/pause:3.7
          resources:
            requests:
              cpu: "1"
              memory: "1Gi"

# Apply workload
kubectl apply -f scale-test.yaml

# Stream Karpenter controller logs to watch provisioning
kubectl logs -f -n karpenter -l app.kubernetes.io/name=karpenter -c controller

# Observe new EC2 nodes spinning up
kubectl get nodes -w