Skip to main content
Karpenter is an open-source node provisioner for Kubernetes. Instead of pre-provisioning fixed node groups, Karpenter watches for unschedulable pods and immediately provisions the right instance type at the right size. It decommissions nodes when they are no longer needed, reducing waste. This example uses the modules/karpenter sub-module to create the required IAM roles, SQS queue (for spot interruption handling), and pod identity association. A small EKS managed node group labelled karpenter.sh/controller: "true" is created as a stable landing zone for the Karpenter controller itself — Karpenter should not run on nodes it manages.

Prerequisites

  • AWS credentials with permissions to create EKS, EC2, IAM, SQS, and VPC resources
  • Terraform >= 1.5.7
  • AWS provider >= 6.28
  • Helm provider (the example installs Karpenter via a Helm chart)
  • aws CLI installed locally (used by the Helm provider to authenticate)
The example pulls the Karpenter Helm chart from the public ECR (public.ecr.aws/karpenter). An aws_ecrpublic_authorization_token data source is used to authenticate, and it must be fetched from the us-east-1 region regardless of where your cluster runs.

Example code

The following is the complete main.tf from examples/karpenter.

How the Karpenter sub-module works

The modules/karpenter sub-module creates the AWS infrastructure that Karpenter needs to function:

Discovery tags

Karpenter uses two discovery tags to find the resources it should manage:
Only one security group per AWS account should carry the karpenter.sh/discovery tag. If multiple clusters share the same account, each must use a distinct cluster name as the tag value.

Karpenter controller isolation

The managed node group uses the label karpenter.sh/controller: "true". The Karpenter Helm values target this label via nodeSelector, ensuring the controller always runs on the stable, non-Karpenter-managed node group:

After installation: NodePool and EC2NodeClass

The Helm chart installs the Karpenter controller but does not create any NodePool or EC2NodeClass resources. You must apply those separately. The role name passed to EC2NodeClass must exactly match node_iam_role_name in the sub-module:

Deploy

1

Initialize Terraform

2

Review the plan

3

Apply

Cluster creation plus the Helm release typically takes 15–20 minutes.
4

Configure kubectl

5

Verify Karpenter is running

6

Apply NodePool and EC2NodeClass

Apply the sample manifests from the repository to start provisioning nodes:

Key outputs

Full example on GitHub

View the complete example including sample NodePool / EC2NodeClass manifests (karpenter.yaml) and a test deployment (inflate.yaml).